Passed
Push — master ( 7201a8...966ca9 )
by Sébastien
10:04 queued 11s
created

EntityRepository::onRelation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Bdf\Prime\Repository;
4
5
use BadMethodCallException;
6
use Bdf\Event\EventNotifier;
7
use Bdf\Prime\Cache\CacheInterface;
8
use Bdf\Prime\Collection\CollectionFactory;
9
use Bdf\Prime\Collection\CollectionInterface;
10
use Bdf\Prime\Collection\EntityCollection;
11
use Bdf\Prime\Collection\Indexer\SingleEntityIndexer;
12
use Bdf\Prime\Connection\ConnectionInterface;
13
use Bdf\Prime\Connection\Event\ConnectionClosedListenerInterface;
14
use Bdf\Prime\Connection\TransactionManagerInterface;
15
use Bdf\Prime\Entity\Criteria;
16
use Bdf\Prime\Events;
17
use Bdf\Prime\Exception\PrimeException;
18
use Bdf\Prime\Mapper\Mapper;
19
use Bdf\Prime\Mapper\Metadata;
20
use Bdf\Prime\Query\Contract\ReadOperation;
21
use Bdf\Prime\Query\Contract\WriteOperation;
22
use Bdf\Prime\Query\QueryInterface;
23
use Bdf\Prime\Query\QueryRepositoryExtension;
24
use Bdf\Prime\Relations\EntityRelation;
25
use Bdf\Prime\Relations\Relation;
26
use Bdf\Prime\Relations\RelationInterface;
27
use Bdf\Prime\Repository\Write\Writer;
28
use Bdf\Prime\Repository\Write\WriterInterface;
29
use Bdf\Prime\Schema\NullResolver;
30
use Bdf\Prime\Schema\Resolver;
31
use Bdf\Prime\Schema\ResolverInterface;
32
use Bdf\Prime\ServiceLocator;
33
use Closure;
34
use Doctrine\Common\EventSubscriber;
35
use Exception;
36
37
/**
38
 * Db repository
39
 * 
40
 * implementation de l'abstraction d'un dépot de données.
0 ignored issues
show
Coding Style introduced by
Doc comment long description must start with a capital letter
Loading history...
41
 * 
42
 * @todo fix: il est possible de desactiver temporairement le cache sur des methodes d ecriture
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
43
 *
44
 * @package Bdf\Prime\Repository
45
 *
46
 * @template E as object
47
 * @implements RepositoryInterface<E>
48
 * @implements RepositoryEventsSubscriberInterface<E>
49
 *
50
 * @mixin RepositoryQueryFactory<E>
51
 */
