1919use Flowpack \ElasticSearch \ContentRepositoryAdaptor \ElasticSearchClient ;
2020use Flowpack \ElasticSearch \ContentRepositoryAdaptor \Exception ;
2121use 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 ;
2529use Neos \Flow \Annotations as Flow ;
2630use Neos \Flow \Cli \CommandController ;
2731use Neos \Flow \Persistence \Exception \IllegalObjectTypeException ;
2832use Neos \Media \Domain \Model \ResourceBasedInterface ;
33+ use Neos \Neos \Domain \NodeLabel \NodeLabelGeneratorInterface ;
34+ use Neos \Neos \Domain \Service \NodeTypeNameFactory ;
2935use Neos \Utility \Arrays ;
3036
3137/**
3238 * @Flow\Scope("singleton")
3339 */
3440class SearchCommandController extends CommandController
3541{
36- /**
37- * @var ContextFactoryInterface
38- * @Flow\Inject
39- */
40- protected $ contextFactory ;
41-
4242 /**
4343 * @Flow\Inject
4444 * @var ElasticSearchClient
4545 */
4646 protected $ elasticSearchClient ;
4747
48+ #[Flow \Inject]
49+ protected ContentRepositoryRegistry $ contentRepositoryRegistry ;
50+
51+ #[Flow \Inject]
52+ protected NodeLabelGeneratorInterface $ nodeLabelGenerator ;
53+
4854 /**
4955 * This commnd can be used to test and debug
5056 * full-text searches
5157 *
5258 * @param string $searchWord The search word to seartch for.
59+ * @param string $contentRepository
5360 * @param string $path Path to the root node. Defaults to '/'
5461 * @param string|null $dimensions The dimesnions to be taken into account.
5562 * @throws Exception
5663 * @throws QueryBuildingException
5764 * @throws IllegalObjectTypeException
5865 * @throws Exception\ConfigurationException
5966 */
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
6168 {
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+ }
6485
6586 if ($ contextNode === null ) {
6687 $ this ->outputLine ('Context node not found ' );
@@ -94,25 +115,37 @@ public function fulltextCommand(string $searchWord, string $path = '/', ?string
94115 * Prints the index content of the given node identifier.
95116 *
96117 * @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"}'
98120 * @param string $field Name or path to a source field to display. Eg. "__fulltext.h1"
99121 * @throws Exception
100122 * @throws IllegalObjectTypeException
101123 * @throws QueryBuildingException
102124 * @throws \Flowpack\ElasticSearch\Exception
103125 * @throws \Neos\Flow\Http\Exception
104126 */
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
106128 {
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 ) {
108130 $ this ->outputLine ('<error>Error: </error>The Dimensions must be given as a JSON array like \'{"language":["de"]} \'' );
109131 $ this ->sendAndExit (1 );
110132 }
111133
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+ }
113146
114147 $ queryBuilder = new ElasticSearchQueryBuilder ();
115- $ queryBuilder ->query ($ context -> getRootNode () );
148+ $ queryBuilder ->query ($ rootNode );
116149 $ queryBuilder ->exactMatch ('neos_node_identifier ' , $ identifier );
117150
118151 $ queryBuilder ->getRequest ()->setValueByPath ('_source ' , []);
@@ -122,7 +155,7 @@ public function viewNodeCommand(string $identifier, ?string $dimensions = null,
122155 $ this ->outputLine ('<info>Results</info> ' );
123156
124157 foreach ($ queryBuilder ->execute () as $ node ) {
125- $ this ->outputLine ('<b>%s</b> ' , [(string )$ node ]);
158+ $ this ->outputLine ('<b>%s</b> ' , [(string )$ node-> aggregateId -> value ]);
126159 $ data = $ queryBuilder ->getFullElasticSearchHitForNode ($ node );
127160
128161 if ($ field !== '' ) {
@@ -143,48 +176,31 @@ public function viewNodeCommand(string $identifier, ?string $dimensions = null,
143176 */
144177 private function outputResults (ElasticSearchQueryResult $ result ): void
145178 {
146- $ results = array_map (static function (NodeInterface $ node ) {
179+ $ results = array_map (function (Node $ node ) {
147180 $ properties = [];
148181
149- foreach ($ node ->getProperties () as $ propertyName => $ propertyValue ) {
182+ foreach ($ node ->properties as $ propertyName => $ propertyValue ) {
150183 if ($ propertyValue instanceof ResourceBasedInterface) {
151184 $ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . (string )$ propertyValue ->getResource ()->getFilename ();
152- } elseif ($ propertyValue instanceof \DateTime ) {
185+ } elseif ($ propertyValue instanceof \DateTimeInterface ) {
153186 $ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . $ propertyValue ->format ('Y-m-d H:i ' );
154187 } elseif (is_array ($ propertyValue )) {
155188 $ 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 ;
158191 } else {
159192 $ properties [$ propertyName ] = '<b> ' . $ propertyName . '</b>: ' . (string )$ propertyValue ;
160193 }
161194 }
162195
163196 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 ,
167200 'properties ' => implode (PHP_EOL , $ properties ),
168201 ];
169202 }, $ result ->toArray ());
170203
171204 $ this ->output ->outputTable ($ results , ['Identifier ' , 'Label ' , 'Node Type ' , 'Properties ' ]);
172205 }
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- }
190206}
0 commit comments