Skip to content

Commit c2a0590

Browse files
committed
feat: ajout des hooks lors de la manipulation des donnees
1 parent 4505713 commit c2a0590

2 files changed

Lines changed: 292 additions & 11 deletions

File tree

src/Builder/BaseBuilder.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,21 @@ final public function count(string $field = '*', ?string $key = null, int $expir
20302030
return (int) ($value ?? 0);
20312031
}
20322032

2033+
/**
2034+
* Génère une chaîne de requête spécifique à la plateforme qui compte tous les enregistrements renvoyés par une requête Query Builder.
2035+
*
2036+
* @return int|string int en mode reel et string (la chaîne SQL) en mode test
2037+
*/
2038+
public function countAllResults(bool $reset = true)
2039+
{
2040+
$clone = clone $this;
2041+
2042+
$clone->limit = '';
2043+
$clone->order = '';
2044+
2045+
return $clone->count();
2046+
}
2047+
20332048
// Méthodes d'extraction de données
20342049

20352050
/**

src/Model.php

Lines changed: 277 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,22 @@ abstract class Model
139139

140140
/**
141141
* Cle primaire.
142-
*
143-
* @var string
144142
*/
145-
protected $primaryKey = 'id';
143+
protected string $primaryKey = 'id';
146144

147145
/**
148146
* Le format dans lequel les résultats doivent être renvoyés.
149147
* Ce format sera surchargé si les méthodes as* sont utilisées.
150148
*/
151149
protected string $returnType = 'array';
152150

151+
/**
152+
* Utilié pour fournir une surchage temporaire pour le format de retour des resultats.
153+
*
154+
* @var string
155+
*/
156+
protected $tempReturnType;
157+
153158
/**
154159
* Primary Key value when inserting and useAutoIncrement is false.
155160
*
@@ -166,19 +171,60 @@ abstract class Model
166171

167172
/**
168173
* Doit-on utiliser l'auto increment.
169-
*
170-
* @var bool
171174
*/
172-
protected $useAutoIncrement = true;
175+
protected bool $useAutoIncrement = true;
173176

174177
/**
175178
* Le type de colonne que created_at et updated_at sont censés avoir.
176179
*
177180
* Autorisé: 'datetime', 'date', 'int'
181+
*/
182+
protected string $dateFormat = 'datetime';
183+
184+
/**
185+
* Si ce modèle doit utiliser "softDeletes" et définir simplement une date à laquelle les lignes sont supprimées,
186+
* ou effectuer des suppressions réelles.
187+
*/
188+
protected bool $useSoftDeletes = false;
189+
190+
/**
191+
* Un tableau de noms de champs qui peuvent être définis par l'utilisateur dans les insertions/mises à jour.
178192
*
179-
* @var string
193+
* @var string[]
194+
*/
195+
protected array $allowedFields = [];
196+
197+
/**
198+
* Si c'est vrai, définira les valeurs Created_at et Updated_at pendant les routines d'insertion et de mise à jour.
180199
*/
181-
protected $dateFormat = 'datetime';
200+
protected bool $useTimestamps = false;
201+
202+
/**
203+
* La colonne utilisée pour insérer les horodatages
204+
*/
205+
protected string $createdField = 'created_at';
206+
207+
/**
208+
* La colonne utilisée pour modifier les horodatages
209+
*/
210+
protected string $updatedField = 'updated_at';
211+
212+
/**
213+
* Utilisé par withDeleted pour remplacer le paramètre softDelete du modèle.
214+
*
215+
* @var bool
216+
*/
217+
protected $tempUseSoftDeletes;
218+
219+
/**
220+
* La colonne utilisée pour enregistrer l'état de suppression réversible.
221+
*/
222+
protected string $deletedField = 'deleted_at';
223+
224+
/**
225+
* Le nombre de données à renvoyer pour la pagination.
226+
*/
227+
protected int $perPage = 15;
182228

