1
- # Install Gedmo Doctrine extensions in Symfony 4
1
+ # Install Gedmo Doctrine extensions in Symfony
2
2
3
- Configure full featured [ Doctrine extensions] ( https://github.com/doctrine-extensions/DoctrineExtensions ) for your Symfony 4 project.
3
+ Configure full featured [ Doctrine extensions] ( https://github.com/doctrine-extensions/DoctrineExtensions ) for your Symfony project.
4
4
This post will show you - how to create a simple configuration file to manage extensions with
5
5
ability to use all features it provides.
6
6
Interested? then bear with me! and don't be afraid, we're not diving into security component :)
@@ -11,19 +11,19 @@ over management of extensions.
11
11
12
12
Content:
13
13
14
- - [ Symfony 4 ] ( #sf4 -app ) application
14
+ - [ Symfony] ( #sf -app ) application
15
15
- Extensions metadata [ mapping] ( #ext-mapping )
16
16
- Extensions filters [ filtering] ( #ext-filtering )
17
17
- Extension [ listeners] ( #ext-listeners )
18
18
- Usage [ example] ( #ext-example )
19
19
- Some [ tips] ( #more-tips )
20
20
- [ Alternative] ( #alternative ) over configuration
21
21
22
- <a name =" sf4 -app" ></a >
22
+ <a name =" sf -app" ></a >
23
23
24
- ## Symfony 4 application
24
+ ## Symfony application
25
25
26
- First of all, we will need a symfony 4 startup application, let's say [ symfony-standard edition
26
+ First of all, we will need a symfony startup application, let's say [ symfony-standard edition
27
27
with composer] ( https://symfony.com/doc/current/best_practices/creating-the-project.html )
28
28
29
29
- ` composer create-project symfony/skeleton [project name] `
@@ -46,15 +46,15 @@ To do so, add some mapping info to your **doctrine.orm** configuration, edit **c
46
46
``` yaml
47
47
doctrine :
48
48
dbal :
49
- # your dbal config here
49
+ # your dbal config here
50
50
51
51
orm :
52
- auto_generate_proxy_classes : %kernel.debug%
52
+ auto_generate_proxy_classes : ' %kernel.debug%'
53
53
auto_mapping : true
54
- # only these lines are added additionally
54
+ # only these lines are added additionally
55
55
mappings :
56
56
translatable :
57
- type : annotation # or attribute
57
+ type : attribute # or annotation or xml
58
58
alias : Gedmo
59
59
prefix : Gedmo\Translatable\Entity
60
60
# make sure vendor library location is correct
@@ -79,7 +79,7 @@ to you also. To skip mapping of these entities, you can map **only superclasses*
79
79
``` yaml
80
80
mappings :
81
81
translatable :
82
- type : annotation # or attribute
82
+ type : attribute # or annotation or xml
83
83
alias : Gedmo
84
84
prefix : Gedmo\Translatable\Entity
85
85
# make sure vendor library location is correct
@@ -101,23 +101,23 @@ everything the extensions provide:
101
101
``` yaml
102
102
# only orm config branch of doctrine
103
103
orm :
104
- auto_generate_proxy_classes : %kernel.debug%
104
+ auto_generate_proxy_classes : ' %kernel.debug%'
105
105
auto_mapping : true
106
- # only these lines are added additionally
106
+ # only these lines are added additionally
107
107
mappings :
108
108
translatable :
109
- type : annotation # or attribute
109
+ type : attribute # or annotation or xml
110
110
alias : Gedmo
111
111
prefix : Gedmo\Translatable\Entity
112
112
# make sure vendor library location is correct
113
113
dir : " %kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity"
114
114
loggable :
115
- type : annotation # or attribute
115
+ type : attribute # or annotation or xml
116
116
alias : Gedmo
117
117
prefix : Gedmo\Loggable\Entity
118
118
dir : " %kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Entity"
119
119
tree :
120
- type : annotation # or attribute
120
+ type : attribute # or annotation or xml
121
121
alias : Gedmo
122
122
prefix : Gedmo\Tree\Entity
123
123
dir : " %kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Tree/Entity"
@@ -130,11 +130,11 @@ To do so, add this filter info to your **doctrine.orm** configuration, edit **co
130
130
` ` ` yaml
131
131
doctrine :
132
132
dbal :
133
- # your dbal config here
133
+ # your dbal config here
134
134
orm :
135
- auto_generate_proxy_classes : %kernel.debug%
135
+ auto_generate_proxy_classes : ' %kernel.debug%'
136
136
auto_mapping : true
137
- # only these lines are added additionally
137
+ # only these lines are added additionally
138
138
filters :
139
139
softdeleteable :
140
140
class : Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
@@ -155,13 +155,24 @@ services:
155
155
gedmo.listener.tree :
156
156
class : Gedmo\Tree\TreeListener
157
157
tags :
158
- - { name: doctrine.event_subscriber, connection: default }
158
+ - { name: doctrine.event_listener, event: 'prePersist'}
159
+ - { name: doctrine.event_listener, event: 'preUpdate'}
160
+ - { name: doctrine.event_listener, event: 'preRemove'}
161
+ - { name: doctrine.event_listener, event: 'onFlush'}
162
+ - { name: doctrine.event_listener, event: 'loadClassMetadata'}
163
+ - { name: doctrine.event_listener, event: 'postPersist'}
164
+ - { name: doctrine.event_listener, event: 'postUpdate'}
165
+ - { name: doctrine.event_listener, event: 'postRemove'}
159
166
calls :
160
167
- [ setAnnotationReader, [ "@annotation_reader" ] ]
161
168
162
169
Gedmo\Translatable\TranslatableListener :
163
170
tags :
164
- - { name: doctrine.event_subscriber, connection: default }
171
+ - { name: doctrine.event_listener, event: 'postLoad' }
172
+ - { name: doctrine.event_listener, event: 'postPersist' }
173
+ - { name: doctrine.event_listener, event: 'preFlush' }
174
+ - { name: doctrine.event_listener, event: 'onFlush' }
175
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
165
176
calls :
166
177
- [ setAnnotationReader, [ "@annotation_reader" ] ]
167
178
- [ setDefaultLocale, [ "%locale%" ] ]
@@ -170,46 +181,63 @@ services:
170
181
gedmo.listener.timestampable :
171
182
class : Gedmo\Timestampable\TimestampableListener
172
183
tags :
173
- - { name: doctrine.event_subscriber, connection: default }
184
+ - { name: doctrine.event_listener, event: 'prePersist' }
185
+ - { name: doctrine.event_listener, event: 'onFlush' }
186
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
174
187
calls :
175
188
- [ setAnnotationReader, [ "@annotation_reader" ] ]
176
189
177
190
gedmo.listener.sluggable :
178
191
class : Gedmo\Sluggable\SluggableListener
179
192
tags :
180
- - { name: doctrine.event_subscriber, connection: default }
193
+ - { name: doctrine.event_listener, event: 'prePersist' }
194
+ - { name: doctrine.event_listener, event: 'onFlush' }
195
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
181
196
calls :
182
197
- [ setAnnotationReader, [ "@annotation_reader" ] ]
183
198
184
199
gedmo.listener.sortable :
185
200
class : Gedmo\Sortable\SortableListener
186
201
tags :
187
- - { name: doctrine.event_subscriber, connection: default }
202
+ - { name: doctrine.event_listener, event: 'onFlush' }
203
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
204
+ - { name: doctrine.event_listener, event: 'prePersist' }
205
+ - { name: doctrine.event_listener, event: 'postPersist' }
206
+ - { name: doctrine.event_listener, event: 'preUpdate' }
207
+ - { name: doctrine.event_listener, event: 'postRemove' }
208
+ - { name: doctrine.event_listener, event: 'postFlush' }
188
209
calls :
189
210
- [ setAnnotationReader, [ "@annotation_reader" ] ]
190
-
211
+
191
212
gedmo.listener.softdeleteable :
192
213
class : Gedmo\SoftDeleteable\SoftDeleteableListener
193
214
tags :
194
- - { name: doctrine.event_subscriber, connection: default }
215
+ - { name: doctrine.event_listener, event: 'onFlush' }
216
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
195
217
calls :
196
218
- [ setAnnotationReader, [ "@annotation_reader" ] ]
197
219
198
220
Gedmo\Loggable\LoggableListener :
199
221
tags :
200
- - { name: doctrine.event_subscriber, connection: default }
222
+ - { name: doctrine.event_listener, event: 'onFlush' }
223
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
224
+ - { name: doctrine.event_listener, event: 'postPersist' }
201
225
calls :
202
226
- [ setAnnotationReader, [ "@annotation_reader" ] ]
203
227
204
228
Gedmo\Blameable\BlameableListener :
205
229
tags :
206
- - { name: doctrine.event_subscriber, connection: default }
230
+ - { name: doctrine.event_listener, event: 'prePersist' }
231
+ - { name: doctrine.event_listener, event: 'onFlush' }
232
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
207
233
calls :
208
234
- [ setAnnotationReader, [ "@annotation_reader" ] ]
209
235
210
236
Gedmo\IpTraceable\IpTraceableListener :
211
237
tags :
212
- - { name: doctrine.event_subscriber, connection: default }
238
+ - { name: doctrine.event_listener, event: 'prePersist' }
239
+ - { name: doctrine.event_listener, event: 'onFlush' }
240
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
213
241
calls :
214
242
- [ setAnnotationReader, [ "@annotation_reader" ] ]
215
243
@@ -224,15 +252,19 @@ You will need to create this subscriber class if you use **loggable** , **transl
224
252
behaviors. This listener will set the ** locale used** from request and ** username** to
225
253
loggable and blameable. So, to finish the setup create ** EventSubscriber\DoctrineExtensionSubscriber**
226
254
227
- ## Register event subscriber for [ Symfony Doctrine MongoDB Bundle] ( https://github.com/doctrine/DoctrineMongoDBBundle )
255
+ ## Register event listener for [ Symfony Doctrine MongoDB Bundle] ( https://github.com/doctrine/DoctrineMongoDBBundle )
228
256
229
- Because DoctrineExtensions does not implement ` EventSubscriberInterface ` from MongoDBBundle, you need to manually tag
230
- the listeners. Otherwise, the listeners will not be listening to the triggered events of Doctrine.
257
+ You also need to manually tag the listeners. Otherwise, the listeners will not be listening to the triggered events
258
+ of Doctrine.
231
259
232
260
``` yaml
233
261
Gedmo\Loggable\LoggableListener :
234
- tags :
235
- - { name: doctrine_mongodb.odm.event_subscriber }
262
+ tags :
263
+ - { name: doctrine_mongodb.odm.event_listener, event: 'onFlush' }
264
+ - { name: doctrine_mongodb.odm.event_listener, event: 'loadClassMetadata' }
265
+ - { name: doctrine_mongodb.odm.event_listener, event: 'postPersist' }
266
+ calls :
267
+ - [ setAnnotationReader, [ "@annotation_reader" ] ]
236
268
` ` `
237
269
238
270
` ` ` php
@@ -245,7 +277,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
245
277
use Symfony\Component\HttpKernel\KernelEvents;
246
278
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
247
279
248
- class DoctrineExtensionSubscriber implements EventSubscriberInterface
280
+ final class DoctrineExtensionSubscriber implements EventSubscriberInterface
249
281
{
250
282
/**
251
283
* @var BlameableListener
@@ -278,7 +310,7 @@ class DoctrineExtensionSubscriber implements EventSubscriberInterface
278
310
}
279
311
280
312
281
- public static function getSubscribedEvents()
313
+ public static function getSubscribedEvents() : array
282
314
{
283
315
return [
284
316
KernelEvents::REQUEST => 'onKernelRequest',
@@ -318,76 +350,90 @@ if you do not believe me, let's create a simple entity in our project:
318
350
319
351
namespace App\Entity;
320
352
321
- use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
322
- use Doctrine\ORM\Mapping as ORM; // doctrine orm annotations
353
+ use DateTimeImmutable;
354
+ use Doctrine\DBAL\Types\Types;
355
+ use Doctrine\ORM\Mapping as ORM;
356
+ use Gedmo\Mapping\Annotation as Gedmo;
323
357
324
358
/**
325
359
* @ORM\Entity
326
360
* @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
327
361
*/
362
+ #[ORM\Entity]
363
+ #[Gedmo\SoftDeleteable(fieldName: 'deletedAt', timeAware: false)]
328
364
class BlogPost
329
365
{
330
366
/**
331
367
* @Gedmo\Slug(fields={"title"}, updatable=false, separator="_")
332
368
* @ORM\Id
333
369
* @ORM\Column(length=32, unique=true)
334
370
*/
335
- private $id;
371
+ #[Gedmo\Slug(fields: ['title', updatable: false, separator: '_'])]
372
+ #[ORM\Id]
373
+ #[ORM\Column(lenght: 32, unique: true)]
374
+ private ?int $id;
336
375
337
376
/**
338
377
* @Gedmo\Translatable
339
378
* @ORM\Column(length=64)
340
379
*/
341
- private $title;
380
+ #[Gedmo\Translatable]
381
+ #[ORM\Column(length: 64)]
382
+ private ?string $title;
342
383
343
384
/**
344
385
* @Gedmo\Timestampable(on="create")
345
- * @ORM\Column(name="created", type="datetime ")
386
+ * @ORM\Column(name="created", type="datetime_immutable ")
346
387
*/
347
- private $created;
388
+ #[Gedmo\Timestampable(on: 'create')]
389
+ #[ORM\Column(name: 'created', type: Types::DATETIME_IMMUTABLE)]
390
+ private ?DateTimeImmutable $created;
348
391
349
392
/**
350
- * @ORM\Column(name="updated", type="datetime ")
393
+ * @ORM\Column(name="updated", type="datetime_immutable ")
351
394
* @Gedmo\Timestampable(on="update")
352
395
*/
353
- private $updated;
396
+ #[Gedmo\Timestampable(on: 'update')]
397
+ #[ORM\Column(name: 'updated', type: Types::DATETIME_IMMUTABLE)]
398
+ private ?DateTimeImmutable $updated;
354
399
355
400
/**
356
- * @ORM\Column(type="datetime ", nullable=true)
401
+ * @ORM\Column(type="datetime_immutable ", nullable=true)
357
402
*/
358
- private $deletedAt;
403
+ #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
404
+ private ?DateTimeImmutable $deletedAt;
359
405
360
- public function getId()
406
+ public function getId(): ?int
361
407
{
362
408
return $this->id;
363
409
}
364
410
365
- public function setTitle($title)
411
+ public function setTitle(?string $title): void
366
412
{
367
413
$this->title = $title;
368
414
}
369
415
370
- public function getTitle()
416
+ public function getTitle(): ?string
371
417
{
372
418
return $this->title;
373
419
}
374
420
375
- public function getCreated()
421
+ public function getCreated(): ?DateTimeImmutable
376
422
{
377
423
return $this->created;
378
424
}
379
425
380
- public function getUpdated()
426
+ public function getUpdated(): ?DateTimeImmutable
381
427
{
382
428
return $this->updated;
383
429
}
384
430
385
- public function getDeletedAt(): ?Datetime
431
+ public function getDeletedAt(): ?DateTimeImmutable
386
432
{
387
433
return $this->deletedAt;
388
434
}
389
435
390
- public function setDeletedAt(?Datetime $deletedAt): void
436
+ public function setDeletedAt(?DateTimeImmutable $deletedAt): void
391
437
{
392
438
$this->deletedAt = $deletedAt;
393
439
}
@@ -409,9 +455,8 @@ and add an action to test how it works:
409
455
/**
410
456
* @Route("/posts", name="_demo_posts")
411
457
*/
412
- public function postsAction()
458
+ public function postsAction(EntityManagerInterface $em): Response
413
459
{
414
- $em = $this->getDoctrine()->getManager();
415
460
$repository = $em->getRepository(App\Entity\BlogPost::class);
416
461
// create some posts in case if there aren't any
417
462
if (!$repository->find('hello_world')) {
@@ -463,7 +508,7 @@ doctrine_mongodb:
463
508
auto_mapping : true
464
509
mappings :
465
510
translatable :
466
- type : annotation # or attribute
511
+ type : attribute # or annotation or xml
467
512
alias : GedmoDocument
468
513
prefix : Gedmo\Translatable\Document
469
514
# make sure vendor library location is correct
0 commit comments