Commit 6f674cd6 authored by Dominique Feyer's avatar Dominique Feyer
Browse files

[TASK] Complete refactoring add Sorting Strategy object

parent 8cb64c2b
<?php
namespace Ttree\Starter\Aspect;
namespace Ttree\SortableNode\Aspect;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.Starter". *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
......@@ -13,7 +13,7 @@ use TYPO3\TYPO3CR\Domain\Model\NodeData;
/**
* An aspect to force sorting node in the TYPO3CR
*
* @package Ttree\Starter\Aspect
* @package Ttree\SortableNode\Aspect
* @Flow\Scope("singleton")
* @Flow\Aspect
*/
......@@ -21,7 +21,7 @@ class NodeSortingAspect {
/**
* @Flow\Inject
* @var \Ttree\Starter\Service\NodeSortingService
* @var \Ttree\SortableNode\Service\NodeSortingService
*/
protected $nodeSortingService;
......@@ -33,7 +33,7 @@ class NodeSortingAspect {
/**
* @param JoinPointInterface $joinPoint
* @Flow\After("setting(Ttree.Starter.nodeSorting.enable) && method(TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository->(update|add)())")
* @Flow\After("setting(Ttree.SortableNode.enabled) && method(TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository->(update|add)())")
*/
public function sortNodesAfterUpdateOrCreate(JoinPointInterface $joinPoint) {
/** @var NodeData $nodeData */
......
<?php
namespace Ttree\SortableNode\Command;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.Plugin.MicroEvent".*
* *
* */
use Ttree\SortableNode\Service\NodeSortingService;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Neos\Domain\Model\Site;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
/**
* Sorting CLI utilities
*/
class SortCommandController extends \TYPO3\Flow\Cli\CommandController {
/**
* @Flow\Inject
* @var NodeSortingService
*/
protected $nodeSortingService;
/**
* @param NodeInterface $path
*/
public function pathCommand(NodeInterface $path) {
$this->nodeSortingService->decideSortingByParentNode($path);
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Domain\Model;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use Ttree\SortableNode\Factory\SortingStrategyFactory;
use Ttree\SortableNode\Service\SettingsService;
use Ttree\SortableNode\Strategy\SortingStrategyInterface;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Utility\Arrays;
use TYPO3\TYPO3CR\Domain\Model\Node;
use TYPO3\TYPO3CR\Domain\Service\NodeTypeManager;
/**
* Node Sorting Definition DTO
*/
class NodeSortingDefinition {
/**
* @Flow\Inject
* @var SortingStrategyFactory
*/
protected $sortingNodeStrategyFactory;
/**
* @Flow\Inject
* @var NodeTypeManager
*/
protected $nodeTypeManager;
/**
* @Flow\Inject
* @var SettingsService
*/
protected $settingsService;
/**
* @var \TYPO3\TYPO3CR\Domain\Model\NodeType
*/
protected $nodeType;
/**
* @var string
*/
protected $label;
/**
* @var string
*/
protected $identifier;
/**
* @var SortingStrategyInterface
*/
protected $strategy;
/**
* @var boolean
*/
protected $enabled;
/**
* @var array
*/
protected $properties = array();
/**
* @param string $nodeTypeName
* @param array $configuration
* @throws Exception
*/
function __construct($nodeTypeName, array $configuration) {
$nodeTypeName = trim($nodeTypeName);
if ($nodeTypeName === '') {
throw new Exception('Empty NodeType name is not allowed', 1380721651);
}
$identifier = trim(Arrays::getValueByPath($configuration, 'identifier'));
if ($identifier === '') {
throw new Exception('Empty identifier is not allowed', 1380718239);
}
$properties = Arrays::getValueByPath($configuration, 'properties');
if (!is_array($properties) || $properties === array()) {
throw new Exception('Properties must be an array and contain at least one property', 1380718300);
}
$this->nodeType = $nodeTypeName;
$this->label = Arrays::getValueByPath($configuration, 'label');
$this->identifier = $identifier;
$this->enabled = Arrays::getValueByPath($configuration, 'enabled') === FALSE ? FALSE : TRUE;
$this->strategy = Arrays::getValueByPath($configuration, 'strategy');
$this->properties = $properties;
}
/**
* Initialize object
*/
public function initializeObject() {
$this->strategy = $this->sortingNodeStrategyFactory->create($this->strategy ?: $this->settingsService->getByPath('defaultSortingStrategy'));
$this->nodeType = $this->nodeTypeManager->getNodeType($this->nodeType);
$properties = $this->nodeType->getProperties();
foreach ($this->properties as $propertyName => $direction) {
if (!isset($properties[$propertyName]) || !is_array($properties)) {
throw new Exception(sprintf('Invalid property (%s) for NodeType (%s)', $propertyName, $this->getNodeType()->getName()), 1380718239);
}
$this->properties[$propertyName] = new PropertySortingDefinition($propertyName, $direction, $properties[$propertyName]['type']);
}
}
/**
* @param string $propertyName
* @return PropertySortingDefinition
*/
public function getPropertySortingConfiguration($propertyName) {
return isset($this->properties[$propertyName]) ? $this->properties[$propertyName] : NULL;
}
/**
* @return \TYPO3\TYPO3CR\Domain\Model\NodeType
*/
public function getNodeType() {
return $this->nodeType;
}
/**
* @return string
*/
public function getHash() {
return md5($this->getNodeType()->getName() . $this->identifier);
}
/**
* @return string
*/
public function getLabel() {
return $this->label;
}
/**
* @return boolean
*/
public function getEnabled() {
return $this->enabled;
}
/**
* @return array
*/
public function getProperties() {
return $this->properties;
}
/**
* @return \Ttree\SortableNode\Strategy\SortingStrategyInterface
*/
public function getStrategy() {
return $this->strategy;
}
/**
* @return boolean
*/
public function isEnabled() {
return $this->enabled;
}
/**
* @param Node $node
* @return bool
*/
public function matchesNode(Node $node) {
$matches = FALSE;
if ($this->identifier === $node->getNodeData()->getIdentifier() || $this->identifier === $node->getNodeData()->getPath()) {
$matches = TRUE;
}
return $matches;
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Domain\Model;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use Ttree\SortableNode\Factory\SortingStrategyFactory;
use Ttree\SortableNode\Service\SettingsService;
use Ttree\SortableNode\Strategy\SortingStrategyInterface;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Utility\Arrays;
use TYPO3\TYPO3CR\Domain\Model\Node;
/**
* Property Sorting Definition DTO
*/
class PropertySortingDefinition {
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $direction;
/**
* @var string
*/
protected $type;
/**
* @param string $name
* @param string $direction
* @param string $type
*/
function __construct($name, $direction, $type) {
$this->name = $name;
$this->direction = $direction;
$this->type = $type;
}
/**
* @return string
*/
public function getDirection() {
return $this->direction;
}
/**
* @return string
*/
public function getName() {
return $this->name;
}
/**
* @return string
*/
public function getType() {
return $this->type;
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Factory;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Object\ObjectManager;
/**
* Sorting Strategy Factory
*
* @Flow\Scope("singleton")
*/
class SortingStrategyFactory {
/**
* @Flow\Inject
* @var ObjectManager
*/
protected $objectManager;
/**
* @param string $type
* @return \Ttree\SortableNode\Strategy\SortingStrategyInterface
* @throws \TYPO3\Flow\Exception
*/
public function create($type) {
$type = trim($type);
if ($type === '') {
throw new Exception('Type of Sorting Strategy can not be empty', 1380716315);
}
if (strpos(trim($type), '\\') !== FALSE) {
$objectName = $type;
} else {
$objectName = sprintf('\Ttree\SortableNode\Strategy\%s', trim($type));
}
if (!class_exists($objectName)) {
throw new Exception(sprintf('Sorting strategy class (%s) not found', $objectName), 1380716380);
}
return $this->objectManager->get($objectName);
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Service;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use Ttree\SortableNode\Domain\Model\NodeSortingDefinition;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Utility\Arrays;
use TYPO3\Flow\Utility\PositionalArraySorter;
use TYPO3\TYPO3CR\Domain\Model\Node;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
use TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository;
/**
* Node Sorting Service
*
* @package Ttree\Plugin\MicroEvent\Service
* @Flow\Scope("singleton")
*/
class NodeSortingService {
/**
* @Flow\Inject
* @var NodeDataRepository
*/
protected $nodeDataRepository;
/**
* @Flow\Inject
* @var SettingsService
*/
protected $settingsService;
/**
* @param NodeInterface $parentNode
* @throws \TYPO3\Flow\Exception
*/
public function decideSortingByParentNode(NodeInterface $parentNode) {
$nodeSortingDefinitions = $this->getNodeSortingDefinitionsByParentNode($parentNode);
foreach ($nodeSortingDefinitions as $nodeSortingDefinition) {
/** @var NodeSortingDefinition $nodeSortingDefinition */
$strategy = $nodeSortingDefinition->getStrategy();
$strategy->sortByParentNodeAndNodeSortingDefinition($parentNode, $nodeSortingDefinition);
}
}
/**
* @param Node $parentNode
* @return array
*/
public function getNodeSortingDefinitionsByParentNode(Node $parentNode) {
$nodeSortingDefinitions = array();
foreach ($this->settingsService->getByPath('configuration') as $nodeTypeName => $configuration) {
$configuration = new PositionalArraySorter($configuration);
foreach ($configuration->toArray() as $pathConfiguration) {
$nodeSortingDefinition = new NodeSortingDefinition($nodeTypeName, $pathConfiguration);
if ($nodeSortingDefinition->matchesNode($parentNode) && $nodeSortingDefinition->isEnabled()) {
$nodeSortingDefinitions[$nodeSortingDefinition->getNodeType()->getName()] = $nodeSortingDefinition;
}
}
}
return $nodeSortingDefinitions;
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Service;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Utility\Arrays;
use TYPO3\Flow\Property\PropertyMappingConfigurationInterface;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
/**
* Settings Service
*
* @Flow\Scope("singleton")
*/
class SettingsService {
/**
* @var array
*/
protected $settings;
/**
* @param array $settings
*/
public function injectSettings(array $settings) {
$this->settings = $settings;
}
/**
* @param string $path
* @return mixed
*/
public function getByPath($path) {
return Arrays::getValueByPath($this->settings, $path);
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Strategy;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use Ttree\SortableNode\Domain\Model\PropertySortingDefinition;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Persistence\Generic\PersistenceManager;
use TYPO3\Flow\Property\PropertyMapper;
use TYPO3\Flow\Property\PropertyMappingConfigurationBuilder;
use TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository;
/**
* Node sorting strategy interface
*
* @package Ttree\Plugin\MicroEvent\Strategy
*/
abstract class AbstractSortingStrategy {
/**
* @Flow\Inject
* @var PropertyMapper
*/
protected $propertyMapper;
/**
* @Flow\Inject
* @var PropertyMappingConfigurationBuilder
*/
protected $propertyMappingConfigurationBuilder;
/**
* @Flow\Inject
* @var NodeDataRepository
*/
protected $nodeDataRepository;
/**
* @param mixed $source
* @param PropertySortingDefinition $propertySortingDefinition
* @return mixed
*/
protected function convertPropertyType($source, PropertySortingDefinition $propertySortingDefinition) {
$propertyMappingConfiguration = $this->propertyMappingConfigurationBuilder->build();
$targetType = NULL;
switch ($propertySortingDefinition->getType()) {
case 'date':
$targetType = 'DateTime';
$propertyMappingConfiguration->setTypeConverterOption(
'TYPO3\Flow\Property\TypeConverter\DateTimeConverter',
\TYPO3\Flow\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT,
'Y-m-d'
);
break;
}
return $targetType ? $this->propertyMapper->convert($source, $targetType, $propertyMappingConfiguration) : $source;
}
}
?>
\ No newline at end of file
<?php
namespace Ttree\SortableNode\Strategy;
/* *
* This script belongs to the TYPO3 Flow package "Ttree.SortableNode". *
* *
* */
use Ttree\SortableNode\Domain\Model\NodeSortingDefinition;
use Ttree\SortableNode\Domain\Model\PropertySortingDefinition;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Exception;
use TYPO3\Flow\Utility\Arrays;
use TYPO3\TYPO3CR\Domain\Model\NodeData;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
use TYPO3\TYPO3CR\Domain\Repository\NodeDataRepository;
/**
* Simple Insertion Sorting Strategy
*
* @package Ttree\Plugin\MicroEvent\Strategy
*/
class DumbSortingStrategy extends AbstractSortingStrategy {
/**
* @param NodeInterface $parentNode
* @param NodeSortingDefinition $nodeSortingDefinition
* @throws \TYPO3\Flow\Exception
*/
public function sortByParentNodeAndNodeSortingDefinition(NodeInterface $parentNode, NodeSortingDefinition $nodeSortingDefinition) {
if (count($nodeSortingDefinition->getProperties()) > 1) {
throw new Exception(sprintf('DumbSortingStrategy support only sorting with one property, %d given in the current configuration', count($nodeSortingDefinition->getProperties())), 1380724384);