Passed
Push — fix-FRAM-102-disallow-using-sa... ( a4f1ec...3b9f7b )
by Vincent
23:20 queued 17:19
created

Prime::push()   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;
4
5
use Bdf\Prime\Connection\Configuration\ConfigurationResolver;
6
use Bdf\Prime\Connection\ConnectionInterface;
7
use Bdf\Prime\Connection\ConnectionRegistry;
8
use Bdf\Prime\Connection\Factory\ChainFactory;
9
use Bdf\Prime\Connection\Factory\ConnectionFactory;
10
use Bdf\Prime\Connection\Factory\MasterSlaveConnectionFactory;
11
use Bdf\Prime\Connection\Factory\ShardingConnectionFactory;
12
use Bdf\Prime\Exception\PrimeException;
13
use Bdf\Prime\Mapper\MapperFactory;
14
use Bdf\Prime\Repository\RepositoryInterface;
15
use Psr\Container\ContainerInterface;
16
use RuntimeException;
17
18
/**
19
 * Prime
20
 *
21
 * Usefull facade to manipulate repositories
22
 * Allow user to create, drop, truncate repositories
23
 * Allow user to find, insert entities
24
 */
25
class Prime
26
{
27
    /**
28
     * @var mixed
29
     */
30
    protected static $config;
31
32
    /**
33
     * @var ServiceLocator
34
     */
35
    protected static $serviceLocator;
36
37
38
    /**
39
     * Configure the locator
40
     *
41
     * @param array|ContainerInterface|ServiceLocator $config
42
     *
43
     * @return void
44
     */
45 369
    public static function configure($config): void
46
    {
47 369
        if ($config instanceof ServiceLocator) {
48 1
            static::$config = null;
49 1
            static::$serviceLocator = $config;
50
        } else {
51 368
            static::$config = $config;
52 368
            static::$serviceLocator = null;
53
        }
54
    }
55
56
    /**
57
     * Check whether prime is configured
58
     *
59
     * @return bool
60
     */
61 1656
    public static function isConfigured()
62
    {
63 1656
        return static::$config !== null;
64
    }
65
66
    //
67
    //--------- repository
68
    //
69
70
    /**
71
     * Get a repository
72
     *
73
     * @param class-string<T>|RepositoryInterface<T>|T $repository
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|RepositoryInterface<T>|T at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|RepositoryInterface<T>|T.
Loading history...
74
     *
75
     * @return RepositoryInterface<T>|null
76
     *
77
     * @template T as object
78
     */
79 976
    public static function repository($repository)
80
    {
81 976
        if ($repository instanceof RepositoryInterface) {
82
            /** @var RepositoryInterface<T> $repository */
83 6
            return $repository;
84
        }
85
86 976
        return static::service()->repository($repository);
87
    }
88
89
    /**
90
     * Create repositories
91
     *
92
     * @param string|array|RepositoryInterface $repositories
93
     * @param boolean                          $force @see EntityRepository::schema
94
     *
95
     * @throws PrimeException
96
     *
97
     * @return void
98
     */
99 1150
    public static function create($repositories, $force = false): void
100
    {
101 1150
        static::callSchemaResolverMethod('migrate', $repositories, $force);
102
    }
103
104
    /**
105
     * Drop repositories
106
     *
107
     * @param string|array|RepositoryInterface $repositories
108
     * @param boolean                          $force @see EntityRepository::schema
109
     *
110
     * @throws PrimeException
111
     *
112
     * @return void
113
     */
114 1135
    public static function drop($repositories, $force = false): void
115
    {
116 1135
        static::callSchemaResolverMethod('drop', $repositories, $force);
117
    }
118
119
    /**
120
     * Truncate repositories
121
     *
122
     * @param string|array|RepositoryInterface $repositories
123
     * @param boolean                          $force @see EntityRepository::schema
124
     *
125
     * @throws PrimeException
126
     *
127
     * @return void
128
     */
129 1
    public static function truncate($repositories, $force = false): void
130
    {
131 1
        static::callSchemaResolverMethod('truncate', $repositories, $force);
132
    }
133
134
    /**
135
     * Call schema resolver method
136
     *
137
     * @param string  $method
138
     * @param mixed   $repositories
139
     * @param boolean $force
140
     *
141
     * @throws PrimeException
142
     *
143
     * @return void
144
     */
145 1163
    protected static function callSchemaResolverMethod($method, $repositories, $force): void
146
    {
147 1163
        if (!is_array($repositories)) {
148 8
            $repositories = [$repositories];
149
        }
150
151 1163
        foreach ($repositories as $repository) {
152 857
            static::repository($repository)->schema($force)->$method();
153
        }
154
    }
155
156
    //
157
    //--------- entities
158
    //
159
160
    /**
161
     * Push multiple entities in repository
162
     * launch replace method from repository
163
     *
164
     * User can add
165
     *  * entity object
166
     *  * collection of entity object
167
     *  * an array of entity attributes
168
     *
169
     * <code>
170
     *  Prime::push(new EntityClass());
171
     *  Prime::push([new EntityClass()]);
172
     *  Prime::push($repository, ['id' => '...']);
173
     *  Prime::push('EntityClass', ['id' => '...']);
174
     *  Prime::push('EntityClass', [['id' => '...']]);
175
     * </code>
176
     *
177
     * @param mixed $repositoryName
178
     * @param mixed $entities
179
     *
180
     * @throws PrimeException
181
     *
182
     * @return void
183
     */
184 43
    public static function push($repositoryName, $entities = null): void
185
    {
186 43
        static::callRepositoryMethod('replace', $repositoryName, $entities);
187
    }
188
189
    /**
190
     * Save multiple entities in repository
191
     * launch save method from repository
192
     *
193
     * User can add
194
     *  * entity object
195
     *  * collection of entity object
196
     *  * an array of entity attributes
197
     *
198
     * <code>
199
     *  Prime::save(new EntityClass());
200
     *  Prime::save([new EntityClass()]);
201
     *  Prime::save($repository, ['id' => '...']);
202
     *  Prime::save('EntityClass', ['id' => '...']);
203
     *  Prime::save('EntityClass', [['id' => '...']]);
204
     * </code>
205
     *
206
     * @param mixed $repositoryName
207
     * @param mixed $entities
208
     *
209
     * @throws PrimeException
210
     *
211
     * @return void
212
     */
213 3
    public static function save($repositoryName, $entities = null): void
214
    {
215 3
        static::callRepositoryMethod('save', $repositoryName, $entities);
216
    }
217
218
    /**
219
     * Remove multiple entities in repository
220
     *
221
     * User can add
222
     *  * entity object
223
     *  * collection of entity object
224
     *  * an array of entity attributes
225
     *
226
     * <code>
227
     *  Prime::remove(new EntityClass());
228
     *  Prime::remove([new EntityClass()]);
229
     *  Prime::remove($repository, ['id' => '...']);
230
     *  Prime::remove('EntityClass', ['id' => '...']);
231
     *  Prime::remove('EntityClass', [['id' => '...']]);
232
     * </code>
233
     *
234
     * @param mixed $repositoryName
235
     * @param mixed $entities
236
     *
237
     * @throws PrimeException
238
     *
239
     * @return void
240
     */
241 1
    public static function remove($repositoryName, $entities = null): void
242
    {
243 1
        static::callRepositoryMethod('delete', $repositoryName, $entities);
244
    }
245
246
    /**
247
     * Call repository method for entities
248
     *
249
     * @param string $method
250
     * @param mixed $repositoryName
251
     * @param mixed $entities
252
     *
253
     * @throws PrimeException
254
     *
255
     * @return void
256
     */
257 46
    protected static function callRepositoryMethod($method, $repositoryName, $entities): void
258
    {
259 46
        if (!is_string($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
260 29
            $entities = $repositoryName;
261 29
            $repositoryName = null;
262
        }
263
264 46
        if (!is_array($entities) || !isset($entities[0])) {
265 46
            $entities = [$entities];
266
        }
267
268 46
        foreach ($entities as $entity) {
269 46
            $repository = static::repository($repositoryName ?: $entity);
270
271 46
            if (is_array($entity)) {
272 31
                $entity = $repository->entity($entity);
273
            }
274
275 46
            $repository->$method($entity);
276
        }
277
    }
278
279
    /**
280
     * Assert that entity exists
281
     *
282
     * @param object $entity
283
     * @param bool   $compare  Will compare entity with the expected one
284
     *
285
     * @return bool
286
     *
287
     * @throws PrimeException
288
     */
289 13
    public static function exists($entity, $compare = true)
290
    {
291 13
        $repository = static::repository($entity);
292
293 13
        $expected = $repository->refresh($entity);
294
295 13
        if ($expected === null) {
296
            return false;
297
        }
298
299 13
        if (!$compare) {
300 4
            return true;
301
        }
302
303 10
        return $entity == $expected
304 10
                ? true
305 10
                : serialize($entity) === serialize($expected);
306
    }
307
308
    /**
309
     * Find entity
310
     *
311
     * <code>
312
     *  Prime::find(new EntityClass());
313
     *  Prime::find('EntityClass', ['id' => '...']);
314
     *  Prime::find($repository, ['id' => '...']);
315
     * </code>
316
     *
317
     * @param class-string<T>|RepositoryInterface<T>|T $repositoryName Repo name or Entity instance
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|RepositoryInterface<T>|T at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|RepositoryInterface<T>|T.
Loading history...
318
     * @param array|object|null $criteria Array of criteria. Optional if repository name is an object
319
     *
320
     * @return T[]|\Bdf\Prime\Collection\CollectionInterface<T>
321
     *
322
     * @throws PrimeException
323
     *
324
     * @template T as object
325
     */
326 1
    public static function find($repositoryName, $criteria = null)
327
    {
328
        /** @psalm-suppress InvalidArgument */
329 1
        $repository = static::repository($repositoryName);
330
331
        // if $repositoryName is an entity
332 1
        if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
333
            $criteria = $repository->mapper()->prepareToRepository($repositoryName);
334
        }
335
336 1
        return $repository->queries()->builder()->where($criteria)->all();
337
    }
338
339
    /**
340
     * Find one entity
341
     *
342
     * <code>
343
     *  Prime::one(new EntityClass());
344
     *  Prime::one('EntityClass', ['id' => '...']);
345
     *  Prime::one($repository, ['id' => '...']);
346
     * </code>
347
     *
348
     * @param class-string<T>|RepositoryInterface<T>|T $repositoryName Repo name or Entity instance
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|RepositoryInterface<T>|T at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|RepositoryInterface<T>|T.
Loading history...
349
     * @param array|object|null $criteria Array of criteria. Optional if repository name is an object
350
     *
351
     * @return T|null
352
     *
353
     * @throws PrimeException
354
     *
355
     * @template T as object
356
     */
357 2
    public static function one($repositoryName, $criteria = null)
358
    {
359
        /** @psalm-suppress InvalidArgument */
360 2
        $repository = static::repository($repositoryName);
361
362
        // if $repositoryName is an entity
363 2
        if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) {
364 1
            $criteria = $repository->mapper()->prepareToRepository($repositoryName);
365
        }
366
367 2
        return $repository->queries()->builder()->where($criteria)->first();
368
    }
