Passed
Push — main ( 40dc38...b0a2e6 )
by Dimitri
11:06
created

BaseModel::modify()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 19
rs 9.6111
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\Config\Database;
16
use BlitzPHP\Contracts\Database\ConnectionInterface;
17
use BlitzPHP\Database\Builder\BaseBuilder;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\Builder\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...
18
use BlitzPHP\Database\Connection\BaseConnection;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\Connection\BaseConnection 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...
19
use BlitzPHP\Database\Exceptions\DataException;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\Exceptions\DataException 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...
20
use BlitzPHP\Database\Result\BaseResult;
0 ignored issues
show
Bug introduced by
The type BlitzPHP\Database\Result\BaseResult 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...
21
use BlitzPHP\Utilities\Date;
22
use InvalidArgumentException;
23
use ReflectionClass;
24
use ReflectionProperty;
25
use stdClass;
26
27
/**
28
 * La classe Model étend BaseModel et fournit des
29
 * fonctionnalités pratiques qui rendent le travail avec une table de base de données SQL moins pénible.
30
 *
31
 * Ce sera:
32
 * - se connecte automatiquement à la base de données
33
 * - autoriser les appels croisés au constructeur
34
 * - supprime le besoin d'utiliser directement l'objet Result dans la plupart des cas
35
 *
36
 * @method array                                                       all(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
37
 * @method float                                                       avg(string $field, ?string $key = null, int $expire = 0)
38
 * @method $this                                                       between(string $field, $value1, $value2)
39
 * @method array                                                       bulckInsert(array $data, ?string $table = null)
40
 * @method int                                                         count(string $field = '*', ?string $key = null, int $expire = 0)
41
 * @method ConnectionInterface                                         db()
42
 * @method $this|\BlitzPHP\Database\BaseResult|string                  delete(?array $where = null, ?int $limit = null, bool $execute = true)
43
 * @method $this                                                       distinct()
44
 * @method \BlitzPHP\Database\BaseResult|\BlitzPHP\Database\Query|bool execute(?string $key = null, int $expire = 0)
45
 * @method array                                                       findAll(array|string $fields = '*', array $options = [], int|string $type = \PDO::FETCH_OBJ)
46
 * @method mixed                                                       findOne(array|string $fields = '*', array $options = [], int|string $type = \PDO::FETCH_OBJ)
47
 * @method mixed                                                       first(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
48
 * @method $this                                                       from(string|string[]|null $from, bool $overwrite = false)
49
 * @method $this                                                       fromSubquery(self $builder, string $alias = '')
50
 * @method $this                                                       fullJoin(string $table, array|string $fields)
51
 * @method string                                                      getTable()
52
 * @method $this                                                       group(string|string[] $field, ?bool $escape = null)
53
 * @method $this                                                       groupBy(string|string[] $field, ?bool $escape = null)
54
 * @method $this                                                       having(array|string $field, $values = null, ?bool $escape = null)
55
 * @method $this                                                       havingIn(string $field, array|callable|self $param)
56
 * @method $this                                                       havingLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false)
57
 * @method $this                                                       havingNotIn(string $field, array|callable|self $param)
58
 * @method $this                                                       havingNotLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false)
59
 * @method $this                                                       in(string $key, array|callable|self $param)
60
 * @method $this                                                       innerJoin(string $table, array|string $fields)
61
 * @method $this|\BlitzPHP\Database\BaseResult|string                  insert(array $data, bool $execute = true)
62
 * @method $this                                                       into(string $table)
63
 * @method $this                                                       join(string $table, array|string $fields, string $type = 'INNER')
64
 * @method $this                                                       leftJoin(string $table, array|string $fields, bool $outer = false)
65
 * @method $this                                                       like(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
66
 * @method $this                                                       limit(int $limit, ?int $offset = null)
67
 * @method float                                                       max(string $field, ?string $key = null, int $expire = 0)
68
 * @method float                                                       min(string $field, ?string $key = null, int $expire = 0)
69
 * @method $this                                                       naturalJoin(array|string $table)
70
 * @method $this                                                       notBetween(string $field, $value1, $value2)
71
 * @method $this                                                       notHavingLike($field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
72
 * @method $this                                                       notIn(string $key, array|callable|self $param)
73
 * @method $this                                                       notLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
74
 * @method $this                                                       notWhere(array|string $key, $value = null, ?bool $escape = null)
75
 * @method $this                                                       offset(int $offset, ?int $limit = null)
76
 * @method mixed                                                       one(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
77
 * @method $this                                                       orBetween(string $field, $value1, $value2)
78
 * @method $this                                                       order(string|string[] $field, string $direction = 'ASC', ?bool $escape = null)
79
 * @method $this                                                       orderBy(string|string[] $field, string $direction = 'ASC', ?bool $escape = null)
80
 * @method $this                                                       orHaving(array|string $field, $values = null, ?bool $escape = null)
81
 * @method $this                                                       orHavingIn(string $field, array|callable|self $param)
82
 * @method $this orHavingLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
83
 * @method $this orHavingNotIn(string $field, array|callable|self $param)
84
 * @method $this orHavingNotLike(array|string $field, $match = '', string $side = 'both', bool $escape = true, bool $insensitiveSearch = false): self
85
 * @method $this                                                       orIn(string $key, array|callable|self $param)
86
 * @method $this                                                       orLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
87
 * @method $this                                                       orNotBetween(string $field, $value1, $value2)
88
 * @method $this                                                       orNotHavingLike($field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
89
 * @method $this                                                       orNotIn(string $key, array|callable|self $param)
90
 * @method $this                                                       orNotLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
91
 * @method $this                                                       orNotWhere(array|string $key, $value = null, ?bool $escape = null)
92
 * @method $this                                                       orWhere(array|string $key, $value = null, ?bool $escape = null)
93
 * @method $this                                                       orWhereBetween(string $field, $value1, $value2)
94
 * @method $this                                                       orWhereIn(string $key, array|callable|self $param)
95
 * @method $this                                                       orWhereLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
96
 * @method $this                                                       orWhereNotBetween(string $field, $value1, $value2)
97
 * @method $this                                                       orWhereNotIn(string $key, array|callable|self $param)
98
 * @method $this                                                       orWhereNotLike(array|string $field, string $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
99
 * @method $this                                                       orWhereNotNull(string|string[] $field)
100
 * @method $this                                                       orWhereNull(string|string[] $field)
101
 * @method $this                                                       params(array $params)
102
 * @method \BlitzPHP\Database\BaseResult|\BlitzPHP\Database\Query|bool query(string $sql, array $params = [])
103
 * @method $this                                                       rand(?int $digit = null)
104
 * @method array                                                       result(int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
105
 * @method $this                                                       rightJoin(string $table, array|string $fields, bool $outer = false)
106
 * @method mixed                                                       row(int $index, int|string $type = \PDO::FETCH_OBJ, ?string $key = null, int $expire = 0)
107
 * @method $this                                                       select(array|string $fields = '*', ?int $limit = null, ?int $offset = null)
108
 * @method $this                                                       set(array|object|string $key, mixed $value = '', ?bool $escape = null)
109
 * @method $this                                                       sortAsc(string|string[] $field, ?bool $escape = null)
110
 * @method $this                                                       sortDesc(string|string[] $field, ?bool $escape = null)
111
 * @method $this                                                       sortRand(?int $digit = null)
112
 * @method string                                                      sql()
113
 * @method float                                                       sum(string $field, ?string $key = null, int $expire = 0)
114
 * @method $this                                                       table(string|string[]|null $table)
115
 * @method self                                                        testMode(bool $mode = true)
116
 * @method $this|\BlitzPHP\Database\BaseResult                         update(array|string $data, bool $execute = true)
117
 * @method mixed|mixed[]                                               value(string|string[] $name, ?string $key = null, int $expire = 0)
118
 * @method mixed[]                                                     values(string|string[] $name, ?string $key = null, int $expire = 0)
119
 * @method $this                                                       where(array|string $key, $value = null, ?bool $escape = null)
120
 * @method $this                                                       whereBetween(string $field, $value1, $value2)
121
 * @method $this                                                       whereIn(string $key, array|callable|self $param)
122
 * @method $this                                                       whereLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
123
 * @method $this                                                       whereNotBetween(string $field, $value1, $value2)
124
 * @method $this                                                       whereNotIn(string $key, array|callable|self $param)
125
 * @method $this                                                       whereNotLike(array|string $field, $match = '', string $side = 'both', ?bool $escape = null, bool $insensitiveSearch = false)
126
 * @method $this                                                       whereNotNull(string|string[] $field)
127
 * @method $this                                                       whereNull(string|string[] $field)
128
 */
