Issue #3471932 by mstrelan, bbrala, quietone: Fix callables that are expected to return bool but don't

merge-requests/9796/head
catch 2024-10-09 14:24:23 +01:00
parent c5193b30d0
commit 3a3c8164c0
11 changed files with 111 additions and 9 deletions

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Drupal\Component\Utility;
/**
* Provides methods to filter arrays.
*
* @ingroup utility
*/
class FilterArray {
/**
* Removes empty strings from an array.
*
* This method removes all empty strings from the input array. This is
* particularly useful to preserve 0 whilst filtering other falsy values. The
* values are first cast to a string before comparison.
*
* @param array $value
* The array to filter.
*
* @return array
* The filtered array.
*/
public static function removeEmptyStrings(array $value): array {
return array_filter($value, static fn ($item) => (string) $item !== '');
}
}

View File

@ -2,6 +2,7 @@
namespace Drupal\Core\Datetime\Element;
use Drupal\Component\Utility\FilterArray;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Variable;
use Drupal\Core\Datetime\DateHelper;
@ -345,7 +346,7 @@ class Datelist extends DateElementBase {
// \Drupal\Core\Datetime\Element\Datelist::valueCallback().
unset($input['object']);
// Filters out empty array values, any valid value would have a string length.
$filtered_input = array_filter($input, 'strlen');
$filtered_input = FilterArray::removeEmptyStrings($input);
return array_diff($parts, array_keys($filtered_input));
}

View File

@ -2,6 +2,7 @@
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Component\Utility\FilterArray;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\Attribute\DataType;
use Drupal\Core\TypedData\ComplexDataInterface;
@ -92,7 +93,7 @@ class ItemList extends TypedData implements \IteratorAggregate, ListInterface {
$strings[] = $item->getString();
}
// Remove any empty strings resulting from empty items.
return implode(', ', array_filter($strings, 'mb_strlen'));
return implode(', ', FilterArray::removeEmptyStrings($strings));
}
/**

View File

@ -2,6 +2,7 @@
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Component\Utility\FilterArray;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\Attribute\DataType;
use Drupal\Core\TypedData\ComplexDataInterface;
@ -106,7 +107,7 @@ class Map extends TypedData implements \IteratorAggregate, ComplexDataInterface
$strings[] = $property->getString();
}
// Remove any empty strings resulting from empty items.
return implode(', ', array_filter($strings, 'mb_strlen'));
return implode(', ', FilterArray::removeEmptyStrings($strings));
}
/**

View File

@ -2,6 +2,7 @@
namespace Drupal\field\Plugin\migrate\process\d6;
use Drupal\Component\Utility\FilterArray;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
@ -27,7 +28,7 @@ class FieldInstanceOptionTranslation extends ProcessPluginBase {
if (isset($global_settings['allowed_values'])) {
$list = explode("\n", $global_settings['allowed_values']);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$list = FilterArray::removeEmptyStrings($list);
switch ($field_type) {
case 'boolean';
$option = preg_replace('/^option_/', '', $row->getSourceProperty('property'));

View File

@ -2,6 +2,7 @@
namespace Drupal\field\Plugin\migrate\process\d6;
use Drupal\Component\Utility\FilterArray;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
@ -29,7 +30,7 @@ class FieldOptionTranslation extends ProcessPluginBase {
if (isset($global_settings['allowed_values'])) {
$list = explode("\n", $global_settings['allowed_values']);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$list = FilterArray::removeEmptyStrings($list);
switch ($field_type) {
case 'list_string':
case 'list_integer':

View File

@ -2,6 +2,7 @@
namespace Drupal\field\Plugin\migrate\process\d6;
use Drupal\Component\Utility\FilterArray;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
@ -50,7 +51,7 @@ class FieldSettings extends ProcessPluginBase {
if (isset($global_settings['allowed_values'])) {
$list = explode("\n", $global_settings['allowed_values']);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$list = FilterArray::removeEmptyStrings($list);
switch ($field_type) {
case 'list_string':
case 'list_integer':

View File

@ -2,6 +2,7 @@
namespace Drupal\sqlite\Driver\Database\sqlite;
use Drupal\Component\Utility\FilterArray;
use Drupal\Core\Database\Connection as DatabaseConnection;
use Drupal\Core\Database\DatabaseNotFoundException;
use Drupal\Core\Database\ExceptionHandler;
@ -246,7 +247,7 @@ class Connection extends DatabaseConnection implements SupportsTemporaryTablesIn
*/
public static function sqlFunctionLeast() {
// Remove all NULL, FALSE and empty strings values but leaves 0 (zero) values.
$values = array_filter(func_get_args(), 'strlen');
$values = FilterArray::removeEmptyStrings(func_get_args());
return count($values) < 1 ? NULL : min($values);
}

View File

@ -2,6 +2,7 @@
namespace Drupal\user\Plugin\migrate\process\d6;
use Drupal\Component\Utility\FilterArray;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
@ -27,7 +28,7 @@ class ProfileFieldOptionTranslation extends ProcessPluginBase {
$allowed_values = [];
$list = explode("\n", $translation);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
$list = FilterArray::removeEmptyStrings($list);
if ($field_type === 'list_string') {
foreach ($list as $value) {
$allowed_values[] = ['label' => $value];

View File

@ -2,6 +2,7 @@
namespace Drupal\views\Plugin\views;
use Drupal\Component\Utility\FilterArray;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
@ -758,7 +759,7 @@ abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
// Filter any empty matches (Like from '++' in a string) and reset the
// array keys. 'strlen' is used as the filter callback so we do not lose
// 0 values (would otherwise evaluate == FALSE).
$value = array_values(array_filter($value, 'strlen'));
$value = array_values(FilterArray::removeEmptyStrings($value));
if ($force_int) {
$value = array_map('intval', $value);

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\FilterArray;
use PHPUnit\Framework\TestCase;
/**
* Test filter array functions.
*
* @group Utility
*
* @coversDefaultClass \Drupal\Component\Utility\FilterArray
*/
class FilterArrayTest extends TestCase {
/**
* Tests removing empty strings.
*
* @dataProvider providerRemoveEmptyStrings
* @covers ::removeEmptyStrings
*/
public function testRemoveEmptyStrings(array $values, array $expected): void {
$this->assertEquals($expected, array_values(FilterArray::removeEmptyStrings($values)));
}
/**
* Data provider for testRemoveEmptyStrings().
*
* @see testRemoveEmptyStrings()
*/
public static function providerRemoveEmptyStrings(): \Generator {
yield 'strings' => [
['', ' ', '0', 'true', 'false'],
[' ', '0', 'true', 'false'],
];
yield 'integers' => [
[-1, 0, 1],
[-1, 0, 1],
];
yield 'null, true, false' => [
[NULL, TRUE, FALSE],
[TRUE],
];
$stringable = new class implements \Stringable {
public function __toString(): string {
return 'foo';
}
};
yield 'non-scalar' => [
[new $stringable()],
[new $stringable()],
];
}
}