Skip to content
This repository has been archived by the owner on Sep 23, 2020. It is now read-only.

Commit

Permalink
Added recursive restore to allow also versions of children (#108)
Browse files Browse the repository at this point in the history
* added recursive restore to allow also versions of children

* added ignore children testcase
  • Loading branch information
wachterjohannes authored and danrot committed Apr 19, 2017
1 parent ef98341 commit 25ae29a
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG for Sulu Document Manager
* dev-develop
* ENHANCEMENT #110 Added node-name-slugifier to centralice additional node name replacer
* ENHANCEMENT #109 Added metadata to configure remove-live
* FEATURE #107 Added recursive restore to allow also versions of children

* 0.9.1 (2017-03-16)
* ENHANCEMENT #107 Added VersionNotFoundException
Expand Down
80 changes: 64 additions & 16 deletions lib/Subscriber/Behavior/VersionSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Jackalope\Version\VersionManager;
use PHPCR\NodeInterface;
use PHPCR\SessionInterface;
use PHPCR\Version\OnParentVersionAction;
use PHPCR\Version\VersionException;
use Sulu\Component\DocumentManager\Behavior\VersionBehavior;
use Sulu\Component\DocumentManager\Event\AbstractMappingEvent;
Expand Down Expand Up @@ -190,12 +191,14 @@ public function applyVersionOperations()
if (!array_key_exists($versionInformation['path'], $nodeVersions)) {
$nodeVersions[$versionInformation['path']] = $versions;
}
$nodeVersions[$versionInformation['path']][] = json_encode([
'locale' => $versionInformation['locale'],
'version' => $version->getName(),
'author' => $versionInformation['author'],
'authored' => date('c'),
]);
$nodeVersions[$versionInformation['path']][] = json_encode(
[
'locale' => $versionInformation['locale'],
'version' => $version->getName(),
'author' => $versionInformation['author'],
'authored' => date('c'),
]
);
}

foreach ($nodes as $path => $node) {
Expand Down Expand Up @@ -226,26 +229,71 @@ public function restoreProperties(RestoreEvent $event)

$node = $event->getNode();

try {
$version = $this->versionManager->getVersionHistory($node->getPath())->getVersion($event->getVersion());

$frozenNode = $version->getFrozenNode();

$this->restoreNode($node, $frozenNode, $contentPropertyPrefix, $systemPropertyPrefix);
} catch (VersionException $exception) {
throw new VersionNotFoundException($event->getDocument(), $event->getVersion());
}
}

