diff --git a/Content/ArticleDataProvider.php b/Content/ArticleDataProvider.php index a0c36389e..082a1015a 100644 --- a/Content/ArticleDataProvider.php +++ b/Content/ArticleDataProvider.php @@ -19,16 +19,20 @@ use ONGR\ElasticsearchDSL\Sort\FieldSort; use ProxyManager\Factory\LazyLoadingValueHolderFactory; use ProxyManager\Proxy\LazyLoadingInterface; +use Sulu\Bundle\AdminBundle\Metadata\FormMetadata\FormMetadataProvider; +use Sulu\Bundle\AdminBundle\Metadata\FormMetadata\TypedFormMetadata; use Sulu\Bundle\ArticleBundle\Document\ArticleDocument; use Sulu\Bundle\ArticleBundle\Document\ArticleViewDocumentInterface; use Sulu\Bundle\WebsiteBundle\ReferenceStore\ReferenceStoreInterface; use Sulu\Component\Content\Compat\PropertyParameter; use Sulu\Component\DocumentManager\DocumentManagerInterface; +use Sulu\Component\Security\Authentication\UserInterface; use Sulu\Component\SmartContent\Configuration\Builder; use Sulu\Component\SmartContent\Configuration\BuilderInterface; use Sulu\Component\SmartContent\DataProviderAliasInterface; use Sulu\Component\SmartContent\DataProviderInterface; use Sulu\Component\SmartContent\DataProviderResult; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** * Introduces articles in smart-content. @@ -70,6 +74,16 @@ class ArticleDataProvider implements DataProviderInterface, DataProviderAliasInt */ protected $defaultLimit; + /** + * @var FormMetadataProvider|null + */ + private $formMetadataProvider; + + /** + * @var TokenStorageInterface|null + */ + private $tokenStorage; + public function __construct( Manager $searchManager, DocumentManagerInterface $documentManager, @@ -77,7 +91,9 @@ public function __construct( ReferenceStoreInterface $referenceStore, ArticleResourceItemFactory $articleResourceItemFactory, string $articleDocumentClass, - int $defaultLimit + int $defaultLimit, + FormMetadataProvider $formMetadataProvider = null, + TokenStorageInterface $tokenStorage = null ) { $this->searchManager = $searchManager; $this->documentManager = $documentManager; @@ -86,6 +102,8 @@ public function __construct( $this->articleResourceItemFactory = $articleResourceItemFactory; $this->articleDocumentClass = $articleDocumentClass; $this->defaultLimit = $defaultLimit; + $this->formMetadataProvider = $formMetadataProvider; + $this->tokenStorage = $tokenStorage; } /** @@ -101,7 +119,7 @@ public function getConfiguration() */ protected function getConfigurationBuilder(): BuilderInterface { - return Builder::create() + $builder = Builder::create() ->enableTags() ->enableCategories() ->enableLimit() @@ -116,6 +134,12 @@ protected function getConfigurationBuilder(): BuilderInterface ['column' => 'author_full_name.raw', 'title' => 'sulu_admin.author'], ] ); + + if (method_exists($builder, 'enableTypes')) { + $builder->enableTypes($this->getTypes()); + } + + return $builder; } /** @@ -140,8 +164,13 @@ public function resolveDataItems( $page = 1, $pageSize = null ) { + // there are two different kinds of types in the context of the article bundle: template-type and article-type + // filtering by article-type is possible via the types xml param + // filtering by template-type is possible via the structureTypes xml param and the admin interface overlay + // unfortunately, the admin frontend sends the selected types in $filters['types'] to the provider + // TODO: adjust the naming of the xml params to be consistent consistent, but this will be a bc break + $filters['structureTypes'] = array_merge($filters['types'] ?? [], $this->getStructureTypesProperty($propertyParameter)); $filters['types'] = $this->getTypesProperty($propertyParameter); - $filters['structureTypes'] = $this->getStructureTypesProperty($propertyParameter); $filters['excluded'] = $this->getExcludedFilter($filters, $propertyParameter); $locale = $options['locale']; @@ -168,8 +197,13 @@ public function resolveResourceItems( $page = 1, $pageSize = null ) { + // there are two different kinds of types in the context of the article bundle: template-type and article-type + // filtering by article-type is possible via the types xml param + // filtering by template-type is possible via the structureTypes xml param and the admin interface overlay + // unfortunately, the admin frontend sends the selected types in $filters['types'] to the provider + // TODO: adjust the naming of the xml params to be consistent consistent, but this will be a bc break + $filters['structureTypes'] = array_merge($filters['types'] ?? [], $this->getStructureTypesProperty($propertyParameter)); $filters['types'] = $this->getTypesProperty($propertyParameter); - $filters['structureTypes'] = $this->getStructureTypesProperty($propertyParameter); $filters['excluded'] = $this->getExcludedFilter($filters, $propertyParameter); $locale = $options['locale']; @@ -325,8 +359,8 @@ private function getTypesProperty(array $propertyParameter): array $filterTypes = []; if (array_key_exists('types', $propertyParameter) - && null !== ($types = explode(',', $propertyParameter['types']->getValue())) - ) { + && !empty($value = $propertyParameter['types']->getValue())) { + $types = is_array($value) ? $value : explode(',', $value); foreach ($types as $type) { $filterTypes[] = $type; } @@ -441,6 +475,30 @@ private function getFilter(array $filters, string $name, $default = null) return $default; } + /** + * @return array> + */ + private function getTypes(): array + { + $types = []; + if ($this->tokenStorage && null !== $this->tokenStorage->getToken() && $this->formMetadataProvider) { + $user = $this->tokenStorage->getToken()->getUser(); + + if (!$user instanceof UserInterface) { + return $types; + } + + /** @var TypedFormMetadata $metadata */ + $metadata = $this->formMetadataProvider->getMetadata('article', $user->getLocale(), []); + + foreach ($metadata->getForms() as $form) { + $types[] = ['type' => $form->getName(), 'title' => $form->getTitle()]; + } + } + + return $types; + } + /** * Returns true if filter-value exists. */ diff --git a/Resources/config/services.xml b/Resources/config/services.xml index aa0b2d0b6..b3389d8ee 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -322,6 +322,8 @@ %sulu_article.view_document.article.class% %sulu_article.smart_content.default_limit% + + diff --git a/Tests/Functional/Content/ArticleDataProviderTest.php b/Tests/Functional/Content/ArticleDataProviderTest.php index 12d0cc2d0..4f2716c88 100644 --- a/Tests/Functional/Content/ArticleDataProviderTest.php +++ b/Tests/Functional/Content/ArticleDataProviderTest.php @@ -190,6 +190,45 @@ public function testResolveDataItemsStructureTypeParamWrong() $this->assertCount(0, $result->getItems()); } + public function testResolveDataItemsStructureTypeFromSmartContentFiltering() + { + $item1 = $this->createArticle(); + $item2 = $this->createArticle('Test', 'simple'); + + /** @var DataProviderInterface $dataProvider */ + $dataProvider = $this->getContainer()->get('sulu_article.content.data_provider'); + + // get all articles with structureType default_fallback + $result = $dataProvider->resolveDataItems( + ['types' => ['simple']], + [], + ['locale' => 'de', 'webspaceKey' => 'sulu_io'] + ); + + $this->assertInstanceOf(DataProviderResult::class, $result); + $this->assertCount(1, $result->getItems()); + + // get all articles with structureType default_fallback + $result = $dataProvider->resolveDataItems( + ['types' => ['default']], + [], + ['locale' => 'de', 'webspaceKey' => 'sulu_io'] + ); + + $this->assertInstanceOf(DataProviderResult::class, $result); + $this->assertCount(1, $result->getItems()); + + // get all articles with structureType default_fallback + $result = $dataProvider->resolveDataItems( + ['types' => ['default', 'simple']], + [], + ['locale' => 'de', 'webspaceKey' => 'sulu_io'] + ); + + $this->assertInstanceOf(DataProviderResult::class, $result); + $this->assertCount(2, $result->getItems()); + } + public function testResolveDataItemsPagination() { $items = [