Completed
Pull Request — master (#5)
by Vincent
07:04
created

EntityRepository   F

Complexity

Total Complexity 102

Size/Duplication

Total Lines 1023
Duplicated Lines 0 %

Test Coverage

Coverage 95.04%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 102
eloc 212
c 1
b 0
f 0
dl 0
loc 1023
ccs 249
cts 262
cp 0.9504
rs 2

67 Methods

Rating   Name   Duplication   Size   Complexity  
A mapper() 0 3 1
A extractOne() 0 3 1
A repository() 0 3 1
A collectionFactory() 0 3 1
A entity() 0 3 1
A transaction() 0 21 3
A __construct() 0 12 1
A hydrateOne() 0 3 1
A connection() 0 3 1
A entityName() 0 3 1
A metadata() 0 3 1
A entityClass() 0 3 1
A collection() 0 3 1
A isReadOnly() 0 3 1
A on() 0 13 2
A criteria() 0 3 1
A with() 0 3 1
A where() 0 3 1
A replace() 0 9 3
A delete() 0 3 1
A findOne() 0 3 1
A wrapAs() 0 3 1
A withoutConstraints() 0 5 1
A saved() 0 9 2
A inserted() 0 9 2
A save() 0 20 4
A updateBy() 0 3 1
A reset() 0 9 2
A onConnectionClosed() 0 3 1
A updated() 0 9 2
A schema() 0 7 3
A constraints() 0 18 5
A deleteAll() 0 12 2
A onRelation() 0 3 1
A changeActiveConnection() 0 11 1
A exists() 0 3 1
A getSubscribedEvents() 0 3 1
A scopes() 0 3 1
A update() 0 3 1
A isWithoutConstraints() 0 3 1
A builder() 0 3 1
A queries() 0 3 1
A deleteBy() 0 3 1
A loadRelations() 0 7 2
A isNew() 0 15 4
A saveAll() 0 12 2
A by() 0 3 1
A relation() 0 7 2
A deleting() 0 9 2
A loaded() 0 9 2
A insert() 0 3 1
A count() 0 3 1
A refresh() 0 9 2
A reloadRelations() 0 7 2
A find() 0 3 1
A saving() 0 9 2
A deleted() 0 9 2
A insertIgnore() 0 3 1
A updating() 0 9 2
A free() 0 4 2
A __call() 0 3 1
A duplicate() 0 5 1
A without() 0 3 1
A destroy() 0 16 2
A filters() 0 3 1
A inserting() 0 9 2
A writer() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like EntityRepository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntityRepository, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Bdf\Prime\Repository;
4
5
use Bdf\Event\EventNotifier;
6
use Bdf\Prime\Cache\CacheInterface;
7
use Bdf\Prime\Collection\CollectionFactory;
8
use Bdf\Prime\Collection\EntityCollection;
9
use Bdf\Prime\Collection\Indexer\SingleEntityIndexer;
10
use Bdf\Prime\Connection\Event\ConnectionClosedListenerInterface;
11
use Bdf\Prime\Entity\Criteria;
12
use Bdf\Prime\Events;
13
use Bdf\Prime\Mapper\Mapper;
14
use Bdf\Prime\Query\QueryInterface;
0 ignored issues
show
introduced by
Unused use statement
Loading history...
15
use Bdf\Prime\Query\QueryRepositoryExtension;
0 ignored issues
show
introduced by
Unused use statement
Loading history...
16
use Bdf\Prime\Relations\EntityRelation;
17
use Bdf\Prime\Relations\Relation;
18
use Bdf\Prime\Relations\RelationInterface;
0 ignored issues
show
introduced by
Unused use statement
Loading history...
19
use Bdf\Prime\Repository\Write\Writer;
20
use Bdf\Prime\Repository\Write\WriterInterface;
0 ignored issues
show
introduced by
Unused use statement
Loading history...
21
use Bdf\Prime\Schema\NullResolver;
22
use Bdf\Prime\Schema\Resolver;
23
use Bdf\Prime\ServiceLocator;
24
use Doctrine\Common\EventSubscriber;
25
26
/**
27
 * Db repository
28
 * 
29
 * 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...
30
 * 
31
 * @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...
Coding Style Documentation introduced by
@todo tag is not allowed in class comment
Loading history...
32
 *
33
 * @package Bdf\Prime\Repository
0 ignored issues
show
Coding Style Documentation introduced by
@package tag is not allowed in class comment
Loading history...
34
 *
35
 * @mixin RepositoryQueryFactory
0 ignored issues
show
Coding Style Documentation introduced by
@mixin tag is not allowed in class comment
Loading history...
36
 */
37
class EntityRepository implements RepositoryInterface, EventSubscriber, ConnectionClosedListenerInterface
38
{
39
    use EventNotifier;
40
    
41
    /**
42
     * @var Mapper 
0 ignored issues
show
introduced by
Expected "Mapper" but found "Mapper " for @var tag in member variable comment
Loading history...
43
     */
44
    protected $mapper;
45
    
46
    /**
47
     * @var ServiceLocator 
0 ignored issues
show
introduced by
Expected "ServiceLocator" but found "ServiceLocator " for @var tag in member variable comment
Loading history...
48
     */
49
    protected $serviceLocator;
50
    
51
    /**
52
     * Query result cache
53
     * 
54
     * @var CacheInterface
55
     */
56
    protected $resultCache;
57
    
58
    /**
59
     * Disable the global constraints for one query
60
     * 
61
     * @var bool
0 ignored issues
show
Bug introduced by
Expected "boolean" but found "bool" for @var tag in member variable comment
Loading history...
62
     */
63
    protected $withoutConstraints = false;
64
    
65
    /**
66
     * Cache of relation instance
67
     * 
68
     * @var RelationInterface[]
69
     */
70
    protected $relations = [];
71
72
    /**
73
     * The collection factory
74
     *
75
     * @var CollectionFactory
76
     */
77
    protected $collectionFactory;
78
79
    /**
80
     * @var RepositoryQueryFactory
81
     */
82
    protected $queries;
83
84
    /**
85
     * @var WriterInterface
86
     */
87
    protected $writer;
88
89
90
    /**
91
     * Constructor
92
     * 
93
     * @param Mapper         $mapper
94
     * @param ServiceLocator $serviceLocator
95
     * @param CacheInterface $cache
96
     */
97 115
    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...
98
    {
99 115
        $this->resultCache = $cache;
100 115
        $this->mapper = $mapper;
101 115
        $this->serviceLocator = $serviceLocator;
102
103 115
        $this->collectionFactory = CollectionFactory::forRepository($this);
104 115
        $this->queries = new RepositoryQueryFactory($this, $cache);
105 115
        $this->writer = new Writer($this, $serviceLocator);
106
107 115
        $this->mapper->events($this);
108 115
        $this->connection()->getEventManager()->addEventSubscriber($this);
109 115
    }
110
    
111
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entity should have a doc-comment as per coding-style.
Loading history...
112
     * {@inheritdoc}
113
     */
114 143
    public function repository($entity)
115
    {
116 143
        return $this->serviceLocator->repository($entity);
117
    }
118
    
119
    /**
120
     * {@inheritdoc}
121
     */
122 764
    public function mapper()
123
    {
124 764
        return $this->mapper;
125
    }
126
    
127
    /**
128
     * {@inheritdoc}
129
     */
130 569
    public function metadata()
131
    {
132 569
        return $this->mapper->metadata();
133
    }
134
    
135
    /**
136
     * {@inheritdoc}
137
     */
138 415
    public function isReadOnly()
139
    {
140 415
        return $this->mapper->isReadOnly();
141
    }
142
    
143
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $criteria should have a doc-comment as per coding-style.
Loading history...
144
     * {@inheritdoc}
145
     */
146 1
    public function criteria(array $criteria = [])
147
    {
148 1
        return new Criteria($criteria);
149
    }
150
    
151
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $data should have a doc-comment as per coding-style.
Loading history...
152
     * {@inheritdoc}
153
     */
154 67
    public function entity(array $data = [])
155
    {
156 67
        return $this->mapper->entity($data);
157
    }
158
    
159
    /**
160
     * {@inheritdoc}
161
     */
162 55
    public function entityName()
163
    {
164 55
        return $this->mapper->metadata()->entityName;
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 70
    public function entityClass()
171
    {
172 70
        return $this->mapper->metadata()->entityClass;
173
    }
174
175
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entities should have a doc-comment as per coding-style.
Loading history...
176
     * {@inheritdoc}
177
     */
178 20
    public function collection(array $entities = [])
179
    {
180 20
        return new EntityCollection($this, $entities);
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186 442
    public function collectionFactory()
187
    {
188 442
        return $this->collectionFactory;
189
    }
190
191
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entity should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $property 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...
192
     * {@inheritdoc}
193
     */
194 131
    public function hydrateOne($entity, $property, $value)
195
    {
196 131
        $this->mapper->hydrateOne($entity, $property, $value);
197 131
    }
198
199
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $entity should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $property should have a doc-comment as per coding-style.
Loading history...
200
     * {@inheritdoc}
201
     */
202 109
    public function extractOne($entity, $property)
203
    {
204 109
        return $this->mapper->extractOne($entity, $property);
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210 603
    public function connection()
211
    {
212 603
        return $this->serviceLocator->connection($this->mapper->metadata()->connection);
213
    }
214
    
215
    /**
216
     * Set the new connection for next queries
217
     * 
218
     * If work is set, the connection will be available only for the work content
219
     * 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...
220
     * 
221
     * @param string   $connection
222
     * @param \Closure $work
223
     * 
224
     * @return $this|mixed  Returns the work result if set or the instance if not set
225
     */
226 6
    public function on($connection, \Closure $work = null)
227
    {
228 6
        $original = $this->changeActiveConnection($connection);
229
230 6
        if ($work !== null) {
231
            try {
232 3
                return $work($this);
233
            } finally {
234 3
                $this->changeActiveConnection($original);
235
            }
236
        }
237
        
238 3
        return $this;
239
    }
240
    
241
    /**
242
     * Launch transactionnal queries
243
     * 
244
     * @param \Closure $work
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
245
     * @return mixed
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
introduced by
Separate the @param and @return sections by a blank line.
Loading history...
246
     * 
247
     * @throws \Exception
0 ignored issues
show
introduced by
Comment missing for @throws tag in function comment
Loading history...
248
     */
249 27
    public function transaction(\Closure $work)
250
    {
251 27
        $connection = $this->connection();
252
        
253
        try {
254 27
            $connection->beginTransaction();
0 ignored issues
show
Bug introduced by
The method beginTransaction() does not exist on Bdf\Prime\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Connection\ConnectionInterface. ( Ignorable by Annotation )

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

254
            $connection->/** @scrutinizer ignore-call */ 
255
                         beginTransaction();
Loading history...
255
            
256 27
            $result = $work($this);
257
            
258 26
            if ($result === false) {
259
                $connection->rollback();
0 ignored issues
show
Bug introduced by
The method rollback() does not exist on Bdf\Prime\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Connection\ConnectionInterface. ( Ignorable by Annotation )

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

259
                $connection->/** @scrutinizer ignore-call */ 
260
                             rollback();
Loading history...
260
            } else {
261 26
                $connection->commit();
0 ignored issues
show
Bug introduced by
The method commit() does not exist on Bdf\Prime\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Connection\ConnectionInterface. ( Ignorable by Annotation )

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

261
                $connection->/** @scrutinizer ignore-call */ 
262
                             commit();
Loading history...
262
            }
263 1
        } catch (\Exception $e) {
264 1
            $connection->rollback();
265
            
266 1
            throw $e;
267
        }
268
        
269 26
        return $result;
270
    }
271
    
272
    /**
273
     * Load relations on given entity
274
     * If the relation is already loaded, the relation will not be reloaded
275
     * Use reloadRelation for force loading
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
276
     * 
277
     * @param object          $entity
278
     * @param string|array    $relations
279
     *
280
     * @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...
281
     *
282
     * @see EntityRepository::reloadRelations() For force load relations
0 ignored issues
show
introduced by
The @see reference should not contain any additional text
Loading history...
283
     */
284 43
    public function loadRelations($entity, $relations)
285
    {
286 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...
287 43
            $this->relation($relationName)->loadIfNotLoaded(
288 43
                new SingleEntityIndexer($this->mapper, $entity),
289 43
                $meta['relations'],
290 43
                $meta['constraints']
291
            );
292
        }
293 42
    }
294
295
    /**
296
     * Force loading relations on given entity
297
     *
298
     * @param object          $entity
299
     * @param string|array    $relations
300
     *
301
     * @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...
302
     *
303
     * @see EntityRepository::loadRelations() For loading relation only if not yet loaded
0 ignored issues
show
introduced by
The @see reference should not contain any additional text
Loading history...
304
     */
305 9
    public function reloadRelations($entity, $relations)
306
    {
307 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...
308 9
            $this->relation($relationName)->load(
309 9
                new SingleEntityIndexer($this->mapper, $entity),
310 9
                $meta['relations'],
311 9
                $meta['constraints']
312
            );
313
        }
314 9
    }
315
316
    /**
317
     * Get a entity relation wrapper linked to the entity
318
     *
319
     * @param string   $relationName
320
     * @param object   $entity
321
     *
322
     * @return EntityRelation
323
     */
324 70
    public function onRelation($relationName, $entity)
325
    {
326 70
        return new EntityRelation($entity, $this->relation($relationName));
327
    }
328
329
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $relationName should have a doc-comment as per coding-style.
Loading history...
330
     * {@inheritdoc}
331
     */
332 198
    public function relation($relationName)
333
    {
334 198
        if (!isset($this->relations[$relationName])) {
335 47
            $this->relations[$relationName] = Relation::make($this, $relationName, $this->mapper->relation($relationName));
336
        }
337
        
338 195
        return $this->relations[$relationName];
339
    }
340
341
    /**
342
     * Save entity and its relations
343
     *
344
     * @param object         $entity
345
     * @param string|array   $relations
346
     *
347
     * @return int
0 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
348
     */
349 12
    public function saveAll($entity, $relations)
350
    {
351 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...
352
353
        return $this->transaction(function() use($entity, $relations) {
0 ignored issues
show
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...
354 12
            $nb = $this->save($entity);
355
356 12
            foreach ((array)$relations as $relationName => $info) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
357 6
                $nb += $this->relation($relationName)->saveAll($entity, $info['relations']);
358
            }
359
360 12
            return $nb;
361 12
        });
362
    }
363
364
    /**
365
     * Delete entity and its relations
366
     *
367
     * @param object         $entity
368
     * @param string|array   $relations
369
     *
370
     * @return int
0 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
371
     */
372 10
    public function deleteAll($entity, $relations)
373
    {
374 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...
375
376
        return $this->transaction(function() use($entity, $relations) {
0 ignored issues
show
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...
377 10
            $nb = $this->delete($entity);
378
379 10
            foreach ((array)$relations as $relationName => $info) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after cast statement; 0 found
Loading history...
380 4
                $nb += $this->relation($relationName)->deleteAll($entity, $info['relations']);
381
            }
382
383 10
            return $nb;
384 10
        });
385
    }
386
387
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $context should have a doc-comment as per coding-style.
Loading history...
388
     * {@inheritdoc}
389
     */
390 492
    public function constraints($context = null)
391
    {
392 492
        if ($this->withoutConstraints === true) {
393 4
            $this->withoutConstraints = false;
394 4
            return [];
395
        }
396
397 491
        $constraints = $this->metadata()->constraints;
398
399 491
        if ($context && is_array($constraints)) {
400 380
            $context .= '.';
401 380
            foreach ($constraints as $key => $value) {
402 27
                $constraints[$context.$key] = $value;
403 27
                unset($constraints[$key]);
404
            }
405
        }
406
407 491
        return $constraints;
408
    }
409
    
410
    /**
411
     * Disable global constraints on this repository.
412
     * Only for the current query
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
413
     * 
414
     * @return $this
415
     */
416 4
    public function withoutConstraints()
417
    {
418 4
        $this->withoutConstraints = true;
419
420 4
        return $this;
421
    }
422
423
    /**
424
     * Check whether the current query has global constraints
425
     *
426
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
427
     */
428 4
    public function isWithoutConstraints()
429
    {
430 4
        return $this->withoutConstraints;
431
    }
432
433
    /**
434
     * Get query builder
435
     * 
436
     * @return QueryInterface
437
     */
438 309
    public function builder()
439
    {
440 309
        return $this->queries->builder();
441
    }
442
443
    /**
444
     * {@inheritdoc}
445
     */
446 140
    public function queries()
447
    {
448 140
        return $this->queries;
449
    }
450
451
    /**
452
     * {@inheritdoc}
453
     */
454 4
    public function writer()
455
    {
456 4
        return $this->writer;
457
    }
458
459
    /**
460
     * Count entity
461
     * 
462
     * @param array $criteria
463
     * @param string|array $attributes
464
     * 
465
     * @return int
0 ignored issues
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
466
     */
467 42
    public function count(array $criteria = [], $attributes = null)
468
    {
469 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

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

894
        return $this->builder()->/** @scrutinizer ignore-call */ with($relations);
Loading history...
895
    }
896
897
    /**
898
     * @see QueryRepositoryExtension::without
899
     *
900
     * @param string|array $relations
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
901
     *
902
     * @return QueryInterface
903
     */
904 11
    public function without($relations)
905
    {
906 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

906
        return $this->builder()->/** @scrutinizer ignore-call */ without($relations);
Loading history...
907
    }
908
    
909
    /**
910
     * @see QueryRepositoryExtension::by
911
     * 
912
     * @param string|array $attribute
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
913
     * @param boolean      $combine
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
914
     * 
915
     * @return QueryInterface
916
     */
917 6
    public function by($attribute, $combine = false)
918
    {
919 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

919
        return $this->builder()->/** @scrutinizer ignore-call */ by($attribute, $combine);
Loading history...
920
    }
921
    
922
    /**
923
     * @see QueryInterface::wrapAs
924
     * 
925
     * @param string $wrapperClass
0 ignored issues
show
Coding Style introduced by
Parameter tags must be defined first in a doc comment
Loading history...
926
     * 
927
     * @return QueryInterface
928
     */
929 7
    public function wrapAs($wrapperClass)
930
    {
931 7
        return $this->builder()->wrapAs($wrapperClass);
932
    }
933
    
934
    /**
935
     * @param array $criteria
936
     * @param array $attributes
937
     * 
938
     * @return array
939
     */
940 6
    public function find(array $criteria, $attributes = null)
0 ignored issues
show
introduced by
Type hint "array" missing for $attributes
Loading history...
941
    {
942 6
        return $this->builder()->find($criteria, $attributes);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->builder()-...$criteria, $attributes) also could return the type Bdf\Prime\Collection\Col...tion\PaginatorInterface which is incompatible with the documented return type array.
Loading history...
943
    }
