Completed
Push — master ( 7a6bdd...324ce1 )
by Sébastien
09:34
created

Prime   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 392
Duplicated Lines 0 %

Test Coverage

Coverage 91.51%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 43
eloc 83
c 1
b 0
f 0
dl 0
loc 392
ccs 97
cts 106
cp 0.9151
rs 8.96

18 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 3 1
A one() 0 10 3
A find() 0 10 3
A exists() 0 17 4
A repository() 0 7 2
A push() 0 3 1
A truncate() 0 3 1
A callSchemaResolverMethod() 0 8 3
B initialize() 0 48 7
B callRepositoryMethod() 0 19 8
A drop() 0 3 1
A save() 0 3 1
A remove() 0 3 1
A isConfigured() 0 3 1
A refresh() 0 5 1
A connection() 0 3 1
A configure() 0 8 2
A service() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Prime 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 Prime, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Bdf\Prime;
4
5
use Bdf\Prime\Connection\ConnectionInterface;
0 ignored issues
show
introduced by
Unused use statement
Loading history...
6
use Bdf\Prime\Connection\ConnectionRegistry;
7
use Bdf\Prime\Connection\Factory\ChainFactory;
8
use Bdf\Prime\Connection\Factory\ConnectionFactory;
9
use Bdf\Prime\Connection\Factory\MasterSlaveConnectionFactory;
10
use Bdf\Prime\Connection\Factory\ShardingConnectionFactory;
11
use Bdf\Prime\Mapper\MapperFactory;
12
use Bdf\Prime\Repository\RepositoryInterface;
13
use Psr\Container\ContainerInterface;
14
use RuntimeException;
15
16
/**
17
 * Prime
18
 * 
19
 * Usefull facade to manipulate repositories
20
 * Allow user to create, drop, truncate repositories
21
 * Allow user to find, insert entities
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
22
 */
