Skip to content

Commit

Permalink
FEATURE: separate triggering node
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellienert committed Feb 4, 2018
1 parent 9cf895f commit ce49e49
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 97 deletions.
41 changes: 31 additions & 10 deletions Classes/Archivist.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<?php

namespace PunktDe\Archivist;

/*
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\ContentRepository\Domain\Repository\NodeDataRepository;
use Neos\Eel\FlowQuery\FlowQuery;
Expand Down Expand Up @@ -51,26 +57,41 @@ class Archivist
protected $context;

/**
* @param NodeInterface $node
* @param NodeInterface $triggeringNode
* @param array $sortingInstructions
*/
public function sortNode(NodeInterface $node, array $sortingInstructions)
public function organizeNode(NodeInterface $triggeringNode, array $sortingInstructions)
{
if (isset($sortingInstructions['affectedNode'])) {
$affectedNode = $this->eelEvaluationService->evaluate($sortingInstructions['affectedNode'], ['node' => $triggeringNode]);
if (!($affectedNode instanceof NodeInterface)) {
$this->logger->log(sprintf('A node of type %s (%s) triggered node organization but the affectedNode was not found.', $triggeringNode->getNodeType()->getName(), $triggeringNode->getIdentifier()));
return;
}
} else {
$affectedNode = $triggeringNode;
}

$this->nodeDataRepository->persistEntities();
$this->logger->log(sprintf('Organize node of type %s with path %s', $node->getNodeType()->getName(), $node->getPath()), LOG_DEBUG);
$context = $this->buildBaseContext($node, $sortingInstructions);

$this->logger->log(sprintf('Organize node of type %s with path %s', $triggeringNode->getNodeType()->getName(), $triggeringNode->getPath()), LOG_DEBUG);
$context = $this->buildBaseContext($triggeringNode, $sortingInstructions);

if (isset($sortingInstructions['context']) && is_array($sortingInstructions['context'])) {
$context = $this->buildCustomContext($context, $sortingInstructions['context']);
}

if (isset($sortingInstructions['hierarchy']) && is_array($sortingInstructions['hierarchy'])) {
$targetNode = $this->hierarchyService->buildHierarchy($sortingInstructions['hierarchy'], $context);
$node->moveInto($targetNode);
}
$hierarchyNode = $this->hierarchyService->buildHierarchy($sortingInstructions['hierarchy'], $context);

if($affectedNode->getParent() !== $hierarchyNode) {
$affectedNode->moveInto($hierarchyNode);
$this->logger->log(sprintf('Moved node %s into hierarchy node %s', $affectedNode->getNodeType()->getName(), $hierarchyNode->getNodeType()->getName()), LOG_DEBUG);
}

if (isset($sortingInstructions['sorting'])) {
$this->sortingService->sort($targetNode, $sortingInstructions['sorting'], null);
if (isset($sortingInstructions['sorting'])) {
$this->sortingService->sortChildren($hierarchyNode, $sortingInstructions['sorting'], null);
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions Classes/Exception/ArchivistConfigurationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
namespace PunktDe\Archivist\Exception;

/*
* (c) 2018 punkt.de GmbH - Karlsruhe, Germany - http://punkt.de
* All rights reserved.
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\Flow\Exception;
Expand Down
12 changes: 10 additions & 2 deletions Classes/NodeSignalInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

namespace PunktDe\Archivist;

/*
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Annotations as Flow;

Expand All @@ -24,7 +32,7 @@ public function nodeAdded(NodeInterface $node) {
return;
}

(new Archivist())->sortNode($node, $this->sortingInstructions[$node->getNodeType()->getName()]);
(new Archivist())->organizeNode($node, $this->sortingInstructions[$node->getNodeType()->getName()]);
}

/**
Expand All @@ -38,6 +46,6 @@ public function nodePropertyChanged(NodeInterface $node, string $propertyName, $
return;
}

(new Archivist())->sortNode($node, $this->sortingInstructions[$node->getNodeType()->getName()]);
(new Archivist())->organizeNode($node, $this->sortingInstructions[$node->getNodeType()->getName()]);
}
}
8 changes: 8 additions & 0 deletions Classes/Package.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<?php
namespace PunktDe\Archivist;

/*
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\ContentRepository\Domain\Model\Node;
use Neos\Flow\Core\Bootstrap;
use Neos\Flow\Package\Package as BasePackage;
Expand Down
8 changes: 8 additions & 0 deletions Classes/Service/EelEvaluationService.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<?php
namespace PunktDe\Archivist\Service;

/*
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\Eel\EelEvaluatorInterface;
use Neos\Eel\Package;
use Neos\Eel\Utility;
Expand Down
17 changes: 12 additions & 5 deletions Classes/Service/HierarchyService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
namespace PunktDe\Archivist\Service;

/*
* (c) 2018 punkt.de GmbH - Karlsruhe, Germany - http://punkt.de
* All rights reserved.
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\ContentRepository\Domain\Repository\NodeDataRepository;
Expand Down Expand Up @@ -73,12 +76,12 @@ public function buildHierarchy(array $hierarchyConfiguration, array $context): N
* @param NodeInterface $parentNode
* @param array $hierarchyLevelConfiguration
* @param array $context
* @return NodeInterface
* @return NodeInterface The created or found hierarchy node
* @throws ArchivistConfigurationException
*/
protected function buildHierarchyLevel(NodeInterface $parentNode, array $hierarchyLevelConfiguration, array $context): NodeInterface
{
$hierarchyLevelNodeName = null;
$hierarchyLevelNodeName = '';
$this->evaluateHierarchyLevelConfiguration($hierarchyLevelConfiguration);

$hierarchyLevelNodeType = $this->nodeTypeManager->getNodeType($hierarchyLevelConfiguration['type']);
Expand All @@ -95,6 +98,10 @@ protected function buildHierarchyLevel(NodeInterface $parentNode, array $hierarc
$hierarchyLevelNodeName = (string)$this->eelEvaluationService->evaluateIfValidEelExpression($hierarchyLevelConfiguration['properties']['name'], $context);
}

if ($hierarchyLevelNodeName === '') {
return $parentNode;
}

$hierarchyLevelNodeTemplate = new NodeTemplate();
$hierarchyLevelNodeTemplate->setNodeType($hierarchyLevelNodeType);

Expand All @@ -111,7 +118,7 @@ protected function buildHierarchyLevel(NodeInterface $parentNode, array $hierarc
$this->logger->log(sprintf('Built hierarchy level on path %s with node type %s ', $hierarchyLevelNode->getPath(), $hierarchyLevelConfiguration['type']), LOG_DEBUG);

if (isset($hierarchyLevelConfiguration['sorting'])) {
$this->sortingService->sort($parentNode, $hierarchyLevelConfiguration['sorting'], $hierarchyLevelNodeType->getName());
$this->sortingService->sortChildren($parentNode, $hierarchyLevelConfiguration['sorting'], $hierarchyLevelNodeType->getName());
}

return $hierarchyLevelNode;
Expand Down
11 changes: 9 additions & 2 deletions Classes/Service/SortingService.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
<?php

namespace PunktDe\Archivist\Service;

/*
* This file is part of the PunktDe.Archivist package.
*
* This package is open source software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Neos\Flow\Annotations as Flow;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Log\SystemLoggerInterface;
Expand All @@ -28,7 +35,7 @@ class SortingService
* @param string $eelOrProperty
* @param string $nodeTypeFilter
*/
public function sort(NodeInterface $parentNode, string $eelOrProperty, $nodeTypeFilter)
public function sortChildren(NodeInterface $parentNode, string $eelOrProperty, $nodeTypeFilter)
{
if ($this->eelEvaluationService->isValidExpression($eelOrProperty)) {
$eelExpression = $eelOrProperty;
Expand Down
7 changes: 7 additions & 0 deletions Configuration/Testing/NodeTypes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@
type: string
date:
type: DateTime

'PunktDe.Archivist.TriggerContentNode':
superTypes:
'Neos.ContentRepository.Testing:Content': true
properties:
title:
type: string
37 changes: 25 additions & 12 deletions Configuration/Testing/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,29 @@ PunktDe:
# Simple sorting on a property
sorting: title

# # Example triggering content node
# #
# # A content node triggers the move of its parent document node
# 'PunktDe.Archivist.TriggerContentNode':
#
# # The query selecting the root node of the automatically created hierarchy
# hierarchyRoot: "${q(site).find('[instanceof Neos.ContentRepository.Testing:Page]').get(0)}"
#
# # The node to be moved. This defaults to the triggering node and is available as node.
# # This can for example be used if a change in a content node should move its parent document node
# #
# targetNode: "${q(node).parent('[instanceof PunktDe.Archivist.TriggerNode]').get(0)}"
# Example triggering content node
#
# A content node triggers the move of its parent document node. For example, you have a
# title node which should be considered to move the page.
'PunktDe.Archivist.TriggerContentNode':

# The query selecting the root node of the automatically created hierarchy
hierarchyRoot: "${q(site).find('[instanceof Neos.ContentRepository.Testing:Page]').get(0)}"

# Optional: The node to be moved, described by an Eel query.
# This defaults to the triggering node if not set. The triggering node is available as "node".
# If the affected node is not found by the operation is skipped.
# This can for example be used if a change in a content node should move its parent document node
#
affectedNode: "${q(node).parent('[instanceof Neos.ContentRepository.Testing:Document]').get(0)}"

# Definition of the auto-generated hierarchy
hierarchy:
-
# The type of the hierarchy-node
type: 'PunktDe.Archivist.HierarchyNode'

# Properties of the new created node.
properties:
name: "${String.charAt(node.properties.title, 0)}"
title: "${String.charAt(node.properties.title, 0)}"
99 changes: 65 additions & 34 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,76 @@ You can configure the behavior differently for every triggering node type. The c
are best explained by example. These examples are taken from ``Configuration/Testing/Settings.yaml``
and are thus automatically tested.

## Example Configurations

### Simple Example

Configuration for the nodeType 'PunktDe.Archivist.TriggerNode'. The sorting is triggered if a
node of this type is created or if a property on this node is changed. This node is than
available as 'node' in the other parts of the configuration

PunktDe:
Archivist:
sortingInstructions:

'PunktDe.Archivist.TriggerNode':

# The query selecting the root node of the automatically created hierarchy
hierarchyRoot: "${q(site).find('[instanceof Neos.ContentRepository.Testing:Page]').get(0)}"

# Optional: The sorting of the nodes inside the target hierarchy. Can be the name of a property
# or an eel expression like seen below
sorting: title

# In the context is evaluated first. You can define variables here which you can use in
# the remaining configuration
context:
publishDate: "${node.properties.date}"

# Definition of the auto-generated hierarchy
hierarchy:
-
# The type of the hierarchy-node
type: 'PunktDe.Archivist.HierarchyNode'

# Properties of the new created node.
properties:
name: "${Date.year(publishDate)}"
title: "${Date.year(publishDate)}"

# The property which is identical throughout all nodes of this level
identity: title

# An eel query that describes the sorting condition
sorting: "${q(a).property('title') < q(b).property('title')}"
-
type: 'PunktDe.Archivist.HierarchyNode'
properties:
name: "${Date.month(publishDate)}"
title: "${Date.month(publishDate)}"
identity: title

# Simple sorting on a property
sorting: title


### Example with a triggering content node

A content node triggers the move of its parent document node. For example, if you have a
title node which should be considered to move the page.

PunktDe:
Archivist:
sortingInstructions:

# Simple Example
#
# Configuration for the nodeType 'PunktDe.Archivist.TriggerNode'. The sorting is triggered if a
# node of this type is created or if a property on this node is changed. This node is than
# available as 'node' in the other parts of the configuration
'PunktDe.Archivist.TriggerNode':
'PunktDe.Archivist.TriggerContentNode':

# The query selecting the root node of the automatically created hierarchy
hierarchyRoot: "${q(site).find('[instanceof Neos.ContentRepository.Testing:Page]').get(0)}"

# Optional: The sorting of the nodes inside the target hierarchy. Can be the name of a property
# or an eel expression like seen below
sorting: title

# In the context is evaluated first. You can define variables here which you can use in
# the remaining configuration
context:
publishDate: "${node.properties.date}"
# Optional: The node to be moved, described by an Eel query.
# This defaults to the triggering node if not set. The triggering node is available as "node".
# If the affected node is not found by the operation is skipped.
# This can for example be used if a change in a content node should move its parent document node
#
affectedNode: "${q(node).parent('[instanceof Neos.ContentRepository.Testing:Document]').get(0)}"

# Definition of the auto-generated hierarchy
hierarchy:
Expand All @@ -50,20 +96,5 @@ and are thus automatically tested.

# Properties of the new created node.
properties:
name: "${Date.year(publishDate)}"
title: "${Date.year(publishDate)}"

# The property which is identical throughout all nodes of this level
identity: title

# An eel query that describes the sorting condition
sorting: "${q(a).property('title') < q(b).property('title')}"
-
type: 'PunktDe.Archivist.HierarchyNode'
properties:
name: "${Date.month(publishDate)}"
title: "${Date.month(publishDate)}"
identity: title

# Simple sorting on a property
sorting: title
name: "${String.charAt(node.properties.title, 0)}"
title: "${String.charAt(node.properties.title, 0)}"
Loading

0 comments on commit ce49e49

Please sign in to comment.