Passed
Pull Request — master (#106)
by
unknown
05:18
created

mergeHighlightsIntoModels()   A

Complexity

Conditions 5
Paths 1

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 15
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 25
ccs 0
cts 15
cp 0
crap 30
rs 9.4555
1
<?php
2
3
4
namespace Matchish\ScoutElasticSearch\ElasticSearch;
5
6
7
use Illuminate\Database\Eloquent\Model;
8
use Laravel\Scout\Builder;
9
use Laravel\Scout\Searchable;
10
11
class HighlightedHitsIterator implements \IteratorAggregate
12
{
13
    /**
14
     * @var array
15
     */
16
    private $results;
17
18
    /**
19
     * @var callable|null
20
     */
21
    private $callback;
22
23
    public function __invoke(array $results, $callback = null)
24
    {
25
        $this->results = $results;
26
        $this->callback = $callback;
27
        return $this;
28
    }
29
30
    /**
31
     * Retrieve an external iterator.
32
     * @link https://php.net/manual/en/iteratoraggregate.getiterator.php
33
     * @return Traversable An instance of an object implementing <b>Iterator</b> or
0 ignored issues
show
Bug introduced by
The type Matchish\ScoutElasticSea...asticSearch\Traversable was not found. Did you mean Traversable? If so, make sure to prefix the type with \.
Loading history...
34
     * <b>Traversable</b>
35
     * @since 5.0.0
36
     */
37
    public function getIterator()
38
    {
39
        $hits = collect();
40
        if ($this->results['hits']['total']) {
41
            $raw = collect($this->results['hits']['hits']);
42
            $models = $this->collectModels($raw);
43
            $eloquentHits = $this->getEloquentHits($raw, $models);
44
            $hits = $this->mergeHighlightsIntoModels($eloquentHits, $raw);
45
        }
46
47
        return new \ArrayIterator($hits);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new ArrayIterator($hits) returns the type ArrayIterator which is incompatible with the documented return type Matchish\ScoutElasticSea...asticSearch\Traversable.
Loading history...
48
    }
49
50
    private function collectModels($rawHits)
51
    {
52
        return collect($rawHits)
53
            ->groupBy('_source.__class_name')
54
            ->map(function ($results, $class) {
55
                $model = new $class;
56
                $builder = new Builder($model, '');
57
                if (! empty($this->callback)) {
58
                    $builder->query($this->callback);
59
                }
60
                /* @var Searchable $model */
61
                return $models = $model->getScoutModelsByIds(
0 ignored issues
show
Unused Code introduced by
The assignment to $models is dead and can be removed.
Loading history...
62
                    $builder, $results->pluck('_id')->all()
63
                );
64
            })
65
            ->flatten()
66
            ->keyBy(function ($model) {
67
                return get_class($model).'::'.$model->getScoutKey();
68
            });
69
    }
70
71
    private function getEloquentHits($hits, $models)
72
    {
73
        return collect($hits)
74
            ->map(function ($hit) use ($models) {
75
                $key = $hit['_source']['__class_name'].'::'.$hit['_id'];
76
77
                return isset($models[$key]) ? $models[$key] : null;
78
            })->filter()->all();
79
    }
80
81
    private function mergeHighlightsIntoModels($eloquentHits, $raw)
82
    {
83
        return collect($eloquentHits)
84
            ->map(function (Model $eloquentHit) use ($raw) {
85
                $raw = collect($raw)
86
                    ->where('_source.__class_name', get_class($eloquentHit))
87
                    ->where('_source.id', $eloquentHit->id)
88
                    ->first();
89
90
                foreach ($raw['highlight'] ?? [] as $key => $highlight) {
91
                    if(in_array($key, ['customer.name', 'billing_address.name', 'shipping_address.name'])){
92
                        $key = 'name';
93
                    }
94
95
                    if(in_array($key, ['customer.email', 'billing_address.email', 'shipping_address.email'])){
96
                        $key = 'email';
97
                    }
98
99
                    if (! in_array($key, ['created_at', 'updated_at'])) {
100
                        $eloquentHit->setAttribute($key, $highlight[0]);
101
                    }
102
                }
103
104
                return $eloquentHit;
105
            })->all();
106
    }
107
}