23
class Prime
24
{
25
    /**
26
     * @var mixed
27
     */
28
    protected static $config;
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line(s) before first member var; 0 found
Loading history...
29
30
    /**
31
     * @var ServiceLocator
32
     */
33
    protected static $serviceLocator;
34
35
36
    /**
37
     * Configure the locator
38
     * 
39
     * @param array|ContainerInterface|ServiceLocator $config
40
     */
41 77
    public static function configure($config)
0 ignored issues
show
Coding Style introduced by
Expected 1 blank line before function; 2 found
Loading history...
42
    {
43 77
        if ($config instanceof ServiceLocator) {
44 1
            static::$config = null;
45 1
            static::$serviceLocator = $config;
46
        } else {
47 76
            static::$config = $config;
48 76
            static::$serviceLocator = null;
49
        }
50 77
    }
51
52
    /**
53
     * Check whether prime is configured
54
     *
55
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
56
     */
57 1291
    public static function isConfigured()
58
    {
59 1291
        return static::$config !== null;
60
    }
61
62
    //
63
    //--------- repository
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// --------- repository" but found "//--------- repository"
Loading history...
64
    //
65
    
66
    /**
67
     * Get a repository
68
     * 
69
     * @param string|object|RepositoryInterface $repository
70
     *
71
     * @return RepositoryInterface
72
     */
73 697
    public static function repository($repository)
74
    {
75 697
        if ($repository instanceof RepositoryInterface) {
76 6
            return $repository;
77
        }
78
79 697
        return static::service()->repository($repository);
80
    }
81
    
82
    /**
83
     * Create repositories
84
     * 
85
     * @param string|array|RepositoryInterface $repositories
86
     * @param boolean                          $force @see EntityRepository::schema
0 ignored issues
show
introduced by
Parameter comment must start with a capital letter
Loading history...
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
87
     */
88 804
    public static function create($repositories, $force = false)
89
    {
90 804
        static::callSchemaResolverMethod('migrate', $repositories, $force);
91 804
    }
92
93
    /**
94
     * Drop repositories
95
     * 
96
     * @param string|array|RepositoryInterface $repositories
97
     * @param boolean                          $force @see EntityRepository::schema
0 ignored issues
show
introduced by
Parameter comment must start with a capital letter
Loading history...
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
98
     */
99 791
    public static function drop($repositories, $force = false)
100
    {
101 791
        static::callSchemaResolverMethod('drop', $repositories, $force);
102 791
    }
103
104
    /**
105
     * Truncate repositories
106
     * 
107
     * @param string|array|RepositoryInterface $repositories
108
     * @param boolean                          $force @see EntityRepository::schema
0 ignored issues
show
introduced by
Parameter comment must start with a capital letter
Loading history...
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
109
     */
110 1
    public static function truncate($repositories, $force = false)
111
    {
112 1
        static::callSchemaResolverMethod('truncate', $repositories, $force);
113 1
    }
114
115
    /**
116
     * Call schema resolver method
117
     * 
118
     * @param string  $method
119
     * @param mixed   $repositories
120
     * @param boolean $force
0 ignored issues
show
introduced by
Expected "bool" but found "boolean" for parameter type
Loading history...
121
     */
122 813
    protected static function callSchemaResolverMethod($method, $repositories, $force)
123
    {
124 813
        if (!is_array($repositories)) {
125 8
            $repositories = [$repositories];
126
        }
127
        
128 813
        foreach ($repositories as $repository) {
129 581
            static::repository($repository)->schema($force)->$method();
130
        }
131 813
    }
132
    
133
    //
134
    //--------- entities
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// --------- entities" but found "//--------- entities"
Loading history...
135
    //
136
137
    /**
138
     * Push multiple entities in repository
139
     * launch replace method from repository
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...
140
     * 
141
     * User can add
142
     *  * entity object
143
     *  * collection of entity object
144
     *  * an array of entity attributes
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
145
     * 
146
     * <code>
147
     *  Prime::push(new EntityClass());
148
     *  Prime::push([new EntityClass()]);
149
     *  Prime::push($repository, ['id' => '...']);
150
     *  Prime::push('EntityClass', ['id' => '...']);
151
     *  Prime::push('EntityClass', [['id' => '...']]);
152
     * </code>
153
     * 
154
     * @param mixed $repositoryName
155
     * @param mixed $entities
156
     */
157 33
    public static function push($repositoryName, $entities = null)
158
    {
159 33
        static::callRepositoryMethod('replace', $repositoryName, $entities);
160 33
    }
161
162
    /**
163
     * Save multiple entities in repository
164
     * launch save method from repository
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...
165
     * 
166
     * User can add
167
     *  * entity object
168
     *  * collection of entity object
169
     *  * an array of entity attributes
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
170
     * 
171
     * <code>
172
     *  Prime::save(new EntityClass());
173
     *  Prime::save([new EntityClass()]);
174
     *  Prime::save($repository, ['id' => '...']);
175
     *  Prime::save('EntityClass', ['id' => '...']);
176
     *  Prime::save('EntityClass', [['id' => '...']]);
177
     * </code>
178
     * 
179
     * @param mixed $repositoryName
180
     * @param mixed $entities
181
     */
182 3
    public static function save($repositoryName, $entities = null)
183
    {
184 3
        static::callRepositoryMethod('save', $repositoryName, $entities);
185 3
    }
186
187
    /**
188
     * Remove multiple entities in repository
189
     * 
190
     * User can add
191
     *  * entity object
192
     *  * collection of entity object
193
     *  * an array of entity attributes
0 ignored issues
show
introduced by
Doc comment long description must end with a full stop
Loading history...
194
     * 
195
     * <code>
196
     *  Prime::remove(new EntityClass());
197
     *  Prime::remove([new EntityClass()]);
198
     *  Prime::remove($repository, ['id' => '...']);
199
     *  Prime::remove('EntityClass', ['id' => '...']);
200
     *  Prime::remove('EntityClass', [['id' => '...']]);
201
     * </code>
202
     * 
203
     * @param mixed $repositoryName
204
     * @param mixed $entities
205
     */
206 1
    public static function remove($repositoryName, $entities = null)
207
    {
208 1
        static::callRepositoryMethod('delete', $repositoryName, $entities);
209 1
    }
210
    
211
    /**
212
     * Call repository method for entities
213
     *  
214
     * @param string $method
215
     * @param mixed $repositoryName
216
     * @param mixed $entities
217
     */
218 36
    protected static function callRepositoryMethod($method, $repositoryName, $entities)
219
    {
220 36
        if (!is_string($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
221 19
            $entities = $repositoryName;
222 19
            $repositoryName = null;
223
        }
224
        
225 36
        if (!is_array($entities) || !isset($entities[0])) {
226 36
            $entities = [$entities];
227
        }
228
        
229 36
        foreach ($entities as $entity) {
230 36
            $repository = static::repository($repositoryName ?: $entity);
0 ignored issues
show
Coding Style introduced by
The value of a comparison must not be assigned to a variable
Loading history...
Coding Style introduced by
Inline IF statements are not allowed
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
231
            
232 36
            if (is_array($entity)) {
233 23
                $entity = $repository->entity($entity);
234
            }
235
            
236 36
            $repository->$method($entity);
237
        }
238 36
    }
239
240
    /**
241
     * Assert that entity exists
242
     * 
243
     * @param object $entity
244
     * @param bool   $compare  Will compare entity with the expected one
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
245
     * 
246
     * @return bool
0 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
247
     */
248 11
    public static function exists($entity, $compare = true)
249
    {
250 11
        $repository = static::repository($entity);
251
        
252 11
        $expected = $repository->findOne($repository->mapper()->primaryCriteria($entity));
0 ignored issues
show
Bug introduced by
The method findOne() does not exist on Bdf\Prime\Repository\RepositoryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Repository\RepositoryInterface. ( Ignorable by Annotation )

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

252
        /** @scrutinizer ignore-call */ 
253
        $expected = $repository->findOne($repository->mapper()->primaryCriteria($entity));
Loading history...
253
        
254 11
        if ($expected === null) {
255
            return false;
256
        }
257
        
258 11
        if (!$compare) {
259 4
            return true;
260
        }
261
        
262 8
        return $entity == $expected 
263 8
                ? true
0 ignored issues
show
Coding Style introduced by
Inline IF statements are not allowed
Loading history...
Coding Style introduced by
Inline shorthand IF statement must be declared on a single line
Loading history...
264 8
                : serialize($entity) === serialize($expected);
265
    }
266
267
    /**
268
     * Find entity
269
     * 
270
     * <code>
271
     *  Prime::find(new EntityClass());
272
     *  Prime::find('EntityClass', ['id' => '...']);
273
     *  Prime::find($repository, ['id' => '...']);
274
     * </code>
275
     * 
276
     * @param string|RepositoryInterface  $repositoryName     Repo name or Entity instance
277
     * @param array|object                $criteria           Array of criteria. Optionnal if repository name is an object
278
     * 
279
     * @return object|array
280
     */
281 1
    public static function find($repositoryName, $criteria = null)
282
    {
283 1
        $repository = static::repository($repositoryName);
284
        
285
        // if $repositoryName is an entity
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
286 1
        if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
0 ignored issues
show
introduced by
$repositoryName is always a sub-type of Bdf\Prime\Repository\RepositoryInterface.
Loading history...
287
            $criteria = $repository->mapper()->prepareToRepository($repositoryName);
288
        }
289
        
290 1
        return $repository->find($criteria);
0 ignored issues
show
Bug introduced by
The method find() does not exist on Bdf\Prime\Repository\RepositoryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Repository\RepositoryInterface. ( Ignorable by Annotation )

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

290
        return $repository->/** @scrutinizer ignore-call */ find($criteria);
Loading history...
291
    }
292
293
    /**
294
     * Find one entity
295
     * 
296
     * <code>
297
     *  Prime::one(new EntityClass());
298
     *  Prime::one('EntityClass', ['id' => '...']);
299
     *  Prime::one($repository, ['id' => '...']);
300
     * </code>
301
     * 
302
     * @param string|RepositoryInterface  $repositoryName     Repo name or Entity instance
303
     * @param array|object                $criteria           Array of criteria. Optionnal if repository name is an object
304
     * 
305
     * @return object|array
306
     */
307 2
    public static function one($repositoryName, $criteria = null)
308
    {
309 2
        $repository = static::repository($repositoryName);
310
        
311
        // if $repositoryName is an entity
0 ignored issues
show
Coding Style Documentation introduced by
Inline comments must start with a capital letter
Loading history...
312 2
        if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
0 ignored issues
show
introduced by
$repositoryName is always a sub-type of Bdf\Prime\Repository\RepositoryInterface.
Loading history...
313 1
            $criteria = $repository->mapper()->prepareToRepository($repositoryName);
314
        }
315
        
316 2
        return $repository->findOne($criteria);
317
    }
