diff --git a/_build/data/transport.core.events.php b/_build/data/transport.core.events.php index ed1b5882a87..5492f065d72 100644 --- a/_build/data/transport.core.events.php +++ b/_build/data/transport.core.events.php @@ -1197,6 +1197,14 @@ 'groupname' => 'Media Sources', ], '', true, true); +/* Search */ +$events['OnManagerSearch']= $xpdo->newObject(modEvent::class); +$events['OnManagerSearch']->fromArray([ + 'name' => 'OnManagerSearch', + 'service' => 2, + 'groupname' => 'System', +], '', true, true); + /* Package Manager */ $events['OnPackageInstall']= $xpdo->newObject(modEvent::class); $events['OnPackageInstall']->fromArray([ diff --git a/core/src/Revolution/Processors/Search/Search.php b/core/src/Revolution/Processors/Search/Search.php index 369cbbe7a8c..085f92535a3 100644 --- a/core/src/Revolution/Processors/Search/Search.php +++ b/core/src/Revolution/Processors/Search/Search.php @@ -11,6 +11,7 @@ namespace MODX\Revolution\Processors\Search; +use ArrayObject; use MODX\Revolution\modChunk; use MODX\Revolution\modContext; use MODX\Revolution\modElement; @@ -94,6 +95,19 @@ public function process() if ($this->modx->hasPermission('edit_user')) { $this->searchUsers(); } + + $providers = new ArrayObject(); + $this->modx->invokeEvent('OnManagerSearch', [ + 'query' => $this->query, + 'providers' => $providers, + 'maxResults' => $this->getMaxResults(), + 'searchInContent' => $this->searchInContent(), + ]); + foreach ($providers as $provider) { + if (is_array($provider)) { + $this->searchProvider($provider); + } + } } return $this->outputArray($this->results); @@ -224,4 +238,111 @@ protected function searchUsers() ]; } } + + /** + * Searches using a provider configuration from the OnManagerSearch event. + * + * Required config keys: class, type, nameField, action. + * Optional: descriptionField, contentField, label, icon, permission, idField, joins, searchFields. + * + * @param array $config Provider configuration + */ + protected function searchProvider(array $config) + { + if ( + empty($config['class']) + || empty($config['type']) + || empty($config['nameField']) + || empty($config['action']) + ) { + return; + } + + if (!empty($config['permission']) && !$this->modx->hasPermission($config['permission'])) { + return; + } + + $class = $config['class']; + + if (!$this->modx->getTableName($class)) { + return; + } + + $nameField = $config['nameField']; + $descriptionField = $config['descriptionField'] ?? ''; + $contentField = $config['contentField'] ?? ''; + $idField = $config['idField'] ?? 'id'; + + $c = $this->modx->newQuery($class); + + if (!empty($config['joins']) && is_array($config['joins'])) { + $pos = strrpos($class, '\\'); + $classAlias = $pos !== false ? substr($class, $pos + 1) : $class; + $c->select($this->modx->getSelectColumns($class, $classAlias)); + + foreach ($config['joins'] as $join) { + if (empty($join['class']) || empty($join['alias']) || empty($join['on'])) { + continue; + } + $joinType = strtolower($join['type'] ?? 'left'); + match ($joinType) { + 'inner' => $c->innerJoin($join['class'], $join['alias'], $join['on']), + 'right' => $c->rightJoin($join['class'], $join['alias'], $join['on']), + default => $c->leftJoin($join['class'], $join['alias'], $join['on']), + }; + } + + foreach ([$nameField, $descriptionField, $contentField, $idField] as $field) { + if ($field !== '' && str_contains($field, '.')) { + $c->select($field); + } + } + } + + $querySearch = [ + $nameField . ':LIKE' => '%' . $this->query . '%', + ]; + if (!empty($descriptionField)) { + $querySearch['OR:' . $descriptionField . ':LIKE'] = '%' . $this->query . '%'; + } + if ($this->searchInContent() && !empty($contentField)) { + $querySearch['OR:' . $contentField . ':LIKE'] = '%' . $this->query . '%'; + } + if (!empty($config['searchFields']) && is_array($config['searchFields'])) { + foreach ($config['searchFields'] as $field) { + if (is_string($field) && $field !== '') { + $querySearch['OR:' . $field . ':LIKE'] = '%' . $this->query . '%'; + } + } + } + $querySearch['OR:' . $idField . ':='] = $this->query; + $c->where($querySearch); + + $sortField = str_contains($nameField, '.') ? $nameField : '`' . $nameField . '`'; + $c->sortby('IF(' . $sortField . ' = ' . $this->modx->quote($this->query) . ', 0, 1)'); + + $c->limit($this->getMaxResults()); + + $nameFieldKey = str_contains($nameField, '.') ? substr($nameField, strrpos($nameField, '.') + 1) : $nameField; + $descFieldKey = ($descriptionField !== '' && str_contains($descriptionField, '.')) + ? substr($descriptionField, strrpos($descriptionField, '.') + 1) : $descriptionField; + $idFieldKey = str_contains($idField, '.') ? substr($idField, strrpos($idField, '.') + 1) : $idField; + + $collection = $this->modx->getIterator($class, $c); + foreach ($collection as $record) { + $result = [ + 'name' => $record->get($nameFieldKey), + 'description' => !empty($descFieldKey) ? $record->get($descFieldKey) : '', + '_action' => $config['action'] . $record->get($idFieldKey), + 'type' => $config['type'], + ]; + if (!empty($config['label'])) { + $result['label'] = $config['label']; + } + if (!empty($config['icon'])) { + $result['icon'] = $config['icon']; + } + $this->results[] = $result; + } + } } diff --git a/setup/includes/upgrades/common/3.2.1-add-on-manager-search-event.php b/setup/includes/upgrades/common/3.2.1-add-on-manager-search-event.php new file mode 100644 index 00000000000..eaba68eac80 --- /dev/null +++ b/setup/includes/upgrades/common/3.2.1-add-on-manager-search-event.php @@ -0,0 +1,35 @@ +%s

'; + +$event = $modx->getObject(modEvent::class, ['name' => 'OnManagerSearch']); +if (!$event) { + $event = $modx->newObject(modEvent::class); + $event->fromArray([ + 'name' => 'OnManagerSearch', + 'service' => 2, + 'groupname' => 'System', + ]); + if ($event->save()) { + $this->runner->addResult( + modInstallRunner::RESULT_SUCCESS, + sprintf($messageTemplate, 'ok', 'Added OnManagerSearch system event.') + ); + } else { + $this->runner->addResult( + modInstallRunner::RESULT_ERROR, + sprintf($messageTemplate, 'error', 'Failed to add OnManagerSearch system event.') + ); + } +} diff --git a/setup/includes/upgrades/mysql/3.2.1-pl.php b/setup/includes/upgrades/mysql/3.2.1-pl.php new file mode 100644 index 00000000000..8351e08482e --- /dev/null +++ b/setup/includes/upgrades/mysql/3.2.1-pl.php @@ -0,0 +1,12 @@ +