Skip to content

Commit

Permalink
Add ghost locale handling
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-schranz committed Oct 15, 2021
1 parent 0343c4c commit dc79ba3
Show file tree
Hide file tree
Showing 23 changed files with 449 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

/*
* This file is part of Sulu.
*
* (c) Sulu GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\Merger;

use Sulu\Bundle\ContentBundle\Content\Domain\Model\DimensionContentInterface;

class DimensionContentMerger implements MergerInterface
{
public function merge(object $targetObject, object $sourceObject): void
{
if (!$targetObject instanceof DimensionContentInterface) {
return;
}

if (!$sourceObject instanceof DimensionContentInterface) {
return;
}

if ($ghostLocale = $sourceObject->getGhostLocale()) {
$targetObject->setGhostLocale($ghostLocale);
}

foreach ($sourceObject->getAvailableLocales() ?: [] as $availableLocale) {
$targetObject->addAvailableLocale($availableLocale);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

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\Domain\Factory\DimensionContentCollectionFactoryInterface;
use Sulu\Bundle\ContentBundle\Content\Domain\Model\ContentRichEntityInterface;
Expand Down Expand Up @@ -60,41 +58,40 @@ public function create(
$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;
$unlocalizedDimensionContent->addAvailableLocale($localizedDimensionContent->getLocale());

if (!$unlocalizedDimensionContent->getGhostLocale() && $localizedDimensionContent) {
$unlocalizedDimensionContent->setGhostLocale($localizedDimensionContent->getLocale());
}
}
}

$dimensionContentCollection = new DimensionContentCollection(
$orderedContentDimensions,
\array_filter([
$unlocalizedDimensionContent,
$localizedDimensionContent,
]),
$dimensionAttributes,
$dimensionContentCollection->getDimensionContentClass()
);
Expand All @@ -105,12 +102,10 @@ public function create(
}

/**
* @param Collection<int, DimensionContentInterface> $dimensionContents
* @param mixed[] $attributes
*/
private function createContentDimension(
ContentRichEntityInterface $contentRichEntity,
Collection $dimensionContents,
array $attributes
): DimensionContentInterface {
$dimensionContent = $contentRichEntity->createDimensionContent();
Expand All @@ -120,7 +115,6 @@ private function createContentDimension(
}

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

return $dimensionContent;
}
Expand Down
23 changes: 23 additions & 0 deletions Content/Domain/Model/DimensionContentInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,39 @@ public static function getResourceKey(): string;

public function getLocale(): ?string;

/**
* @internal should only be set by content bundle services not from outside
*/
public function setLocale(?string $locale): void;

/**
* @internal should only be set by content bundle services not from outside
*/
public function setGhostLocale(?string $ghostLocale): void;

public function getGhostLocale(): ?string;

/**
* @internal should only be set by content bundle services not from outside
*/
public function addAvailableLocale(string $availableLocale): void;

public function getAvailableLocales(): ?array;

public function getStage(): string;

/**
* @internal should only be set by content bundle services not from outside
*/
public function setStage(string $stage): void;

public function getResource(): ContentRichEntityInterface;

public function isMerged(): bool;

/**
* @internal should only be set by content bundle services not from outside
*/
public function markAsMerged(): void;

/**
Expand Down
51 changes: 51 additions & 0 deletions Content/Domain/Model/DimensionContentTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ trait DimensionContentTrait
*/
protected $locale;

/**
* @var string|null
*/
protected $ghostLocale;

/**
* @var string[]|null
*/
protected $availableLocales;

/**
* @var string
*/
Expand All @@ -30,6 +40,9 @@ trait DimensionContentTrait
*/
private $isMerged = false;

/**
* @internal should only be set by content bundle services not from outside
*/
public function setLocale(?string $locale): void
{
$this->locale = $locale;
Expand All @@ -40,6 +53,41 @@ public function getLocale(): ?string
return $this->locale;
}

/**
* @internal should only be set by content bundle services not from outside
*/
public function setGhostLocale(?string $ghostLocale): void
{
$this->ghostLocale = $ghostLocale;
}

public function getGhostLocale(): ?string
{
return $this->ghostLocale;
}

/**
* @internal should only be set by content bundle services not from outside
*/
public function addAvailableLocale(string $availableLocale): void
{
if (null === $this->availableLocales) {
$this->availableLocales = [];
}

if (!\in_array($availableLocale, $this->availableLocales, true)) {
$this->availableLocales[] = $availableLocale;
}
}

public function getAvailableLocales(): ?array
{
return $this->availableLocales;
}

/**
* @internal should only be set by content bundle services not from outside
*/
public function setStage(string $stage): void
{
$this->stage = $stage;
Expand All @@ -55,6 +103,9 @@ public function isMerged(): bool
return $this->isMerged;
}