318
319
    /**
320
     * Refresh entity from repository
321
     * 
322
     * @param object $entity
323
     * @param array  $additionnalCriteria  Criteria to add to primary key
324
     * 
325
     * @return object New refresh entity
326
     */
327 1
    public static function refresh($entity, $additionnalCriteria = [])
0 ignored issues
show
introduced by
Type hint "array" missing for $additionnalCriteria
Loading history...
328
    {
329 1
        $repository = static::repository($entity);
330
        
331 1
        return $repository->findOne($repository->mapper()->primaryCriteria($entity) + $additionnalCriteria);
332
    }
333
    
334
    //
335
    //--------- service
0 ignored issues
show
Coding Style introduced by
No space found before comment text; expected "// --------- service" but found "//--------- service"
Loading history...
336
    //
337
    
338
    /**
339
     * Get active connection from profile name
340
     * 
341
     * @param string $name
342
     * 
343
     * @return ConnectionInterface
344
     */
345 291
    public static function connection($name = null)
346
    {
347 291
        return static::service()->connection($name);
348
    }
349
350
    /**
351
     * Get service locator
352
     * 
353
     * @return ServiceLocator
354
     */
355 1305
    public static function service()
356
    {
357 1305
        if (static::$serviceLocator === null) {
358 71
            static::initialize();
359
        }
360
361 1305
        return static::$serviceLocator;
362
    }
