EloquentFiller::fillModel()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 6
nop 2
dl 0
loc 19
ccs 9
cts 10
cp 0.9
crap 4.016
rs 9.9666
c 0
b 0
f 0
1
<?php
2
namespace Triadev\Leopard\Business\Filler;
3
4
use Illuminate\Database\Eloquent\Model;
5
use Illuminate\Database\Eloquent\Relations\Relation;
6
use Illuminate\Support\Collection;
7
use Triadev\Leopard\Contract\FillerContract;
8
use Triadev\Es\Dsl\Model\SearchResult;
9
use Triadev\Leopard\Searchable;
10
11
class EloquentFiller implements FillerContract
12
{
13
    /**
14
     * Fill
15
     *
16
     * @param Model $model
17
     * @param SearchResult $searchResult
18
     */
19 1
    public function fill(Model $model, SearchResult $searchResult)
20
    {
21 1
        $searchResult->setHits(
22
            $searchResult->getHits()->map(function (array $hit) use ($model) {
23 1
                return $this->fillModel($model, $hit);
24 1
            })
25
        );
26 1
    }
27
    
28
    /**
29
     * Fill model
30
     *
31
     * @param Model $model
32
     * @param array $hit
33
     * @return Model
34
     */
35 1
    public function fillModel(Model $model, array $hit = []) : Model
36
    {
37 1
        $source = array_get($hit, '_source', []);
38
        
39 1
        if ($id = array_get($hit, '_id', null)) {
40 1
            $source[$model->getKeyName()] = is_numeric($id) ? intval($id) : $id;
41
        }
42
        
43
        /** @var Model|Searchable $instance */
44 1
        $instance = $this->newFromBuilderRecursive($model, $source);
45
        
46 1
        $instance->documentScore = array_get($hit, '_score');
47 1
        $instance->isDocument = true;
48
        
49 1
        if ($version = array_get($hit, '_version')) {
50
            $instance->documentVersion = $version;
51
        }
52
        
53 1
        return $instance;
54
    }
55
    
56
    /**
57
     * Fill a model with form an elastic hit.
58
     *
59
     * @param Model $model
60
     * @param array $attributes
61
     *
62
     * @return Model
63
     */
64 1
    public function newFromBuilderRecursive(Model $model, array $attributes = []) : Model
65
    {
66 1
        $instance = $model->newInstance([], $exists = true);
67
        
68 1
        $instance->unguard();
69
        
70 1
        $instance->fill($attributes);
71 1
        $instance->reguard();
72
        
73 1
        $this->loadRelationsAttributesRecursive($instance);
74
        
75 1
        return $instance;
76
    }
77
    
78
    /**
79
     * Get the relations attributes from a model.
80
     *
81
     * @param \Illuminate\Database\Eloquent\Model $model
82
     */
83 1
    protected function loadRelationsAttributesRecursive(Model $model)
84
    {
85 1
        foreach ($model->getAttributes() as $key => $value) {
86 1
            if (!method_exists($model, $key)) {
87 1
                continue;
88
            }
89
            
90
            try {
91
                if ((new \ReflectionMethod($model, $key))->class != Model::class) {
92
                    $relation = $model->$key();
93
                    if ($relation instanceof Relation) {
94
                        if ($value === null) {
95
                            $models = null;
96
                        } else {
97
                            if (!$multiLevelRelation = $this->isMultiLevelArray($value)) {
98
                                $value = [$value];
99
                            }
100
                
101
                            $models = $this->hydrateRecursive($relation->getModel(), $value);
102
                            if (!$multiLevelRelation) {
103
                                $models = $models->first();
104
                            }
105
                        }
106
            
107
                        unset($model[$key]);
108
                        $model->setRelation($key, $models);
109
                    }
110
                }
111
            } catch (\ReflectionException $e) {
112
                continue;
113
            }
114
        }
115 1
    }
116
    
117
    /**
118
     * Create a collection of models from plain arrays recursive.
119
     *
120
     * @param Model    $model
121
     * @param array    $items
122
     *
123
     * @return Collection
124
     */
125
    protected function hydrateRecursive(Model $model, array $items)
126
    {
127
        return $model->newCollection(array_map(function ($item) use ($model) {
128
            return $this->newFromBuilderRecursive($model, $item);
129
        }, $items));
130
    }
131
    
132
    /**
133
     * Check if an array is multi-level array like [[id], [id], [id]].
134
     *
135
     * For detect if a relation field is single model or collections.
136
     *
137
     * @param array $array
138
     *
139
     * @return bool
140
     */
141
    private function isMultiLevelArray(array $array)
142
    {
143
        foreach ($array as $key => $value) {
144
            if (!is_array($value)) {
145
                return false;
146
            }
147
        }
148
        
149
        return true;
150
    }
151
}
152