944
    
945
    /**
946
     * @param array $criteria
947
     * @param array $attributes
948
     * 
949
     * @return object
950
     */
951 25
    public function findOne(array $criteria, $attributes = null)
0 ignored issues
show
introduced by
Type hint "array" missing for $attributes
Loading history...
952
    {
953 25
        return $this->builder()->findOne($criteria, $attributes);
954
    }
955
    
956
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $column should have a doc-comment as per coding-style.
Loading history...
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...
957
     * @see QueryInterface::where
958
     * 
959
     * @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...
960
     * 
961
     * @return QueryInterface
962
     */
963 46
    public function where($column, $operator = null, $value = null)
964
    {
965 46
        return $this->builder()->where($column, $operator, $value);
966
    }
967
968
    /**
969
     * {@inheritdoc}
970
     */
971 3
    public function onConnectionClosed()
972
    {
973 3
        $this->reset();
974 3
    }
975
976
    /**
977
     * {@inheritdoc}
978
     */
979 121
    public function getSubscribedEvents()
980
    {
981 121
        return [ConnectionClosedListenerInterface::EVENT_NAME];
982
    }
983
984
    /**
985
     * Free metadata information on the given entity
986
     * Note: This method is called by the model destructor
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
987
     *
988
     * @param object $entity
989
     *
990
     * @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...
991
     */
