1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Bdf\Prime; |
4
|
|
|
|
5
|
|
|
use Bdf\Prime\Connection\ConnectionInterface; |
|
|
|
|
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 |
|
|
|
|
22
|
|
|
*/ |
23
|
|
|
class Prime |
24
|
|
|
{ |
25
|
|
|
/** |
26
|
|
|
* @var mixed |
27
|
|
|
*/ |
28
|
|
|
protected static $config; |
|
|
|
|
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) |
|
|
|
|
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 |
|
|
|
|
56
|
|
|
*/ |
57
|
1291 |
|
public static function isConfigured() |
58
|
|
|
{ |
59
|
1291 |
|
return static::$config !== null; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
// |
63
|
|
|
//--------- repository |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
135
|
|
|
// |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Push multiple entities in repository |
139
|
|
|
* launch replace method from repository |
|
|
|
|
140
|
|
|
* |
141
|
|
|
* User can add |
142
|
|
|
* * entity object |
143
|
|
|
* * collection of entity object |
144
|
|
|
* * an array of entity attributes |
|
|
|
|
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 |
|
|
|
|
165
|
|
|
* |
166
|
|
|
* User can add |
167
|
|
|
* * entity object |
168
|
|
|
* * collection of entity object |
169
|
|
|
* * an array of entity attributes |
|
|
|
|
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 |
|
|
|
|
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); |
|
|
|
|
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 |
|
|
|
|
245
|
|
|
* |
246
|
|
|
* @return bool |
|
|
|
|
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)); |
|
|
|
|
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 |
|
|
|
|
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 |
|
|
|
|
286
|
1 |
|
if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) { |
|
|
|
|
287
|
|
|
$criteria = $repository->mapper()->prepareToRepository($repositoryName); |
288
|
|
|
} |
289
|
|
|
|
290
|
1 |
|
return $repository->find($criteria); |
|
|
|
|
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 |
|
|
|
|
312
|
2 |
|
if (is_object($repositoryName) && !$repositoryName instanceof RepositoryInterface) { |
|
|
|
|
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 = []) |
|
|
|
|
328
|
|
|
{ |
329
|
1 |
|
$repository = static::repository($entity); |
330
|
|
|
|
331
|
1 |
|
return $repository->findOne($repository->mapper()->primaryCriteria($entity) + $additionnalCriteria); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
// |
335
|
|
|
//--------- service |
|
|
|
|
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
|
|
|
*/ |
|
|
|
|
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'] ?? [], |
|
|
|
|
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, |
|
|
|
|
392
|
71 |
|
static::$config['resultCache'] ?? null |
|
|
|
|
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) { |
|
|
|
|
401
|
|
|
$registry->getDefaultConfiguration()->setSQLLogger($logger); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
// TODO remove in 1.2. Inject caches for legacy usage |
|
|
|
|
405
|
71 |
|
if ($cache = static::$config['resultCache'] ?? null) { |
|
|
|
|
406
|
|
|
$registry->getDefaultConfiguration()->setResultCache($cache); |
407
|
|
|
} |
408
|
|
|
|
409
|
71 |
|
if ($cache = static::$config['metadataCache'] ?? null) { |
|
|
|
|
410
|
|
|
$registry->getDefaultConfiguration()->setMetadataCache($cache); |
411
|
|
|
} |
412
|
|
|
|
413
|
71 |
|
if ($serializer = static::$config['serializer'] ?? null) { |
|
|
|
|
414
|
|
|
static::$serviceLocator->setSerializer($serializer); |
415
|
|
|
} |
416
|
71 |
|
} |
417
|
|
|
} |
418
|
|
|
|