Makes collections persist. Introduces FieldParentInterface and FieldParentTrait

This commit is contained in:
Ivo Valchev
2020-01-13 10:05:01 +01:00
parent 1e3abf1ca3
commit b366ebf3cf
5 changed files with 117 additions and 105 deletions
@@ -10,6 +10,7 @@ use Bolt\Controller\CsrfTrait;
use Bolt\Controller\TwigAwareController;
use Bolt\Entity\Content;
use Bolt\Entity\Field;
use Bolt\Entity\Field\CollectionField;
use Bolt\Entity\Field\SetField;
use Bolt\Entity\Relation;
use Bolt\Entity\User;
@@ -317,62 +318,44 @@ class ContentEditController extends TwigAwareController implements BackendZone
}
}
// if (isset($formData['collections'])) {
// foreach ($formData['collections'] as $collection => $collectionItems) {
// $fieldsInCollection = [];
// $orderArray = array_flip($collectionItems['order']);
//
// //update all fields of the collection and collect their field_name and field_reference
// foreach ($collectionItems as $collectionItemName => $collectionItemValue) {
// if ($collectionItemName === 'order') {
// continue;
// }
//
// $collectionItemDefinition = $content->getDefinition()->get('fields')->get($collection)->get('fields')->get($collectionItemName);
// if ($collectionItemDefinition['type'] === 'set') {
// // if this is a set field, create fields for each field within the set
// foreach ($collectionItemValue as $hash => $fieldValue) {
// continue;
//// $this->updateSetItems($content, $collectionItemDefinition, $hash, $fieldValue, $locale);
// }
// } else {
// // if this is any other field
// $fieldDBname = $collection . '::' . $collectionItemName;
// $field = $this->getFieldToUpdate($content, $fieldDBname, $collectionItemDefinition);
// $this->updateField($field, $collectionItemValue, $locale);
// }
//
// //iterate over all submitted fields within the collection, get the correct index/order, to persist references
// //in the collection value
//// foreach ($collectionItemValue as $hash => $fieldValue) {
//// $index = $orderArray[$hash];
//// $fieldsInCollection[$index] = [
//// 'field_name' => $collectionItemName,
//// 'field_reference' => $hash,
//// 'field_type' => $collectionItemDefinition['type'],
//// ];
//// }
// }
//
// //create the collection field itself
// if ($content->hasField($collection)) {
// $collectionField = $content->getField($collection);
// } else {
// $collectionField = FieldRepository::factory($content->getDefinition()->get('fields')->get($collection));
// }
//
// //sort the array keys (1,3,2) ascending (1,2,3)
// ksort($fieldsInCollection);
//
// $collectionField->setName($collection);
// $collectionField->setValue($fieldsInCollection);
// $collectionField->setLocale($locale);
//
// if (! $content->hasField($collectionField->getName())) {
// $content->addField($collectionField);
// }
// }
// }
if (isset($formData['collections'])) {
foreach ($formData['collections'] as $collectionName => $collectionItems) {
$collectionDefinition = $content->getDefinition()->get('fields')->get($collectionName);
$orderArray = array_flip($collectionItems['order']);
if ($content->hasField($collectionName)) {
/** @var CollectionField $collection */
$collection = $content->getField($collectionName);
} else {
/** @var CollectionField $collection */
$collection = Field::factory($collectionDefinition, $collectionName);
$collection->setLocale($locale);
$content->addField($collection);
}
foreach ($collectionItems as $name => $collectionItemValue) {
// order field is only used to determine the order in which fields are submitted
if ($name === 'order') {
continue;
}
$hash = array_key_first($collectionItemValue);
$value = $collectionItemValue[$hash];
$order = $orderArray[$hash];
if($collection->hasChild($name)) {
$field = $collection->getChild($name);
} else {
$field = Field::factory($collectionDefinition->get('fields')->get($name), $name);
$field->setParent($collection);
$field->setSortorder($order);
$content->addField($field);
}
$this->updateField($field, $value, $locale);
}
}
}
if (isset($formData['taxonomy'])) {
foreach ($formData['taxonomy'] as $fieldName => $taxonomy) {
+29 -31
View File
@@ -6,53 +6,31 @@ namespace Bolt\Entity\Field;
use Bolt\Entity\Field;
use Bolt\Entity\FieldInterface;
use Bolt\Repository\FieldRepository;
use Bolt\Entity\FieldParentInterface;
use Bolt\Entity\FieldParentTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Sirius\Upload\Util\Arr;
/**
* @ORM\Entity
*/
class CollectionField extends Field implements FieldInterface
class CollectionField extends Field implements FieldInterface, FieldParentInterface
{
use FieldParentTrait;
public function getType(): string
{
return 'collection';
}
private function getCollectionFieldValues(): array
{
return parent::getValue();
}
public function getValue(): array
{
$fieldDefinitions = $this->getDefinition()->get('fields', []);
$result = [];
$thisFieldValues = $this->getCollectionFieldValues();
$i = 0;
foreach ($thisFieldValues as $thisFieldValue) {
if ($thisFieldValue['field_type'] === 'set') {
$field = new SetField();
$field->setContent($this->getContent());
$field->setValue($thisFieldValue['field_reference']);
$field->setDefinition($thisFieldValue['field_name'], $this->getDefinition()->get('fields')[$thisFieldValue['field_name']]);
$field->setName($thisFieldValue['field_name']);
} else {
$fieldDBname = $this->getName() . '::' . $thisFieldValue['field_name'];
$field = $this->getContent()->getField($fieldDBname);
//The field value persists ALL the values for the same type collection items (e.g. all 'ages') in an array
//To display the value for the current item, we set the value for the specific key only
//As $this->getValue() is called multiple times, clone the object to ensure $field->setValue() is called once per instance
$field = clone $field;
$field->setName($thisFieldValue['field_name']);
$field->setValue($field->getValue()[$thisFieldValue['field_reference']]);
$field->setDefinition($thisFieldValue['field_name'], $this->getDefinition()->get('fields')[$thisFieldValue['field_name']]);
}
$result['fields'][$i] = $field;
$i++;
}
$result['fields'] = $this->getOrderedChildren();
foreach ($fieldDefinitions as $fieldName => $fieldDefinition) {
$templateField = FieldRepository::factory($fieldDefinition, '', $fieldName);
@@ -63,4 +41,24 @@ class CollectionField extends Field implements FieldInterface
return $result;
}
private function getOrderedChildren(): ArrayCollection
{
if(! $this->getContent())
{
return new ArrayCollection();
}
$query = $this->getContent()->getRawFields()->filter(function (Field $field) {
return $field->getParent() === $this;
});
$iterator = $query->getIterator();
$iterator->uasort(function (Field $first, Field $second){
return (int) $first->getSortorder() > (int) $second->getSortorder() ? 1 : -1;
});
return new ArrayCollection(iterator_to_array($iterator));
}
}
+5 -18
View File
@@ -6,14 +6,17 @@ namespace Bolt\Entity\Field;
use Bolt\Entity\Field;
use Bolt\Entity\FieldInterface;
use Bolt\Repository\FieldRepository;
use Bolt\Entity\FieldParentInterface;
use Bolt\Entity\FieldParentTrait;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class SetField extends Field implements FieldInterface
class SetField extends Field implements FieldInterface, FieldParentInterface
{
use FieldParentTrait;
public function getType(): string
{
return 'set';
@@ -44,20 +47,4 @@ class SetField extends Field implements FieldInterface
return $result;
}
public function getChild(string $fieldName): Field
{
return $this->getContent()->getRawFields()->filter(function (Field $field) use ($fieldName) {
return $field->getParent() === $this && $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;
});
return ! $query->isEmpty();
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Bolt\Entity;
/**
* Any Field entity that has child fields must implement this interface.
*/
interface FieldParentInterface
{
public function getChild(string $fieldName): Field;
public function hasChild(string $fieldName): bool;
}
+29
View File
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Bolt\Entity;
/**
* Implements the methods of the FieldParentInterface.
*/
trait FieldParentTrait
{
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;
})->first();
}
public function hasChild(string $fieldName): bool
{
$query = $this->getContent()->getRawFields()->filter(function (Field $field) use ($fieldName) {
return $field->getParent() === $this && $field->getName() === $fieldName;
});
return ! $query->isEmpty();
}
}