363
364
    /**
365
     * Initializes the service locator
366
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag in function comment
Loading history...
367 71
    protected static function initialize()
368
    {
369 71
        if (static::$config instanceof ContainerInterface) {
370
            static::$serviceLocator = static::$config->get('prime');
371
            
372
            return;
373
        }
374
        
375 71
        if (!is_array(static::$config)) {
376
            throw new RuntimeException('Prime is not configured');
377
        }
378
379 71
        $factory = new ConnectionFactory();
380 71
        $registry = new ConnectionRegistry(
381 71
            static::$config['connection']['config'] ?? [],
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
382 71
            new ChainFactory([
383 71
                new MasterSlaveConnectionFactory($factory),
384 71
                new ShardingConnectionFactory($factory),
385 71
                $factory,
386
            ])
387
        );
388
389 71
        $mapperFactory = new MapperFactory(
390 71
            null,
391 71
            static::$config['metadataCache'] ?? null,
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
392 71
            static::$config['resultCache'] ?? null
0 ignored issues
show
Coding Style introduced by
Operation must be bracketed
Loading history...
393
        );
394
395 71
        static::$serviceLocator = new ServiceLocator(
396 71
            new ConnectionManager($registry),
397 71
            $mapperFactory
398
        );
399
400 71
        if ($logger = static::$config['logger'] ?? null) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
401
            $registry->getDefaultConfiguration()->setSQLLogger($logger);
402
        }
403
404
        // TODO remove in 1.2. Inject caches for legacy usage
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...
405 71
        if ($cache = static::$config['resultCache'] ?? null) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
406
            $registry->getDefaultConfiguration()->setResultCache($cache);
407
        }
408
409 71
        if ($cache = static::$config['metadataCache'] ?? null) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
410
            $registry->getDefaultConfiguration()->setMetadataCache($cache);
411
        }
412
413 71
        if ($serializer = static::$config['serializer'] ?? null) {
0 ignored issues
show
Coding Style introduced by
Variable assignment found within a condition. Did you mean to do a comparison ?
Loading history...
Coding Style introduced by
Assignments must be the first block of code on a line
Loading history...
Coding Style introduced by
Operation must be bracketed
Loading history...
414
            static::$serviceLocator->setSerializer($serializer);
415
        }
416 71
    }
417
}
418