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 | 368 | public static function configure($config): void |
|||
46 | { |
||||
47 | 368 | if ($config instanceof ServiceLocator) { |
|||
48 | 1 | static::$config = null; |
|||
49 | 1 | static::$serviceLocator = $config; |
|||
50 | } else { |
||||
51 | 367 | static::$config = $config; |
|||
52 | 367 | static::$serviceLocator = null; |
|||
53 | } |
||||
54 | } |
||||
55 | |||||
56 | /** |
||||
57 | * Check whether prime is configured |
||||
58 | * |
||||
59 | * @return bool |
||||
60 | */ |
||||
61 | 1650 | public static function isConfigured() |
|||
62 | { |
||||
63 | 1650 | 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
![]() |
|||||
74 | * |
||||
75 | * @return RepositoryInterface<T>|null |
||||
76 | * |
||||
77 | * @template T as object |
||||
78 | */ |
||||
79 | 975 | public static function repository($repository) |
|||
80 | { |
||||
81 | 975 | if ($repository instanceof RepositoryInterface) { |
|||
82 | /** @var RepositoryInterface<T> $repository */ |
||||
83 | 6 | return $repository; |
|||
84 | } |
||||
85 | |||||
86 | 975 | 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 | 1149 | public static function create($repositories, $force = false): void |
|||
100 | { |
||||
101 | 1149 | 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 | 1134 | public static function drop($repositories, $force = false): void |
|||
115 | { |
||||
116 | 1134 | 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 | 1162 | protected static function callSchemaResolverMethod($method, $repositories, $force): void |
|||
146 | { |
||||
147 | 1162 | if (!is_array($repositories)) { |
|||
148 | 8 | $repositories = [$repositories]; |
|||
149 | } |
||||
150 | |||||
151 | 1162 | foreach ($repositories as $repository) { |
|||
152 | 856 | 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
|
|||||
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
|
|||||
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 | 312 | public static function connection($name = null) |
|||
401 | { |
||||
402 | 312 | return static::service()->connection($name); |
|||
403 | } |
||||
404 | |||||
405 | /** |
||||
406 | * Get service locator |
||||
407 | * |
||||
408 | * @return ServiceLocator |
||||
409 | */ |
||||
410 | 1664 | public static function service() |
|||
411 | { |
||||
412 | 1664 | if (static::$serviceLocator === null) { |
|||
413 | 359 | static::initialize(); |
|||
414 | } |
||||
415 | |||||
416 | 1664 | return static::$serviceLocator; |
|||
417 | } |
||||
418 | |||||
419 | /** |
||||
420 | * Initializes the service locator |
||||
421 | * |
||||
422 | * @return void |
||||
423 | */ |
||||
424 | 359 | protected static function initialize() |
|||
425 | { |
||||
426 | 359 | if (static::$config instanceof ContainerInterface) { |
|||
427 | static::$serviceLocator = static::$config->get('prime'); |
||||
428 | |||||
429 | return; |
||||
430 | } |
||||
431 | |||||
432 | 359 | if (!is_array(static::$config)) { |
|||
433 | throw new RuntimeException('Prime is not configured'); |
||||
434 | } |
||||
435 | |||||
436 | 359 | $factory = new ConnectionFactory(); |
|||
437 | 359 | $registry = new ConnectionRegistry( |
|||
438 | 359 | static::$config['connection']['config'] ?? [], |
|||
439 | 359 | new ChainFactory([ |
|||
440 | 359 | new MasterSlaveConnectionFactory($factory), |
|||
441 | 359 | new ShardingConnectionFactory($factory), |
|||
442 | 359 | $factory, |
|||
443 | 359 | ]), |
|||
444 | 359 | new ConfigurationResolver([], $configuration = new Configuration()) |
|||
445 | 359 | ); |
|||
446 | |||||
447 | 359 | $mapperFactory = new MapperFactory( |
|||
448 | 359 | null, |
|||
449 | 359 | static::$config['metadataCache'] ?? null, |
|||
450 | 359 | static::$config['resultCache'] ?? null |
|||
451 | 359 | ); |
|||
452 | |||||
453 | 359 | static::$serviceLocator = new ServiceLocator( |
|||
454 | 359 | new ConnectionManager($registry), |
|||
455 | 359 | $mapperFactory |
|||
456 | 359 | ); |
|||
457 | |||||
458 | 359 | if ($logger = static::$config['logger'] ?? null) { |
|||
459 | /** @psalm-suppress InternalMethod */ |
||||
460 | $configuration->setSQLLogger($logger); |
||||
0 ignored issues
–
show
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
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. ![]() |
|||||
461 | } |
||||
462 | |||||
463 | 359 | if ($types = static::$config['types'] ?? null) { |
|||
464 | 359 | foreach ($types as $alias => $type) { |
|||
465 | 359 | $configuration->getTypes()->register($type, is_string($alias) ? $alias : null); |
|||
466 | } |
||||
467 | } |
||||
468 | |||||
469 | 359 | if ($serializer = static::$config['serializer'] ?? null) { |
|||
470 | static::$serviceLocator->setSerializer($serializer); |
||||
471 | } |
||||
472 | } |
||||
473 | } |
||||
474 |