-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from sitegeist/feature/contentCollectionCompar…
…ison FEATURE: Optional overview to compare translation on collection and document level
- Loading branch information
Showing
33 changed files
with
5,606 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\LostInTranslation\Domain\CollectionComparison; | ||
|
||
use Neos\ContentRepository\Domain\Service\Context; | ||
use Neos\Flow\Annotations as Flow; | ||
use Neos\ContentRepository\Domain\Model\NodeInterface; | ||
use Neos\Neos\Domain\Service\ContentContextFactory; | ||
|
||
class Comparator | ||
{ | ||
/** | ||
* @var ContentContextFactory | ||
* @Flow\Inject | ||
*/ | ||
protected $contextFactory; | ||
|
||
public function compareCollectionNode(NodeInterface $currentNode, NodeInterface $referenceNode): Result | ||
{ | ||
if ($currentNode->getNodeType()->isOfType('Neos.Neos:ContentCollection') === false) { | ||
throw new \InvalidArgumentException($currentNode->getNodeType()->getName() . " is not of type Neos.Neos:ContentCollection"); | ||
} | ||
|
||
$result = Result::createEmpty(); | ||
|
||
// ensure deleted but not yet published nodes are found aswell so we will not try to translate those | ||
$currentContextProperties = $currentNode->getContext()->getProperties(); | ||
$currentContextProperties['removedContentShown'] = true; | ||
$currentContextIncludingRemovedItems = $this->contextFactory->create($currentContextProperties); | ||
|
||
$result = $this->traverseContentCollectionForAlteredNodes( | ||
$currentNode, | ||
$referenceNode, | ||
$currentContextIncludingRemovedItems, | ||
$result | ||
); | ||
|
||
return $result; | ||
} | ||
|
||
public function compareDocumentNode(NodeInterface $currentNode, NodeInterface $referenceNode): Result | ||
{ | ||
if ($currentNode->getNodeType()->isOfType('Neos.Neos:Document') === false) { | ||
throw new \InvalidArgumentException($currentNode->getNodeType()->getName() . " is not of type Neos.Neos:Document"); | ||
} | ||
|
||
$result = Result::createEmpty(); | ||
|
||
// ensure deleted but not yet published nodes are found as well, so we will not try to translate those | ||
$currentContextProperties = $currentNode->getContext()->getProperties(); | ||
$currentContextProperties['removedContentShown'] = true; | ||
$currentContextIncludingRemovedItems = $this->contextFactory->create($currentContextProperties); | ||
|
||
$referenceContentContext = $referenceNode->getContext(); | ||
|
||
if ($referenceNode->getNodeData()->getLastModificationDateTime() > $currentNode->getNodeData()->getLastModificationDateTime()) { | ||
$result = $result->withOutdatedNodes(new OutdatedNodeReference( | ||
$currentNode, | ||
$referenceNode | ||
)); | ||
} | ||
|
||
foreach ($currentNode->getChildNodes('Neos.Neos:ContentCollection') as $currentCollectionChild) { | ||
if ($currentCollectionChild->isAutoCreated() === false) { | ||
// skip nodes that are not autocreated | ||
continue; | ||
} | ||
$referenceCollectionChild = $referenceContentContext->getNodeByIdentifier($currentCollectionChild->getIdentifier()); | ||
if ($referenceCollectionChild) { | ||
$result = $this->traverseContentCollectionForAlteredNodes( | ||
$currentCollectionChild, | ||
$referenceCollectionChild, | ||
$currentContextIncludingRemovedItems, | ||
$result | ||
); | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
private function traverseContentCollectionForAlteredNodes( | ||
NodeInterface $currentNode, | ||
NodeInterface $referenceNode, | ||
Context $currentContextIncludingRemovedItems, | ||
Result $result, | ||
): Result { | ||
|
||
$missing = []; | ||
$outdated = []; | ||
|
||
$reduceToArrayWithIdentifier = function (array $carry, NodeInterface $item) { | ||
$carry[$item->getIdentifier()] = $item; | ||
return $carry; | ||
}; | ||
|
||
$currentNodeInContextShowingRemovedItems = $currentContextIncludingRemovedItems->getNodeByIdentifier($currentNode->getIdentifier()); | ||
if (is_null($currentNodeInContextShowingRemovedItems)) { | ||
return $result; | ||
} | ||
|
||
/** | ||
* @var array<string,NodeInterface> $currentCollectionChildren | ||
*/ | ||
$currentCollectionChildren = array_reduce($currentNodeInContextShowingRemovedItems->getChildNodes(), $reduceToArrayWithIdentifier, []); | ||
|
||
/** | ||
* @var array<string,NodeInterface> $referenceCollectionChildren | ||
*/ | ||
$referenceCollectionChildren = array_reduce($referenceNode->getChildNodes(), $reduceToArrayWithIdentifier, []); | ||
$referenceCollectionChildrenIdentifiers = array_keys($referenceCollectionChildren); | ||
|
||
foreach ($referenceCollectionChildren as $identifier => $referenceCollectionChild) { | ||
if (!array_key_exists($identifier, $currentCollectionChildren)) { | ||
$position = array_search($identifier, $referenceCollectionChildrenIdentifiers); | ||
$previousIdentifier = ($position !== false && array_key_exists($position - 1, $referenceCollectionChildrenIdentifiers)) ? $referenceCollectionChildrenIdentifiers[$position - 1] : null; | ||
$nextIdentifier = ($position !== false && array_key_exists($position + 1, $referenceCollectionChildrenIdentifiers)) ? $referenceCollectionChildrenIdentifiers[$position + 1] : null; | ||
|
||
$missing[] = new MissingNodeReference( | ||
$referenceCollectionChild, | ||
$currentNode, | ||
$previousIdentifier, | ||
$nextIdentifier | ||
); | ||
} | ||
} | ||
|
||
foreach ($currentCollectionChildren as $identifier => $currentCollectionCollectionChild) { | ||
if ( | ||
array_key_exists($identifier, $referenceCollectionChildren) | ||
&& $referenceCollectionChildren[$identifier]->getNodeData()->getLastModificationDateTime() > $currentCollectionCollectionChild->getNodeData()->getLastModificationDateTime() | ||
) { | ||
$outdated[] = new OutdatedNodeReference( | ||
$currentCollectionCollectionChild, | ||
$referenceCollectionChildren[$identifier] | ||
); | ||
} | ||
|
||
if ( | ||
($currentCollectionCollectionChild->hasChildNodes() || $currentCollectionCollectionChild->getNodeType()->isOfType('Neos.Neos:ContentCollection')) | ||
&& array_key_exists($identifier, $referenceCollectionChildren) | ||
) { | ||
$result = $this->traverseContentCollectionForAlteredNodes( | ||
$currentCollectionCollectionChild, | ||
$referenceCollectionChildren[$identifier], | ||
$currentContextIncludingRemovedItems, | ||
$result | ||
); | ||
} | ||
} | ||
|
||
if ($missing) { | ||
$result = $result->withMissingNodes(...$missing); | ||
} | ||
|
||
if ($outdated) { | ||
$result = $result->withOutdatedNodes(...$outdated); | ||
} | ||
|
||
return $result; | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
Classes/Domain/CollectionComparison/MissingNodeReference.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\LostInTranslation\Domain\CollectionComparison; | ||
|
||
use Neos\ContentRepository\Domain\Model\Node; | ||
use Neos\ContentRepository\Domain\Model\NodeInterface; | ||
use Neos\Flow\Annotations as Flow; | ||
|
||
/** | ||
* @Flow\Proxy(false) | ||
*/ | ||
final class MissingNodeReference | ||
{ | ||
protected NodeInterface $node; | ||
|
||
protected NodeInterface $referenceNode; | ||
protected ?string $previousIdentifier; | ||
protected ?string $nextIdentifier; | ||
|
||
public function __construct(NodeInterface $node, NodeInterface $referenceNode, ?string $previousIdentifier, ?string $nextIdentifier) | ||
{ | ||
$this->node = $node; | ||
$this->referenceNode = $referenceNode; | ||
$this->previousIdentifier = $previousIdentifier; | ||
$this->nextIdentifier = $nextIdentifier; | ||
} | ||
|
||
public function getNode(): NodeInterface | ||
{ | ||
return $this->node; | ||
} | ||
|
||
public function getReferenceNode(): NodeInterface | ||
{ | ||
return $this->referenceNode; | ||
} | ||
|
||
public function getPreviousIdentifier(): ?string | ||
{ | ||
return $this->previousIdentifier; | ||
} | ||
|
||
public function getNextIdentifier(): ?string | ||
{ | ||
return $this->nextIdentifier; | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
Classes/Domain/CollectionComparison/OutdatedNodeReference.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\LostInTranslation\Domain\CollectionComparison; | ||
|
||
use Neos\ContentRepository\Domain\Model\Node; | ||
use Neos\ContentRepository\Domain\Model\NodeInterface; | ||
use Neos\Flow\Annotations as Flow; | ||
|
||
/** | ||
* @Flow\Proxy(false) | ||
*/ | ||
final class OutdatedNodeReference | ||
{ | ||
protected NodeInterface $node; | ||
protected NodeInterface $referenceNode; | ||
|
||
public function __construct(NodeInterface $node, NodeInterface $referenceNode) | ||
{ | ||
$this->node = $node; | ||
$this->referenceNode = $referenceNode; | ||
} | ||
|
||
public function getNode(): NodeInterface | ||
{ | ||
return $this->node; | ||
} | ||
|
||
public function getReferenceNode(): NodeInterface | ||
{ | ||
return $this->referenceNode; | ||
} | ||
} |
Oops, something went wrong.