52
class EntityRepository implements RepositoryInterface, EventSubscriber, ConnectionClosedListenerInterface, RepositoryEventsSubscriberInterface
53
{
54
    use EventNotifier;
55
    
56
    /**
57
     * @var Mapper<E>
0 ignored issues
show
introduced by
Expected "MapperE" but found "Mapper<E>" for @var tag in member variable comment
Loading history...
58
     */
59
    protected $mapper;
60
    
61
    /**
62
     * @var ServiceLocator 
0 ignored issues
show
introduced by
Expected "ServiceLocator" but found "ServiceLocator " for @var tag in member variable comment
Loading history...
63
     */
64
    protected $serviceLocator;
65
    
66
    /**
67
     * Query result cache
68
     * 
69
     * @var CacheInterface
70
     */
71
    protected $resultCache;
72
    
73
    /**
74
     * Disable the global constraints for one query
75
     * 
76
     * @var bool
0 ignored issues
show
Bug introduced by
Expected "boolean" but found "bool" for @var tag in member variable comment
Loading history...
77
     */
78
    protected $withoutConstraints = false;
79
    
80
    /**
81
     * Cache of relation instance
82
     * 
83
     * @var RelationInterface[]
84
     */
85
    protected $relations = [];
86
87
    /**
88
     * The collection factory
89
     *
90
     * @var CollectionFactory
91
     */
92
    protected $collectionFactory;
93
94
    /**
95
     * @var RepositoryQueryFactory<E>
0 ignored issues
show
introduced by
Expected "RepositoryQueryFactoryE" but found "RepositoryQueryFactory<E>" for @var tag in member variable comment
Loading history...
96
     */
97
    protected $queries;
98
99
    /**
100
     * @var WriterInterface<E>
0 ignored issues
show
introduced by
Expected "WriterInterfaceE" but found "WriterInterface<E>" for @var tag in member variable comment
Loading history...
101
     */
102
    protected $writer;
103
104
    /**
105
     * @var ConnectionInterface|null
106
     */
107
    protected $connection;
108
109
110
    /**
111
     * Constructor
112
     * 
113
     * @param Mapper<E> $mapper
0 ignored issues
show
introduced by
Expected "MapperE" but found "Mapper<E>" for parameter type
Loading history...
114
     * @param ServiceLocator $serviceLocator
115
     * @param CacheInterface|null $cache
116
     */
117 139
    public function __construct(Mapper $mapper, ServiceLocator $serviceLocator, ?CacheInterface $cache = null)
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before function; 2 found
Loading history...
118
    {
119 139
        $this->resultCache = $cache;
120 139
        $this->mapper = $mapper;
121 139
        $this->serviceLocator = $serviceLocator;
122
123 139
        $this->collectionFactory = CollectionFactory::forRepository($this);
124 139
        $this->queries = new RepositoryQueryFactory($this, $cache);
125 139
        $this->writer = new Writer($this, $serviceLocator);
126
127 139
        $this->mapper->events($this);
128 139
    }
129
    
130
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entity should have a doc-comment as per coding-style.
Loading history...
131
     * {@inheritdoc}
132
     */
133 146
    public function repository($entity): ?RepositoryInterface
134
    {
135 146
        return $this->serviceLocator->repository($entity);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 805
    public function mapper(): Mapper
142
    {
143 805
        return $this->mapper;
144
    }
145
    
146
    /**
147
     * {@inheritdoc}
148
     */
149 607
    public function metadata(): Metadata
150
    {
151 607
        return $this->mapper->metadata();
152
    }
153
    
154
    /**
155
     * {@inheritdoc}
156
     */
157 443
    public function isReadOnly(): bool
158
    {
159 443
        return $this->mapper->isReadOnly();
160
    }
161
    
162
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $criteria should have a doc-comment as per coding-style.
Loading history...
163
     * {@inheritdoc}
164
     */
165 1
    public function criteria(array $criteria = []): Criteria
166
    {
167 1
        return new Criteria($criteria);
168
    }
169
    
170
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $data should have a doc-comment as per coding-style.
Loading history...
171
     * {@inheritdoc}
172
     */
173 68
    public function entity(array $data = [])
174
    {
175 68
        return $this->mapper->entity($data);
176
    }
177
    
178
    /**
179
     * {@inheritdoc}
180
     */
181 54
    public function entityName(): string
182
    {
183 54
        return $this->mapper->metadata()->entityName;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189 71
    public function entityClass(): string
190
    {
191 71
        return $this->mapper->metadata()->entityClass;
192
    }
193
194
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entities should have a doc-comment as per coding-style.
Loading history...
195
     * {@inheritdoc}
196
     */
197 20
    public function collection(array $entities = []): CollectionInterface
198
    {
199 20
        return new EntityCollection($this, $entities);
0 ignored issues
show
Bug introduced by
$entities of type array is incompatible with the type Bdf\Prime\Collection\CollectionInterface expected by parameter $storage of Bdf\Prime\Collection\Ent...llection::__construct(). ( Ignorable by Annotation )

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

199
        return new EntityCollection($this, /** @scrutinizer ignore-type */ $entities);
Loading history...
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205 473
    public function collectionFactory(): CollectionFactory
206
    {
207 473
        return $this->collectionFactory;
208
    }
209
210
    /**
211
     * Hydrate on property value of an entity
212
     *
213
     * @param E $entity
214
     * @param string $property
215
     * @param mixed  $value
216
     *
217
     * @return void
0 ignored issues
show
introduced by
If there is no return value for a function, there must not be a @return tag.
Loading history...
218
     *
219
     * @see Mapper::hydrateOne()
220
     */
221
    public function hydrateOne($entity, string $property, $value): void
0 ignored issues
show
introduced by
Type hint "E" missing for $entity
Loading history...
222
    {
223
        $this->mapper->hydrateOne($entity, $property, $value);
224
    }
225
226
    /**
227
     * Get attribute value of an entity
228
     *
229
     * @param E $entity
230
     * @param string $property
231
     *
232
     * @return mixed
233
     *
234
     * @see Mapper::extractOne()
235
     */
236 52
    public function extractOne($entity, string $property)
0 ignored issues
show
introduced by
Type hint "E" missing for $entity
Loading history...
237
    {
238 52
        return $this->mapper->extractOne($entity, $property);
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244 592
    public function connection(): ConnectionInterface
245
    {
246 592
        if ($this->connection === null) {
247
            //Repository query factory load the connection on its constructor. Use lazy to let the connection being loaded as late as possible.
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// Repository query factory load the connection on its constructor. Use lazy to let the connection being loaded as late as possible." but found "//Repository query factory load the connection on its constructor. Use lazy to let the connection being loaded as late as possible."
Loading history...
248 119
            $this->connection = $this->serviceLocator->connection($this->mapper->metadata()->connection);
249 119
            $this->connection->getEventManager()->addEventSubscriber($this);
250
        }
251
252 592
        return $this->connection;
253
    }
254
    
255
    /**
256
     * Set the new connection for next queries
257
     * 
258
     * If work is set, the connection will be available only for the work content
259
     * Else the repository will be linked with this new connection
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
260
     * 
261
     * @param string   $connection
262
     * @param Closure|null $work
263
     * 
264
     * @return $this|mixed  Returns the work result if set or the instance if not set
265
     */
266 6
    public function on($connection, ?Closure $work = null)
267
    {
268 6
        $original = $this->changeActiveConnection($connection);
269
270 6
        if ($work !== null) {
271
            try {
272 3
                return $work($this);
273
            } finally {
274 3
                $this->changeActiveConnection($original);
275
            }
276
        }
277
        
278 3
        return $this;
279
    }
280
281
    /**
282
     * Launch transactional queries
283
     * 
284
     * @param callable(EntityRepository):R $work
0 ignored issues
show
introduced by
Expected "callableEntityRepositoryR" but found "callable(EntityRepository):R" for parameter type
Loading history...
285
     * @return R
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
286
     * 
287
     * @throws Exception
288
     * @throws PrimeException
289
     *
290
     * @template R
291
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag for "BadMethodCallException" exception
Loading history...
292 27
    public function transaction(callable $work)
293
    {
294 27
        $connection = $this->connection();
295
296 27
        if (!$connection instanceof TransactionManagerInterface) {
297
            throw new BadMethodCallException('Transactions are not supported by the connection '.$connection->getName());
298
        }
299
300
        // @todo handle Doctrine DBAL Exception ?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
301
        // @todo transaction method on connection ?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
302
        try {
303 27
            $connection->beginTransaction();
304
305 27
            $result = $work($this);
306
307 26
            if ($result === false) {
308
                $connection->rollback();
309
            } else {
310 26
                $connection->commit();
311
            }
312 1
        } catch (Exception $e) {
313 1
            $connection->rollback();
314
315 1
            throw $e;
316
        }
317
318 26
        return $result;
319
    }
320
321
    /**
322
     * Load relations on given entity
323
     * If the relation is already loaded, the relation will not be reloaded
324
     * Use reloadRelation for force loading
325
     * 
326
     * @param E $entity
327
     * @param string|array $relations
328
     *
329
     * @return void
330
     * @throws PrimeException
331
     *
332
     * @see EntityRepository::reloadRelations() For force load relations
333
     */
334
    #[ReadOperation]
335 43
    public function loadRelations($entity, $relations): void
336
    {
337 43
        foreach (Relation::sanitizeRelations((array)$relations) as $relationName => $meta) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
338 43
            $this->relation($relationName)->loadIfNotLoaded(
339 43
                new SingleEntityIndexer($this->mapper, $entity),
340 43
                $meta['relations'],
341 43
                $meta['constraints']
342
            );
343
        }
344 42
    }
345
346
    /**
347
     * Force loading relations on given entity
348
     *
349
     * @param E $entity
350
     * @param string|array $relations
351
     *
352
     * @return void
353
     * @throws PrimeException
354
     *
355
     * @see EntityRepository::loadRelations() For loading relation only if not yet loaded
356
     */
357
    #[ReadOperation]
358 9
    public function reloadRelations($entity, $relations): void
359
    {
360 9
        foreach (Relation::sanitizeRelations((array)$relations) as $relationName => $meta) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
361 9
            $this->relation($relationName)->load(
362 9
                new SingleEntityIndexer($this->mapper, $entity),
363 9
                $meta['relations'],
364 9
                $meta['constraints']
365
            );
366
        }
367 9
    }
368
369
    /**
370
     * Get a entity relation wrapper linked to the entity
371
     *
372
     * @param string $relationName
373
     * @param E $entity
374
     *
375
     * @return EntityRelation<E, object>
376
     */
377 71
    public function onRelation(string $relationName, $entity): EntityRelation
0 ignored issues
show
introduced by
Type hint "E" missing for $entity
Loading history...
378
    {
379 71
        return new EntityRelation($entity, $this->relation($relationName));
380
    }
381
382
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $relationName should have a doc-comment as per coding-style.
Loading history...
383
     * {@inheritdoc}
384
     */
385 199
    public function relation(string $relationName): RelationInterface
386
    {
387 199
        if (!isset($this->relations[$relationName])) {
388 50
            $this->relations[$relationName] = Relation::make($this, $relationName, $this->mapper->relation($relationName));
389
        }
390
        
391 195
        return $this->relations[$relationName];
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    #[WriteOperation]
398 12
    public function saveAll($entity, $relations): int
399
    {
400 12
        $relations = Relation::sanitizeRelations((array)$relations);
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
401
402
        return $this->transaction(function() use($entity, $relations) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->transactio...ion(...) { /* ... */ }) returns the type Bdf\Prime\Repository\R which is incompatible with the type-hinted return integer.
Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after USE keyword; found 0
Loading history...
403 12
            $nb = $this->save($entity);
404
405 12
            foreach ($relations as $relationName => $info) {
406 6
                $nb += $this->relation($relationName)->saveAll($entity, $info['relations']);
407
            }
408
409 12
            return $nb;
410 12
        });
411
    }
412
413
    /**
414
     * {@inheritdoc}
415
     */
416
    #[WriteOperation]
417 10
    public function deleteAll($entity, $relations): int
418
    {
419 10
        $relations = Relation::sanitizeRelations((array)$relations);
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
420
421
        return $this->transaction(function() use($entity, $relations) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->transactio...ion(...) { /* ... */ }) returns the type Bdf\Prime\Repository\R which is incompatible with the type-hinted return integer.
Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
Coding Style introduced by
Expected 1 space after USE keyword; found 0
Loading history...
422 10
            $nb = $this->delete($entity);
423
424 10
            foreach ($relations as $relationName => $info) {
425 4
                $nb += $this->relation($relationName)->deleteAll($entity, $info['relations']);
426
            }
427
428 10
            return $nb;
429 10
        });
430
    }