992 507
    public function free($entity)
993
    {
994 507
        foreach ($this->relations as $relation) {
995 252
            $relation->clearInfo($entity);
996
        }
997 507
    }
998
999
    /**
1000
     * Clear dependencies for break cyclic references
1001
     * After this call, the repository will be unusable
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
1002
     *
1003
     * @internal
1004
     */
1005 1
    public function destroy()
1006
    {
1007 1
        $this->connection()->getEventManager()->removeEventSubscriber($this);
1008
1009 1
        $this->serviceLocator = null;
1010 1
        $this->queries = null;
1011 1
        $this->writer = null;
1012 1
        $this->relations = [];
1013 1
        $this->collectionFactory = null;
1014
1015 1
        $this->mapper->destroy();
1016 1
        $this->mapper = null;
1017
1018 1
        if ($this->resultCache) {
1019
            $this->resultCache->clear();
1020
            $this->resultCache = null;
1021
        }
1022 1
    }
1023
1024
    /**
1025
     * Change the active connection on the repository
1026
     * All queries will be reseted
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
1027
     *
1028
     * /!\ 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...
1029
     *
1030
     * @param string $connectionName The new connection name
1031
     *
1032
     * @return string The last active connection name
1033
     */
1034 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...
1035
    {
1036 6
        $this->connection()->getEventManager()->removeEventSubscriber($this);
1037
1038 6
        $original = $this->mapper->metadata()->connection;
1039 6
        $this->mapper->metadata()->connection = $connectionName;
1040
1041 6
        $this->connection()->getEventManager()->addEventSubscriber($this);
1042 6
        $this->reset();
1043
1044 6
        return $original;
1045
    }
1046
1047
    /**
1048
     * Reset the inner queries
1049
     * Use for invalidate prepared queries, or when connection changed
0 ignored issues
show
introduced by
Doc comment short description must be on a single line, further text should be a separate paragraph
Loading history...
1050
     */
1051 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...
1052
    {
1053
        // Reset queries
1054 8
        $this->queries = new RepositoryQueryFactory($this, $this->resultCache);
1055 8
        $this->writer = new Writer($this, $this->serviceLocator);
1056 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...
1057
1058 8
        if ($this->resultCache) {
1059
            $this->resultCache->clear();
1060
        }
1061 8
    }
1062
}
1063