183229
/**
184230
* Connexion à la base de données
@@ -219,11 +265,122 @@ abstract class Model
219265
'getCompiledUpdate',
220266
];
221267

268+
/**
269+
* Callbacks.
270+
*
271+
* Chaque tableau doit contenir les noms de méthodes (au sein du modèle) qui doivent
272+
* être appelées lorsque ces événements sont déclenchés.
273+
*
274+
* Les méthodes « Update » et « Delete » reçoivent les mêmes éléments que ceux attribués
275+
* à leur méthode respective.
276+
*
277+
* Les méthodes "Find" reçoivent l'ID recherché (s'il est présent),
278+
* et "afterFind" reçoit en outre les résultats trouvés.
279+
*/
280+
281+
/**
282+
* S'il faut déclencher les callbacks définis
283+
*/
284+
protected bool $allowCallbacks = true;
285+
286+
/**
287+
* Utilisé par AllowCallbacks() pour remplacer le paramètre allowCallbacks du modèle.
288+
*
289+
* @var bool
290+
*/
291+
protected $tempAllowCallbacks;
292+
293+
/**
294+
* Callbacks pour beforeInsert
295+
*
296+
* @var string[]
297+
*/
298+
protected array $beforeInsert = [];
299+
300+
/**
301+
* Callbacks pour afterInsert
302+
*
303+
* @var string[]
304+
*/
305+
protected array $afterInsert = [];
306+
307+
/**
308+
* Callbacks pour beforeUpdate
309+
*
310+
* @var string[]
311+
*/
312+
protected array $beforeUpdate = [];
313+
314+
/**
315+
* Callbacks pour afterUpdate
316+
*
317+
* @var string[]
318+
*/
319+
protected array $afterUpdate = [];
320+
321+
/**
322+
* Callbacks pour beforeInsertBatch
323+
*
324+
* @var string[]
325+
*/
326+
protected array $beforeInsertBatch = [];
327+
328+
/**
329+
* Callbacks pour afterInsertBatch
330+
*
331+
* @var string[]
332+
*/
333+
protected array $afterInsertBatch = [];
334+
335+
/**
336+
* Callbacks pour beforeUpdateBatch
337+
*
338+
* @var string[]
339+
*/
340+
protected array $beforeUpdateBatch = [];
341+
342+
/**
343+
* Callbacks pour afterUpdateBatch
344+
*
345+
* @var string[]
346+
*/
347+
protected array $afterUpdateBatch = [];
348+
349+
/**
350+
* Callbacks pour beforeFind
351+
*
352+
* @var string[]
353+
*/
354+
protected array $beforeFind = [];
355+
356+
/**
357+
* Callbacks pour afterFind
358+
*
359+
* @var string[]
360+
*/
361+
protected array $afterFind = [];
362+
363+
/**
364+
* Callbacks pour beforeDelete
365+
*
366+
* @var string[]
367+
*/
368+
protected array $beforeDelete = [];
369+
370+
/**
371+
* Callbacks pour afterDelete
372+
*
373+
* @var string[]
374+
*/
375+
protected array $afterDelete = [];
376+
222377
public function __construct(protected ConnectionResolverInterface $resolver, ?ConnectionInterface $db = null)
223378
{
224-
$db ??= $this->resolver->connection($this->group);
379+
$this->db = $db ?: $this->resolver->connection($this->group);
225380

226-
$this->db = $db;
381+
$this->tempReturnType = $this->returnType;
382+
$this->tempUseSoftDeletes = $this->useSoftDeletes;
383+
$this->tempAllowCallbacks = $this->allowCallbacks;
227384
}
228385

229386
/**
@@ -372,7 +529,7 @@ public function save(array|object $data): bool
372529
*/
373530
public function chunk(int $size, Closure $userFunc)
374531
{
375-
$total = (clone $this->builder())->count();
532+
$total = $this->builder()->countAllResults();
376533
$offset = 0;
377534

378535
while ($offset <= $total) {
@@ -397,6 +554,74 @@ public function chunk(int $size, Closure $userFunc)
397554
}
398555
}
399556