129
abstract class BaseModel
130
{
131
    /**
132
     * Nom de la table
133
     *
134
     * @var string
135
     */
136
    protected $table;
137
138
    /**
139
     * Cle primaire.
140
     *
141
     * @var string
142
     */
143
    protected $primaryKey = 'id';
144
145
    /**
146
     * Primary Key value when inserting and useAutoIncrement is false.
147
     *
148
     * @var int|string|null
149
     */
150
    private $primaryKeyValue;
151
152
    /**
153
     * Groupe de la base de données a utiliser
154
     *
155
     * @var string
156
     */
157
    protected $group;
158
159
    /**
160
     * Doit-on utiliser l'auto increment.
161
     *
162
     * @var bool
163
     */
164
    protected $useAutoIncrement = true;
165
166
    /**
167
     * Le type de colonne que created_at et updated_at sont censés avoir.
168
     *
169
     * Autorisé: 'datetime', 'date', 'int'
170
     *
171
     * @var string
172
     */
173
    protected $dateFormat = 'datetime';
174
 
175
    /**
176
     * Connexion à la base de données
177
     *
178
     * @var BaseConnection
179
     */
180
    protected $db;
181
182
    /**
183
     * Query Builder
184
     *
185
     * @var BaseBuilder|null
186
     */
187
    protected $builder;
188
189
    /**
190
     * Contient les informations transmises via 'set' afin que nous puissions les capturer (pas le constructeur) et nous assurer qu'elles sont validées en premier.
191
     *
192
     * @var array
193
     */
194
    protected $tempData = [];
195
196
    /**
197
     * Tableau d'échappement qui mappe l'utilisation de l'indicateur d'échappement pour chaque paramètre.
198
     *
199
     * @var array
200
     */
201
    protected $escape = [];
202
203
    /**
204
     * Methodes du builder qui ne doivent pas etre utilisees dans le model.
205
     *
206
     * @var string[] method name
207
     */
208
    private array $builderMethodsNotAvailable = [
209
        'getCompiledInsert',
210
        'getCompiledSelect',
211
        'getCompiledUpdate',
212
    ];
213
214
    public function __construct(?ConnectionInterface $db = null)
215
    {
216
        $db ??= Database::connect($this->group);
217
218
        $this->db = $db;
0 ignored issues
show
Documentation Bug introduced by
It seems like $db of type BlitzPHP\Contracts\Database\ConnectionInterface is incompatible with the declared type BlitzPHP\Database\Connection\BaseConnection of property $db.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
219
    }
220
221
    /**
222
     * Fourni une instance partagee du Query Builder.
223
     *
224
     * @throws ModelException
225
     */
226
    public function builder(?string $table = null): BaseBuilder
227
    {
228
        if ($this->builder instanceof BaseBuilder) {            
229
            // S'assurer que la table utilisee differe de celle du builder
230
            $builderTable = $this->builder->getTable();
231
            if ($table && $builderTable !== $this->db->prefixTable($table)) {
232
                return $this->db->table($table);
233
            }
234
235
            if (empty($builderTable) && !empty($this->table)) {
236
                $this->builder = $this->builder->table($this->table);
237
            }
238
          
239
            return $this->builder;
240
        }
241
242
        // S'assurer qu'on a une bonne connxion a la base de donnees
243
        if (! $this->db instanceof ConnectionInterface) {
244
            $this->db = Database::connect($this->group);
0 ignored issues
show
Documentation Bug introduced by
It seems like BlitzPHP\Config\Database::connect($this->group) of type BlitzPHP\Contracts\Database\ConnectionInterface is incompatible with the declared type BlitzPHP\Database\Connection\BaseConnection of property $db.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
245
        }
246
247
        $table = empty($table) ? $this->table : $table;
248
249
        if (empty($table)) {
250
            $builder = $this->db->table('.')->from([], true);
251
        } else {
252
            $builder = $this->db->table($table);
253
        }
254
255
        // Considerer que c'est partagee seulement si la table est correct
256
        if ($table === $this->table) {
257
            $this->builder = $builder;
0 ignored issues
show
Documentation Bug introduced by
It seems like $builder of type BlitzPHP\Contracts\Database\BuilderInterface is incompatible with the declared type BlitzPHP\Database\Builder\BaseBuilder|null of property $builder.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
258
        }
259
260
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type BlitzPHP\Contracts\Database\BuilderInterface which is incompatible with the type-hinted return BlitzPHP\Database\Builder\BaseBuilder.
Loading history...
261
    }
262
263
    /**
264
     * Insere les données dans la base de données.
265
     * Si un objet est fourni, il tentera de le convertir en un tableau.
266
     *
267
     * @param bool              $returnID Si l'ID de l'element inséré doit être retourné ou non.
268
     *
269
     * @return BaseResult|int
270
     *
271
     * @throws ReflectionException
272
     */
273
    public function create(array|object|null $data = null, bool $returnID = true)
274
    {
275
        if (! empty($this->tempData['data'])) {
276
            if (empty($data)) {
277
                $data = $this->tempData['data'];
278
            } else {
279
                $data = $this->transformDataToArray($data, 'insert');
280
                $data = array_merge($this->tempData['data'], $data);
281
            }
282
        }
283
284
        if ($this->useAutoIncrement === false) {
285
            if (is_array($data) && isset($data[$this->primaryKey])) {
286
                $this->primaryKeyValue = $data[$this->primaryKey];
287
            } elseif (is_object($data) && isset($data->{$this->primaryKey})) {
288
                $this->primaryKeyValue = $data->{$this->primaryKey};
289
            }
290
        }
291
292
        $this->escape   = $this->tempData['escape'] ?? [];
293
        $this->tempData = [];
294
295
        /** @var BaseResult $inserted */
296
        $inserted = $this->builder()->insert($data);
297
298
        if ($returnID) {
299
            return $inserted->lastId();
300
        }
301
302
        return $inserted;
303
    }
304
305
    /**
306
     * Met à jour un seul enregistrement dans la base de données.
307
     * Si un objet est fourni, il tentera de le convertir en tableau.
308
     *
309
     * @param array|int|string|null $id
310
     * @param array|object|null     $data
311
     *
312
     * @throws ReflectionException
313
     */
314
    public function modify($id = null, $data = null): bool
315
    {
316
        $id = $id ?: $this->primaryKeyValue;
317
318
        if (! empty($this->tempData['data'])) {
319
            if (empty($data)) {
320
                $data = $this->tempData['data'];
321
            } else {
322
                $data = $this->transformDataToArray($data, 'update');
323
                $data = array_merge($this->tempData['data'], $data);
324
            }
325
326
            $id = $id ?: $this->idValue($data);
327
        }
328
329
        $this->escape   = $this->tempData['escape'] ?? [];
330
        $this->tempData = [];
331
332
        return $this->builder()->whereIn($this->primaryKey, (array) $id)->update($data);
333
    }
334
    
335
    /**
336
     * Une méthode pratique qui tentera de déterminer si les données doivent être insérées ou mises à jour.
337
     * Fonctionnera avec un tableau ou un objet.
338
     * Lors de l'utilisation avec des objets de classe personnalisés, vous devez vous assurer que la classe fournira l'accès aux variables de classe, même via une méthode magique.
339
     */
340
    public function save(array|object $data): bool
341
    {
342
        if (empty($data)) {
343
            return true;
344
        }
345
346
        if ($this->shouldUpdate($data)) {
347
            $response = $this->modify($this->idValue($data), $data);
348
        } else {
349
            $response = $this->create($data, false);
350
351
            if ($response !== false) {
0 ignored issues
show
introduced by
The condition $response !== false is always true.
Loading history...
352
                $response = true;
353
            }
354
        }
355
356
        return $response;
357
    }
358
359
    /**
360
     * Fournit/instancie la connexion builder/db et les noms de table/clé primaire du modèle et le type de retour.
361
     *
362
     * @return mixed
363
     */
364
    public function __get(string $name)
365
    {
366
        if (property_exists($this, $name)) {
367
            return $this->{$name};
368
        }
369
370
        if (isset($this->db->{$name})) {
371
            return $this->db->{$name};
372
        }
373
374
        if (isset($this->builder()->{$name})) {
375
            return $this->builder()->{$name};
376
        }
377
378
        return null;
379
    }
380
381
    /**
382
     * Verifie si une propriete existe dans le modele, le builder, et la db connection.
383
     */
384
    public function __isset(string $name): bool
385
    {
386
        if (property_exists($this, $name)) {
387
            return true;
388
        }
389
390
        if (isset($this->db->{$name})) {
391
            return true;
392
        }
393
394
        return isset($this->builder()->{$name});
395
    }
396
397
    /**
398
     * Fourni un acces direct a une methode du builder (si disponible)
399
     * et la database connection.
400
     *
401
     * @return mixed
402
     */
403
    public function __call(string $name, array $params)
404
    {
405
        $builder = $this->builder();
406
        $result  = null;
407
408
        if (method_exists($this->db, $name)) {
409
            $result = $this->db->{$name}(...$params);
410
        } elseif (method_exists($builder, $name)) {
411
            $this->checkBuilderMethod($name);
412
            
413
            $result = $builder->{$name}(...$params);
414
        } else {
415
            throw new BadMethodCallException('Call to undefined method ' . static::class . '::' . $name);
416
        }
417
418
        if ($result instanceof BaseBuilder) {
419
            return $this;
420
        }
421
422
        return $result;
423
    }
424
    
425
    /**
426
     * Renvoie la valeur id pour le tableau de données ou l'objet.
427
     *
428
     * @return array|int|string|null
429
     */
430
    protected function idValue(array|object $data)
431
    {
432
       if (is_object($data) && isset($data->{$this->primaryKey})) {
0 ignored issues
show
introduced by
The condition is_object($data) is always false.
Loading history...
433
            return $data->{$this->primaryKey};
434
        }
435
436
        if (is_array($data) && ! empty($data[$this->primaryKey])) {
437
            return $data[$this->primaryKey];
438
        }
439
440
        return null;
441
    }
442
443
    /**
444
     * Cette méthode est appelée lors de la sauvegarde pour déterminer si l'entrée doit être mise à jour.
445
     * Si cette méthode renvoie une opération d'insertion fausse, elle sera exécutée
446
     */
447
    protected function shouldUpdate(array|object $data): bool
448
    {
449
        return ! empty($this->idValue($data));
450
    }
451
452
    /**
453
     * Prend une classe et retourne un tableau de ses propriétés publiques et protégées sous la forme d'un tableau adapté à une utilisation dans les créations et les mises à jour.
454
     * Cette méthode utilise objectToRawArray() en interne et effectue la conversion en chaîne sur toutes les instances Time
455
     *
456
     * @param bool          $onlyChanged Propriété modifiée uniquement
457
     * @param bool          $recursive   Si vrai, les entités internes seront également converties en tableau
458
     *
459
     * @throws ReflectionException
460
     */
461
    protected function objectToArray(object|string $data, bool $onlyChanged = true, bool $recursive = false): array
462
    {
463
        $properties = $this->objectToRawArray($data, $onlyChanged, $recursive);
464
465
        // Convertissez toutes les instances de Date en $dateFormat approprié
466
        if ($properties) {
467
            $properties = array_map(function ($value) {
468
                if ($value instanceof Date) {
469
                    return $this->timeToDate($value);
470
                }
471
472
                return $value;
473
            }, $properties);
474
        }
475
476
        return $properties;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $properties could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
477
    }
478
479
    /**
480
     * Prend une classe et renvoie un tableau de ses propriétés publiques et protégées sous la forme d'un tableau avec des valeurs brutes.
481
     *
482
     * @param bool          $onlyChanged Propriété modifiée uniquement
483
     * @param bool          $recursive   Si vrai, les entités internes seront également converties en tableau
484
     *
485
     * @throws ReflectionException
486
     */
487
    protected function objectToRawArray(object|string $data, bool $onlyChanged = true, bool $recursive = false): ?array
488
    {
489
        if (method_exists($data, 'toRawArray')) {
490
            $properties = $data->toRawArray($onlyChanged, $recursive);
491
        } else if (method_exists($data, 'toArray')) {
492
            $properties = $data->toArray();
493
        } else {
494
            $mirror = new ReflectionClass($data);
495
            $props  = $mirror->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
496
497
            $properties = [];
498
499
            // Boucle sur chaque propriété, en enregistrant le nom/valeur dans un nouveau tableau 
500
            // que nous pouvons retourner.
501
            foreach ($props as $prop) {
502
                // Doit rendre les valeurs protégées accessibles.
503
                $prop->setAccessible(true);
504
                $properties[$prop->getName()] = $prop->getValue($data);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type string; however, parameter $object of ReflectionProperty::getValue() does only seem to accept null|object, 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

504
                $properties[$prop->getName()] = $prop->getValue(/** @scrutinizer ignore-type */ $data);
Loading history...
505
            }
506
        }
507
508
        return $properties;
509
    }
510
    
511
    /**
512
     * Convertit la valeur Date en chaîne en utilisant $this->dateFormat.
513
     *
514
     * Les formats disponibles sont :
515
     * - 'int' - Stocke la date sous la forme d'un horodatage entier
516
     * - 'datetime' - Stocke les données au format datetime SQL
517
     * - 'date' - Stocke la date (uniquement) au format de date SQL.
518
     *
519
     * @return int|string
520
     */
521
    protected function timeToDate(Date $value)
522
    {
523
        switch ($this->dateFormat) {
524
            case 'datetime':
525
                return $value->format('Y-m-d H:i:s');
526
527
            case 'date':
528
                return $value->format('Y-m-d');
529
530
            case 'int':
531
                return $value->getTimestamp();
532
533
            default:
534
                return (string) $value;
535
        }
536
    }
537
538
    /**
539
     * Transformer les données en tableau.
540
     *
541
     * @param string            $type Type de donnees (insert|update)
542
     *
543
     * @throws DataException
544
     * @throws InvalidArgumentException
545
     * @throws ReflectionException
546
     */
547
    protected function transformDataToArray(array|object|null $data, string $type): array
548
    {
549
        if (! in_array($type, ['insert', 'update'], true)) {
550
            throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type));
551
        }
