Skip to content

Commit

Permalink
Refractor dimension content collection behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-schranz committed Oct 6, 2021
1 parent 32a6d9c commit e8c8b7b
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 113 deletions.
16 changes: 13 additions & 3 deletions Content/Application/ContentDataMapper/ContentDataMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,21 @@ public function __construct(iterable $dataMappers)
}

public function map(
array $data,
DimensionContentCollectionInterface $dimensionContentCollection
DimensionContentCollectionInterface $dimensionContentCollection,
array $data
): void {
$localizedDimensionAttributes = $dimensionContentCollection->getDimensionAttributes();
$unlocalizedDimensionAttributes = $localizedDimensionAttributes;
$unlocalizedDimensionAttributes['locale'] = null;

$unlocalizedDimensionContent = $dimensionContentCollection->getDimensionContent($unlocalizedDimensionAttributes)
?: $dimensionContentCollection->createDimensionContent($unlocalizedDimensionAttributes);

$localizedDimensionContent = $dimensionContentCollection->getDimensionContent($localizedDimensionAttributes)
?: $dimensionContentCollection->createDimensionContent($localizedDimensionAttributes);

foreach ($this->dataMappers as $mapper) {
$mapper->map($data, $dimensionContentCollection);
$mapper->map($data, $unlocalizedDimensionContent, $localizedDimensionContent);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface ContentDataMapperInterface
* @param array<string, mixed> $data
*/
public function map(
array $data,
DimensionContentCollectionInterface $dimensionContentCollection
DimensionContentCollectionInterface $dimensionContentCollection,
array $data
): void;
}
26 changes: 14 additions & 12 deletions Content/Application/ContentPersister/ContentPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@

namespace Sulu\Bundle\ContentBundle\Content\Application\ContentPersister;

use Sulu\Bundle\ContentBundle\Content\Application\ContentDataMapper\ContentDataMapperInterface;
use Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\ContentMergerInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Factory\DimensionContentCollectionFactoryInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\ContentRichEntityInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentCollectionInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentInterface;

class ContentPersister implements ContentPersisterInterface
Expand All @@ -25,35 +27,35 @@ class ContentPersister implements ContentPersisterInterface
*/
private $dimensionContentCollectionFactory;

/**
* @var ContentDataMapperInterface
*/
private $contentDataMapper;

/**
* @var ContentMergerInterface
*/
private $contentMerger;

public function __construct(
DimensionContentCollectionFactoryInterface $dimensionContentCollectionFactory,
ContentDataMapperInterface $contentDataMapper,
ContentMergerInterface $contentMerger
) {
$this->dimensionContentCollectionFactory = $dimensionContentCollectionFactory;
$this->contentDataMapper = $contentDataMapper;
$this->contentMerger = $contentMerger;
}

public function persist(ContentRichEntityInterface $contentRichEntity, array $data, array $dimensionAttributes): DimensionContentInterface
public function persist(ContentRichEntityInterface $contentRichEntity, array $data, array $dimensionAttributes): DimensionContentCollectionInterface
{
/*
* Data should always be persisted to the STAGE_DRAFT content-dimension of the given $dimensionAttributes.
* Modifying data of other content-dimensions (eg. STAGE_LIVE) should only be possible by applying transitions
* of the ContentWorkflow.
*
* TODO: maybe throw an exception here if the $dimensionAttributes contain another stage than 'STAGE_DRAFT'
*/

$dimensionContentCollection = $this->dimensionContentCollectionFactory->create(
$contentRichEntity,
$dimensionAttributes,
$data
$dimensionAttributes
);

return $this->contentMerger->merge($dimensionContentCollection);
$this->contentDataMapper->map($dimensionContentCollection, $data);

return $dimensionContentCollection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,115 +13,51 @@

namespace Sulu\Bundle\ContentBundle\Content\Application\DimensionContentCollectionFactory;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Sulu\Bundle\ContentBundle\Content\Application\ContentDataMapper\ContentDataMapperInterface;
use Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\Merger\MergerInterface;
use Sulu\Bundle\ContentBundle\Content\Application\ContentMetadataInspector\ContentMetadataInspectorInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Factory\DimensionContentCollectionFactoryInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\ContentRichEntityInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentCollection;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentCollectionInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Repository\DimensionContentRepositoryInterface;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;

class DimensionContentCollectionFactory implements DimensionContentCollectionFactoryInterface
{
/**
* @var DimensionContentRepositoryInterface
* @var ContentMetadataInspectorInterface
*/
private $dimensionContentRepository;
private $contentMetadataInspector;

/**
* @var ContentDataMapperInterface
* @var iterable<MergerInterface>
*/
private $contentDataMapper;
private $mergers;

/**
* @var PropertyAccessorInterface
* @var PropertyAccessor
*/
private $propertyAccessor;

public function __construct(
DimensionContentRepositoryInterface $dimensionContentRepository,
ContentDataMapperInterface $contentDataMapper,
iterable $mergers,
ContentMetadataInspectorInterface $contentMetadataInspector,
PropertyAccessor $propertyAccessor
) {
$this->dimensionContentRepository = $dimensionContentRepository;
$this->contentDataMapper = $contentDataMapper;
$this->mergers = $mergers;
$this->contentMetadataInspector = $contentMetadataInspector;
$this->propertyAccessor = $propertyAccessor;
}

public function create(
ContentRichEntityInterface $contentRichEntity,
array $dimensionAttributes,
array $data
array $dimensionAttributes
): DimensionContentCollectionInterface {
$dimensionContentCollection = $this->dimensionContentRepository->load($contentRichEntity, $dimensionAttributes);
$dimensionAttributes = $dimensionContentCollection->getDimensionAttributes();

$orderedContentDimensions = \iterator_to_array($dimensionContentCollection);
$dimensionContents = new ArrayCollection($orderedContentDimensions);

$unlocalizedAttributes = $dimensionAttributes;
$unlocalizedAttributes['locale'] = null;

// get or create unlocalized dimension content
$unlocalizedDimensionContent = $dimensionContentCollection->getDimensionContent($unlocalizedAttributes);

if (!$unlocalizedDimensionContent) {
$unlocalizedDimensionContent = $this->createContentDimension(
$contentRichEntity,
$dimensionContents,
$unlocalizedAttributes
);
$orderedContentDimensions[] = $unlocalizedDimensionContent;
}

$localizedDimensionContent = null;
if (isset($dimensionAttributes['locale'])) {
// get or create localized dimension content
$localizedDimensionContent = $dimensionContentCollection->getDimensionContent($dimensionAttributes);

if (!$localizedDimensionContent) {
$localizedDimensionContent = $this->createContentDimension(
$contentRichEntity,
$dimensionContents,
$dimensionAttributes
);
$orderedContentDimensions[] = $localizedDimensionContent;
}
}

$dimensionContentCollection = new DimensionContentCollection(
$orderedContentDimensions,
return new DimensionContentCollection(
$contentRichEntity,
$dimensionAttributes,
$dimensionContentCollection->getDimensionContentClass()
$this->contentMetadataInspector->getDimensionContentClass(\get_class($this)),
$this->mergers,
$this->propertyAccessor
);

$this->contentDataMapper->map($data, $dimensionContentCollection);

return $dimensionContentCollection;
}

/**
* @param Collection<int, DimensionContentInterface> $dimensionContents
* @param mixed[] $attributes
*/
private function createContentDimension(
ContentRichEntityInterface $contentRichEntity,
Collection $dimensionContents,
array $attributes
): DimensionContentInterface {
$dimensionContent = $contentRichEntity->createDimensionContent();

foreach ($attributes as $attributeName => $attributeValue) {
$this->propertyAccessor->setValue($dimensionContent, $attributeName, $attributeValue);
}

$contentRichEntity->addDimensionContent($dimensionContent);
$dimensionContents->add($dimensionContent);

return $dimensionContent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ interface DimensionContentCollectionFactoryInterface
*/
public function create(
ContentRichEntityInterface $contentRichEntity,
array $dimensionAttributes,
array $data
array $dimensionAttributes
): DimensionContentCollectionInterface;
}
1 change: 1 addition & 0 deletions Content/Domain/Model/ContentRichEntityInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Sulu\Bundle\ContentBundle\Content\Domain\Model;

use Doctrine\Common\Collections\Collection;
use Sulu\Bundle\ContentBundle\Content\Domain\Factory\DimensionContentCollectionFactoryInterface;

interface ContentRichEntityInterface
{
Expand Down
94 changes: 81 additions & 13 deletions Content/Domain/Model/DimensionContentCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\Merger\MergerInterface;
use Sulu\Component\Util\SortUtils;
use Symfony\Component\PropertyAccess\PropertyAccessor;

/**
* @implements \IteratorAggregate<DimensionContentInterface>
*/
class DimensionContentCollection implements \IteratorAggregate, DimensionContentCollectionInterface
{
/**
* @var ArrayCollection<int, DimensionContentInterface>
* @var ContentRichEntityInterface
*/
private $dimensionContents;
private $contentRichEntity;

/**
* @var mixed[]
Expand All @@ -42,26 +44,37 @@ class DimensionContentCollection implements \IteratorAggregate, DimensionContent
*/
private $defaultDimensionAttributes;

/**
* @var iterable<MergerInterface>
*/
private $mergers;

/**
* @var PropertyAccessor
*/
private $propertyAccessor;

/**
* DimensionContentCollection constructor.
*
* @param DimensionContentInterface[] $dimensionContents
* @param ContentRichEntityInterface $contentRichEntity
* @param mixed[] $dimensionAttributes
* @param class-string<DimensionContentInterface> $dimensionContentClass
* @param iterable<MergerInterface>
*/
public function __construct(
array $dimensionContents,
ContentRichEntityInterface $contentRichEntity,
array $dimensionAttributes,
string $dimensionContentClass
string $dimensionContentClass,
iterable $mergers,
PropertyAccessor $propertyAccessor
) {
$this->contentRichEntity = $contentRichEntity;
$this->dimensionContentClass = $dimensionContentClass;
$this->defaultDimensionAttributes = $dimensionContentClass::getDefaultDimensionAttributes();
$this->dimensionAttributes = $dimensionContentClass::getEffectiveDimensionAttributes($dimensionAttributes);

$this->dimensionContents = new ArrayCollection(
// dimension contents need to be sorted from most specific to least specific when they are merged
SortUtils::multisort($dimensionContents, \array_keys($this->dimensionAttributes), 'asc')
);
$this->mergers = $mergers;
$this->propertyAccessor = $propertyAccessor;
}

public function getDimensionContentClass(): string
Expand All @@ -84,7 +97,20 @@ public function getDimensionContent(array $dimensionAttributes): ?DimensionConte
$criteria->andWhere($expr);
}

return $this->dimensionContents->matching($criteria)->first() ?: null;
return $this->contentRichEntity->getDimensionContents()->matching($criteria)->first() ?: null;
}

public function createDimensionContent(array $dimensionAttributes): DimensionContentInterface
{
$dimensionContent = $this->contentRichEntity->createDimensionContent();

foreach ($dimensionAttributes as $attributeName => $attributeValue) {
$this->propertyAccessor->setValue($dimensionContent, $attributeName, $attributeValue);
}

$this->contentRichEntity->addDimensionContent($dimensionContent);

return $dimensionContent;
}

public function getDimensionAttributes(): array
Expand All @@ -94,11 +120,53 @@ public function getDimensionAttributes(): array

public function getIterator()
{
return $this->dimensionContents;
return new ArrayCollection(SortUtils::multisort(
$this->contentRichEntity->getDimensionContents()->toArray(),
\array_keys($this->dimensionAttributes), 'asc'
));
}

public function count(): int
{
return \count($this->dimensionContents);
return $this->contentRichEntity->getDimensionContents()->count();
}

public function getMergedDimensionContent(): DimensionContentInterface
{
$unlocalizedDimensionAttributes = $this->dimensionAttributes;
$unlocalizedDimensionAttributes['locale'] = null;

$dimensionContents = \array_filter([
$this->getDimensionContent($unlocalizedDimensionAttributes),
$this->getDimensionContent($this->dimensionAttributes),
]);

$mergedDimensionContent = null;

foreach ($dimensionContents as $dimensionContent) {
if (!$mergedDimensionContent) {
$contentRichEntity = $dimensionContent->getResource();
$mergedDimensionContent = $contentRichEntity->createDimensionContent();
$mergedDimensionContent->markAsMerged();
}

foreach ($this->mergers as $merger) {
$merger->merge($mergedDimensionContent, $dimensionContent);
}

foreach ($this->dimensionAttributes as $key => $value) {
$this->propertyAccessor->setValue(
$mergedDimensionContent,
$key,
$this->propertyAccessor->getValue($dimensionContent, $key)
);
}
}

if (!$mergedDimensionContent) {
throw new \RuntimeException('Expected at least one dimensionContent given.');
}

return $mergedDimensionContent;
}
}
Loading

0 comments on commit e8c8b7b

Please sign in to comment.