557+
/**
558+
* Remplacez countAllResults pour tenir compte des lignes supprimés de manière logique (softdeletes).
559+
*
560+
* @return int|string
561+
*/
562+
public function countAllResults(bool $reset = true, bool $test = false)
563+
{
564+
if ($this->tempUseSoftDeletes) {
565+
$this->builder()->whereNull($this->table . '.' . $this->deletedField);
566+
}
567+
568+
// Lorsque $reset === false, $tempUseSoftDeletes dépendra de la valeur $useSoftDeletes
569+
// car nous ne voulons pas ajouter la même condition "where" pour la deuxième fois.
570+
$this->tempUseSoftDeletes = $reset
571+
? $this->useSoftDeletes
572+
: ($this->useSoftDeletes ? false : $this->useSoftDeletes);
573+
574+
return $this->builder()->testMode($test)->countAllResults($reset);
575+
}
576+
577+
public function paginate(?int $limit = null, ?int $page = null, ?int $total = null): array
578+
{
579+
$page = max((int) $page, 1);
580+
$total = $total ?: $this->countAllResults(false);
581+
$limit = $limit ?: $this->perPage;
582+
$offset = ($page - 1) * $limit;
583+
584+
return $this->findAll($limit, $offset);
585+
}
586+
587+
/**
588+
* Récupère tous les résultats, tout en les limitant éventuellement.
589+
*/
590+
public function findAll(int $limit = 0, int $offset = 0): array
591+
{
592+
if ($this->tempAllowCallbacks) {
593+
// Call the before event and check for a return
594+
$eventData = $this->trigger('beforeFind', [
595+
'method' => 'findAll',
596+
'limit' => $limit,
597+
'offset' => $offset,
598+
'singleton' => false,
599+
]);
600+
601+
if (isset($eventData['returnData']) && $eventData['returnData'] === true) {
602+
return $eventData['data'];
603+
}
604+
}
605+
606+
$eventData = [
607+
'data' => $this->builder()->findAll('*', compact('limit', 'offset'), $this->returnType),
608+
'limit' => $limit,
609+
'offset' => $offset,
610+
'method' => 'findAll',
611+
'singleton' => false,
612+
];
613+
614+
if ($this->tempAllowCallbacks) {
615+
$eventData = $this->trigger('afterFind', $eventData);
616+
}
617+
618+
$this->tempReturnType = $this->returnType;
619+
$this->tempUseSoftDeletes = $this->useSoftDeletes;
620+
$this->tempAllowCallbacks = $this->allowCallbacks;
621+
622+
return $eventData['data'];
623+
}
624+
400625
/**
401626
* Fournit/instancie la connexion builder/db et les noms de table/clé primaire du modèle et le type de retour.
402627
*
@@ -615,6 +840,47 @@ protected function transformDataToArray(null|array|object $data, string $type):
615840
return $data;
616841
}
617842

843+
/**
844+
* Définit la valeur $tempAllowCallbacks afin que nous puissions temporairement remplacer le paramètre.
845+
* Se réinitialise après la prochaine méthode utilisant des déclencheurs.
846+
*/
847+
public function allowCallbacks(bool $val = true): self
848+
{
849+
$this->tempAllowCallbacks = $val;
850+
851+
return $this;
852+
}
853+
854+
/**
855+
* Un simple déclencheur d'événement pour les événements de modèle qui permet une manipulation supplémentaire des données au sein du modèle.
856+
* Spécifiquement destiné à être utilisé par les modèles enfants, il peut être utilisé pour formater des données, enregistrer/charger des classes associées, etc.
857+
*
858+
* Il est de la responsabilité des méthodes de rappel de renvoyer les données elles-mêmes.
859+
*
860+
* Chaque tableau $eventData DOIT avoir une clé 'data' avec les données pertinentes pour les méthodes de rappel (comme un tableau de paires clé/valeur à insérer ou à mettre à jour, un tableau de résultats, etc.)
861+
*
862+
* Si les rappels ne sont pas autorisés, renvoie immédiatement $eventData.
863+
*
864+
* @throws DataException
865+
*/
866+
protected function trigger(string $event, array $eventData): array
867+
{
868+
// S'assurer que c'est un evenement valide
869+
if (! isset($this->{$event}) || $this->{$event} === []) {
870+
return $eventData;
871+
}
872+
873+
foreach ($this->{$event} as $callback) {
874+
if (! method_exists($this, $callback)) {
875+
throw DataException::invalidMethodTriggered($callback);
876+
}
877+
878+
$eventData = $this->{$callback}($eventData);
879+
}
880+
881+
return $eventData;
882+
}
883+
618884
/**
619885
* Verifie si la methode du builder peut etre utilisee dans le modele.
620886
*/

0 commit comments

Comments
 (0)