Passed
Push — main ( 633b92...66245a )
by Dimitri
12:27
created

BaseModel::__get()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 15
rs 10
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Models;
13
14
use BadMethodCallException;
15
use BlitzPHP\Core\Database;
16
use BlitzPHP\Database\BaseBuilder;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\BaseBuilder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use BlitzPHP\Database\Contracts\ConnectionInterface;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\Contracts\ConnectionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
/**
20
 * The Model class extends BaseModel and provides additional
21
 * convenient features that makes working with a SQL database
22
 * table less painful.
23
 *
24
 * It will:
25
 *      - automatically connect to database
26
 *      - allow intermingling calls to the builder
27
 *      - removes the need to use Result object directly in most cases
28
 *
29
 * @property ConnectionInterface $db
30
 *
31
 * @method array                         all(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
32
 * @method float                         avg(string $field, ?string $key = null, int $expire = 0)
33
 * @method $this                         between(string $field, $value1, $value2)
34
 * @method int                           count(string $field = '*', ?string $key = null, int $expire = 0)
35
 * @method $this                         distinct()
36
 * @method \BlitzPHP\Database\BaseResult execute(?string $key = null, int $expire = 0)
37
 * @method mixed                         first(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
38
 * @method $this                         from(string|string[]|null $from, bool $overwrite = false)
39
 * @method $this                         fromSubquery(self $builder, string $alias = '')
40
 * @method $this                         fullJoin(string $table, array $fields)
41
 * @method $this                         group(string|string[] $field, ?bool $escape = null)
42
 * @method $this                         groupBy(string|string[] $field, ?bool $escape = null)
43
 * @method $this                         having(array|string $field, $values = null, ?bool $escape = null)
44
 * @method $this                         havingIn(string $field, array|callable|self $param)
45
 * @method $this havingLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
46
 * @method $this havingNotIn(string $field, array|callable|self $param)
47
 * @method $this havingNotLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
48
 * @method $this in(string $key, array|callable|self $param)
49
 * @method $this innerJoin(string $table, array $fields)
50
 * @method $this into(string $table)
51
 * @method $this join(string $table, array $fields, string $type = 'INNER')
52
 * @method $this leftJoin(string $table, array $fields)
53
 * @method $this like(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
54
 * @method $this limit(int $limit, ?int $offset = null)
55
 * @method float max(string $field, ?string $key = null, int $expire = 0)
56
 * @method float min(string $field, ?string $key = null, int $expire = 0)
57
 * @method $this notBetween(string $field, $value1, $value2)
58
 * @method $this notHavingLike($field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
59
 * @method $this notIn(string $key, array|callable|self $param)
60
 * @method $this notLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
61
 * @method $this notWhere(array|string $key, $value = null, ?bool $escape = null)
62
 * @method $this offset(int $offset, ?int $limit = null)
63
 * @method mixed one(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
64
 * @method $this orBetween(string $field, $value1, $value2)
65
 * @method $this order(string|string[] $field, string $direction = 'ASC', ?bool $escape = null)
66
 * @method $this orderBy(string|string[] $field, string $direction = 'ASC', ?bool $escape = null)
67
 * @method $this orHaving(array|string $field, $values = null, ?bool $escape = null)
68
 * @method $this orHavingIn(string $field, array|callable|self $param)
69
 * @method $this orHavingLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
70
 * @method $this orHavingNotIn(string $field, array|callable|self $param)
71
 * @method $this orHavingNotLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
72
 * @method $this                         orIn(string $key, array|callable|self $param)
73
 * @method $this                         orLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
74
 * @method $this                         orNotBetween(string $field, $value1, $value2)
75
 * @method $this                         orNotHavingLike($field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
76
 * @method $this                         orNotIn(string $key, array|callable|self $param)
77
 * @method $this                         orNotLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
78
 * @method $this                         orNotWhere(array|string $key, $value = null, ?bool $escape = null)
79
 * @method $this                         orWhere(array|string $key, $value = null, ?bool $escape = null)
80
 * @method $this                         orWhereBetween(string $field, $value1, $value2)
81
 * @method $this                         orWhereIn(string $key, array|callable|self $param)
82
 * @method $this                         orWhereLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
83
 * @method $this                         orWhereNotBetween(string $field, $value1, $value2)
84
 * @method $this                         orWhereNotIn(string $key, array|callable|self $param)
85
 * @method $this                         orWhereNotLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
86
 * @method $this                         orWhereNotNull(string|string[] $field)
87
 * @method $this                         orWhereNull(string|string[] $field)
88
 * @method \BlitzPHP\Database\BaseResult query(string $sql, array $params = [])
89
 * @method $this                         rand(?int $digit = null)
90
 * @method array                         result(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
91
 * @method $this                         rightJoin(string $table, array $fields)
92
 * @method mixed                         row(int $index, int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
93
 * @method $this                         select(array|string $fields = '*', ?int $limit = null, ?int $offset = null)
94
 * @method $this                         sortAsc(string|string[] $field, ?bool $escape = null)
95
 * @method $this                         sortDesc(string|string[] $field, ?bool $escape = null)
96
 * @method float                         sum(string $field, ?string $key = null, int $expire = 0)
97
 * @method $this                         table(string|string[]|null $table)
98
 * @method mixed                         value(string $name, ?string $key = null, int $expire = 0)
99
 * @method $this                         where(array|string $key, $value = null, ?bool $escape = null)
100
 * @method $this                         whereBetween(string $field, $value1, $value2)
101
 * @method $this                         whereIn(string $key, array|callable|self $param)
102
 * @method $this                         whereLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
103
 * @method $this                         whereNotBetween(string $field, $value1, $value2)
104
 * @method $this                         whereNotIn(string $key, array|callable|self $param)
105
 * @method $this                         whereNotLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
106
 * @method $this                         whereNotNull(string|string[] $field)
107
 * @method $this                         whereNull(string|string[] $field)
108
 */