431
432
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $context should have a doc-comment as per coding-style.
Loading history...
433
     * {@inheritdoc}
434
     */
435 527
    public function constraints(string $context = null): array
436
    {
437 527
        if ($this->withoutConstraints === true) {
438 4
            $this->withoutConstraints = false;
439 4
            return [];
440
        }
441
442 526
        $constraints = $this->metadata()->constraints;
443
444 526
        if ($context && is_array($constraints)) {
445 404
            $context .= '.';
446 404
            foreach ($constraints as $key => $value) {
447 32
                $constraints[$context.$key] = $value;
448 32
                unset($constraints[$key]);
449
            }
450
        }
451
452 526
        return $constraints;
453
    }
454
    
455
    /**
456
     * Disable global constraints on this repository.
457
     * Only for the current query
458
     * 
459
     * @return $this
460
     */
461 4
    public function withoutConstraints()
462
    {
463 4
        $this->withoutConstraints = true;
464
465 4
        return $this;
466
    }
467
468
    /**
469
     * Check whether the current query has global constraints
470
     *
471
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
472
     */
473 4
    public function isWithoutConstraints(): bool
474
    {
475 4
        return $this->withoutConstraints;
476
    }
477
478
    /**
479
     * Get query builder
480
     * 
481
     * @return QueryInterface<ConnectionInterface, E>
482
     */
