Skip to content

Ensure fields inside sets and collections have their correct definition #1568

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 0 additions & 1 deletion config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ services:
Bolt\Event\Listener\ContentFillListener:
tags:
- { name: doctrine.event_listener, event: postLoad }
- { name: doctrine.event_listener, event: preUpdate }
- { name: doctrine.event_listener, event: prePersist }

Bolt\Event\Listener\FieldFillListener:
Expand Down
15 changes: 13 additions & 2 deletions src/Configuration/Content/FieldType.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,21 @@ private static function defaults(): Collection
]);
}

public static function factory(string $name, ContentType $contentType): self
public static function factory(string $name, ContentType $contentType, array $parents = []): self
{
$defaults = static::defaults();
$fromContentType = new self($contentType->get('fields')->get($name, []));

if (empty($parents)) {
$fromContentType = new self($contentType->get('fields')->get($name, []));
} else {
$definition = $contentType;

foreach ($parents as $parent) {
$definition = $definition->get('fields')->get($parent, collect([]));
}

$fromContentType = $definition->get('fields', collect([]))->get($name, collect([]));
}

return new self($defaults->merge($fromContentType));
}
Expand Down
21 changes: 0 additions & 21 deletions src/Event/Listener/ContentFillListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

use Bolt\Configuration\Config;
use Bolt\Entity\Content;
use Bolt\Entity\Field;
use Bolt\Entity\FieldParentInterface;
use Bolt\Entity\User;
use Bolt\Enum\Statuses;
use Bolt\Repository\UserRepository;
Expand All @@ -32,25 +30,6 @@ public function __construct(Config $config, ContentExtension $contentExtension,
$this->users = $users;
}

public function preUpdate(LifecycleEventArgs $args): void
{
$entity = $args->getEntity();
// FieldParentInterface fields do not store anything in them.
// But the setValue and getValue methods are still useful in runtime.
// So, let's clear their value.
if ($entity instanceof Content) {
$entity->getFields()->filter(function (Field $field) {
// @todo: Allow sets to be cleared as well.
// Now they cannot be cleared, because the value
// can be used in a collection after preUpdate on
// the set is called.
return $field instanceof Field\CollectionField;
})->map(function (Field $field): void {
$field->setValue([]);
});
}
}

public function prePersist(LifecycleEventArgs $args): void
{
$entity = $args->getEntity();
Expand Down
45 changes: 25 additions & 20 deletions src/Event/Listener/FieldFillListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Bolt\Entity\Field\SetField;
use Bolt\Repository\FieldRepository;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Tightenco\Collect\Support\Collection;

class FieldFillListener
{
Expand All @@ -30,43 +29,49 @@ public function postLoad(LifecycleEventArgs $args): void
{
$entity = $args->getEntity();

if ($entity instanceof Field) {
$this->fillField($entity);
}

if ($entity instanceof CollectionField) {
// By calling fillContent form here, we ensure $entity has definition.
$this->cfl->fillContent($entity->getContent());
$this->fillCollection($entity);
}

if ($entity instanceof SetField) {
$this->cfl->fillContent($entity->getContent());
$this->fillSet($entity);
}
}

public function fillSet(SetField $entity): void
public function fillField(Field $field): void
{
$definition = $entity->getDefinition();
$fields = $this->fields->findAllByParent($entity);
// Fill in the definition of the field
$parents = $this->getParents($field);
$this->cfl->fillContent($field->getContent());
$contentDefinition = $field->getContent()->getDefinition();
$field->setDefinition($field->getName(), FieldType::factory($field->getName(), $contentDefinition, $parents));
}

private function getParents(Field $field): array
{
$parents = [];

/** @var Field $field */
foreach ($fields as $field) {
$definition = $definition->get('fields')[$field->getName()] ?? new Collection();
$field->setDefinition($field->getName(), $definition);
if ($field->hasParent()) {
$parents = $this->getParents($field->getParent());
$parents[] = $field->getParent()->getName();
}

return $parents;
}

public function fillSet(SetField $entity): void
{
$fields = $this->fields->findAllByParent($entity);
$entity->setValue($fields);
}

public function fillCollection(CollectionField $entity): void
{
$definition = $entity->getDefinition();
$fields = $this->intersectFieldsAndDefinition($this->fields->findAllByParent($entity), $definition);

/** @var Field $field */
foreach ($fields as $field) {
$fieldDefiniton = $entity->getDefinition()->get('fields')[$field->getName()] ?? new Collection();
$field->setDefinition($field->getName(), $fieldDefiniton);
}

$fields = $this->intersectFieldsAndDefinition($this->fields->findAllByParent($entity), $entity->getDefinition());
$entity->setValue($fields);
}

Expand Down
12 changes: 12 additions & 0 deletions src/Repository/FieldRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,16 @@ public static function factory(Collection $definition, string $name = '', string

return $field;
}

public function findParents(Field $field)
{
$qb = $this->getQueryBuilder();

return $qb
->andWhere('field.parent = :parentId')
->setParameter('parentId', $field->getId())
->orderBy('field.sortorder', 'ASC')
->getQuery()
->getResult();
}
}
4 changes: 1 addition & 3 deletions templates/_macro/_macro.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@

{% include '@bolt/_partials/fields/' ~ item_field.type ~ '.html.twig' with context only %}
{% endset %}
{# set the label manually as set in _base.html.twig, to pass to Collection.vue for templates #}
{% set label = item_field.definition.label|default(item_field.name|default('unnamed')|ucwords) %}
{% set fieldsHtml = fieldsHtml|merge([{'html': new_field, 'hash': hash, 'label': label}]) %}
{% set fieldsHtml = fieldsHtml|merge([{'html': new_field, 'hash': hash}]) %}
{% endfor %}
{{ fieldsHtml|json_encode }}
{% endapply %}{% endmacro %}
Expand Down