-
-
Notifications
You must be signed in to change notification settings - Fork 219
/
PluginService.php
225 lines (204 loc) · 8.15 KB
/
PluginService.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<?php
namespace Neos\Neos\Service;
/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* 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\Flow\Security\Context;
use Neos\Neos;
use Neos\Neos\Domain\Model\PluginViewDefinition;
use Neos\Neos\Domain\Service\ContentContext;
use Neos\Neos\Domain\Service\ContentContextFactory;
use Neos\ContentRepository\Domain\Factory\NodeFactory;
use Neos\ContentRepository\Domain\Model\Node;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Model\NodeType;
use Neos\ContentRepository\Domain\Repository\NodeDataRepository;
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
/**
* Central authority for interactions with plugins.
* Whenever details about Plugins or PluginViews are needed this service should be used.
*
* For some methods the ContentContext has to be specified. This is required in order for the ContentRepository to fetch nodes
* of the current workspace. The context can be retrieved from any node of the correct workspace & tree. If no node
* is available (e.g. for CLI requests) the ContentContextFactory can be used to create a context instance.
*
* @Flow\Scope("singleton")
*/
class PluginService
{
/**
* @var NodeTypeManager
* @Flow\Inject
*/
protected $nodeTypeManager;
/**
* @Flow\Inject
* @var NodeDataRepository
*/
protected $nodeDataRepository;
/**
* @Flow\Inject
* @var Context
*/
protected $securityContext;
/**
* @Flow\Inject
* @var ContentContextFactory
*/
protected $contentContextFactory;
/**
* @Flow\Inject
* @var NodeFactory
*/
protected $nodeFactory;
/**
* Returns an array of all available plugin nodes
*
* @param ContentContext $context current content context, see class doc comment for details
* @return array<NodeInterface> all plugin nodes in the current $context
*/
public function getPluginNodes(ContentContext $context)
{
$pluginNodeTypes = $this->nodeTypeManager->getSubNodeTypes('Neos.Neos:Plugin', false);
return $this->getNodes(array_keys($pluginNodeTypes), $context);
}
/**
* Returns an array of all plugin nodes with View Definitions
*
* @param ContentContext $context
* @return array<NodeInterface> all plugin nodes with View Definitions in the current $context
*/
public function getPluginNodesWithViewDefinitions(ContentContext $context)
{
$pluginNodes = [];
foreach ($this->getPluginNodes($context) as $pluginNode) {
/** @var NodeInterface $pluginNode */
if ($this->getPluginViewDefinitionsByPluginNodeType($pluginNode->getNodeType()) !== []) {
$pluginNodes[] = $pluginNode;
}
}
return $pluginNodes;
}
/**
* Find all nodes of a specific node type
*
* @param array $nodeTypes
* @param ContentContext $context current content context, see class doc comment for details
* @return array<NodeInterface> all nodes of type $nodeType in the current $context
*/
protected function getNodes(array $nodeTypes, ContentContext $context)
{
$nodes = [];
$siteNode = $context->getCurrentSiteNode();
foreach ($this->nodeDataRepository->findByParentAndNodeTypeRecursively($siteNode->getPath(), implode(',', $nodeTypes), $context->getWorkspace()) as $nodeData) {
$nodes[] = $this->nodeFactory->createFromNodeData($nodeData, $context);
}
return $nodes;
}
/**
* Get all configured PluginView definitions for a specific $pluginNodeType
*
* @param NodeType $pluginNodeType node type name of the master plugin
* @return array<PluginViewDefinition> list of PluginViewDefinition instances for the given $pluginNodeName
*/
public function getPluginViewDefinitionsByPluginNodeType(NodeType $pluginNodeType)
{
$viewDefinitions = [];
foreach ($this->getPluginViewConfigurationsByPluginNodeType($pluginNodeType) as $pluginViewName => $pluginViewConfiguration) {
$viewDefinitions[] = new PluginViewDefinition($pluginNodeType, $pluginViewName, $pluginViewConfiguration);
}
return $viewDefinitions;
}
/**
* @param NodeType $pluginNodeType
* @return array
*/
protected function getPluginViewConfigurationsByPluginNodeType(NodeType $pluginNodeType)
{
$pluginNodeTypeOptions = $pluginNodeType->getOptions();
return isset($pluginNodeTypeOptions['pluginViews']) ? $pluginNodeTypeOptions['pluginViews'] : [];
}
/**
* returns a plugin node or one of it's view nodes
* if an view has been configured for that specific
* controller and action combination
*
* @param NodeInterface $currentNode
* @param string $controllerObjectName
* @param string $actionName
* @return NodeInterface
*/
public function getPluginNodeByAction(NodeInterface $currentNode, $controllerObjectName, $actionName)
{
$viewDefinition = $this->getPluginViewDefinitionByAction($controllerObjectName, $actionName);
if ($currentNode->getNodeType()->isOfType('Neos.Neos:PluginView')) {
$masterPluginNode = $this->getPluginViewNodeByMasterPlugin($currentNode, $viewDefinition->getName());
} else {
$masterPluginNode = $currentNode;
}
if ($viewDefinition !== null) {
$viewNode = $this->getPluginViewNodeByMasterPlugin($currentNode, $viewDefinition->getName());
if ($viewNode instanceof Node) {
return $viewNode;
}
}
return $masterPluginNode;
}
/**
* Fetch a PluginView definition that matches the specified controller and action combination
*
* @param string $controllerObjectName
* @param string $actionName
* @return PluginViewDefinition
* @throws Neos\Exception if more than one PluginView matches the given controller/action pair
*/
public function getPluginViewDefinitionByAction($controllerObjectName, $actionName)
{
$pluginNodeTypes = $this->nodeTypeManager->getSubNodeTypes('Neos.Neos:Plugin', false);
$matchingPluginViewDefinitions = [];
foreach ($pluginNodeTypes as $pluginNodeType) {
/** @var $pluginViewDefinition PluginViewDefinition */
foreach ($this->getPluginViewDefinitionsByPluginNodeType($pluginNodeType) as $pluginViewDefinition) {
if ($pluginViewDefinition->matchesControllerActionPair($controllerObjectName, $actionName) !== true) {
continue;
}
$matchingPluginViewDefinitions[] = $pluginViewDefinition;
}
}
if (count($matchingPluginViewDefinitions) > 1) {
throw new Neos\Exception(sprintf('More than one PluginViewDefinition found for controller "%s", action "%s":%s', $controllerObjectName, $actionName, chr(10) . implode(chr(10), $matchingPluginViewDefinitions)), 1377597671);
}
return count($matchingPluginViewDefinitions) > 0 ? current($matchingPluginViewDefinitions) : null;
}
/**
* returns a specific view node of an master plugin
* or NULL if it does not exist
*
* @param NodeInterface $node
* @param string $viewName
* @return NodeInterface
*/
public function getPluginViewNodeByMasterPlugin(NodeInterface $node, $viewName)
{
/** @var $context ContentContext */
$context = $node->getContext();
foreach ($this->getNodes(['Neos.Neos:PluginView'], $context) as $pluginViewNode) {
/** @var NodeInterface $pluginViewNode */
if ($pluginViewNode === null || $pluginViewNode->isRemoved()) {
continue;
}
if ($pluginViewNode->getProperty('plugin') === $node->getIdentifier()
&& $pluginViewNode->getProperty('view') === $viewName) {
return $pluginViewNode;
}
}
return null;
}
}