19
19
use Flowpack \ElasticSearch \ContentRepositoryAdaptor \ElasticSearchClient ;
20
20
use Flowpack \ElasticSearch \ContentRepositoryAdaptor \Exception ;
21
21
use Flowpack \ElasticSearch \ContentRepositoryAdaptor \Exception \QueryBuildingException ;
22
- use Neos \ContentRepository \Domain \Model \NodeInterface ;
23
- use Neos \ContentRepository \Domain \Service \Context ;
24
- use Neos \ContentRepository \Domain \Service \ContextFactoryInterface ;
22
+ use Neos \ContentRepository \Core \DimensionSpace \DimensionSpacePoint ;
23
+ use Neos \ContentRepository \Core \Projection \ContentGraph \Node ;
24
+ use Neos \ContentRepository \Core \Projection \ContentGraph \VisibilityConstraints ;
25
+ use Neos \ContentRepository \Core \SharedModel \ContentRepository \ContentRepositoryId ;
26
+ use Neos \ContentRepository \Core \SharedModel \Node \NodeAggregateId ;
27
+ use Neos \ContentRepository \Core \SharedModel \Workspace \WorkspaceName ;
28
+ use Neos \ContentRepositoryRegistry \ContentRepositoryRegistry ;
25
29
use Neos \Flow \Annotations as Flow ;
26
30
use Neos \Flow \Cli \CommandController ;
27
31
use Neos \Flow \Persistence \Exception \IllegalObjectTypeException ;
28
32
use Neos \Media \Domain \Model \ResourceBasedInterface ;
33
+ use Neos \Neos \Domain \NodeLabel \NodeLabelGeneratorInterface ;
34
+ use Neos \Neos \Domain \Service \NodeTypeNameFactory ;
29
35
use Neos \Utility \Arrays ;
30
36
31
37
/**
32
38
* @Flow\Scope("singleton")
33
39
*/
34
40
class SearchCommandController extends CommandController
35
41
{
36
- /**
37
- * @var ContextFactoryInterface
38
- * @Flow\Inject
39
- */
40
- protected $ contextFactory ;
41
-
42
42
/**
43
43
* @Flow\Inject
44
44
* @var ElasticSearchClient
45
45
*/
46
46
protected $ elasticSearchClient ;
47
47
48
+ #[Flow \Inject]
49
+ protected ContentRepositoryRegistry $ contentRepositoryRegistry ;
50
+
51
+ #[Flow \Inject]
52
+ protected NodeLabelGeneratorInterface $ nodeLabelGenerator ;
53
+
48
54
/**
49
55
* This commnd can be used to test and debug
50
56
* full-text searches
51
57
*
52
58
* @param string $searchWord The search word to seartch for.
59
+ * @param string $contentRepository
53
60
* @param string $path Path to the root node. Defaults to '/'
54
61
* @param string|null $dimensions The dimesnions to be taken into account.
55
62
* @throws Exception
56
63
* @throws QueryBuildingException
57
64
* @throws IllegalObjectTypeException
58
65
* @throws Exception\ConfigurationException
59
66
*/
60
- public function fulltextCommand (string $ searchWord , string $ path = '/ ' , ?string $ dimensions = null ): void
67
+ public function fulltextCommand (string $ searchWord , $ contentRepository = 'default ' , ? string $ nodeAggregateId = null , ?string $ dimensions = null ): void
61
68
{
62
- $ context = $ this ->createContext ($ dimensions );
63
- $ contextNode = $ context ->getNode ($ path );
69
+ if ($ dimensions !== null && is_array (json_decode ($ dimensions , true )) === false ) {
70
+ $ this ->outputLine ('<error>Error: </error>The Dimensions must be given as a JSON array like \'{"language":["de"]} \'' );
71
+ $ this ->sendAndExit (1 );
72
+ }
73
+
74
+ $ contentRepositoryId = ContentRepositoryId::fromString ($ contentRepository );
75
+ $ dimensionSpacePoint = $ dimensions ? DimensionSpacePoint::fromJsonString ($ dimensions ) : DimensionSpacePoint::createWithoutDimensions ();
76
+
77
+ $ contentGraph = $ this ->contentRepositoryRegistry ->get ($ contentRepositoryId )->getContentGraph (WorkspaceName::forLive ());
78
+ $ subgraph = $ contentGraph ->getSubgraph ($ dimensionSpacePoint , VisibilityConstraints::withoutRestrictions ());
79
+
80
+ if ($ nodeAggregateId !== null ) {
81
+ $ contextNode = $ subgraph ->findNodeById (NodeAggregateId::fromString ($ nodeAggregateId ));
82
+ } else {
83
+ $ contextNode = $ subgraph ->findRootNodeByType (NodeTypeNameFactory::forSites ());
84
+ }
64
85
65
86
if ($ contextNode === null ) {
66
87
$ this ->outputLine ('Context node not found ' );
@@ -94,25 +115,37 @@ public function fulltextCommand(string $searchWord, string $path = '/', ?string
94
115
* Prints the index content of the given node identifier.
95
116
*
96
117
* @param string $identifier The node identifier
97
- * @param string|null $dimensions Dimensions, specified in JSON format, like '{"language":["de"]}'
118
+ * @param string $contentRepository
119
+ * @param string|null $dimensions Dimensions, specified in JSON format, like '{"language":"en"}'
98
120
* @param string $field Name or path to a source field to display. Eg. "__fulltext.h1"
99
121
* @throws Exception
100
122
* @throws IllegalObjectTypeException
101
123
* @throws QueryBuildingException
102
124
* @throws \Flowpack\ElasticSearch\Exception
103
125
* @throws \Neos\Flow\Http\Exception
104
126
*/
105
- public function viewNodeCommand (string $ identifier , ?string $ dimensions = null , string $ field = '' ): void
127
+ public function viewNodeCommand (string $ identifier , string $ contentRepository = ' default ' , ?string $ dimensions = null , string $ field = '' ): void
106
128
{
107
- if ($ dimensions !== null && is_array (json_decode ($ dimensions , true , 512 , JSON_THROW_ON_ERROR )) === false ) {
129
+ if ($ dimensions !== null && is_array (json_decode ($ dimensions , true )) === false ) {
108
130
$ this ->outputLine ('<error>Error: </error>The Dimensions must be given as a JSON array like \'{"language":["de"]} \'' );
109
131
$ this ->sendAndExit (1 );
110
132
}
111
133
112
- $ context = $ this ->createContext ($ dimensions );
134
+ $ contentRepositoryId = ContentRepositoryId::fromString ($ contentRepository );
135
+ $ dimensionSpacePoint = $ dimensions ? DimensionSpacePoint::fromJsonString ($ dimensions ) : DimensionSpacePoint::createWithoutDimensions ();
136
+
137
+ $ contentGraph = $ this ->contentRepositoryRegistry ->get ($ contentRepositoryId )->getContentGraph (WorkspaceName::forLive ());
138
+ $ subgraph = $ contentGraph ->getSubgraph ($ dimensionSpacePoint , VisibilityConstraints::withoutRestrictions ());
139
+
140
+ $ rootNode = $ subgraph ->findRootNodeByType (NodeTypeNameFactory::forSites ());
141
+
142
+ if ($ rootNode === null ) {
143
+ $ this ->outputLine ('<error>Error: </error>No root node found for the given dimensions ' );
144
+ return ;
145
+ }
113
146
114
147
$ queryBuilder = new ElasticSearchQueryBuilder ();
115
- $ queryBuilder ->query ($ context -> getRootNode () );
148
+ $ queryBuilder ->query ($ rootNode );
116
149
$ queryBuilder ->exactMatch ('neos_node_identifier ' , $ identifier );
117
150
118
151
$ queryBuilder ->getRequest ()->setValueByPath ('_source ' , []);
@@ -122,7 +155,7 @@ public function viewNodeCommand(string $identifier, ?string $dimensions = null,
122
155
$ this ->outputLine ('<info>Results</info> ' );
123
156
124
157
foreach ($ queryBuilder ->execute () as $ node ) {
125
- $ this ->outputLine ('<b>%s</b> ' , [(string )$ node ]);
158
+ $ this ->outputLine ('<b>%s</b> ' , [(string )$ node-> aggregateId -> value ]);
126
159
$ data = $ queryBuilder ->getFullElasticSearchHitForNode ($ node );
127
160
128
161
if ($ field !== '' ) {
@@ -143,48 +176,31 @@ public function viewNodeCommand(string $identifier, ?string $dimensions = null,
143
176
*/
144
177
private function outputResults (ElasticSearchQueryResult $ result ): void
145
178
{
146
- $ results = array_map (static function (NodeInterface $ node ) {
179
+ $ results = array_map (function (Node $ node ) {
147
180
$ properties = [];
148
181
149
- foreach ($ node ->getProperties () as $ propertyName => $ propertyValue ) {
182
+ foreach ($ node ->properties as $ propertyName => $ propertyValue ) {
150
183
if ($ propertyValue instanceof ResourceBasedInterface) {
151
184
$ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . (string )$ propertyValue ->getResource ()->getFilename ();
152
- } elseif ($ propertyValue instanceof \DateTime ) {
185
+ } elseif ($ propertyValue instanceof \DateTimeInterface ) {
153
186
$ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . $ propertyValue ->format ('Y-m-d H:i ' );
154
187
} elseif (is_array ($ propertyValue )) {
155
188
$ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . 'array ' ;
156
- } elseif ($ propertyValue instanceof NodeInterface ) {
157
- $ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . $ propertyValue ->getIdentifier () ;
189
+ } elseif ($ propertyValue instanceof Node ) {
190
+ $ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . $ propertyValue ->aggregateId -> value ;
158
191
} else {
159
192
$ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . (string )$ propertyValue ;
160
193
}
161
194
}
162
195
163
196
return [
164
- 'identifier ' => $ node ->getIdentifier () ,
165
- 'label ' => $ node -> getLabel (),
166
- 'nodeType ' => $ node ->getNodeType ()-> getName () ,
197
+ 'identifier ' => $ node ->aggregateId -> value ,
198
+ 'label ' => $ this -> nodeLabelGenerator -> getLabel ($ node ),
199
+ 'nodeType ' => $ node ->nodeTypeName -> value ,
167
200
'properties ' => implode (PHP_EOL , $ properties ),
168
201
];
169
202
}, $ result ->toArray ());
170
203
171
204
$ this ->output ->outputTable ($ results , ['Identifier ' , 'Label ' , 'Node Type ' , 'Properties ' ]);
172
205
}
173
-
174
- /**
175
- * @param string|null $dimensions
176
- * @return Context
177
- */
178
- private function createContext (string $ dimensions = null ): Context
179
- {
180
- $ contextConfiguration = [
181
- 'workspaceName ' => 'live ' ,
182
- ];
183
-
184
- if ($ dimensions !== null ) {
185
- $ contextConfiguration ['dimensions ' ] = json_decode ($ dimensions , true );
186
- }
187
-
188
- return $ this ->contextFactory ->create ($ contextConfiguration );
189
- }
190
206
}
0 commit comments