369
370
    /**
371
     * Refresh entity from repository
372
     *
373
     * @param T $entity
374
     * @param array $additionalCriteria  Criteria to add to primary key
375
     *
376
     * @return T|null New refresh entity
377
     *
378
     * @throws PrimeException
379
     *
380
     * @template T as object
381
     */
382 1
    public static function refresh($entity, $additionalCriteria = [])
383
    {
384 1
        $repository = static::repository($entity);
385
386 1
        return $repository->refresh($entity, $additionalCriteria);
387
    }
388
389
    //
390
    //--------- service
391
    //
392
393
    /**
394
     * Get active connection from profile name
395
     *
396
     * @param string $name
397
     *
398
     * @return ConnectionInterface
399
     */
400 313
    public static function connection($name = null)
401
    {
402 313
        return static::service()->connection($name);
403
    }
404
405
    /**
406
     * Get service locator
407
     *
408
     * @return ServiceLocator
409
     */
410 1670
    public static function service()
411
    {
412 1670
        if (static::$serviceLocator === null) {
413 360
            static::initialize();
414
        }
415
416 1670
        return static::$serviceLocator;
417
    }
418
419
    /**
420
     * Initializes the service locator
421
     *
422
     * @return void
423
     */
424 360
    protected static function initialize()
425
    {
426 360
        if (static::$config instanceof ContainerInterface) {
427
            static::$serviceLocator = static::$config->get('prime');
428
429
            return;
430
        }
431
432 360
        if (!is_array(static::$config)) {
433
            throw new RuntimeException('Prime is not configured');
434
        }
435
436 360
        $factory = new ConnectionFactory();
437 360
        $registry = new ConnectionRegistry(
438 360
            static::$config['connection']['config'] ?? [],
439 360
            new ChainFactory([
440 360
                new MasterSlaveConnectionFactory($factory),
441 360
                new ShardingConnectionFactory($factory),
442 360
                $factory,
443 360
            ]),
444 360
            new ConfigurationResolver([], $configuration = new Configuration())
445 360
        );
446
447 360
        $mapperFactory = new MapperFactory(
448 360
            null,
449 360
            static::$config['metadataCache'] ?? null,
450 360
            static::$config['resultCache'] ?? null
451 360
        );
452
453 360
        static::$serviceLocator = new ServiceLocator(
454 360
            new ConnectionManager($registry),
455 360
            $mapperFactory
456 360
        );
457
458 360
        if ($logger = static::$config['logger'] ?? null) {
459
            /** @psalm-suppress InternalMethod */
460
            $configuration->setSQLLogger($logger);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Configuration::setSQLLogger() has been deprecated: Use {@see setMiddlewares()} and {@see \Doctrine\DBAL\Logging\Middleware} instead. ( Ignorable by Annotation )

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

460
            /** @scrutinizer ignore-deprecated */ $configuration->setSQLLogger($logger);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
461
        }
462
463 360
        if ($types = static::$config['types'] ?? null) {
464 360
            foreach ($types as $alias => $type) {
465 360
                $configuration->getTypes()->register($type, is_string($alias) ? $alias : null);
466
            }
467
        }
468
469 360
        if ($types = static::$config['platformTypes'] ?? null) {
470 1
            foreach ($types as $alias => $type) {
471 1
                $configuration->addPlatformType($type, is_string($alias) ? $alias : null);
472
            }
473
        }
474
475 360
        if ($serializer = static::$config['serializer'] ?? null) {
476
            static::$serviceLocator->setSerializer($serializer);
477
        }
478
    }
479
}
480