Issues (368)

src/Services/GlobalSearchService.php (1 issue)

1
<?php
2
3
namespace Arbory\Base\Services;
4
5
use Arbory\Base\Admin\Admin;
6
use Arbory\Base\Admin\Module;
7
use Arbory\Base\Exceptions\GlobalSearchException;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Database\Eloquent\Model;
10
use Illuminate\Support\Collection;
11
use Illuminate\Support\Str;
12
13
class GlobalSearchService
14
{
15
    protected const ALLOWED_RELATIONSHIP_NESTING_LEVEL = 2;
16
17
    public function __construct(protected Admin $admin)
18
    {
19
    }
20
21
    /**
22
     * @throws GlobalSearchException
23
     */
24
    public function search(string $term): array
25
    {
26
        $searchableModules = $this->admin
27
            ->modules()
28
            ->all()
29
            ->filter(function ($module) {
30
                /**
31
                 * @var Module $module
32
                 */
33
                $configuration = $module->getConfiguration();
34
                $controller = app($configuration->getControllerClass());
35
36
                return property_exists($controller, 'module') &&
37
                    $module->isAuthorized() &&
38
                    property_exists($controller, 'searchBy') &&
39
                    ! empty($controller->searchBy);
40
            });
41
42
        return $searchableModules->mapWithKeys(function ($module) use ($term) {
43
            $configuration = $module->getConfiguration();
44
            $controller = app($configuration->getControllerClass());
45
            $searchFields = $controller->searchBy;
46
            $model = $controller->resource();
0 ignored issues
show
The method resource() does not exist on Illuminate\Contracts\Foundation\Application. Did you maybe mean resourcePath()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
            /** @scrutinizer ignore-call */ 
47
            $model = $controller->resource();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
47
48
            $formattedResults = $this->findResults($module, $model, $searchFields, $term);
49
            if (! $formattedResults->count()) {
50
                return [];
51
            }
52
53
            return [ucfirst($module->name()) => $formattedResults];
54
        })->toArray();
55
    }
56
57
    protected function findResults(Module $module, Model $model, array $searchFields, string $term): Collection
58
    {
59
        $searchQuery = $model::query();
60
61
        foreach ($searchFields as $searchField) {
62
            $searchField = Str::of($searchField)->explode('.');
63
64
            if ($searchField->count() > self::ALLOWED_RELATIONSHIP_NESTING_LEVEL) {
65
                throw new GlobalSearchException('Only one level nested relationship search is allowed');
66
            }
67
68
            if ($searchField->count() === self::ALLOWED_RELATIONSHIP_NESTING_LEVEL) {
69
                $searchQuery->orWhereHas($searchField[0], function (Builder $query) use ($searchField, $term) {
70
                    return $query->where($searchField[1], 'LIKE', '%' . $term . '%');
71
                });
72
            } else {
73
                $searchQuery = $searchQuery->orWhere($searchField[0], 'LIKE', '%' . $term . '%');
74
            }
75
        }
76
77
        $results = $searchQuery->take(config('arbory.search.results_count_per_module'))->get();
78
79
        return $this->formattedResults($module, $results);
80
    }
81
82
    protected function formattedResults(Module $module, Collection $results): Collection
83
    {
84
        return $results->map(function ($row) use ($module) {
85
            return [
86
                'title' => Str::of((string) $row)
87
                    ->limit(config('arbory.search.result_title_length'))
88
                    ->ucfirst(),
89
                'url' => $module->url('edit', $row->getKey()),
90
            ];
91
        });
92
    }
93
}
94