diff --git a/phpstan-baseline-7.4.neon b/phpstan-baseline-7.4.neon index beddd115ca..cbd8af7e6c 100644 --- a/phpstan-baseline-7.4.neon +++ b/phpstan-baseline-7.4.neon @@ -20,21 +20,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentDraftController.php - - - message: "#^Parameter \\#1 \\$array_arg of function usort expects TArray of array\\, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#1 \\$s1 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#2 \\$s2 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, iterable\\ given\\.$#" count: 1 diff --git a/phpstan-baseline-8.0.neon b/phpstan-baseline-8.0.neon index 199f1d4121..823c62473f 100644 --- a/phpstan-baseline-8.0.neon +++ b/phpstan-baseline-8.0.neon @@ -10,21 +10,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentDraftController.php - - - message: "#^Parameter \\#1 \\$array of function usort expects TArray of array\\, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#1 \\$string1 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#2 \\$string2 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" count: 1 diff --git a/phpstan-baseline-8.3.neon b/phpstan-baseline-8.3.neon index 9c45740199..37591e0e3c 100644 --- a/phpstan-baseline-8.3.neon +++ b/phpstan-baseline-8.3.neon @@ -10,21 +10,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentDraftController.php - - - message: "#^Parameter \\#1 \\$array of function usort expects TArray of array\\, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#1 \\$string1 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - - - message: "#^Parameter \\#2 \\$string2 of function strnatcasecmp expects string, string\\|null given\\.$#" - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" count: 1 diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index bf81b30be2..e095a2f931 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -318,12 +318,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentTypeController.php - - - message: '#^Parameter \#1 \$array of class Pagerfanta\\Adapter\\ArrayAdapter constructor expects array, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: '#^Parameter \#1 \$contentType of method Ibexa\\Bundle\\AdminUi\\Controller\\ContentTypeController\:\:tryToCreateContentTypeDraft\(\) expects Ibexa\\Contracts\\Core\\Repository\\Values\\ContentType\\ContentType, Ibexa\\Contracts\\Core\\Repository\\Values\\ContentType\\ContentType\|null given\.$#' identifier: argument.type @@ -336,12 +330,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentTypeController.php - - - message: '#^Parameter \#1 \$contentTypes of method Ibexa\\Bundle\\AdminUi\\Controller\\ContentTypeController\:\:getContentTypesNumbers\(\) expects array\, iterable\<\(int\|string\), mixed\> given\.$#' - identifier: argument.type - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: '#^Parameter \#2 \$handler of method Ibexa\\AdminUi\\Form\\SubmitHandler\:\:handle\(\) expects callable\(mixed\)\: \(Symfony\\Component\\HttpFoundation\\Response\|null\), Closure\(\)\: void given\.$#' identifier: argument.type @@ -354,12 +342,6 @@ parameters: count: 1 path: src/bundle/Controller/ContentTypeController.php - - - message: '#^Variable \$contentTypeGroupList in PHPDoc tag @var does not match assigned variable \$types\.$#' - identifier: varTag.differentVariable - count: 1 - path: src/bundle/Controller/ContentTypeController.php - - message: '#^Variable \$newContentTypeDraft might not be defined\.$#' identifier: variable.undefined diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index 5f0d946114..1174da63cf 100644 --- a/src/bundle/Controller/ContentTypeController.php +++ b/src/bundle/Controller/ContentTypeController.php @@ -18,6 +18,7 @@ use Ibexa\AdminUi\Form\Factory\FormFactory; use Ibexa\AdminUi\Form\SubmitHandler; use Ibexa\AdminUi\Form\Type\ContentType\ContentTypeUpdateType; +use Ibexa\AdminUi\Pagination\Pagerfanta\ContentTypeListAdapter; use Ibexa\AdminUi\Service\MetaFieldType\MetaFieldDefinitionServiceInterface; use Ibexa\AdminUi\Tab\ContentType\TranslationsTab; use Ibexa\AdminUi\UI\Module\FieldTypeToolbar\FieldTypeToolbarFactory; @@ -36,10 +37,13 @@ use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft; use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup; +use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\ContentTypeQuery; +use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\Criterion\ContentTypeGroupId; +use Ibexa\Contracts\Core\Repository\Values\ContentType\Query\SortClause\Name; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute; +use function Ibexa\PolyfillPhp82\iterator_to_array; use JMS\TranslationBundle\Annotation\Desc; -use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Pagerfanta; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -132,24 +136,23 @@ public function __construct( public function listAction(ContentTypeGroup $group, string $routeName, int $page): Response { $deletableTypes = []; - $contentTypes = $this->contentTypeService->loadContentTypes($group, $this->configResolver->getParameter('languages')); - - usort($contentTypes, static function (ContentType $contentType1, ContentType $contentType2) { - return strnatcasecmp($contentType1->getName(), $contentType2->getName()); - }); + $languages = $this->configResolver->getParameter('languages'); + $limit = $this->configResolver->getParameter('pagination.content_type_limit'); + $query = new ContentTypeQuery(new ContentTypeGroupId($group->id), [new Name()]); $pagerfanta = new Pagerfanta( - new ArrayAdapter($contentTypes) + new ContentTypeListAdapter($this->contentTypeService, $languages, $query) ); - $pagerfanta->setMaxPerPage($this->configResolver->getParameter('pagination.content_type_limit')); + $pagerfanta->setMaxPerPage($limit); $pagerfanta->setCurrentPage(min($page, $pagerfanta->getNbPages())); - /** @var \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeGroup[] $contentTypeGroupList */ $types = $pagerfanta->getCurrentPageResults(); $deleteContentTypesForm = $this->formFactory->deleteContentTypes( - new ContentTypesDeleteData($this->getContentTypesNumbers($types)) + new ContentTypesDeleteData($this->getContentTypesNumbers( + iterator_to_array($types) + )) ); foreach ($types as $type) { @@ -157,7 +160,7 @@ public function listAction(ContentTypeGroup $group, string $routeName, int $page } $copyData = new ContentTypeCopyData(null, $group); - $contentTypeCopyForm = $this->contentTypeFormFactory->contentTypeCopy($copyData, null)->createView(); + $contentTypeCopyForm = $this->contentTypeFormFactory->contentTypeCopy($copyData)->createView(); return $this->render('@ibexadesign/content_type/list.html.twig', [ 'content_type_group' => $group, diff --git a/src/lib/Pagination/Pagerfanta/ContentTypeListAdapter.php b/src/lib/Pagination/Pagerfanta/ContentTypeListAdapter.php new file mode 100644 index 0000000000..818a475260 --- /dev/null +++ b/src/lib/Pagination/Pagerfanta/ContentTypeListAdapter.php @@ -0,0 +1,54 @@ + */ + private array $languages; + + /** + * @param list $languages + */ + public function __construct( + ContentTypeService $contentTypeService, + array $languages, + ?ContentTypeQuery $query = null + ) { + $this->contentTypeService = $contentTypeService; + $this->languages = $languages; + $this->query = $query ?? new ContentTypeQuery(null, [new Identifier()]); + } + + public function getNbResults(): int + { + $query = clone $this->query; + $query->setLimit(0); + + return $this->contentTypeService->findContentTypes($query, $this->languages)->getTotalCount(); + } + + public function getSlice($offset, $length): iterable + { + $query = clone $this->query; + $query->setOffset($offset); + $query->setLimit($length); + + return $this->contentTypeService->findContentTypes($query, $this->languages)->getIterator(); + } +} diff --git a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php new file mode 100644 index 0000000000..c501d74dd2 --- /dev/null +++ b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php @@ -0,0 +1,79 @@ +contentTypeService = $this->createMock(ContentTypeService::class); + } + + public function testGetNbResults(): void + { + $languages = ['en-GB', 'de-DE']; + + $searchResults = new SearchResult([ + 'totalCount' => 10, + 'items' => [], + ]); + + $this->contentTypeService + ->expects(self::once()) + ->method('findContentTypes') + ->with(self::isInstanceOf(ContentTypeQuery::class), $languages) + ->willReturn($searchResults); + + $adapter = new ContentTypeListAdapter($this->contentTypeService, $languages); + + self::assertEquals( + 10, + $adapter->getNbResults() + ); + } + + public function testGetSlice(): void + { + $languages = ['en-GB']; + $offset = 5; + $limit = 25; + + $item1 = $this->createMock(ContentType::class); + $item2 = $this->createMock(ContentType::class); + $items = [$item1, $item2]; + + $searchResults = new SearchResult([ + 'totalCount' => 2, + 'items' => $items, + ]); + + $this->contentTypeService + ->expects(self::once()) + ->method('findContentTypes') + ->with($this->isInstanceOf(ContentTypeQuery::class), $languages) + ->willReturn($searchResults); + + $adapter = new ContentTypeListAdapter($this->contentTypeService, $languages); + + self::assertEquals( + $searchResults->getIterator(), + $adapter->getSlice($offset, $limit) + ); + } +}