Skip to content

Commit

Permalink
Merge pull request #1362 from bolt/feature/set-default
Browse files Browse the repository at this point in the history
Feature/set default
  • Loading branch information
bobdenotter authored May 12, 2020
2 parents d7f85f0 + e360c87 commit b8820ed
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 43 deletions.
31 changes: 31 additions & 0 deletions config/bolt/contenttypes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,37 @@ tests:
values: [ A-tuin, Donatello, Rafael, Leonardo, Michelangelo, Koopa, Squirtle ]
multiple: true
postfix: "Select your favourite turtle(s)."
set_field:
type: set
fields:
title:
type: text
year:
type: number
default:
title: "This is the default title value"
year: 2020
collection_field:
type: collection
fields:
photo:
type: image
paragraph:
type: text
default:
0:
field: photo
default:
filename: "kitten.jpg"
alt: "Cute kitten"
1:
field: paragraph
default: "An image, followed by some content"
2:
field: photo
default:
filename: "joey.jpg"
alt: "Photo of a foal"
taxonomy: [ groups, categories, tags, foobars ]
record_template: custom/test.twig
listing_template: listing.twig
Expand Down
20 changes: 8 additions & 12 deletions src/Controller/Backend/ContentEditController.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,12 @@ private function removeFieldChildren(Content $content, FieldParentInterface $fie

/** @var Field $child */
$content->removeField($child);
$this->em->remove($child);

// Only attempt removal if the entity is already persisted (managed)
// by the entity manager
if ($this->em->contains($child)) {
$this->em->remove($child);
}
}
}

Expand Down Expand Up @@ -421,19 +426,10 @@ private function updateField(Field $field, $value, ?string $locale): void
$value = Json::findArray($value);
}

