"Fossies" - the Fresh Open Source Software Archive

Member "neos-development-collection-7.0.1/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php" (23 Feb 2021, 9144 Bytes) of package /linux/www/neos-development-collection-7.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "DimensionsMenuItemsImplementation.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 7.0.0_vs_7.0.1.

    1 <?php
    2 namespace Neos\Neos\Fusion;
    3 
    4 use Neos\Eel\FlowQuery\FlowQuery;
    5 use Neos\Flow\Annotations as Flow;
    6 use Neos\Neos\Domain\Service\ConfigurationContentDimensionPresetSource;
    7 use Neos\ContentRepository\Domain\Model\NodeInterface;
    8 use Neos\ContentRepository\Domain\Service\ContentDimensionCombinator;
    9 
   10 /**
   11  * Fusion implementation for a dimensions menu items.
   12  *
   13  * The items generated by this menu will be all possible variants (according to the configured dimensions
   14  * and presets) of the given node (including the given node).
   15  *
   16  * If a 'dimension' is configured via Fusion, only the possible variants for that dimension will
   17  * be included in the menu, any other dimensions will be kept from the current context.
   18  *
   19  * Main Options:
   20  * - dimension (optional, string): name of the dimension which this menu should be limited to. Example: "language".
   21  * - presets (optional, array): If set, the presets are not loaded from the Settings, but instead taken from this property. Must be used with "dimension" set.
   22  */
   23 class DimensionsMenuItemsImplementation extends AbstractMenuItemsImplementation
   24 {
   25 
   26     /**
   27      * @Flow\Inject
   28      * @var ConfigurationContentDimensionPresetSource
   29      */
   30     protected $configurationContentDimensionPresetSource;
   31 
   32     /**
   33      * @Flow\Inject
   34      * @var ContentDimensionCombinator
   35      */
   36     protected $contentDimensionCombinator;
   37 
   38     /**
   39      * @return string
   40      */
   41     public function getDimension()
   42     {
   43         return $this->fusionValue('dimension');
   44     }
   45 
   46     /**
   47      * @return array
   48      */
   49     public function getPresets()
   50     {
   51         return $this->fusionValue('presets');
   52     }
   53 
   54     /**
   55      * @return array
   56      */
   57     public function getIncludeAllPresets()
   58     {
   59         return $this->fusionValue('includeAllPresets');
   60     }
   61 
   62     /**
   63      * Builds the array of Menu items for this variant menu
   64      */
   65     protected function buildItems()
   66     {
   67         $menuItems = [];
   68         $targetDimensionsToMatch = [];
   69         $allDimensionPresets = $this->configurationContentDimensionPresetSource->getAllPresets();
   70         $includeAllPresets = $this->getIncludeAllPresets();
   71         $pinnedDimensionValues = $this->getPresets();
   72 
   73         $pinnedDimensionName = $this->getDimension();
   74         if ($pinnedDimensionName !== null) {
   75             $targetDimensionsToMatch = $this->currentNode->getContext()->getTargetDimensions();
   76             unset($targetDimensionsToMatch[$pinnedDimensionName]);
   77         }
   78 
   79         foreach ($this->contentDimensionCombinator->getAllAllowedCombinations() as $allowedCombination) {
   80             $targetDimensions = $this->calculateTargetDimensionsForCombination($allowedCombination);
   81 
   82             if ($pinnedDimensionName !== null && is_array($pinnedDimensionValues)) {
   83                 if (!in_array($targetDimensions[$pinnedDimensionName], $pinnedDimensionValues)) {
   84                     continue;
   85                 }
   86             }
   87 
   88             // skip variants not matching the current target dimensions (except the dimension this menu covers)
   89             if ($targetDimensionsToMatch !== []) {
   90                 foreach ($targetDimensionsToMatch as $dimensionName => $dimensionValue) {
   91                     if ($targetDimensions[$dimensionName] !== $dimensionValue) {
   92                         continue 2;
   93                     }
   94                 }
   95             }
   96 
   97             $nodeInDimensions = $this->getNodeInDimensions($allowedCombination, $targetDimensions);
   98 
   99             // no match, so we look further...
  100             if ($nodeInDimensions === null && $includeAllPresets) {
  101                 $nodeInDimensions = $this->findAcceptableNode($allowedCombination, $allDimensionPresets);
  102             }
  103 
  104             if ($nodeInDimensions !== null && ($this->isNodeHidden($nodeInDimensions) || $this->hasHiddenNodeParent($nodeInDimensions))) {
  105                 $nodeInDimensions = null;
  106             }
  107 
  108             // determine metadata for target dimensions of node
  109             array_walk($targetDimensions, function (&$dimensionValue, $dimensionName, $allDimensionPresets) use ($pinnedDimensionName) {
  110                 $dimensionValue = [
  111                     'value' => $dimensionValue,
  112                     'label' => $allDimensionPresets[$dimensionName]['presets'][$dimensionValue]['label'],
  113                     'isPinnedDimension' => ($pinnedDimensionName === null || $dimensionName == $pinnedDimensionName) ? true : false
  114                 ];
  115             }, $allDimensionPresets);
  116 
  117             $menuItems[] = [
  118                 'node' => $nodeInDimensions,
  119                 'state' => $this->calculateItemState($nodeInDimensions),
  120                 'label' => $this->itemLabel($pinnedDimensionName, $nodeInDimensions, $targetDimensions),
  121                 'dimensions' => $allowedCombination,
  122                 'targetDimensions' => $targetDimensions
  123             ];
  124         }
  125 
  126         // sort/limit according to configured "presets" if needed
  127         if ($pinnedDimensionName !== null && is_array($pinnedDimensionValues)) {
  128             $sortedMenuItems = [];
  129             foreach ($pinnedDimensionValues as $pinnedDimensionValue) {
  130                 foreach ($menuItems as $menuItemKey => $menuItem) {
  131                     if ($menuItem['targetDimensions'][$pinnedDimensionName]['value'] === $pinnedDimensionValue) {
  132                         $sortedMenuItems[$menuItemKey] = $menuItem;
  133                     }
  134                 }
  135             }
  136 
  137             return $sortedMenuItems;
  138         }
  139 
  140         return $menuItems;
  141     }
  142 
  143     /**
  144      * Render and return a label for the $nodeInDimensions in the built menu item.
  145      *
  146      * @param string $pinnedDimensionName
  147      * @param NodeInterface $nodeInDimensions
  148      * @param array $targetDimensions
  149      * @return string
  150      */
  151     protected function itemLabel(string $pinnedDimensionName = null, NodeInterface $nodeInDimensions = null, array $targetDimensions = null): string
  152     {
  153         if ($nodeInDimensions === null && $pinnedDimensionName === null) {
  154             $itemLabel = '';
  155             foreach ($targetDimensions as $item) {
  156                 $itemLabel .= $item['label'] . ' - ';
  157             }
  158 
  159             return trim($itemLabel, ' -');
  160         } elseif ($nodeInDimensions instanceof NodeInterface && $pinnedDimensionName === null) {
  161             return $nodeInDimensions->getLabel();
  162         }
  163 
  164         return $targetDimensions[$pinnedDimensionName]['label'];
  165     }
  166 
  167     /**
  168      * Get the current node in the given dimensions.
  169      * If it doesn't exist the method returns null.
  170      *
  171      * @param array $dimensions
  172      * @param array $targetDimensions
  173      * @return NodeInterface|null
  174      */
  175     protected function getNodeInDimensions(array $dimensions, array $targetDimensions)
  176     {
  177         if ($this->currentNode === null) {
  178             return null;
  179         }
  180 
  181         $q = new FlowQuery([$this->currentNode]);
  182 
  183         return $q->context([
  184             'dimensions' => $dimensions,
  185             'targetDimensions' => $targetDimensions
  186         ])->get(0);
  187     }
  188 
  189     /**
  190      *
  191      * @param array $allowedCombination
  192      * @param $allDimensionPresets
  193      * @return null|NodeInterface
  194      */
  195     protected function findAcceptableNode(array $allowedCombination, array $allDimensionPresets)
  196     {
  197         $pinnedDimensionName = $this->getDimension();
  198         foreach ($allowedCombination[$pinnedDimensionName] as $allowedPresetIdentifier) {
  199             $acceptableCombination = [$pinnedDimensionName => $allDimensionPresets[$pinnedDimensionName]['presets'][$allowedPresetIdentifier]['values']];
  200             $allowedAdditionalPresets = $this->configurationContentDimensionPresetSource->getAllowedDimensionPresetsAccordingToPreselection('country', [$pinnedDimensionName => $allowedPresetIdentifier]);
  201             foreach ($allowedAdditionalPresets as $allowedAdditionalDimensionName => $allowedAdditionalPreset) {
  202                 $acceptableCombination[$allowedAdditionalDimensionName] = $allowedAdditionalPreset['presets'][$allowedAdditionalPreset['defaultPreset']]['values'];
  203             }
  204             $nodeInDimensions = $this->getNodeInDimensions($acceptableCombination, []);
  205             if ($nodeInDimensions !== null) {
  206                 return $nodeInDimensions;
  207             }
  208         }
  209 
  210         return null;
  211     }
  212 
  213     /**
  214      * Calculates the target dimensions for a given dimension combination.
  215      *
  216      * @param array $dimensionCombination
  217      * @return array
  218      */
  219     protected function calculateTargetDimensionsForCombination(array $dimensionCombination)
  220     {
  221         $targetDimensions = [];
  222         foreach ($dimensionCombination as $dimensionName => $dimensionValues) {
  223             $targetDimensions[$dimensionName] = reset($dimensionValues);
  224         }
  225 
  226         return $targetDimensions;
  227     }
  228 
  229     /**
  230      * Returns TRUE if the node has a inaccessible parent.
  231      *
  232      * @param NodeInterface $node
  233      * @return bool
  234      */
  235     protected function hasHiddenNodeParent(NodeInterface $node): bool
  236     {
  237         $rootNode = $node->getContext()->getRootNode();
  238         $nodesOnPath = $node->getContext()->getNodesOnPath($rootNode, $node);
  239 
  240         return count($nodesOnPath) < $node->getDepth();
  241     }
  242 }