diff --git a/extensions/tags/src/Api/Controller/ListTagsController.php b/extensions/tags/src/Api/Controller/ListTagsController.php index 26ff9620c5..0715ebcbfc 100644 --- a/extensions/tags/src/Api/Controller/ListTagsController.php +++ b/extensions/tags/src/Api/Controller/ListTagsController.php @@ -55,9 +55,7 @@ protected function data(ServerRequestInterface $request, Document $document): it } if (array_key_exists('q', $filters)) { - $results = $this->search - ->for(Tag::class) - ->search(new SearchCriteria($actor, $filters, $limit, $offset)); + $results = $this->search->query(Tag::class, new SearchCriteria($actor, $filters, $limit, $offset)); $tags = $results->getResults(); diff --git a/framework/core/src/Api/ApiServiceProvider.php b/framework/core/src/Api/ApiServiceProvider.php index acd7a8b636..91a481ced6 100644 --- a/framework/core/src/Api/ApiServiceProvider.php +++ b/framework/core/src/Api/ApiServiceProvider.php @@ -56,7 +56,7 @@ public function register(): void $this->container->singleton('flarum.api.middleware', function () { return [ HttpMiddleware\InjectActorReference::class, - 'flarum.api.error_handler', +// 'flarum.api.error_handler', HttpMiddleware\ParseJsonBody::class, Middleware\FakeHttpMethods::class, HttpMiddleware\StartSession::class, diff --git a/framework/core/src/Api/Controller/ListAccessTokensController.php b/framework/core/src/Api/Controller/ListAccessTokensController.php index 5c8a8211cc..98a3eeb14b 100644 --- a/framework/core/src/Api/Controller/ListAccessTokensController.php +++ b/framework/core/src/Api/Controller/ListAccessTokensController.php @@ -38,9 +38,7 @@ protected function data(ServerRequestInterface $request, Document $document): it $limit = $this->extractLimit($request); $filter = $this->extractFilter($request); - $tokens = $this->search - ->for(AccessToken::class) - ->search(new SearchCriteria($actor, $filter, $limit, $offset)); + $tokens = $this->search->query(AccessToken::class, new SearchCriteria($actor, $filter, $limit, $offset)); $document->addPaginationLinks( $this->url->to('api')->route('access-tokens.index'), diff --git a/framework/core/src/Api/Controller/ListDiscussionsController.php b/framework/core/src/Api/Controller/ListDiscussionsController.php index a5ba1a6f8d..22043b7eb4 100644 --- a/framework/core/src/Api/Controller/ListDiscussionsController.php +++ b/framework/core/src/Api/Controller/ListDiscussionsController.php @@ -55,9 +55,10 @@ protected function data(ServerRequestInterface $request, Document $document): it $offset = $this->extractOffset($request); $include = array_merge($this->extractInclude($request), ['state']); - $results = $this->search - ->for(Discussion::class) - ->search(new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)); + $results = $this->search->query( + Discussion::class, + new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault) + ); $document->addPaginationLinks( $this->url->to('api')->route('discussions.index'), diff --git a/framework/core/src/Api/Controller/ListGroupsController.php b/framework/core/src/Api/Controller/ListGroupsController.php index b3c5c4ce85..935964e3b0 100644 --- a/framework/core/src/Api/Controller/ListGroupsController.php +++ b/framework/core/src/Api/Controller/ListGroupsController.php @@ -43,9 +43,10 @@ protected function data(ServerRequestInterface $request, Document $document): it $limit = $this->extractLimit($request); $offset = $this->extractOffset($request); - $queryResults = $this->search - ->for(Group::class) - ->search(new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)); + $queryResults = $this->search->query( + Group::class, + new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault) + ); $document->addPaginationLinks( $this->url->to('api')->route('groups.index'), diff --git a/framework/core/src/Api/Controller/ListPostsController.php b/framework/core/src/Api/Controller/ListPostsController.php index 21768de32f..4c419bb640 100644 --- a/framework/core/src/Api/Controller/ListPostsController.php +++ b/framework/core/src/Api/Controller/ListPostsController.php @@ -54,9 +54,10 @@ protected function data(ServerRequestInterface $request, Document $document): it $offset = $this->extractOffset($request); $include = $this->extractInclude($request); - $results = $this->search - ->for(Post::class) - ->search(new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)); + $results = $this->search->query( + Post::class, + new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault) + ); $document->addPaginationLinks( $this->url->to('api')->route('posts.index'), diff --git a/framework/core/src/Api/Controller/ListUsersController.php b/framework/core/src/Api/Controller/ListUsersController.php index 00136b4569..0547afc71b 100644 --- a/framework/core/src/Api/Controller/ListUsersController.php +++ b/framework/core/src/Api/Controller/ListUsersController.php @@ -59,9 +59,10 @@ protected function data(ServerRequestInterface $request, Document $document): it $offset = $this->extractOffset($request); $include = $this->extractInclude($request); - $results = $this->search - ->for(User::class) - ->search(new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)); + $results = $this->search->query( + User::class, + new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault) + ); $document->addPaginationLinks( $this->url->to('api')->route('users.index'), diff --git a/framework/core/src/Discussion/Search/FulltextFilter.php b/framework/core/src/Discussion/Search/FulltextFilter.php index 62b44b7792..da0b62a039 100644 --- a/framework/core/src/Discussion/Search/FulltextFilter.php +++ b/framework/core/src/Discussion/Search/FulltextFilter.php @@ -14,6 +14,7 @@ use Flarum\Search\AbstractFulltextFilter; use Flarum\Search\Database\DatabaseSearchState; use Flarum\Search\SearchState; +use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Expression; /** @@ -62,7 +63,7 @@ public function search(SearchState $state, string $value): void ->groupBy('discussions.id') ->addBinding($subquery->getBindings(), 'join'); - $state->setDefaultSort(function ($query) use ($grammar, $value) { + $state->setDefaultSort(function (Builder $query) use ($grammar, $value) { $query->orderByRaw('MATCH('.$grammar->wrap('discussions.title').') AGAINST (?) desc', [$value]); $query->orderBy('posts_ft.score', 'desc'); }); diff --git a/framework/core/src/Search/AbstractDriver.php b/framework/core/src/Search/AbstractDriver.php index d35119127b..983778b42d 100644 --- a/framework/core/src/Search/AbstractDriver.php +++ b/framework/core/src/Search/AbstractDriver.php @@ -3,6 +3,7 @@ namespace Flarum\Search; use Flarum\Database\AbstractModel; +use Illuminate\Contracts\Container\Container; abstract class AbstractDriver { @@ -10,13 +11,14 @@ public function __construct( /** * @var array, class-string> */ - protected array $searchers + protected array $searchers, + protected Container $container ) { } abstract public static function name(): string; - public function searchers(): array + public function getSearchers(): array { return $this->searchers; } @@ -25,4 +27,9 @@ public function supports(string $modelClass): bool { return isset($this->searchers[$modelClass]); } + + public function searcher(string $resourceClass): SearcherInterface + { + return $this->container->make($this->searchers[$resourceClass]); + } } diff --git a/framework/core/src/Search/Database/AbstractSearcher.php b/framework/core/src/Search/Database/AbstractSearcher.php index ccc2162ef5..a6df983511 100644 --- a/framework/core/src/Search/Database/AbstractSearcher.php +++ b/framework/core/src/Search/Database/AbstractSearcher.php @@ -33,7 +33,7 @@ public function search(SearchCriteria $criteria): SearchResults $query = $this->getQuery($actor); - $search = new DatabaseSearchState($actor, in_array('q', array_keys($criteria->filters), true)); + $search = new DatabaseSearchState($actor, $criteria->isFulltext()); $search->setQuery($query->getQuery()); $this->filters->apply($search, $criteria->filters); @@ -58,38 +58,38 @@ public function search(SearchCriteria $criteria): SearchResults return new SearchResults($results, $areMoreResults); } - protected function applySort(DatabaseSearchState $query, ?array $sort = null, bool $sortIsDefault = false): void + protected function applySort(DatabaseSearchState $state, ?array $sort = null, bool $sortIsDefault = false): void { - if ($sortIsDefault && ! empty($query->getDefaultSort())) { - $sort = $query->getDefaultSort(); + if ($sortIsDefault && ! empty($state->getDefaultSort())) { + $sort = $state->getDefaultSort(); } if (is_callable($sort)) { - $sort($query->getQuery()); + $sort($state->getQuery()); } else { foreach ((array) $sort as $field => $order) { if (is_array($order)) { foreach ($order as $value) { - $query->getQuery()->orderByRaw(Str::snake($field).' != ?', [$value]); + $state->getQuery()->orderByRaw(Str::snake($field).' != ?', [$value]); } } else { - $query->getQuery()->orderBy(Str::snake($field), $order); + $state->getQuery()->orderBy(Str::snake($field), $order); } } } } - protected function applyOffset(DatabaseSearchState $query, int $offset): void + protected function applyOffset(DatabaseSearchState $state, int $offset): void { if ($offset > 0) { - $query->getQuery()->skip($offset); + $state->getQuery()->skip($offset); } } - protected function applyLimit(DatabaseSearchState $query, ?int $limit): void + protected function applyLimit(DatabaseSearchState $state, ?int $limit): void { if ($limit > 0) { - $query->getQuery()->take($limit); + $state->getQuery()->take($limit); } } } diff --git a/framework/core/src/Search/SearchCriteria.php b/framework/core/src/Search/SearchCriteria.php index 1f7382ce9e..c13f408d1c 100644 --- a/framework/core/src/Search/SearchCriteria.php +++ b/framework/core/src/Search/SearchCriteria.php @@ -38,4 +38,9 @@ public function __construct( public bool $sortIsDefault = false, ) { } + + public function isFulltext(): bool + { + return in_array('q', array_keys($this->filters), true); + } } diff --git a/framework/core/src/Search/SearchManager.php b/framework/core/src/Search/SearchManager.php index 898b938622..18061105df 100644 --- a/framework/core/src/Search/SearchManager.php +++ b/framework/core/src/Search/SearchManager.php @@ -7,7 +7,6 @@ use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Container\Container; use Illuminate\Support\Arr; -use InvalidArgumentException; class SearchManager { @@ -26,7 +25,7 @@ public function driver(string $name): AbstractDriver $driver = Arr::first($this->drivers, fn ($driver) => $driver::name() === $name); if (! $driver) { - $driver = $this->driver(DatabaseSearchDriver::name()); + return $this->driver(DatabaseSearchDriver::name()); } return $this->container->make($driver); @@ -37,26 +36,6 @@ public function driverFor(string $resourceClass): AbstractDriver return $this->driver($this->settings->get("search_driver_$resourceClass")); } - public function searchable(string $resourceClass): bool - { - return $this->driverFor($resourceClass)->supports($resourceClass); - } - - /** - * @param class-string $resourceClass - */ - public function for(string $resourceClass): SearcherInterface - { - $driver = $this->driverFor($resourceClass); - $searchers = $driver->searchers(); - - if (! isset($searchers[$resourceClass])) { - throw new InvalidArgumentException("Driver {$driver::name()} does not support searching for $resourceClass."); - } - - return $this->container->make($searchers[$resourceClass]); - } - /** * @param class-string $resourceClass * @return array> @@ -70,4 +49,16 @@ public function indexable(string $resourceClass): bool { return ! empty($this->indexers[$resourceClass]); } + + public function query(string $resourceClass, SearchCriteria $criteria): SearchResults + { + $driver = $this->driverFor($resourceClass); + $defaultDriver = $this->driver(DatabaseSearchDriver::name()); + + if ($criteria->isFulltext() || ! $defaultDriver->supports($resourceClass)) { + return $driver->searcher($resourceClass)->search($criteria); + } + + return $defaultDriver->searcher($resourceClass)->search($criteria); + } } diff --git a/framework/core/src/Settings/SettingsServiceProvider.php b/framework/core/src/Settings/SettingsServiceProvider.php index d929b85cd2..0fb6c506cb 100644 --- a/framework/core/src/Settings/SettingsServiceProvider.php +++ b/framework/core/src/Settings/SettingsServiceProvider.php @@ -25,7 +25,7 @@ public function register(): void 'theme_primary_color' => '#4D698E', 'theme_secondary_color' => '#4D698E', 'search_driver_Flarum\User\User' => 'default', // @todo: use a morph map instead `User::class => 'user'` = search_driver_user (below as well) - 'search_driver_Flarum\Discussion\Discussion' => 'default', + 'search_driver_Flarum\Discussion\Discussion' => 'blomstra-elasticsearch', //'blomstra-elasticsearch', 'search_driver_Flarum\Group\Group' => 'default', 'search_driver_Flarum\Post\Post' => 'default', 'search_driver_Flarum\Http\AccessToken' => 'default',