diff --git a/Content/ArticleDataProvider.php b/Content/ArticleDataProvider.php index 2a463c847..00e7cd1e2 100644 --- a/Content/ArticleDataProvider.php +++ b/Content/ArticleDataProvider.php @@ -19,17 +19,21 @@ 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\PageBundle\Content\Types\SegmentSelect; 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. @@ -71,6 +75,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, @@ -78,7 +92,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; @@ -87,6 +103,8 @@ public function __construct( $this->articleResourceItemFactory = $articleResourceItemFactory; $this->articleDocumentClass = $articleDocumentClass; $this->defaultLimit = $defaultLimit; + $this->formMetadataProvider = $formMetadataProvider; + $this->tokenStorage = $tokenStorage; } /** @@ -102,7 +120,7 @@ public function getConfiguration() */ protected function getConfigurationBuilder(): BuilderInterface { - return Builder::create() + $builder = Builder::create() ->enableTags() ->enableCategories() ->enableLimit() @@ -117,6 +135,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; } /** @@ -141,8 +165,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']; @@ -169,8 +198,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']; @@ -343,8 +377,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; } @@ -459,6 +493,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 327800b90..8a578e64c 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -333,6 +333,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 07a3e43c7..3852b926d 100644 --- a/Tests/Functional/Content/ArticleDataProviderTest.php +++ b/Tests/Functional/Content/ArticleDataProviderTest.php @@ -191,6 +191,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 = [