483 283
    public function builder()
484
    {
485 283
        return $this->queries->builder();
486
    }
487
488
    /**
489
     * {@inheritdoc}
490
     */
491 226
    public function queries(): RepositoryQueryFactory
492
    {
493 226
        return $this->queries;
494
    }
495
496
    /**
497
     * {@inheritdoc}
498
     */
499 4
    public function writer(): WriterInterface
500
    {
501 4
        return $this->writer;
502
    }
503
504
    /**
505
     * Count entity
506
     * 
507
     * @param array $criteria
508
     * @param string|array|null $attributes
509
     * 
510
     * @return int
511
     * @throws PrimeException
512
     */
513
    #[ReadOperation]
514 42
    public function count(array $criteria = [], $attributes = null): int
515
    {
516
        /** @psalm-suppress UndefinedInterfaceMethod */
0 ignored issues
show
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
517 42
        return $this->builder()->where($criteria)->count($attributes);
0 ignored issues
show
Bug introduced by
The method count() does not exist on Bdf\Prime\Query\QueryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Query\QueryInterface. ( Ignorable by Annotation )

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

517
        return $this->builder()->where($criteria)->/** @scrutinizer ignore-call */ count($attributes);
Loading history...
518
    }
519
520
    /**
521
     * {@inheritdoc}
522
     */
