From 6fc024084fd031740d5c13ad692530ecfe826b71 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Wed, 1 Oct 2025 09:35:40 +0200 Subject: [PATCH 1/9] Used new `findContentTypes` PAPI contract in content type list --- .../Controller/ContentTypeController.php | 24 +++++---- .../Pagerfanta/ContentTypeListAdapter.php | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/lib/Pagination/Pagerfanta/ContentTypeListAdapter.php diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index 5f0d946114..e103c29b9d 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,12 @@ 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 JMS\TranslationBundle\Annotation\Desc; -use Pagerfanta\Adapter\ArrayAdapter; use Pagerfanta\Pagerfanta; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -132,24 +135,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( + \Ibexa\PolyfillPhp82\iterator_to_array($types) + )) ); foreach ($types as $type) { @@ -157,7 +159,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(); + } +} From acac4df61a51537878d6432e663888ef9b65a988 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 14:18:39 +0200 Subject: [PATCH 2/9] Baseline --- phpstan-baseline.neon | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 17059dbcbe..3a3de4abde 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 From ee1d68051250e7b5dfecc6a5f34f5972ff5639c0 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 14:22:44 +0200 Subject: [PATCH 3/9] Baseline --- phpstan-baseline-7.4.neon | 15 --------------- phpstan-baseline-8.0.neon | 15 --------------- phpstan-baseline-8.3.neon | 15 --------------- 3 files changed, 45 deletions(-) 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 From a84b788017448311d767f985f5ffc23ce4f085d6 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 14:56:53 +0200 Subject: [PATCH 4/9] Import --- src/bundle/Controller/ContentTypeController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index e103c29b9d..97b685e281 100644 --- a/src/bundle/Controller/ContentTypeController.php +++ b/src/bundle/Controller/ContentTypeController.php @@ -42,6 +42,7 @@ 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 as iteratorToArray; use JMS\TranslationBundle\Annotation\Desc; use Pagerfanta\Pagerfanta; use Symfony\Component\Form\FormInterface; @@ -150,7 +151,7 @@ public function listAction(ContentTypeGroup $group, string $routeName, int $page $deleteContentTypesForm = $this->formFactory->deleteContentTypes( new ContentTypesDeleteData($this->getContentTypesNumbers( - \Ibexa\PolyfillPhp82\iterator_to_array($types) + iteratorToArray($types) )) ); From 24b53e5e2d39b676b42c32ff0b0378cd760f5952 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 15:13:53 +0200 Subject: [PATCH 5/9] Unit test --- .../Pagerfanta/ContentTypeListAdapterTest.php | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php diff --git a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php new file mode 100644 index 0000000000..292849986f --- /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($this->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) + ); + } +} From 410db153cc1bdcfaa462bfa4c3025dcfbb62fc33 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 15:14:58 +0200 Subject: [PATCH 6/9] Review remark --- src/bundle/Controller/ContentTypeController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index 97b685e281..709721ae9e 100644 --- a/src/bundle/Controller/ContentTypeController.php +++ b/src/bundle/Controller/ContentTypeController.php @@ -42,7 +42,6 @@ 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 as iteratorToArray; use JMS\TranslationBundle\Annotation\Desc; use Pagerfanta\Pagerfanta; use Symfony\Component\Form\FormInterface; From 41c921e7a5f27054e6c9079cbd17394db7f039a3 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 15:15:19 +0200 Subject: [PATCH 7/9] Review remark --- src/bundle/Controller/ContentTypeController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index 709721ae9e..994f265550 100644 --- a/src/bundle/Controller/ContentTypeController.php +++ b/src/bundle/Controller/ContentTypeController.php @@ -150,7 +150,7 @@ public function listAction(ContentTypeGroup $group, string $routeName, int $page $deleteContentTypesForm = $this->formFactory->deleteContentTypes( new ContentTypesDeleteData($this->getContentTypesNumbers( - iteratorToArray($types) + iterator_to_array($types) )) ); From 42384cd9f2c93e39798a9a51a2e063d1f33f673d Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 15:18:46 +0200 Subject: [PATCH 8/9] Fixup --- src/bundle/Controller/ContentTypeController.php | 1 + tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bundle/Controller/ContentTypeController.php b/src/bundle/Controller/ContentTypeController.php index 994f265550..1174da63cf 100644 --- a/src/bundle/Controller/ContentTypeController.php +++ b/src/bundle/Controller/ContentTypeController.php @@ -42,6 +42,7 @@ 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\Pagerfanta; use Symfony\Component\Form\FormInterface; diff --git a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php index 292849986f..2f11dbf6d3 100644 --- a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php +++ b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php @@ -17,7 +17,7 @@ final class ContentTypeListAdapterTest extends TestCase { - /** @var \Ibexa\Contracts\Core\Repository\ContentTypeService|\PHPUnit\Framework\MockObject\MockObject */ + /** @var \Ibexa\Contracts\Core\Repository\ContentTypeService&\PHPUnit\Framework\MockObject\MockObject */ private ContentTypeService $contentTypeService; protected function setUp(): void From 3162c8bafb244be6758820e06dec87d743e7dbfa Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Mon, 6 Oct 2025 15:28:33 +0200 Subject: [PATCH 9/9] Review remark --- tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php index 2f11dbf6d3..c501d74dd2 100644 --- a/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php +++ b/tests/lib/Pagination/Pagerfanta/ContentTypeListAdapterTest.php @@ -37,7 +37,7 @@ public function testGetNbResults(): void $this->contentTypeService ->expects(self::once()) ->method('findContentTypes') - ->with($this->isInstanceOf(ContentTypeQuery::class), $languages) + ->with(self::isInstanceOf(ContentTypeQuery::class), $languages) ->willReturn($searchResults); $adapter = new ContentTypeListAdapter($this->contentTypeService, $languages);