/**
* @internal should only be set by content bundle services not from outside
*/
public function markAsMerged(): void
{
$this->isMerged = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
use Webmozart\Assert\Assert;

/**
* TODO add loadGhost functionality
* add loadShadow functionality.
* TODO add loadShadow functionality.
*
* @final
*/
Expand Down Expand Up @@ -88,6 +87,7 @@ public function __construct(
* tagNames?: string[],
* tagOperator?: 'AND'|'OR',
* templateKeys?: string[],
* loadGhost?: bool,
* } $filters
*/
public function addFilters(
Expand All @@ -114,6 +114,11 @@ public function addFilters(
continue;
}

if ('locale' === $key && ($filters['loadGhost'] ?? false)) {
// do not filter by locale when loadGhost is active
continue;
}

$queryBuilder->andWhere('filterDimensionContent.' . $key . '= :' . $key)
->setParameter($key, $value);
}
Expand Down
2 changes: 2 additions & 0 deletions Content/Infrastructure/Doctrine/MetadataLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $event): void
if ($reflection->implementsInterface(DimensionContentInterface::class)) {
$this->addField($metadata, 'stage', 'string', ['length' => 16, 'nullable' => false]);
$this->addField($metadata, 'locale', 'string', ['length' => 7, 'nullable' => true]);
$this->addField($metadata, 'ghostLocale', 'string', ['length' => 7, 'nullable' => true]);
$this->addField($metadata, 'availableLocales', 'json', ['nullable' => true]);
}

if ($reflection->implementsInterface(SeoInterface::class)) {
Expand Down
4 changes: 4 additions & 0 deletions Resources/config/merger.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<!-- Merger -->
<service id="sulu_content.dimension_content_merger" class="Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\Merger\DimensionContentMerger">
<tag name="sulu_content.merger" priority="256"/>
</service>

<service id="`sulu_content.template_merger`" class="Sulu\Bundle\ContentBundle\Content\Application\ContentMerger\Merger\TemplateMerger">
<tag name="sulu_content.merger" priority="128"/>
</service>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public function cgetAction(Request $request): Response
$fieldDescriptors = $this->fieldDescriptorFactory->getFieldDescriptors(Example::RESOURCE_KEY);
/** @var DoctrineListBuilder $listBuilder */
$listBuilder = $this->listBuilderFactory->create(Example::class);
$listBuilder->addSelectField($fieldDescriptors['locale']);
$listBuilder->addSelectField($fieldDescriptors['ghostLocale']);
$listBuilder->setParameter('locale', $request->query->get('locale'));
$this->restHelper->initializeListBuilder($listBuilder, $fieldDescriptors);

Expand Down Expand Up @@ -183,6 +185,25 @@ public function postTriggerAction(string $id, Request $request): Response
$action = $request->query->get('action');

switch ($action) {
case 'copy-locale':
$dimensionContent = $this->contentManager->copy(
$example,
[
'stage' => DimensionContentInterface::STAGE_DRAFT,
'locale' => $request->query->get('src'),
],
$example,
[
'stage' => DimensionContentInterface::STAGE_DRAFT,
'locale' => $request->query->get('dest'),
],
);

$this->entityManager->flush();

return $this->handleView($this->view($this->normalize($example, $dimensionContent)));

break;
case 'unpublish':
$dimensionContent = $this->contentManager->applyTransition(
$example,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,56 @@
</join>
</joins>

<joins name="unlocalizedDimensionContent">
<join>
<entity-name>unlocalizedDimensionContent</entity-name>
<field-name>Sulu\Bundle\ContentBundle\Tests\Application\ExampleTestBundle\Entity\Example.dimensionContents</field-name>
<method>LEFT</method>
<condition>unlocalizedDimensionContent.locale IS NULL AND unlocalizedDimensionContent.stage = 'draft'</condition>
</join>
</joins>

<joins name="ghostDimensionContent" ref="unlocalizedDimensionContent">
<join>
<entity-name>ghostDimensionContent</entity-name>
<field-name>Sulu\Bundle\ContentBundle\Tests\Application\ExampleTestBundle\Entity\Example.dimensionContents</field-name>
<method>LEFT</method>
<condition>ghostDimensionContent.locale = unlocalizedDimensionContent.ghostLocale AND ghostDimensionContent.stage = 'draft'</condition>
</join>
</joins>

<properties>
<property name="id" translation="sulu_admin.id">
<field-name>id</field-name>
<entity-name>Sulu\Bundle\ContentBundle\Tests\Application\ExampleTestBundle\Entity\Example</entity-name>
</property>

<property name="title" visibility="yes" translation="sulu_admin.title">
<field-name>title</field-name>
<case-property name="title" translation="sulu_admin.title" visibility="always" searchability="yes">
<field>
<field-name>title</field-name>
<entity-name>dimensionContent</entity-name>

<joins ref="dimensionContent"/>
</field>

<field>
<field-name>title</field-name>
<entity-name>ghostDimensionContent</entity-name>

<joins ref="ghostDimensionContent"/>
</field>

<transformer type="title"/>
</case-property>

<property name="locale" translation="sulu_admin.locale" visibility="never">
<field-name>locale</field-name>
<entity-name>dimensionContent</entity-name>
</property>

<joins ref="dimensionContent"/>
<property name="ghostLocale" translation="sulu_admin.ghost_locale" visibility="never">
<field-name>ghostLocale</field-name>
<entity-name>unlocalizedDimensionContent</entity-name>
</property>
</properties>
</list>

0 comments on commit dc79ba3

Please sign in to comment.