Skip to content

Commit

Permalink
Add SmartContent template filtering (#529)
Browse files Browse the repository at this point in the history
* Add type filtering

* Add BC layer

* Add test

* Add comment
  • Loading branch information
Prokyonn authored Nov 26, 2020
1 parent f0d8a35 commit 0c2c451
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 6 deletions.
70 changes: 64 additions & 6 deletions Content/ArticleDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -70,14 +74,26 @@ class ArticleDataProvider implements DataProviderInterface, DataProviderAliasInt
*/
protected $defaultLimit;

/**
* @var FormMetadataProvider|null
*/
private $formMetadataProvider;

/**
* @var TokenStorageInterface|null
*/
private $tokenStorage;

public function __construct(
Manager $searchManager,
DocumentManagerInterface $documentManager,
LazyLoadingValueHolderFactory $proxyFactory,
ReferenceStoreInterface $referenceStore,
ArticleResourceItemFactory $articleResourceItemFactory,
string $articleDocumentClass,
int $defaultLimit
int $defaultLimit,
FormMetadataProvider $formMetadataProvider = null,
TokenStorageInterface $tokenStorage = null
) {
$this->searchManager = $searchManager;
$this->documentManager = $documentManager;
Expand All @@ -86,6 +102,8 @@ public function __construct(
$this->articleResourceItemFactory = $articleResourceItemFactory;
$this->articleDocumentClass = $articleDocumentClass;
$this->defaultLimit = $defaultLimit;
$this->formMetadataProvider = $formMetadataProvider;
$this->tokenStorage = $tokenStorage;
}

/**
Expand All @@ -101,7 +119,7 @@ public function getConfiguration()
*/
protected function getConfigurationBuilder(): BuilderInterface
{
return Builder::create()
$builder = Builder::create()
->enableTags()
->enableCategories()
->enableLimit()
Expand All @@ -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;
}

/**
Expand All @@ -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'];
Expand All @@ -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'];
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -441,6 +475,30 @@ private function getFilter(array $filters, string $name, $default = null)
return $default;
}

/**
* @return array<int, array<string, string>>
*/
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.
*/
Expand Down
2 changes: 2 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@
<argument type="service" id="sulu_article.factory.resource_item"/>
<argument type="string">%sulu_article.view_document.article.class%</argument>
<argument type="string">%sulu_article.smart_content.default_limit%</argument>
<argument type="service" id="sulu_admin.form_metadata_provider" on-invalid="null"/>
<argument type="service" id="security.token_storage" on-invalid="null"/>

<tag name="sulu.smart_content.data_provider" alias="articles"/>
</service>
Expand Down
39 changes: 39 additions & 0 deletions Tests/Functional/Content/ArticleDataProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down

0 comments on commit 0c2c451

Please sign in to comment.