552
553
        if (empty($data)) {
554
            throw DataException::emptyDataset($type);
555
        }
556
557
        // Si $data utilise une classe personnalisée avec des propriétés publiques ou protégées représentant 
558
        // les éléments de la collection, nous devons les saisir sous forme de tableau.
559
        if (is_object($data) && ! $data instanceof stdClass) {
0 ignored issues
show
introduced by
The condition is_object($data) is always false.
Loading history...
560
            $data = $this->objectToArray($data, $type === 'update', true);
561
        }
562
563
        // S'il s'agit toujours d'une stdClass, continuez et convertissez en un tableau afin que 
564
        // les autres méthodes de modèle n'aient pas à effectuer de vérifications spéciales.
565
        if (is_object($data)) {
0 ignored issues
show
introduced by
The condition is_object($data) is always false.
Loading history...
566
            $data = (array) $data;
567
        }
568
569
        // S'il est toujours vide ici, cela signifie que $data n'a pas changé ou est un objet vide
570
        if (! $this->allowEmptyInserts && empty($data)) {
0 ignored issues
show
Bug Best Practice introduced by
The property allowEmptyInserts does not exist on BlitzPHP\Models\BaseModel. Since you implemented __get, consider adding a @property annotation.
Loading history...
571
            throw DataException::emptyDataset($type);
572
        }
573
574
        return $data;
575
    }
576
577
    /**
578
     * Verifie si la methode du builder peut etre utilisee dans le modele.
579
     */
580
    private function checkBuilderMethod(string $name): void
581
    {
582
        if (in_array($name, $this->builderMethodsNotAvailable, true)) {
583
            //   throw ModelException::forMethodNotAvailable(static::class, $name . '()');
584
        }
585
    }
586
}
587