523
    #[ReadOperation]
524 45
    public function exists($entity): bool
525
    {
526 45
        return $this->queries->countKeyValue($this->mapper()->primaryCriteria($entity)) > 0;
527
    }
528
529
    /**
530
     * {@inheritdoc}
531
     */
532
    #[ReadOperation]
533 40
    public function refresh($entity, array $criteria = [])
534
    {
535 40
        if (empty($criteria)) {
536 40
            return $this->queries->findById($this->mapper()->primaryCriteria($entity));
537
        }
538
539 1
        $criteria += $this->mapper()->primaryCriteria($entity);
540
541 1
        return $this->builder()->where($criteria)->first();
542
    }
543
544
    /**
545
     * Check if the entity is new
546
     *
547
     * @param E $entity
548
     *
549
     * @return bool|null Returns null if entity is composite primary
0 ignored issues
show
Coding Style introduced by
Expected "boolean|null" but found "bool|null" for function return type
Loading history...
550
     */
551 72
    public function isNew($entity): ?bool
0 ignored issues
show
introduced by
Type hint "E" missing for $entity
Loading history...
552
    {
553 72
        $metadata = $this->mapper->metadata();
554
555 72
        if ($metadata->isCompositePrimaryKey()) {
556 6
            return null;
557
        }
558
559 68
        $primaryValue = $this->mapper->getId($entity);
560
561 68
        if (empty($primaryValue)) {
562 28
            return true;
563
        }
564
565 46
        return $metadata->isForeignPrimaryKey() ? null : false;
566
    }
567
568
    /**
569
     * {@inheritdoc}
570
     */
571
    #[WriteOperation]
572 34
    public function save($entity): int
573
    {
574 34
        $isNew = $this->isNew($entity);
575
576 34
        if ($this->notify(Events::PRE_SAVE, [$entity, $this, $isNew]) === false) {
577
            return 0;
578
        }
579
580
        // composite primary
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
581 34
        if ($isNew === null) {
582 14
            $count = $this->replace($entity);
583 26
        } elseif ($isNew) {
0 ignored issues
show
Coding Style introduced by
Usage of ELSEIF not allowed; use ELSE IF instead
Loading history...
584 18
            $count = $this->insert($entity);
585
        } else {
586 11
            $count = $this->update($entity);
587
        }
588
589 32
        $this->notify(Events::POST_SAVE, [$entity, $this, $count, $isNew]);
590
        
591 32
        return $count;
592
    }
593
594
    /**
595
     * Replace an entity
596
     *
597
     * @param E $entity
598
     *
599
     * @return int  Returns 2 if updated and 1 if inserting
600
     * @throws PrimeException
601
     */
602
    #[WriteOperation]
603 52
    public function replace($entity): int
604
    {
605 52
        $isNew = $this->isNew($entity);
606
607 52
        if ($isNew !== true && $this->exists($entity)) {
608 10
            return $this->update($entity) + 1;
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
609
        }
610
611 44
        return $this->insert($entity);
612
    }
613
614
    /**
615
     * Duplicate an entity
616
     * remove primary key and launch insertion
617
     * 
618
     * @param E $entity
619
     * 
620
     * @return int
621
     * @throws PrimeException
622
     */
623
    #[WriteOperation]
624 2
    public function duplicate($entity): int
625
    {
626 2
        $this->mapper()->setId($entity, null);
627
        
628 2
        return $this->insert($entity);
629
    }
630
    
631
    /**
632
     * Insert an entity
633
     * 
634
     * @param E $entity
635
     * @param bool $ignore
636
     * 
637
     * @return int
638
     * @throws PrimeException
639
     */
640
    #[WriteOperation]
641 407
    public function insert($entity, bool $ignore = false): int
642
    {
643 407
        return $this->writer->insert($entity, ['ignore' => $ignore]);
644
    }
645
646
    /**
647
     * Insert ignore
648
     * 
649
     * @param E $entity
650
     * 
651
     * @return int
652
     * @throws PrimeException
653
     */
654
    #[WriteOperation]
655 2
    public function insertIgnore($entity): int
656
    {
657 2
        return $this->insert($entity, true);
658
    }
659
    
660
    /**
661
     * {@inheritdoc}
662
     */
663
    #[WriteOperation]
664 45
    public function update($entity, array $attributes = null): int
665
    {
666 45
        return $this->writer->update($entity, ['attributes' => $attributes]);
667
    }