/**
* Restore given node with properties given from frozen-node.
* Will be called recursive.
*
* @param NodeInterface $node
* @param NodeInterface $frozenNode
* @param string $contentPropertyPrefix
* @param string $systemPropertyPrefix
*/
private function restoreNode(
NodeInterface $node,
NodeInterface $frozenNode,
$contentPropertyPrefix,
$systemPropertyPrefix
) {
// remove the properties for the given language, so that values being added since the last version are removed
foreach ($node->getProperties() as $property) {
if ($this->isRestoreProperty($property->getName(), $contentPropertyPrefix, $systemPropertyPrefix)) {
$property->remove();
}
}

try {
$version = $this->versionManager->getVersionHistory($node->getPath())->getVersion($event->getVersion());
// set all the properties from the saved version to the node
foreach ($frozenNode->getPropertiesValues() as $name => $value) {
if ($this->isRestoreProperty($name, $contentPropertyPrefix, $systemPropertyPrefix)) {
$node->setProperty($name, $value);
}
}

$frozenNode = $version->getFrozenNode();
/** @var NodeInterface $childNode */
foreach ($frozenNode->getNodes() as $childNode) {
// create new node if it not exists
if (!$node->hasNode($childNode->getName())) {
$newNode = $node->addNode($childNode->getName());
$newNode->setMixins($childNode->getPropertyValueWithDefault('jcr:frozenMixinTypes', []));
}

// set all the properties from the saved version to the node
foreach ($frozenNode->getPropertiesValues() as $name => $value) {
if ($this->isRestoreProperty($name, $contentPropertyPrefix, $systemPropertyPrefix)) {
$node->setProperty($name, $value);
}
$this->restoreNode(
$node->getNode($childNode->getName()),
$childNode,
$contentPropertyPrefix,
$systemPropertyPrefix
);
}

// remove child-nodes which do not exists in frozen-node
foreach ($node->getNodes() as $childNode) {
if ($childNode->getDefinition()->getOnParentVersion() !== OnParentVersionAction::COPY
|| $frozenNode->hasNode($childNode->getName())
) {
continue;
}
} catch (VersionException $exception) {
throw new VersionNotFoundException($event->getDocument(), $event->getVersion());

$childNode->remove();
}
}

Expand Down
133 changes: 133 additions & 0 deletions tests/Unit/Subscriber/Behavior/VersionSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
use Jackalope\Version\Version as JackalopeVersion;
use Jackalope\Workspace;
use PHPCR\NodeInterface;
use PHPCR\NodeType\NodeDefinitionInterface;
use PHPCR\PropertyInterface;
use PHPCR\SessionInterface;
use PHPCR\Version\OnParentVersionAction;
use PHPCR\Version\VersionHistoryInterface;
use PHPCR\Version\VersionInterface;
use PHPCR\Version\VersionManagerInterface;
Expand Down Expand Up @@ -343,6 +345,7 @@ public function testRestoreLocalizedProperties()
$property3 = $this->prophesize(PropertyInterface::class);
$property3->getName()->willReturn('jcr:uuid');
$node->getProperties()->willReturn([$property1->reveal(), $property2->reveal(), $property3->reveal()]);
$node->getNodes()->willReturn([]);

$property1->remove()->shouldBeCalled();
$property2->remove()->shouldBeCalled();
Expand All @@ -351,6 +354,7 @@ public function testRestoreLocalizedProperties()
$this->propertyEncoder->localizedContentName('', 'de')->willReturn('i18n:de-');
$this->propertyEncoder->localizedSystemName('', 'de')->willReturn('i18n:de-');

$frozenNode->getNodes()->willReturn([]);
$frozenNode->getPropertiesValues()->willReturn([
'i18n:de-test' => 'Title',
'non-translatable-test' => 'Article',
Expand All @@ -372,4 +376,133 @@ public function testRestoreLocalizedProperties()

$this->versionSubscriber->restoreProperties($event->reveal());
}

public function testRestoreChildren()
{
$event = $this->prophesize(RestoreEvent::class);
$document = $this->prophesize(VersionBehavior::class);
$node = $this->prophesize(NodeInterface::class);
$versionHistory = $this->prophesize(VersionHistoryInterface::class);
$version = $this->prophesize(JackalopeVersion::class);
$frozenNode = $this->prophesize(NodeInterface::class);

$node->getPath()->willReturn('/node');
$node->getProperties()->willReturn([]);
$node->hasNode('child1')->willReturn(false);
$node->hasNode('child2')->willReturn(true);
$node->hasNode('child3')->willReturn(true);

$definition = $this->prophesize(NodeDefinitionInterface::class);
$definition->getOnParentVersion()->willReturn(OnParentVersionAction::COPY);

$newChild2Node = $this->prophesize(NodeInterface::class);
$newChild2Node->getName()->willReturn('child2');
$newChild2Node->getProperties()->willReturn([]);
$newChild2Node->getNodes()->willReturn([]);
$newChild2Node->getDefinition()->willReturn($definition->reveal());

$newChild3Node = $this->prophesize(NodeInterface::class);
$newChild3Node->getName()->willReturn('child3');
$newChild3Node->getDefinition()->willReturn($definition->reveal());
$newChild3Node->remove()->shouldBeCalled();

$newChild1Node = $this->prophesize(NodeInterface::class);
$newChild1Node->getName()->willReturn('child1');
$newChild1Node->setMixins(['jcr:referencable'])->shouldBeCalled();
$newChild1Node->getProperties()->willReturn([]);
$newChild1Node->getNodes()->willReturn([]);
$newChild1Node->getDefinition()->willReturn($definition->reveal());
$node->addNode('child1')->will(
function () use ($node, $newChild1Node, $newChild2Node, $newChild3Node) {
$node->getNode('child1')->willReturn($newChild1Node->reveal());
$node->getNodes()->willReturn(
[$newChild1Node->reveal(), $newChild2Node->reveal(), $newChild3Node->reveal()]
);

return $newChild1Node->reveal();
}
);

$node->getNode('child2')->willReturn($newChild2Node->reveal());
$node->getNode('child3')->willReturn($newChild3Node->reveal());
$node->getNodes()->willReturn([$newChild2Node->reveal(), $newChild3Node->reveal()]);

$this->propertyEncoder->localizedContentName('', 'de')->willReturn('i18n:de-');
$this->propertyEncoder->localizedSystemName('', 'de')->willReturn('i18n:de-');

$child1 = $this->prophesize(NodeInterface::class);
$child1->getName()->willReturn('child1');
$child1->getPropertyValueWithDefault('jcr:frozenMixinTypes', [])->willReturn(['jcr:referencable']);
$child1->getPropertiesValues()->willReturn([]);
$child1->getNodes()->willReturn([]);
$child2 = $this->prophesize(NodeInterface::class);
$child2->getName()->willReturn('child2');
$child2->getPropertiesValues()->willReturn([]);
$child2->getNodes()->willReturn([]);

$frozenNode->getNodes()->willReturn([$child1->reveal(), $child2->reveal()]);
$frozenNode->getPropertiesValues()->willReturn([]);
$frozenNode->hasNode('child1')->willReturn(true);
$frozenNode->hasNode('child2')->willReturn(true);
$frozenNode->hasNode('child3')->willReturn(false);

$event->getDocument()->willReturn($document->reveal());
$event->getNode()->willReturn($node->reveal());
$event->getVersion()->willReturn('1.0');
$event->getLocale()->willReturn('de');

$this->versionManager->getVersionHistory('/node')->willReturn($versionHistory->reveal());
$versionHistory->getVersion('1.0')->willReturn($version->reveal());
$version->getFrozenNode()->willReturn($frozenNode->reveal());

$this->versionSubscriber->restoreProperties($event->reveal());
}

public function testRestoreIgnoreChildren()
{
$event = $this->prophesize(RestoreEvent::class);
$document = $this->prophesize(VersionBehavior::class);
$node = $this->prophesize(NodeInterface::class);
$versionHistory = $this->prophesize(VersionHistoryInterface::class);
$version = $this->prophesize(JackalopeVersion::class);
$frozenNode = $this->prophesize(NodeInterface::class);

$node->getPath()->willReturn('/node');
$node->getProperties()->willReturn([]);
$node->hasNode('child')->willReturn(true);

$definition = $this->prophesize(NodeDefinitionInterface::class);
$definition->getOnParentVersion()->willReturn(OnParentVersionAction::IGNORE);

$childNode = $this->prophesize(NodeInterface::class);
$childNode->getName()->willReturn('child');
$childNode->getProperties()->willReturn([]);
$childNode->getNodes()->willReturn([]);
$childNode->getDefinition()->willReturn($definition->reveal());

$node->getNode('child')->willReturn($childNode->reveal());
$node->getNodes()->willReturn([$childNode->reveal()]);

$this->propertyEncoder->localizedContentName('', 'de')->willReturn('i18n:de-');
$this->propertyEncoder->localizedSystemName('', 'de')->willReturn('i18n:de-');

$frozenNode->getNodes()->willReturn([]);
$frozenNode->getPropertiesValues()->willReturn([]);
$frozenNode->hasNode(Argument::type('string'))->willReturn(false);

$event->getDocument()->willReturn($document->reveal());
$event->getNode()->willReturn($node->reveal());
$event->getVersion()->willReturn('1.0');
$event->getLocale()->willReturn('de');

$this->versionManager->getVersionHistory('/node')->willReturn($versionHistory->reveal());
$versionHistory->getVersion('1.0')->willReturn($version->reveal());
$version->getFrozenNode()->willReturn($frozenNode->reveal());

// the child-node should not be touched
$childNode->remove()->shouldNotBeCalled();
$childNode->setProperty(Argument::cetera())->shouldNotBeCalled();

$this->versionSubscriber->restoreProperties($event->reveal());
}
}

0 comments on commit 25ae29a

Please sign in to comment.