109
abstract class BaseModel
110
{
111
    /**
112
     * Nom de la table
113
     *
114
     * @var string
115
     */
116
    protected $table;
117
118
    /**
119
     * Cle primaire.
120
     *
121
     * @var string
122
     */
123
    protected $primaryKey = 'id';
124
125
    /**
126
     * Groupe de la base de données a utiliser
127
     *
128
     * @var string
129
     */
130
    protected $group;
131
132
    /**
133
     * Doit-on utiliser l'auto increment.
134
     *
135
     * @var bool
136
     */
137
    protected $useAutoIncrement = true;
138
139
    /**
140
     * Query Builder
141
     *
142
     * @var BaseBuilder|null
143
     */
144
    protected $builder;
145
146
    /**
147
     * Holds information passed in via 'set'
148
     * so that we can capture it (not the builder)
149
     * and ensure it gets validated first.
150
     *
151
     * @var array
152
     */
153
    protected $tempData = [];
154
155
    /**
156
     * Escape array that maps usage of escape
157
     * flag for every parameter.
158
     *
159
     * @var array
160
     */
161
    protected $escape = [];
162
163
    /**
164
     * Methodes du builder qui ne doivent pas etre utilisees dans le model.
165
     *
166
     * @var string[] method name
167
     */
168
    private array $builderMethodsNotAvailable = [
169
        'getCompiledInsert',
170
        'getCompiledSelect',
171
        'getCompiledUpdate',
172
    ];
173
174
    public function __construct(?ConnectionInterface $db = null)
175
    {
176
        $db ??= Database::connect($this->group);
177
178
        $this->db = $db;
179
    }
180
181
    /**
182
     * Fourni une instance partagee du Query Builder.
183
     *
184
     * @throws ModelException
185
     */
186
    public function builder(?string $table = null): BaseBuilder
187
    {
188
        if ($this->builder instanceof BaseBuilder) {
189
            // S'assurer que la table utilisee differe de celle du builder
190
            if ($table && $this->builder->getTable() !== $table) {
191
                return $this->db->table($table);
192
            }
193
194
            return $this->builder;
195
        }
196
197
        $table = empty($table) ? $this->table : $table;
198
199
        // S'assurer qu'on a une bonne connxion a la base de donnees
200
        if (! $this->db instanceof ConnectionInterface) {
201
            $this->db = Database::connect($this->group);
202
        }
203
204
        if (empty($table)) {
205
            $builder = $this->db->table('.')->from([], true);
206
        } else {
207
            $builder = $this->db->table($table);
208
        }
209
210
        // Considerer que c'est partagee seulement si la table est correct
211
        if ($table === $this->table) {
212
            $this->builder = $builder;
213
        }
214
215
        return $builder;
216
    }
217
218
    /**
219
     * Provides/instantiates the builder/db connection and model's table/primary key names and return type.
220
     *
221
     * @return mixed
222
     */
223
    public function __get(string $name)
224
    {
225
        if (property_exists($this, $name)) {
226
            return $this->{$name};
227
        }
228
229
        if (isset($this->db->{$name})) {
230
            return $this->db->{$name};
231
        }
232
233
        if (isset($this->builder()->{$name})) {
234
            return $this->builder()->{$name};
235
        }
236
237
        return null;
238
    }
239
240
    /**
241
     * Verifie si une propriete existe dans le modele, le builder, et la db connection.
242
     */
243
    public function __isset(string $name): bool
244
    {
245
        if (property_exists($this, $name)) {
246
            return true;
247
        }
248
249
        if (isset($this->db->{$name})) {
250
            return true;
251
        }
252
253
        return isset($this->builder()->{$name});
254
    }
255
256
    /**
257
     * Fourni un acces direct a une methode du builder (si disponible)
258
     * et la database connection.
259
     *
260
     * @return mixed
261
     */
262
    public function __call(string $name, array $params)
263
    {
264
        $builder = $this->builder();
265
        $result  = null;
266
267
        if (method_exists($this->db, $name)) {
268
            $result = $this->db->{$name}(...$params);
269
        } elseif (method_exists($builder, $name)) {
270
            $this->checkBuilderMethod($name);
271
272
            $result = $builder->{$name}(...$params);
273
        } else {
274
            throw new BadMethodCallException('Call to undefined method ' . static::class . '::' . $name);
275
        }
276
277
        if ($result instanceof BaseBuilder) {
278
            return $this;
279
        }
280
281
        return $result;
282
    }
283
284
    /**
285
     * Verifie si la methode du builder peut etre utilisee dans le modele.
286
     */
287
    private function checkBuilderMethod(string $name): void
288
    {
289
        if (in_array($name, $this->builderMethodsNotAvailable, true)) {
290
            //   throw ModelException::forMethodNotAvailable(static::class, $name . '()');
291
        }
292
    }
293
}
294