668
669
    /**
670
     * Update collection of entities
671
     * 
672
     * @param array $attributes
673
     * @param array $criteria
674
     * 
675
     * @return int
676
     * @throws PrimeException
677
     */
678
    #[WriteOperation]
679
    public function updateBy(array $attributes, array $criteria = []): int
680
    {
681
        return $this->builder()->where($criteria)->update($attributes);
682
    }
683
    
684
    /**
685
     * {@inheritdoc}
686
     */
687
    #[WriteOperation]
688 26
    public function delete($entity): int
689
    {
690 26
        return $this->writer->delete($entity);
691
    }
692
    
693
    /**
694
     * Remove a collection of entities
695
     * 
696
     * @param array $criteria
697
     * 
698
     * @return int
699
     * @throws PrimeException
700
     */
701
    #[WriteOperation]
702
    public function deleteBy(array $criteria): int
703
    {
704
        return $this->builder()->where($criteria)->delete();
705
    }
706
707
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $force should have a doc-comment as per coding-style.
Loading history...
708
     * {@inheritdoc}
709
     */
710 636
    public function schema(bool $force = false): ResolverInterface
711
    {
712 636
        if (!$this->mapper->hasSchemaManager() && !$force) {
713
            return new NullResolver();
714
        }
715
        
716 636
        return new Resolver($this->serviceLocator, $this->mapper->metadata());
717
    }
718
    
719
    /**
720
     * Gets custom filters
721
     *
722
     * @return array
723
     */
724
    public function filters()
725
    {
726
        return $this->mapper->filters();
727
    }
728
    
729
    /**
730
     * Repository extensions
731
     *
732
     * @return array
733
     */
734 1
    public function scopes()
735
    {
736 1
        return $this->mapper->scopes();
737
    }
738
    
739
    //----- events
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// ----- events" but found "//----- events"
Loading history...
740
741
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
742
     * {@inheritdoc}
743
     */
744 1
    public function loaded(callable $listener, bool $once = false)
745
    {
746 1
        if ($once) {
747 1
            $this->once(Events::POST_LOAD, $listener);
748
        } else {
749
            $this->listen(Events::POST_LOAD, $listener);
750
        }
751
752 1
        return $this;
753
    }
754
755
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
756
     * {@inheritdoc}
757
     */
758 1
    public function saving(callable $listener, bool $once = false)
759
    {
760 1
        if ($once) {
761 1
            $this->once(Events::PRE_SAVE, $listener);
762
        } else {
763
            $this->listen(Events::PRE_SAVE, $listener);
764
        }
765
766 1
        return $this;
767
    }
768
769
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
770
     * {@inheritdoc}
771
     */
772 1
    public function saved(callable $listener, bool $once = false)
773
    {
774 1
        if ($once) {
775 1
            $this->once(Events::POST_SAVE, $listener);
776
        } else {
777
            $this->listen(Events::POST_SAVE, $listener);
778
        }
779
780 1
        return $this;
781
    }
782
783
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
784
     * {@inheritdoc}
785
     */
786 5
    public function inserting(callable $listener, bool $once = false)
787
    {
788 5
        if ($once) {
789 1
            $this->once(Events::PRE_INSERT, $listener);
790
        } else {
791 4
            $this->listen(Events::PRE_INSERT, $listener);
792
        }
793
794 5
        return $this;
795
    }
796
797
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
798
     * {@inheritdoc}
799
     */
800 2
    public function inserted(callable $listener, bool $once = false)
801
    {
802 2
        if ($once) {
803 1
            $this->once(Events::POST_INSERT, $listener);
804
        } else {
805 1
            $this->listen(Events::POST_INSERT, $listener);
806
        }
807
808 2
        return $this;
809
    }
810
811
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
812
     * {@inheritdoc}
813
     */
814 6
    public function updating(callable $listener, bool $once = false)
815
    {
816 6
        if ($once) {
817 2
            $this->once(Events::PRE_UPDATE, $listener);
818
        } else {
819 4
            $this->listen(Events::PRE_UPDATE, $listener);
820
        }
821
822 6
        return $this;
823
    }
824
825
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
826
     * {@inheritdoc}
827
     */
828 2
    public function updated(callable $listener, bool $once = false)
829
    {
830 2
        if ($once) {
831 1
            $this->once(Events::POST_UPDATE, $listener);
832
        } else {
833 1
            $this->listen(Events::POST_UPDATE, $listener);
834
        }
835
836 2
        return $this;
837
    }
838
839
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
840
     * {@inheritdoc}
