Passed
Push — master ( cf3945...82a00b )
by Arthur
03:12
created

BaseModelTrait::getModelEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
namespace SoliDry\Extension;
4
5
use Illuminate\Database\Eloquent\Collection;
6
use Illuminate\Database\Query\Builder;
7
use Illuminate\Support\Facades\DB;
8
use SoliDry\Types\ModelsInterface;
9
use SoliDry\Types\PhpInterface;
10
use SoliDry\Types\ApiInterface;
11
use SoliDry\Helpers\SqlOptions;
12
13
/**
14
 * Class BaseModelTrait
15
 * @package SoliDry\Extension
16
 *
17
 * @property ApiController modelEntity
18
 * @property CustomSql customSql
19
 */
20
trait BaseModelTrait
21
{
22
    private $pagination = false;
23
24
    /**
25
     * @param bool $pagination
26
     */
27
    public function setPagination(bool $pagination): void
28
    {
29
        $this->pagination = $pagination;
30
    }
31
32
    /**
33
     * @param int|string $id
34
     * @param array $data
35
     *
36
     * @return mixed
37
     */
38
    private function getEntity($id, array $data = ModelsInterface::DEFAULT_DATA)
39
    {
40
        $obj = \call_user_func_array(
41
            PhpInterface::BACKSLASH . $this->modelEntity . PhpInterface::DOUBLE_COLON
0 ignored issues
show
Bug introduced by
Are you sure $this->modelEntity of type SoliDry\Extension\ApiController can be used in concatenation? Consider adding a __toString()-method. ( Ignorable by Annotation )

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

41
            PhpInterface::BACKSLASH . /** @scrutinizer ignore-type */ $this->modelEntity . PhpInterface::DOUBLE_COLON
Loading history...
42
            . ModelsInterface::MODEL_METHOD_WHERE, [ApiInterface::RAML_ID, $id]
43
        );
44
45
        if ($data[0] !== PhpInterface::ASTERISK) {
46
            // add id to output it in json-api entity
47
            $data[] = ModelsInterface::ID;
48
        }
49
50
        return $obj->first($data);
51
    }
52
53
    /**
54
     * Gets all or custom entities
55
     *
56
     * @param SqlOptions $sqlOptions
57
     * @return \Illuminate\Support\Collection|mixed
58
     */
59
    private function getEntities(SqlOptions $sqlOptions)
60
    {
61
        /** @var CustomSql $customSql */
62
        if ($this->customSql->isEnabled()) {
63
            return $this->getCustomSqlEntities($this->customSql);
64
        }
65
66
        return $this->getAllEntities($sqlOptions);
67
    }
68
69
    /**
70
     * @param string $modelEntity
71
     * @param int|string $id
72
     *
73
     * @return mixed
74
     */
75
    private function getModelEntity($modelEntity, $id)
76
    {
77
        $obj = \call_user_func_array(
78
            PhpInterface::BACKSLASH . $modelEntity . PhpInterface::DOUBLE_COLON
79
            . ModelsInterface::MODEL_METHOD_WHERE, [ApiInterface::RAML_ID, $id]
80
        );
81
82
        return $obj->first();
83
    }
84
85
    /**
86
     * @param string $modelEntity
87
     * @param array $params
88
     *
89
     * @return mixed
90
     */
91
    private function getModelEntities($modelEntity, array $params)
92
    {
93
        return \call_user_func_array(
94
            PhpInterface::BACKSLASH . $modelEntity . PhpInterface::DOUBLE_COLON
95
            . ModelsInterface::MODEL_METHOD_WHERE, $params
96
        );
97
    }
98
99
    /**
100
     * Get rows from particular Entity
101
     *
102
     * @param SqlOptions $sqlOptions
103
     *
104
     * @return mixed
105
     */
106
    private function getAllEntities(SqlOptions $sqlOptions)
107
    {
108
        $limit        = $sqlOptions->getLimit();
109
        $page         = $sqlOptions->getPage();
110
        $data         = $sqlOptions->getData();
111
        $orderBy      = $sqlOptions->getOrderBy();
112
        $filter       = $sqlOptions->getFilter();
113
114
        $defaultOrder = [];
115
        $order        = [];
116
117
        $first        = true;
118
        foreach ($orderBy as $column => $value) {
119
            if ($first === true) {
120
                $defaultOrder = [$column, $value];
121
            } else {
122
                $order[] = [ModelsInterface::COLUMN    => $column,
123
                            ModelsInterface::DIRECTION => $value];
124
            }
125
            $first = false;
126
        }
127
        $from = ($limit * $page) - $limit;
128
        $to   = $limit * $page;
129
130
        /** @var Builder $obj */
131
        $obj = \call_user_func_array(
132
            PhpInterface::BACKSLASH . $this->modelEntity . PhpInterface::DOUBLE_COLON .
0 ignored issues
show
Bug introduced by
Are you sure $this->modelEntity of type SoliDry\Extension\ApiController can be used in concatenation? Consider adding a __toString()-method. ( Ignorable by Annotation )

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

132
            PhpInterface::BACKSLASH . /** @scrutinizer ignore-type */ $this->modelEntity . PhpInterface::DOUBLE_COLON .
Loading history...
133
            ModelsInterface::MODEL_METHOD_ORDER_BY,
134
            $defaultOrder
135
        );
136
137
        // it can be empty if nothing more then 1st passed
138
        $obj->order = $order;
0 ignored issues
show
Bug introduced by
The property order does not exist on Illuminate\Database\Query\Builder. Did you mean orders?
Loading history...
139
140
        if ($this->pagination === true) {
141
            return $obj->where($filter)->paginate($limit, $data, 'page', $page);
142
        }
143
144
        return $obj->where($filter)->take($to)->skip($from)->get($data);
145
    }
146
147
    /**
148
     * Selects a collection of items based on custom sql
149
     *
150
     * @param CustomSql $customSql
151
     * @return \Illuminate\Support\Collection
152
     */
153
    private function getCustomSqlEntities(CustomSql $customSql): \Illuminate\Support\Collection
154
    {
155
        $result     = DB::select($customSql->getQuery(), $customSql->getBindings());
156
        $collection = [];
157
        foreach ($result as $item) {
158
            $class        = PhpInterface::BACKSLASH . $this->modelEntity;
0 ignored issues
show
Bug introduced by
Are you sure $this->modelEntity of type SoliDry\Extension\ApiController can be used in concatenation? Consider adding a __toString()-method. ( Ignorable by Annotation )

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

158
            $class        = PhpInterface::BACKSLASH . /** @scrutinizer ignore-type */ $this->modelEntity;
Loading history...
159
            $collection[] = (new $class())->fill((array)$item);
160
        }
161
        return collect($collection);
162
    }
163
164
    /**
165
     * Collects all tree elements
166
     *
167
     * @param SqlOptions $sqlOptions
168
     * @return Collection
169
     */
170
    public function getAllTreeEntities(SqlOptions $sqlOptions) : Collection
171
    {
172
        return Collection::make($this->buildTree($this->getAllEntities($sqlOptions)));
0 ignored issues
show
Bug introduced by
It seems like $this->getAllEntities($sqlOptions) can also be of type Illuminate\Pagination\LengthAwarePaginator; however, parameter $data of SoliDry\Extension\BaseModelTrait::buildTree() does only seem to accept Illuminate\Database\Eloquent\Collection, maybe add an additional type check? ( Ignorable by Annotation )

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

172
        return Collection::make($this->buildTree(/** @scrutinizer ignore-type */ $this->getAllEntities($sqlOptions)));
Loading history...
173
    }
174
175
    /**
176
     * Builds the tree based on children/parent axiom
177
     *
178
     * @param Collection $data
179
     * @param int|string $id
180
     * @return array
181
     */
182
    private function buildTree(Collection $data, $id = 0): array
183
    {
184
        $tree = [];
185
        foreach ($data as $k => $child) {
186
            if ($child->parent_id === $id) { // child found
187
                // clear found children to free stack
188
                unset($data[$k]);
189
                $child->children = $this->buildTree($data, $child->id);
190
                $tree[]          = $child;
191
            }
192
        }
193
194
        return $tree;
195
    }
196
197
    /**
198
     * Collects all tree elements
199
     *
200
     * @param SqlOptions $sqlOptions
201
     * @param int|string $id
202
     * @return array
203
     */
204
    public function getSubTreeEntities(SqlOptions $sqlOptions, $id) : array
205
    {
206
        return $this->buildSubTree($this->getAllEntities($sqlOptions), $id);
0 ignored issues
show
Bug introduced by
It seems like $this->getAllEntities($sqlOptions) can also be of type Illuminate\Pagination\LengthAwarePaginator; however, parameter $data of SoliDry\Extension\BaseModelTrait::buildSubTree() does only seem to accept Illuminate\Database\Eloquent\Collection, maybe add an additional type check? ( Ignorable by Annotation )

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

206
        return $this->buildSubTree(/** @scrutinizer ignore-type */ $this->getAllEntities($sqlOptions), $id);
Loading history...
207
    }
208
209
    /**
210
     * Builds the sub-tree for top most ancestor
211
     *
212
     * @param Collection $data
213
     * @param int|string $searchId
214
     * @param int|string $id
215
     * @param bool $isParentFound
216
     * @return array
217
     */
218
    private function buildSubTree(Collection $data, $searchId, $id = 0, bool $isParentFound = false) : array
219
    {
220
        $tree = [];
221
        foreach ($data as $k => $child) {
222
            if ($searchId === $child->id) {
223
                $isParentFound = true;
224
            }
225
            if ($child->parent_id === $id && true === $isParentFound) { // child found
226
                // clear found children to free stack
227
                unset($data[$k]);
228
                $child->children = $this->buildSubTree($data, $searchId, $child->id, $isParentFound);
229
                $tree[]          = $child;
230
            }
231
            if (true === $isParentFound && 0 === $id) {
232
                return $tree;
233
            }
234
        }
235
236
        return $tree;
237
    }
238
}