1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* (c) FSi sp. z o.o. <[email protected]> |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
declare(strict_types=1); |
11
|
|
|
|
12
|
|
|
namespace FSi\Bundle\AdminBundle\Behat\Context; |
13
|
|
|
|
14
|
|
|
use Behat\Gherkin\Node\TableNode; |
15
|
|
|
use DateTime; |
16
|
|
|
use Doctrine\ORM\Tools\SchemaTool; |
17
|
|
|
use FSi\FixturesBundle\Entity\Category; |
18
|
|
|
use FSi\FixturesBundle\Entity\News; |
19
|
|
|
use FSi\FixturesBundle\Entity\Person; |
20
|
|
|
use FSi\FixturesBundle\Entity\Subscriber; |
21
|
|
|
use FSi\FixturesBundle\Entity\Tag; |
22
|
|
|
use InvalidArgumentException; |
23
|
|
|
use RuntimeException; |
24
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccess; |
25
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccessor; |
26
|
|
|
use function expect; |
27
|
|
|
use function file_exists; |
28
|
|
|
|
29
|
|
|
class DataContext extends AbstractContext |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* @var PropertyAccessor|null |
33
|
|
|
*/ |
34
|
|
|
private $propertyAccessor = null; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @BeforeScenario |
38
|
|
|
*/ |
39
|
|
|
public function createDatabase(): void |
40
|
|
|
{ |
41
|
|
|
$this->deleteDatabaseIfExist(); |
42
|
|
|
|
43
|
|
|
$entityManager = $this->getEntityManager(); |
44
|
|
|
$metadata = $entityManager->getMetadataFactory()->getAllMetadata(); |
45
|
|
|
|
46
|
|
|
$tool = new SchemaTool($entityManager); |
47
|
|
|
$tool->createSchema($metadata); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @AfterScenario |
52
|
|
|
*/ |
53
|
|
|
public function deleteDatabaseIfExist(): void |
54
|
|
|
{ |
55
|
|
|
$dbFilePath = $this->getKernel()->getRootDir() . '/data.sqlite'; |
|
|
|
|
56
|
|
|
if (true === file_exists($dbFilePath)) { |
57
|
|
|
unlink($dbFilePath); |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @Transform :className |
63
|
|
|
*/ |
64
|
|
|
public function entityToClassName(string $entityName): string |
65
|
|
|
{ |
66
|
|
|
switch ($entityName) { |
67
|
|
|
case 'news': |
68
|
|
|
return News::class; |
69
|
|
|
case 'category': |
70
|
|
|
case 'categories': |
71
|
|
|
return Category::class; |
72
|
|
|
case 'subscriber': |
73
|
|
|
case 'subscribers': |
74
|
|
|
return Subscriber::class; |
75
|
|
|
case 'person': |
76
|
|
|
return Person::class; |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @Given there are :count :className |
82
|
|
|
* @Given there is :count :className |
83
|
|
|
*/ |
84
|
|
|
public function thereIsNumberOfEntities(int $count, string $className) |
85
|
|
|
{ |
86
|
|
|
$entityManager = $this->getEntityManager(); |
87
|
|
|
for ($i = 0; $i < $count; $i++) { |
88
|
|
|
$instance = new $className(); |
89
|
|
|
$this->applyFieldFormatters($instance); |
90
|
|
|
$this->applyEntityModifiers($instance); |
91
|
|
|
$entityManager->persist($instance); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
$entityManager->flush(); |
95
|
|
|
|
96
|
|
|
expect(count($this->getRepository($className)->findAll()))->toBe($count); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @Given there is a :className with :field :value present in the database |
101
|
|
|
*/ |
102
|
|
|
public function thereIsAnEntityWithField(string $className, string $field, $value) |
103
|
|
|
{ |
104
|
|
|
$instance = new $className(); |
105
|
|
|
$formatters = $this->getFieldFormatters($className); |
106
|
|
|
$formatters[$field] = function () use ($value) { |
107
|
|
|
return $this->parseScenarioValue((string) $value); |
108
|
|
|
}; |
109
|
|
|
$this->applyEntityModifiers($instance); |
110
|
|
|
$this->applyFieldFormatters($instance, $formatters); |
111
|
|
|
|
112
|
|
|
$entityManager = $this->getEntityManager(); |
113
|
|
|
$entityManager->persist($instance); |
114
|
|
|
$entityManager->flush(); |
115
|
|
|
|
116
|
|
|
expect($this->getRepository($className)->findOneBy([$field => $value]))->toBeAnInstanceOf($className); |
|
|
|
|
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @Then there should be a :className with :field :value present in the database |
121
|
|
|
*/ |
122
|
|
|
public function entityWithFieldShouldExist(string $className, string $field, $value) |
123
|
|
|
{ |
124
|
|
|
expect($this->getRepository($className)->findOneBy([$field => $value]))->toBeAnInstanceOf($className); |
|
|
|
|
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @Given :className with :field :value should not exist in database anymore |
129
|
|
|
*/ |
130
|
|
|
public function entityShouldNotExistInDatabaseAnymore(string $className, string $field, $value) |
131
|
|
|
{ |
132
|
|
|
expect($this->getRepository($className)->findOneBy([$field => $value]))->toBe(null); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @Then new :className should be created |
137
|
|
|
*/ |
138
|
|
|
public function newEntityShouldBeCreated(string $className) |
139
|
|
|
{ |
140
|
|
|
$this->thereShouldExistsNumberOfEntities(1, $className); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @Then there should not be any :className present in the database |
145
|
|
|
*/ |
146
|
|
|
public function thereShouldNotBeAnyEntities(string $className) |
147
|
|
|
{ |
148
|
|
|
$this->thereShouldExistsNumberOfEntities(0, $className); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @Then there should be :count :className present in the database |
153
|
|
|
*/ |
154
|
|
|
public function thereShouldExistsNumberOfEntities($count, string $className) |
155
|
|
|
{ |
156
|
|
|
expect(count($this->getRepository($className)->findAll()))->toBe($count); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @Given /^the following news exist in database$/ |
161
|
|
|
*/ |
162
|
|
|
public function followingNewsExistInDatabase(TableNode $table) |
163
|
|
|
{ |
164
|
|
|
$manager = $this->getEntityManager(); |
165
|
|
|
$faker = $this->getFaker(); |
166
|
|
|
$newsRepository = $this->getRepository(News::class); |
167
|
|
|
$categoryRepository = $this->getRepository(Category::class); |
168
|
|
|
|
169
|
|
|
foreach ($table->getHash() as $newsNode) { |
170
|
|
|
$news = $newsRepository->findOneByTitle($newsNode['Title']); |
171
|
|
|
if (!isset($news)) { |
172
|
|
|
$news = new News(); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$news->setTitle($newsNode['Title']); |
176
|
|
|
if (isset($newsNode['Date']) && $newsNode['Date']) { |
177
|
|
|
$news->setDate(DateTime::createFromFormat('Y-m-d', $newsNode['Date'])); |
178
|
|
|
} |
179
|
|
|
if (isset($newsNode['Category']) && $newsNode['Category']) { |
180
|
|
|
/** @var Category|null $category */ |
181
|
|
|
$category = $categoryRepository->findOneBy(['title' => $newsNode['Category']]); |
182
|
|
|
|
183
|
|
|
if ($category === null) { |
184
|
|
|
throw new InvalidArgumentException(sprintf( |
185
|
|
|
'Can\'t find category by title "%s"', |
186
|
|
|
$newsNode['Category'] |
187
|
|
|
)); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
$news->addCategory($category); |
191
|
|
|
} |
192
|
|
|
$news->setCreatedAt($faker->dateTime()); |
193
|
|
|
$news->setVisible($faker->boolean()); |
194
|
|
|
$news->setCreatorEmail($faker->email()); |
195
|
|
|
|
196
|
|
|
$manager->persist($news); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
$manager->flush(); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @Then :className with :field :value should have :expectedCount elements in collection :collectionName |
204
|
|
|
*/ |
205
|
|
|
public function entityShouldHaveElementsInCollection( |
206
|
|
|
string $className, |
207
|
|
|
string $field, |
208
|
|
|
$value, |
209
|
|
|
$expectedCount, |
210
|
|
|
string $collectionName |
211
|
|
|
) { |
212
|
|
|
$entity = $this->getRepository($className)->findOneBy([$field => $value]); |
213
|
|
|
$this->getEntityManager()->refresh($entity); |
|
|
|
|
214
|
|
|
|
215
|
|
|
expect(count($this->getEntityField($entity, $collectionName)))->toBe($expectedCount); |
|
|
|
|
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* @Then :className with id :id should have changed :field to :value |
220
|
|
|
*/ |
221
|
|
|
public function entityWithIdShouldHaveChangedField(string $className, $id, string $field, $value) |
222
|
|
|
{ |
223
|
|
|
$entity = $this->getRepository($className)->find($id); |
224
|
|
|
$this->getEntityManager()->refresh($entity); |
|
|
|
|
225
|
|
|
|
226
|
|
|
expect($this->getEntityField($entity, $field))->toBe($value); |
|
|
|
|
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @Then :className with id :id should not have his :field changed to :value |
231
|
|
|
*/ |
232
|
|
|
public function entityWithIdShouldNotHaveChangedFieldValue(string $className, $id, string $field, $value) |
233
|
|
|
{ |
234
|
|
|
$entity = $this->getRepository($className)->find($id); |
235
|
|
|
$this->getEntityManager()->refresh($entity); |
|
|
|
|
236
|
|
|
|
237
|
|
|
expect($this->getEntityField($entity, $field))->notToBe($value); |
|
|
|
|
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* @param object $instance |
242
|
|
|
* @return void |
243
|
|
|
* @throws InvalidArgumentException |
244
|
|
|
*/ |
245
|
|
|
private function applyFieldFormatters($instance, ?array $formatters = null) |
246
|
|
|
{ |
247
|
|
|
$className = get_class($instance); |
248
|
|
|
if (null === $formatters) { |
249
|
|
|
$formatters = $this->getFieldFormatters($className); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
switch (true) { |
253
|
|
|
case $instance instanceof News: |
254
|
|
|
/** @var News $instance */ |
255
|
|
|
|
256
|
|
|
/** @var string title */ |
257
|
|
|
$title = $formatters['title'](); |
258
|
|
|
$instance->setTitle($title); |
259
|
|
|
|
260
|
|
|
/** @var string $creatorEmail */ |
261
|
|
|
$creatorEmail = $formatters['creatorEmail'](); |
262
|
|
|
$instance->setCreatorEmail($creatorEmail); |
263
|
|
|
|
264
|
|
|
/** @var Category|null $categories */ |
265
|
|
|
$categories = $formatters['categories'](); |
266
|
|
|
array_walk( |
267
|
|
|
$categories, |
268
|
|
|
static function (Category $category, int $key, News $news): void { |
269
|
|
|
$news->addCategory($category); |
270
|
|
|
}, |
271
|
|
|
$instance |
272
|
|
|
); |
273
|
|
|
|
274
|
|
|
/** @var bool $visible */ |
275
|
|
|
$visible = $formatters['visible'](); |
276
|
|
|
$instance->setVisible($visible); |
277
|
|
|
|
278
|
|
|
/** @var string|null $photoKey */ |
279
|
|
|
$photoKey = $formatters['photoKey'](); |
280
|
|
|
$instance->setPhotoKey($photoKey); |
281
|
|
|
break; |
282
|
|
|
case $instance instanceof Person: |
283
|
|
|
/** @var Person $instance */ |
284
|
|
|
|
285
|
|
|
/** @var string $email */ |
286
|
|
|
$email = $formatters['email'](); |
287
|
|
|
$instance->setEmail($email); |
288
|
|
|
break; |
289
|
|
|
case $instance instanceof Subscriber; |
290
|
|
|
/** @var Subscriber $instance */ |
291
|
|
|
|
292
|
|
|
/** @var string $email */ |
293
|
|
|
$email = $formatters['email'](); |
294
|
|
|
$instance->setEmail($email); |
295
|
|
|
|
296
|
|
|
/** @var bool $active */ |
297
|
|
|
$active = $formatters['active'](); |
298
|
|
|
$instance->setActive($active); |
299
|
|
|
break; |
300
|
|
|
case $instance instanceof Category: |
301
|
|
|
|
302
|
|
|
/** @var string title */ |
303
|
|
|
$title = $formatters['title'](); |
304
|
|
|
$instance->setTitle($title); |
305
|
|
|
break; |
306
|
|
|
default: |
307
|
|
|
throw new InvalidArgumentException(sprintf( |
308
|
|
|
'Cannot find any column formatters for class "%s', |
309
|
|
|
$className |
310
|
|
|
)); |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
private function getFieldFormatters(string $className): array |
315
|
|
|
{ |
316
|
|
|
$faker = $this->getFaker(); |
317
|
|
|
$formatters = [ |
318
|
|
|
News::class => [ |
319
|
|
|
'title' => function () use ($faker) { |
320
|
|
|
return $faker->title; |
321
|
|
|
}, |
322
|
|
|
'creatorEmail' => function() use ($faker): string { |
323
|
|
|
return $faker->email(); |
324
|
|
|
}, |
325
|
|
|
'categories' => function() use ($faker): array { |
326
|
|
|
/** @var array<Category> $categories */ |
327
|
|
|
$categories = $this->getRepository(Category::class)->findAll(); |
328
|
|
|
if (0 !== count($categories)) { |
329
|
|
|
/** @var Category $randomCategory */ |
330
|
|
|
$randomCategory = $faker->randomElement($categories); |
331
|
|
|
$categories = [$randomCategory]; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
return $categories; |
335
|
|
|
|
336
|
|
|
}, |
337
|
|
|
'photoKey' => function (): ?string { |
338
|
|
|
return null; |
339
|
|
|
}, |
340
|
|
|
'visible' => function (): bool { |
341
|
|
|
return true; |
342
|
|
|
} |
343
|
|
|
], |
344
|
|
|
Person::class => [ |
345
|
|
|
'email' => function() use ($faker): string { |
346
|
|
|
return $faker->email(); |
347
|
|
|
} |
348
|
|
|
], |
349
|
|
|
Subscriber::class => [ |
350
|
|
|
'email' => function() use ($faker): string { |
351
|
|
|
return $faker->email(); |
352
|
|
|
}, |
353
|
|
|
'active' => function (): bool { |
354
|
|
|
return true; |
355
|
|
|
} |
356
|
|
|
], |
357
|
|
|
Category::class => [ |
358
|
|
|
'title' => function () use ($faker): string { |
359
|
|
|
return $faker->title; |
360
|
|
|
} |
361
|
|
|
] |
362
|
|
|
]; |
363
|
|
|
|
364
|
|
|
if (false === array_key_exists($className, $formatters)) { |
365
|
|
|
throw new RuntimeException("No formatters for class \"{$className}\""); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
return $formatters[$className]; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* @param object $instance |
373
|
|
|
* @return void |
374
|
|
|
* @throws InvalidArgumentException |
375
|
|
|
*/ |
376
|
|
|
private function applyEntityModifiers($instance): void |
377
|
|
|
{ |
378
|
|
|
$faker = $this->getFaker(); |
379
|
|
|
switch (true) { |
380
|
|
|
case $instance instanceof News: |
381
|
|
|
$instance->setTitle($faker->title); |
382
|
|
|
$instance->setCreatedAt(new DateTime()); |
383
|
|
|
$tag = new Tag(); |
384
|
|
|
$tag->setName($faker->sentence()); |
385
|
|
|
$tag->setNews($instance); |
386
|
|
|
$instance->setTags([$tag]); |
387
|
|
|
break; |
388
|
|
|
case $instance instanceof Subscriber: |
389
|
|
|
$instance->setCreatedAt(new DateTime()); |
390
|
|
|
break; |
391
|
|
|
case $instance instanceof Person: |
392
|
|
|
case $instance instanceof Category: |
393
|
|
|
break; |
394
|
|
|
default: |
395
|
|
|
throw new InvalidArgumentException(sprintf( |
396
|
|
|
'Cannot find any modifiers for class "%s', |
397
|
|
|
get_class($instance) |
398
|
|
|
)); |
399
|
|
|
} |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
/** |
403
|
|
|
* @param object $entity |
404
|
|
|
* @param string $field |
405
|
|
|
* @return mixed |
406
|
|
|
*/ |
407
|
|
|
private function getEntityField($entity, string $field) |
408
|
|
|
{ |
409
|
|
|
if (null === $this->propertyAccessor) { |
410
|
|
|
$this->propertyAccessor = PropertyAccess::createPropertyAccessor(); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
return $this->propertyAccessor->getValue($entity, strtolower($field)); |
414
|
|
|
} |
415
|
|
|
} |
416
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.