841
     */
842 6
    public function deleting(callable $listener, bool $once = false)
843
    {
844 6
        if ($once) {
845 1
            $this->once(Events::PRE_DELETE, $listener);
846
        } else {
847 5
            $this->listen(Events::PRE_DELETE, $listener);
848
        }
849
850 6
        return $this;
851
    }
852
853
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $listener should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $once should have a doc-comment as per coding-style.
Loading history...
854
     * {@inheritdoc}
855
     */
856 2
    public function deleted(callable $listener, bool $once = false)
857
    {
858 2
        if ($once) {
859 1
            $this->once(Events::POST_DELETE, $listener);
860
        } else {
861 1
            $this->listen(Events::POST_DELETE, $listener);
862
        }
863
864 2
        return $this;
865
    }
866
867
    /**
868
     * Query method
869
     * redirect method to the query builder
870
     * 
871
     * @param string $name         Query builder method
872
     * @param array  $arguments
873
     * 
874
     * @return int|QueryInterface
0 ignored issues
show
Coding Style introduced by
Expected "integer|QueryInterface" but found "int|QueryInterface" for function return type
Loading history...
875
     */
876 108
    public function __call($name, $arguments)
0 ignored issues
show
introduced by
Type hint "array" missing for $arguments
Loading history...
877
    {
878 108
        return $this->queries->$name(...$arguments);
879
    }
880
    
881
    //--- Methodes for optimisation: alias of query methods
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// --- Methodes for optimisation: alias of query methods" but found "//--- Methodes for optimisation: alias of query methods"
Loading history...
882
    
883
    /**
884
     * @see QueryRepositoryExtension::with
885
     * 
886
     * @param string|array $relations
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
887
     * 
888
     * @return QueryInterface<ConnectionInterface, E>
889
     */
890 35
    public function with($relations)
891
    {
892 35
        return $this->builder()->with($relations);
0 ignored issues
show
Bug introduced by
The method with() does not exist on Bdf\Prime\Query\QueryInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\SqlQueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

892
        return $this->builder()->/** @scrutinizer ignore-call */ with($relations);
Loading history...
893
    }
894
895
    /**
896
     * @see QueryRepositoryExtension::without
897
     *
898
     * @param string|array $relations
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
899
     *
900
     * @return QueryInterface<ConnectionInterface, E>
901
     */
902 11
    public function without($relations)
903
    {
904 11
        return $this->builder()->without($relations);
0 ignored issues
show
Bug introduced by
The method without() does not exist on Bdf\Prime\Query\QueryInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\SqlQueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

904
        return $this->builder()->/** @scrutinizer ignore-call */ without($relations);
Loading history...
905
    }
906
    
907
    /**
908
     * @see QueryRepositoryExtension::by
909
     * 
910
     * @param string|array $attribute
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
911
     * @param boolean      $combine
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
912
     * 
913
     * @return QueryInterface<ConnectionInterface, E>
914
     */
915 6
    public function by($attribute, $combine = false)
916
    {
917 6
        return $this->builder()->by($attribute, $combine);
0 ignored issues
show
Bug introduced by
The method by() does not exist on Bdf\Prime\Query\QueryInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\SqlQueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

917
        return $this->builder()->/** @scrutinizer ignore-call */ by($attribute, $combine);
Loading history...
918
    }
919
    
920
    /**
921
     * @see QueryInterface::wrapAs
922
     * 
923
     * @param string $wrapperClass
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
924
     * 
925
     * @return QueryInterface<ConnectionInterface, E>
926
     */
927 7
    public function wrapAs($wrapperClass)
928
    {
929 7
        return $this->builder()->wrapAs($wrapperClass);
930
    }
931
    
932
    /**
933
     * @param array $criteria
934
     * @param array $attributes
935
     * 
936
     * @return array|CollectionInterface<E>
937
     * @throws PrimeException
938
     */
939
    #[ReadOperation]
940 5
    public function find(array $criteria, $attributes = null)
941
    {
942 5
        return $this->builder()->find($criteria, $attributes);
943
    }
944
945
    /**
946
     * @param array $criteria
947
     * @param array $attributes
948
     * 
949
     * @return E|null
950
     * @throws PrimeException
951
     */
952
    #[ReadOperation]
953 11
    public function findOne(array $criteria, $attributes = null)
954
    {
955 11
        return $this->builder()->findOne($criteria, $attributes);
956
    }