if ($field->getType() === SetField::TYPE) {
if ($field instanceof SetField) {
foreach ($value as $name => $svalue) {
/** @var SetField $field */
if ($field->hasChild($name)) {
$child = $field->getChild($name);
} else {
$child = FieldRepository::factory($field->getDefinition()->get('fields')->get($name), $name);
$child->setParent($field);
$field->getContent()->addField($child);
}

$child = $field->getChild($name);
$child->setDefinition($child->getName(), $field->getDefinition()->get('fields')->get($child->getName()));

$this->updateField($child, $svalue, $locale);
}
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/DataFixtures/ContentFixtures.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,14 @@ private function loadSetField(Content $content, Field $set, ContentType $content
{
$setChildren = $set->getDefinition()->get('fields');

$children = [];
foreach ($setChildren as $setChild => $setChildType) {
$child = $this->loadField($content, $setChild, $setChildType, $contentType, $preset, false);
$child->setParent($set);
$content->addField($child);
$children[] = $child;
}

$set->setValue($children);

return $set;
}

Expand Down
5 changes: 2 additions & 3 deletions src/Entity/Field/CollectionField.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ public function getDefaultValue()

$result = [];

foreach ($default as $i) {
/** @var ContentType $type */
$type = $default[$i];
/** @var ContentType $type */
foreach ($default as $type) {
$value = $type->toArray()['default'];
$name = $type->toArray()['field'];
$definition = $this->getDefinition()->get('fields')[$name];
Expand Down
17 changes: 17 additions & 0 deletions src/Entity/Field/EmailField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Bolt\Entity\Field;

use Bolt\Entity\Field;
use Bolt\Entity\FieldInterface;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
class EmailField extends Field implements FieldInterface
{
public const TYPE = 'email';
}
76 changes: 62 additions & 14 deletions src/Entity/Field/SetField.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

namespace Bolt\Entity\Field;

use Bolt\Entity\Content;
use Bolt\Entity\Field;
use Bolt\Entity\FieldInterface;
use Bolt\Entity\FieldParentInterface;
use Bolt\Entity\FieldParentTrait;
use Bolt\Repository\FieldRepository;
use Doctrine\ORM\Mapping as ORM;
use Tightenco\Collect\Support\Collection;

/**
* @ORM\Entity
Expand All @@ -22,28 +24,60 @@ class SetField extends Field implements FieldInterface, FieldParentInterface

public function getValue(): array
{
$result = [];
if (empty(parent::getValue())) {
// create new ones from the definition
$fieldDefinitions = $this->getDefinition()->get('fields');

$fieldDefinitions = $this->getDefinition()->get('fields');
if (! is_iterable($fieldDefinitions)) {
return [];
}

// If there's no current $fieldDefinitions, we can return early
if (! is_iterable($fieldDefinitions)) {
return $result;
$newFields = [];
foreach ($fieldDefinitions as $name => $definition) {
$newFields[] = FieldRepository::factory($definition, $name);
}
$this->setValue($newFields);
}

foreach ($fieldDefinitions as $name => $definition) {
if ($this->getContent() && $this->hasChild($name)) {
$field = $this->getChild($name);
$field->setDefinition($name, $definition);
return parent::getValue();
}

public function setValue($fields): Field
{
if (! is_iterable($fields)) {
return $this;
}

$definedFields = array_flip($this->getDefinition()->get('fields', new Collection())->keys()->toArray());

$value = [];

/** @var Field $field */
foreach ($fields as $field) {
$field->setParent($this);
$value[$field->getName()] = $field;
}

// Sorts the fields in the order specified in the definition
$value = array_merge(array_flip(array_intersect(array_keys($definedFields), array_keys($value))), $value);

parent::setValue($value);

return $this;
}

public function setContent(?Content $content): Field
{
/** @var Field $child */
foreach ($this->getValue() as $child) {
if ($content !== null) {
$content->addField($child);
} else {
$field = FieldRepository::factory($definition);
$child->setContent($content);
}

$field->setName($name);
$result[$name] = $field;
}

return $result;
return parent::setContent($content);
}

public function getApiValue()
Expand All @@ -56,4 +90,18 @@ public function getApiValue()

return $result;
}

public function getDefaultValue()
{
$defaultValues = parent::getDefaultValue();
$value = $this->getValue();

foreach ($defaultValues as $name => $default) {
if (array_key_exists($name, $value)) {
$value[$name]->setValue($default);
}
}

return $value;
}
}
14 changes: 6 additions & 8 deletions src/Entity/FieldParentTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ abstract public function getContent(): ?Content;

public function getChild(string $fieldName): Field
{
return $this->getContent()->getRawFields()->filter(function (Field $field) use ($fieldName) {
return $field->getParent() === $this && $field->getName() === $fieldName;
return collect($this->getValue())->filter(function (Field $field) use ($fieldName) {
return $field->getName() === $fieldName;
})->first();
}

public function hasChild(string $fieldName): bool
{
$query = $this->getContent()->getRawFields()->filter(function (Field $field) use ($fieldName) {
return $field->getParent() === $this && $field->getName() === $fieldName;
$query = collect($this->getValue())->filter(function (Field $field) use ($fieldName) {
return $field->getName() === $fieldName;
});

return ! $query->isEmpty();
}

public function hasChildren(): bool
{
$query = $this->getContent()->getRawFields()->filter(function (Field $field) {
$query = collect($this->getValue())->filter(function (Field $field) {
return $field->getParent() === $this;
});

Expand All @@ -38,9 +38,7 @@ public function hasChildren(): bool

public function getChildren(): array
{
return $this->getContent()->getRawFields()->filter(function (Field $field) {
return $field->getParent() === $this;
})->toArray();
return $this->getValue();
}

public function setLocale(?string $locale): Field
Expand Down
6 changes: 5 additions & 1 deletion src/Event/Listener/ContentFillListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ public function preUpdate(LifecycleEventArgs $args): void
// So, let's clear their value.
if ($entity instanceof Content) {
$entity->getFields()->filter(function (Field $field) {
return $field instanceof FieldParentInterface;
// @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([]);
});
Expand Down
19 changes: 19 additions & 0 deletions src/Event/Listener/FieldFillListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Bolt\Entity\Field;
use Bolt\Entity\Field\CollectionField;
use Bolt\Entity\Field\SetField;
use Bolt\Repository\FieldRepository;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Tightenco\Collect\Support\Collection;
Expand Down Expand Up @@ -33,6 +34,24 @@ public function postLoad(LifecycleEventArgs $args): void
$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
{
$fields = $this->fields->findAllByParent($entity);

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

$entity->setValue($fields);
}

public function fillCollection(CollectionField $entity): void
Expand Down
2 changes: 1 addition & 1 deletion src/Repository/FieldRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function findOneBySlug(string $slug): ?Field

public function findAllByParent(Field $field): ?array
{
if (! $field instanceof FieldParentInterface) {
if (! $field instanceof FieldParentInterface || ! $field->getId()) {
return [];
}

Expand Down
28 changes: 26 additions & 2 deletions tests/e2e/edit_record_1.feature
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,14 @@ Feature: Edit record
And I should see "Collection:" in the "label[for='field-collection']" element

#templates dropdown
When I click "#multiselect-undefined > div > div.multiselect__select"
When I scroll "#multiselect-undefined > div > div.multiselect__select" into view
And I click "#multiselect-undefined > div > div.multiselect__select"

Then I should see "Set" in the "#multiselect-undefined li:nth-child(1) > span" element
And I should see "Textarea" in the "#multiselect-undefined li:nth-child(2) > span" element

When I click "#multiselect-undefined > div > div.multiselect__content-wrapper > ul > li:nth-child(2) > span"
When I click "#multiselect-undefined > div > div.multiselect__select"
And I click "#multiselect-undefined > div > div.multiselect__content-wrapper > ul > li:nth-child(2) > span"
And I press "Add item"

Then I should see an ".collection-item" element
Expand Down Expand Up @@ -318,8 +320,30 @@ Feature: Edit record
And the "fields[title]" field should contain "Title of a test contenttype"
And the "fields[image][filename]" field should contain "foal.jpg"

And the "sets[set_field][title]" field should contain "This is the default title value"
And the "sets[set_field][year]" field should contain "2020"

And the "collections[collection_field][photo][1][filename]" field should contain "kitten.jpg"
And the "collections[collection_field][photo][1][alt]" field should contain "Cute kitten"

And the "collections[collection_field][paragraph][2]" field should contain "An image, followed by some content"

And the "collections[collection_field][photo][3][filename]" field should contain "joey.jpg"
And the "collections[collection_field][photo][3][alt]" field should contain "Photo of a foal"

When I scroll "Save changes" into view
And I press "Save changes"

Then the "fields[title]" field should contain "Title of a test contenttype"
And the "fields[image][filename]" field should contain "foal.jpg"

And the "sets[set_field][title]" field should contain "This is the default title value"
And the "sets[set_field][year]" field should contain "2020"

And the "collections[collection_field][photo][1][filename]" field should contain "kitten.jpg"
And the "collections[collection_field][photo][1][alt]" field should contain "Cute kitten"

And the "collections[collection_field][paragraph][2]" field should contain "An image, followed by some content"

And the "collections[collection_field][photo][3][filename]" field should contain "joey.jpg"
And the "collections[collection_field][photo][3][alt]" field should contain "Photo of a foal"

0 comments on commit b8820ed

Please sign in to comment.