Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named types #13

Draft
wants to merge 4 commits into
base: 1.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/research/named_field_types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Named query field types

A higher level version of the query field type. Through configuration, queries are associated to a name. Those are added added to the list of available field types. When added, they query type isn't show, and the parameters are immediately displayed for editing. It saves time when modelling the content by allowing to reuse the same type for a similar concept.

## Examples

```
ezplatform:
queries:
children:
type: eZ:Children
default_parameters:
location: '@=mainLocation'
type: '@=returnedType'
relating_content:
type: eZ:ContentRelatedTo
default_parameters:
to_content: '@=content'
type: '@=returnedType'
```

## Extra features

### Default query type parameters

Content and location level (not field) based parameters can get a default value: the current content, its section, the returned type...

### Translation

That extra layer is a good place for translating parameters.

### Customization

Custom templates could be associated to named query field types, giving extra flexibility.
It would allow to use or extend the same template when the same list type is used, without
template configuration.

### Extensibiliy

Named queries make it easy for 3rd parties to add their own field types without developing any:

- define new query types, with custom criteria if needed
- define named queries that would show up as field types, without implementing an actual field type
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
*/
namespace EzSystems\EzPlatformQueryFieldType\Symfony\DependencyInjection;

use EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery;
use EzSystems\EzPlatformQueryFieldType\eZ\Persistence\Legacy\Content\FieldValue\Converter\QueryConverter;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
Expand All @@ -27,6 +31,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('services.yml');

$this->addContentViewConfig($container);
$this->handleNamedTypes($container);
}

public function prepend(ContainerBuilder $container)
Expand Down Expand Up @@ -100,4 +105,51 @@ protected function prependFieldTemplateConfig(ContainerBuilder $container): void
$container->prependExtensionConfig('ezpublish', $config);
$container->addResource(new FileResource($configFile));
}

private function handleNamedTypes(ContainerBuilder $container)
{
if (!$container->hasParameter('ezcontentquery_named')) {
return;
}

foreach ($container->getParameter('ezcontentquery_named') as $name => $config) {
// @todo validate name syntax
$fieldTypeIdentifier = 'ezcontentquery_' . $name;

$this->defineFieldTypeService($container, $fieldTypeIdentifier, $config);
$this->tagFieldTypeConverter($container, $fieldTypeIdentifier);
$this->tagFieldTypeFormMapper($container, $config, $fieldTypeIdentifier);
}
}

private function defineFieldTypeService(ContainerBuilder $container, string $fieldTypeIdentifier, array $config)
{
$serviceId = NamedQuery\Type::class . '\\' . $fieldTypeIdentifier;

$definition = new ChildDefinition('ezpublish.fieldType');
$definition->setClass(NamedQuery\Type::class);
$definition->setAutowired(true);
$definition->setPublic(true);
$definition->addTag('ezpublish.fieldType', ['alias' => $fieldTypeIdentifier]);
$definition->setArgument('$identifier', $fieldTypeIdentifier);
$definition->setArgument('$config', $config);
$container->setDefinition($serviceId, $definition);
}

private function tagFieldTypeConverter(ContainerBuilder $container, string $fieldTypeIdentifier)
{
$container->getDefinition(QueryConverter::class)->addTag(
'ezpublish.storageEngine.legacy.converter',
['alias' => $fieldTypeIdentifier]
);
}

private function tagFieldTypeFormMapper(ContainerBuilder $container, array $config, string $fieldTypeIdentifier)
{
$definition = new Definition(NamedQuery\Mapper::class);
$definition->addTag('ez.fieldFormMapper.definition', ['fieldType' => $fieldTypeIdentifier]);
$definition->setAutowired(true);
$definition->setArgument('$queryType', $config['query_type']);
$container->setDefinition(NamedQuery\Mapper::class . '\\' . $fieldTypeIdentifier, $definition);
}
}
11 changes: 11 additions & 0 deletions src/Symfony/Resources/config/default_parameters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@ parameters:
ezcontentquery_field_view: 'content_query_field'
ezcontentquery_item_view: 'line'
ezcontentquery_identifier: 'ezcontentquery'
ezcontentquery_named:
children:
query_type: eZ:Children
default_parameters:
location: 'mainLocation'
type: 'returnedType'
relating:
query_type: AppBundle:RelatedToContent
default_parameters:
to_content: 'content'
type: 'returnedType'
15 changes: 15 additions & 0 deletions src/Symfony/Resources/config/services/ezplatform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,18 @@ services:
$views: { field: '%ezcontentquery_field_view%', item: '%ezcontentquery_item_view%' }
tags:
- { name: kernel.event_subscriber }

EzSystems\EzPlatformQueryFieldType\eZ\Twig\QueryFieldBlockRenderer:
decorates: ezpublish.templating.field_block_renderer.twig
arguments:
$innerRenderer: '@EzSystems\EzPlatformQueryFieldType\eZ\Twig\QueryFieldBlockRenderer.inner'

EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form\FieldDefinitionParametersType:
arguments:
$parametersSubscriber: '@EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form\EventSubscriber\FieldDefinitionParametersSubscriber'
tags:
- { name: form.type }

EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form\EventSubscriber\FieldDefinitionParametersSubscriber:
tags:
- { name: kernel.event_subscriber }
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,17 @@
{{- form_widget(form.Parameters) -}}
</div>
{% endblock %}

{% block ezcontentquery_named_field_definition_edit %}
<div class="query-returned-type{% if group_class is not empty %} {{ group_class }}{% endif %}">
{{- form_label(form.ReturnedType) -}}
{{- form_errors(form.ReturnedType) -}}
{{- form_widget(form.ReturnedType) -}}
</div>

<div class="query-parameters{% if group_class is not empty %} {{ group_class }}{% endif %}">
{{- form_label(form.Parameters) -}}
{{- form_errors(form.Parameters) -}}
{{- form_widget(form.Parameters) -}}
</div>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@
{{ block( 'settings_defaultvalue' ) }}
</ul>
{% endblock %}

{% block ezcontentquery_named_settings %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form\EventSubscriber;

use eZ\Publish\Core\QueryType\QueryTypeRegistry;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class FieldDefinitionParametersSubscriber implements EventSubscriberInterface
{
/** @var \eZ\Publish\Core\QueryType\QueryTypeRegistry */
private $queryTypeRegistry;

public function __construct(QueryTypeRegistry $queryTypeRegistry)
{
$this->queryTypeRegistry = $queryTypeRegistry;
}

public static function getSubscribedEvents()
{
return [FormEvents::PRE_SET_DATA => 'addParametersFormFields'];
}

public function addParametersFormFields(FormEvent $event)
{
$data = $event->getData();
if ($data === null) {
return;
}

$queryTypeIdentifier = $event->getForm()->getConfig()->getOption('query_type');
if ($queryTypeIdentifier === null) {
return;
}

$queryType = $this->queryTypeRegistry->getQueryType($queryTypeIdentifier);
foreach ($queryType->getSupportedParameters() as $parameter) {
$event->getForm()->add(
$parameter,
Type\TextType::class,
[
'label' => $parameter,
'property_path' => sprintf('[%s]', $parameter),
'required' => false,
]
);
}
}
}
39 changes: 39 additions & 0 deletions src/eZ/FieldType/NamedQuery/Form/FieldDefinitionParametersType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FieldDefinitionParametersType extends AbstractType
{
/** @var \Symfony\Component\EventDispatcher\EventSubscriberInterface */
private $parametersSubscriber;

public function __construct(EventSubscriberInterface $parametersSubscriber)
{
$this->parametersSubscriber = $parametersSubscriber;
}

public function getParent()
{
return Type\FormType::class;
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('query_type', null);
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber($this->parametersSubscriber);
}
}
73 changes: 73 additions & 0 deletions src/eZ/FieldType/NamedQuery/Mapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery;

use eZ\Publish\API\Repository\ContentTypeService;
use eZ\Publish\Core\QueryType\QueryTypeRegistry;
use EzSystems\EzPlatformQueryFieldType\eZ\FieldType\Mapper\ParametersTransformer;
use EzSystems\EzPlatformQueryFieldType\eZ\FieldType\NamedQuery\Form\FieldDefinitionParametersType;
use EzSystems\RepositoryForms\Data\FieldDefinitionData;
use EzSystems\RepositoryForms\FieldType\FieldDefinitionFormMapperInterface;
use Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class Mapper implements FieldDefinitionFormMapperInterface
{
/** @var ContentTypeService */
private $contentTypeService;
/**
* @var string
*/
private $queryType;
/**
* @var \eZ\Publish\Core\QueryType\QueryTypeRegistry
*/
private $queryTypeRegistry;

public function __construct(ContentTypeService $contentTypeService, QueryTypeRegistry $queryTypeRegistry, string $queryType)
{
$this->contentTypeService = $contentTypeService;
$this->queryType = $queryType;
$this->queryTypeRegistry = $queryTypeRegistry;
}

public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data)
{
$fieldDefinitionForm
->add('ReturnedType', Type\ChoiceType::class,
[
'label' => 'Returned type',
'property_path' => 'fieldSettings[ReturnedType]',
'choices' => $this->getContentTypes(),
'required' => true,
]
)
->add('Parameters', FieldDefinitionParametersType::class,
[
'property_path' => 'fieldSettings[Parameters]',
'query_type' => $data->fieldSettings['QueryType'],
]);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'translation_domain' => 'ezrepoforms_content_type',
]);
}

private function getContentTypes()
{
foreach ($this->contentTypeService->loadContentTypeGroups() as $contentTypeGroup) {
foreach ($this->contentTypeService->loadContentTypes($contentTypeGroup) as $contentType) {
yield $contentType->getName() => $contentType->identifier;
}
}
}
}
Loading