957
958
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $operator should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
introduced by
Parameter $column is not described in comment
Loading history...
introduced by
Parameter $operator is not described in comment
Loading history...
introduced by
Parameter $value is not described in comment
Loading history...
Coding Style introduced by
Parameter $column should have a doc-comment as per coding-style.
Loading history...
959
     * @see QueryInterface::where
960
     * 
961
     * @param string|array $relations
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
Coding Style introduced by
Doc comment for parameter $relations does not match actual variable name $column
Loading history...
introduced by
Doc comment for parameter $relations does not match actual variable name $value
Loading history...
962
     * 
963
     * @return QueryInterface<ConnectionInterface, E>
964
     */
965 49
    public function where($column, $operator = null, $value = null)
966
    {
967 49
        return $this->builder()->where($column, $operator, $value);
968
    }
969
970
    /**
971
     * {@inheritdoc}
972
     */
973 3
    public function onConnectionClosed()
974
    {
975 3
        $this->reset();
976 3
    }
977
978
    /**
979
     * {@inheritdoc}
980
     */
981 121
    public function getSubscribedEvents()
982
    {
983 121
        return [ConnectionClosedListenerInterface::EVENT_NAME];
984
    }
985
986
    /**
987
     * Free metadata information on the given entity
988
     * Note: This method is called by the model destructor
989
     *
990
     * @param E $entity
991
     *
992
     * @return void
0 ignored issues
show
introduced by
If there is no return value for a function, there must not be a @return tag.
Loading history...
993
     */
994 531
    public function free($entity)
0 ignored issues
show
introduced by
Type hint "E" missing for $entity
Loading history...
995
    {
996 531
        foreach ($this->relations as $relation) {
997 253
            $relation->clearInfo($entity);
998
        }
999 531
    }
1000
1001
    /**
1002
     * Clear dependencies for break cyclic references
1003
     * After this call, the repository will be unusable
1004
     *
1005
     * @internal
1006
     */
1007 1
    public function destroy()
1008
    {
1009 1
        if ($this->connection !== null) {
1010 1
            $this->connection->getEventManager()->removeEventSubscriber($this);
1011 1
            $this->connection = null;
1012
        }
1013
1014 1
        $this->serviceLocator = null;
1015 1
        $this->queries = null;
1016 1
        $this->writer = null;
1017 1
        $this->relations = [];
1018 1
        $this->collectionFactory = null;
1019
1020 1
        $this->mapper->destroy();
1021 1
        $this->mapper = null;
1022
1023 1
        if ($this->resultCache) {
1024
            $this->resultCache->clear();
1025
            $this->resultCache = null;
1026
        }
1027 1
    }
1028
1029
    /**
1030
     * Change the active connection on the repository
1031
     * All queries will be reseted
1032
     *
1033
     * /!\ The method will not check if the connection exists nor the new connection is same as the active
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
1034
     *
1035
     * @param string $connectionName The new connection name
1036
     *
1037
     * @return string The last active connection name
1038
     */
1039 6
    private function changeActiveConnection($connectionName)
0 ignored issues
show
Coding Style introduced by
Private method name "EntityRepository::changeActiveConnection" must be prefixed with an underscore
Loading history...
1040
    {
1041 6
        $this->reset();
1042
1043
        /** @var string $original */
0 ignored issues
show
Coding Style introduced by
Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead
Loading history...
Coding Style introduced by
Block comments must be started with /*
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
1044 6
        $original = $this->mapper->metadata()->connection;
1045 6
        $this->mapper->metadata()->connection = $connectionName;
1046
1047 6
        return $original;
1048
    }
1049
1050
    /**
1051
     * Reset the inner queries and the connection.
1052
     * Use for invalidate prepared queries, or when connection changed
1053
     */
1054 8
    private function reset()
0 ignored issues
show
Coding Style introduced by
Private method name "EntityRepository::reset" must be prefixed with an underscore
Loading history...
1055
    {
1056 8
        if ($this->connection !== null) {
1057 7
            $this->connection->getEventManager()->removeEventSubscriber($this);
1058 7
            $this->connection = null;
1059
        }
1060
1061
        // Reset queries
1062 8
        $this->queries = new RepositoryQueryFactory($this, $this->resultCache);
1063 8
        $this->writer = new Writer($this, $this->serviceLocator);
1064 8
        $this->relations = []; // Relation may contains inner query : it must be reseted
0 ignored issues
show
Coding Style introduced by
Comments may not appear after statements
Loading history...
1065
1066 8
        if ($this->resultCache) {
1067
            $this->resultCache->clear();
1068
        }
1069 8
    }
1070
}
1071