diff --git a/src/AutoMapper/RestRequestMapper.php b/src/AutoMapper/RestRequestMapper.php index 638696441..c3f698070 100644 --- a/src/AutoMapper/RestRequestMapper.php +++ b/src/AutoMapper/RestRequestMapper.php @@ -43,7 +43,7 @@ abstract class RestRequestMapper implements MapperInterface */ public function map($source, string $targetClass, array $context = []): RestDtoInterface { - /** @psalm-var class-string $targetClass */ + /** @psalm-var class-string $targetClass */ $destination = new $targetClass(); return $this->mapToObject($source, $destination, $context); diff --git a/src/Command/ApiKey/ApiKeyHelper.php b/src/Command/ApiKey/ApiKeyHelper.php index 9f0bcc318..bb548da60 100644 --- a/src/Command/ApiKey/ApiKeyHelper.php +++ b/src/Command/ApiKey/ApiKeyHelper.php @@ -11,10 +11,8 @@ use App\Entity\ApiKey; use App\Resource\ApiKeyResource; use App\Security\RolesService; -use Closure; use Symfony\Component\Console\Style\SymfonyStyle; use Throwable; -use function array_map; use function implode; use function sprintf; @@ -90,35 +88,20 @@ public function getApiKeyMessage(string $message, ApiKey $apiKey): array */ private function getApiKeyEntity(SymfonyStyle $io, string $question): ?ApiKey { + /** @var array $choices */ $choices = []; - array_map( - $this->getApiKeyIterator($choices), - $this->apiKeyResource->find(orderBy: [ - 'token' => 'ASC', - ]) - ); - - $choices['Exit'] = 'Exit command'; - - return $this->apiKeyResource->findOne((string)$io->choice($question, $choices)); - } - - /** - * Method to return ApiKeyIterator closure. This will format ApiKey - * entities for choice list. - * - * @param array $choices - */ - private function getApiKeyIterator(array &$choices): Closure - { - return function (ApiKey $apiKey) use (&$choices): void { + foreach ($this->apiKeyResource->find() as $apiKey) { $choices[$apiKey->getId()] = sprintf( '[Token: %s] %s - Roles: %s', $apiKey->getToken(), $apiKey->getDescription(), implode(', ', $this->rolesService->getInheritedRoles($apiKey->getRoles())), ); - }; + } + + $choices['Exit'] = 'Exit command'; + + return $this->apiKeyResource->findOne((string)$io->choice($question, $choices)); } } diff --git a/src/Command/ApiKey/ListApiKeysCommand.php b/src/Command/ApiKey/ListApiKeysCommand.php index 0486844a4..4116a1a48 100644 --- a/src/Command/ApiKey/ListApiKeysCommand.php +++ b/src/Command/ApiKey/ListApiKeysCommand.php @@ -69,7 +69,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * Getter method for formatted API key rows for console table. * - * @return array + * @return array * * @throws Throwable */ diff --git a/src/Command/User/ListUserGroupsCommand.php b/src/Command/User/ListUserGroupsCommand.php index 630d71115..11acd34ce 100644 --- a/src/Command/User/ListUserGroupsCommand.php +++ b/src/Command/User/ListUserGroupsCommand.php @@ -67,7 +67,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * Getter method for formatted user group rows for console table. * - * @return array + * @return array * * @throws Throwable */ diff --git a/src/Command/User/ListUsersCommand.php b/src/Command/User/ListUsersCommand.php index 5a3d9680b..3e7534c95 100644 --- a/src/Command/User/ListUsersCommand.php +++ b/src/Command/User/ListUsersCommand.php @@ -71,7 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * Getter method for formatted user rows for console table. * - * @return array + * @return array * * @throws Throwable */ diff --git a/src/Rest/Interfaces/SearchTermInterface.php b/src/Rest/Interfaces/SearchTermInterface.php index b2ada2c70..dd1d2b537 100644 --- a/src/Rest/Interfaces/SearchTermInterface.php +++ b/src/Rest/Interfaces/SearchTermInterface.php @@ -37,7 +37,7 @@ interface SearchTermInterface * @param int|null $mode Used mode on LIKE search. See MODE_* constants. Defaults to * self::MODE_FULL * - * @return array>>|null + * @return array>>|null */ public static function getCriteria( array | string $column, diff --git a/tests/Unit/Rest/SearchTermTest.php b/tests/Unit/Rest/SearchTermTest.php index d81ecb276..6a2bbdbcb 100644 --- a/tests/Unit/Rest/SearchTermTest.php +++ b/tests/Unit/Rest/SearchTermTest.php @@ -24,40 +24,49 @@ class SearchTermTest extends KernelTestCase { #[DataProvider('dataProviderTestThatWithoutColumnOrSearchTermCriteriaIsNull')] #[TestDox('Test that `getCriteria` method returns null with `$column` + `$search` parameters')] - public function testThatWithoutColumnOrSearchTermCriteriaIsNull(mixed $column, mixed $search): void - { - self::assertNull(SearchTerm::getCriteria( - $column instanceof StringableArrayObject ? $column->getArrayCopy() : $column, - $search instanceof StringableArrayObject ? $search->getArrayCopy() : $search - ), 'Criteria was not NULL with given parameters'); + public function testThatWithoutColumnOrSearchTermCriteriaIsNull( + string|StringableArrayObject|null $column, + string|StringableArrayObject|null $search, + ): void { + if ($column instanceof StringableArrayObject) { + /** @var array $column */ + $column = $column->getArrayCopy(); + } + + if ($search instanceof StringableArrayObject) { + /** @var array $search */ + $search = $search->getArrayCopy(); + } + + self::assertNull(SearchTerm::getCriteria($column, $search), 'Criteria was not NULL with given parameters'); } - /** - * @phpstan-param StringableArrayObject $inputArguments - * @phpstan-param StringableArrayObject | null $expected - * @psalm-param StringableArrayObject $inputArguments - * @psalm-param StringableArrayObject | null $expected - */ #[DataProvider('dataProviderTestThatReturnedCriteriaIsExpected')] #[TestDox('Test that `getCriteria` method returns `$expected` with given `$inputArguments` arguments')] public function testThatReturnedCriteriaIsExpected( StringableArrayObject $inputArguments, StringableArrayObject|null $expected ): void { + /** + * @var array{ + * column: array|string|null, + * search: array|string|null, + * operand: string|null, + * mode: int|null, + * } $input + */ + $input = $inputArguments->getArrayCopy(); + self::assertSame( $expected?->getArrayCopy(), - call_user_func_array(SearchTerm::getCriteria(...), $inputArguments->getArrayCopy()) + call_user_func_array(SearchTerm::getCriteria(...), $input), ); } /** * Data provider for testThatWithoutColumnOrSearchTermCriteriaIsNull * - * @psalm-return Generator - * @phpstan-return Generator, - * 1: null|string|StringableArrayObject, - * }> + * @return Generator */ public static function dataProviderTestThatWithoutColumnOrSearchTermCriteriaIsNull(): Generator { @@ -89,14 +98,13 @@ public static function dataProviderTestThatWithoutColumnOrSearchTermCriteriaIsNu /** * Data provider for testThatReturnedCriteriaIsExpected * - * @psalm-return Generator - * @phpstan-return Generator, 1: StringableArrayObject|null}> + * @return Generator */ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generator { // To cover array_filter on search term yield [ - new StringableArrayObject(['c1', '0']), + new StringableArrayObject(['c1', '0', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -107,37 +115,37 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([null, null]), + new StringableArrayObject([null, null, null, null]), null, ]; yield [ - new StringableArrayObject(['c1', null]), + new StringableArrayObject(['c1', null, null, null]), null, ]; yield [ - new StringableArrayObject([null, 'word']), + new StringableArrayObject([null, 'word', null, null]), null, ]; yield [ - new StringableArrayObject(['', '']), + new StringableArrayObject(['', '', null, null]), null, ]; yield [ - new StringableArrayObject(['c1', '']), + new StringableArrayObject(['c1', '', null, null]), null, ]; yield [ - new StringableArrayObject(['', 'word']), + new StringableArrayObject(['', 'word', null, null]), null, ]; yield [ - new StringableArrayObject(['c1', 'word']), + new StringableArrayObject(['c1', 'word', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -148,7 +156,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', 'word ']), + new StringableArrayObject(['c1', 'word ', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -159,7 +167,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], ['search', 'word']]), + new StringableArrayObject([['c1', 'c2'], ['search', 'word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -173,7 +181,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], [' search', ' word ']]), + new StringableArrayObject([['c1', 'c2'], [' search', ' word '], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -187,7 +195,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], ['search word']]), + new StringableArrayObject([['c1', 'c2'], ['search word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -199,7 +207,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], [' search word ']]), + new StringableArrayObject([['c1', 'c2'], [' search word '], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -211,7 +219,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], 'search word']), + new StringableArrayObject([['c1', 'c2'], 'search word', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -225,7 +233,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], ' search word ']), + new StringableArrayObject([['c1', 'c2'], ' search word ', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -239,7 +247,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], '"search word"']), + new StringableArrayObject([['c1', 'c2'], '"search word"', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -251,7 +259,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'c2'], ' " search word " ']), + new StringableArrayObject([['c1', 'c2'], ' " search word " ', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -263,7 +271,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', 'search word']), + new StringableArrayObject(['someTable.c1', 'search word', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -275,7 +283,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', ' search word ']), + new StringableArrayObject(['someTable.c1', ' search word ', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -287,7 +295,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', '"search word"']), + new StringableArrayObject(['someTable.c1', '"search word"', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -298,7 +306,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', '" search word "']), + new StringableArrayObject(['someTable.c1', '" search word "', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -309,7 +317,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', ['search', 'word']]), + new StringableArrayObject(['someTable.c1', ['search', 'word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -321,7 +329,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', [' search', 'word ', ' foo bar ']]), + new StringableArrayObject(['someTable.c1', [' search', 'word ', ' foo bar '], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -334,7 +342,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', ['search word']]), + new StringableArrayObject(['someTable.c1', ['search word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -345,7 +353,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['someTable.c1', [' search word ']]), + new StringableArrayObject(['someTable.c1', [' search word '], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -356,7 +364,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], 'search word']), + new StringableArrayObject([['c1', 'someTable.c1'], 'search word', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -370,7 +378,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], ' search word ']), + new StringableArrayObject([['c1', 'someTable.c1'], ' search word ', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -384,7 +392,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], 'search word "word search"']), + new StringableArrayObject([['c1', 'someTable.c1'], 'search word "word search"', null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -400,7 +408,9 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], ' search word " word search "']), + new StringableArrayObject([[ + 'c1', 'someTable.c1'], ' search word " word search "', null, null, + ]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -416,7 +426,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], ['search', 'word']]), + new StringableArrayObject([['c1', 'someTable.c1'], ['search', 'word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -430,7 +440,9 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], [' search', 'word ', ' foo bar ']]), + new StringableArrayObject([ + ['c1', 'someTable.c1'], [' search', 'word ', ' foo bar '], null, null, + ]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -446,7 +458,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], ['search word']]), + new StringableArrayObject([['c1', 'someTable.c1'], ['search word'], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -458,7 +470,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject([['c1', 'someTable.c1'], [' search word ']]), + new StringableArrayObject([['c1', 'someTable.c1'], [' search word '], null, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -470,7 +482,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', 'search word', SearchTerm::OPERAND_AND]), + new StringableArrayObject(['c1', 'search word', SearchTerm::OPERAND_AND, null]), new StringableArrayObject([ 'and' => [ 'and' => [ @@ -482,7 +494,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', ' search word ', SearchTerm::OPERAND_AND]), + new StringableArrayObject(['c1', ' search word ', SearchTerm::OPERAND_AND, null]), new StringableArrayObject([ 'and' => [ 'and' => [ @@ -494,7 +506,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '"search word"', SearchTerm::OPERAND_AND]), + new StringableArrayObject(['c1', '"search word"', SearchTerm::OPERAND_AND, null]), new StringableArrayObject([ 'and' => [ 'and' => [ @@ -505,7 +517,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '" search word "', SearchTerm::OPERAND_AND]), + new StringableArrayObject(['c1', '" search word "', SearchTerm::OPERAND_AND, null]), new StringableArrayObject([ 'and' => [ 'and' => [ @@ -516,7 +528,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', 'search word', SearchTerm::OPERAND_OR]), + new StringableArrayObject(['c1', 'search word', SearchTerm::OPERAND_OR, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -528,7 +540,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', ' search word ', SearchTerm::OPERAND_OR]), + new StringableArrayObject(['c1', ' search word ', SearchTerm::OPERAND_OR, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -540,7 +552,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '"search word"', SearchTerm::OPERAND_OR]), + new StringableArrayObject(['c1', '"search word"', SearchTerm::OPERAND_OR, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -551,7 +563,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '" search word "', SearchTerm::OPERAND_OR]), + new StringableArrayObject(['c1', '" search word "', SearchTerm::OPERAND_OR, null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -562,7 +574,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', 'search word', 'notSupportedOperand']), + new StringableArrayObject(['c1', 'search word', 'notSupportedOperand', null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -574,7 +586,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', ' search word ', 'notSupportedOperand']), + new StringableArrayObject(['c1', ' search word ', 'notSupportedOperand', null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -586,7 +598,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '"search word"', 'notSupportedOperand']), + new StringableArrayObject(['c1', '"search word"', 'notSupportedOperand', null]), new StringableArrayObject([ 'and' => [ 'or' => [ @@ -597,7 +609,7 @@ public static function dataProviderTestThatReturnedCriteriaIsExpected(): Generat ]; yield [ - new StringableArrayObject(['c1', '" search word "', 'notSupportedOperand']), + new StringableArrayObject(['c1', '" search word "', 'notSupportedOperand', null]), new StringableArrayObject([ 'and' => [ 'or' => [ diff --git a/tests/Unit/Utils/Tests/PHPUnitUtilTest.php b/tests/Unit/Utils/Tests/PHPUnitUtilTest.php index 03d2ff7bf..e0227064a 100644 --- a/tests/Unit/Utils/Tests/PHPUnitUtilTest.php +++ b/tests/Unit/Utils/Tests/PHPUnitUtilTest.php @@ -20,6 +20,7 @@ use stdClass; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Throwable; +use function is_string; /** * @package App\Tests\Unit\Utils\Tests @@ -64,13 +65,16 @@ public function testThatGetValidValueReturnsExpectedValue(mixed $expected, strin { $value = PhpUnitUtil::getValidValueForType(PhpUnitUtil::getType($input)); + /** @var StringableArrayObject|mixed $expected */ $expected = $expected instanceof StringableArrayObject ? $expected->getArrayCopy() : $expected; if ($strict) { self::assertSame($expected, $value); - } else { - /** @psalm-var class-string $expected */ + } elseif (is_string($expected)) { + /** @var class-string $expected */ self::assertInstanceOf($expected, $value); + } else { + throw new LogicException('This should not happen...'); } } diff --git a/tests/Utils/PhpUnitUtil.php b/tests/Utils/PhpUnitUtil.php index 9ed0998fc..3af60dfac 100644 --- a/tests/Utils/PhpUnitUtil.php +++ b/tests/Utils/PhpUnitUtil.php @@ -214,6 +214,7 @@ public static function getValidValueForType(string $type, ?array $meta = null): $cacheKey = $type . serialize($meta); if (!array_key_exists($cacheKey, self::$validValueCache)) { + /** @psalm-suppress MixedAssignment */ self::$validValueCache[$cacheKey] = self::getValidValue($meta, $type); } @@ -261,7 +262,7 @@ public static function getInvalidValueForType(string $type): DateTime | stdClass */ private static function getValidValue( ?array $meta, - string $type + string $type, ): mixed { $meta ??= []; @@ -272,6 +273,16 @@ private static function getValidValue( /** @var class-string $class */ $class = $meta !== [] && array_key_exists('targetEntity', $meta) ? $meta['targetEntity'] : $type; + if (!class_exists($class)) { + throw new LogicException( + sprintf( + "Cannot create valid value for type '%s' because class '%s' does not exist.", + $type, + $class, + ), + ); + } + $type = self::TYPE_CUSTOM_CLASS; if ((new ReflectionClass($class))->isEnum()) { @@ -286,6 +297,11 @@ private static function getValidValue( } } + /** + * @psalm-suppress MixedArgument, MixedMethodCall + * + * @var mixed $output + */ $output = match ($type) { self::TYPE_ENUM => current($class::cases()), // TODO: fix this self::TYPE_CUSTOM_CLASS => new $class(...$params), @@ -299,6 +315,7 @@ private static function getValidValue( }; if (str_contains($type, '|')) { + /** @var mixed $output */ $output = self::getValidValueForType(explode('|', $type)[0], $meta); } elseif (str_contains($type, '[]')) { /** @var array $output */