Issues (150)

src/Extension/BaseModelTrait.php (8 issues)

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
    /**
23
     * @var bool
24
     */
25
    private bool $pagination = false;
26
27
    /**
28
     * @param bool $pagination
29
     */
30
    public function setPagination(bool $pagination): void
31
    {
32
        $this->pagination = $pagination;
33
    }
34
35
    /**
36
     * @param int|string $id
37
     * @param array $data
38
     *
39
     * @return mixed
40
     */
41
    private function getEntity($id, array $data = ModelsInterface::DEFAULT_DATA)
42
    {
43
        $obj = \call_user_func_array(
44
            PhpInterface::BACKSLASH . $this->modelEntity . PhpInterface::DOUBLE_COLON
0 ignored issues
show
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

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

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

161
            $class        = PhpInterface::BACKSLASH . /** @scrutinizer ignore-type */ $this->modelEntity;
Loading history...
162
            $collection[] = (new $class())->fill((array)$item);
163
        }
164
        return collect($collection);
0 ignored issues
show
$collection of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

164
        return collect(/** @scrutinizer ignore-type */ $collection);
Loading history...
165
    }
166
167
    /**
168
     * Collects all tree elements
169
     *
170
     * @param SqlOptions $sqlOptions
171
     * @return Collection
172
     */
173
    public function getAllTreeEntities(SqlOptions $sqlOptions) : Collection
174
    {
175
        return Collection::make($this->buildTree($this->getAllEntities($sqlOptions)));
0 ignored issues
show
$this->buildTree($this->...lEntities($sqlOptions)) of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

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

175
        return Collection::make(/** @scrutinizer ignore-type */ $this->buildTree($this->getAllEntities($sqlOptions)));
Loading history...
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

175
        return Collection::make($this->buildTree(/** @scrutinizer ignore-type */ $this->getAllEntities($sqlOptions)));
Loading history...
176
    }
177
178
    /**
179
     * Builds the tree based on children/parent axiom
180
     *
181
     * @param Collection $data
182
     * @param int|string $id
183
     * @return array
184
     */
185
    private function buildTree(Collection $data, $id = 0): array
186
    {
187
        $tree = [];
188
        foreach ($data as $k => $child) {
189
            if ($child->parent_id === $id) { // child found
190
                // clear found children to free stack
191
                unset($data[$k]);
192
                $child->children = $this->buildTree($data, $child->id);
193
                $tree[]          = $child;
194
            }
195
        }
196
197
        return $tree;
198
    }
199
200
    /**
201
     * Collects all tree elements
202
     *
203
     * @param SqlOptions $sqlOptions
204
     * @param int|string $id
205
     * @return array
206
     */
207
    public function getSubTreeEntities(SqlOptions $sqlOptions, $id) : array
208
    {
209
        return $this->buildSubTree($this->getAllEntities($sqlOptions), $id);
0 ignored issues
show
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

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