diff --git a/README.md b/README.md
index 774737c540..74b096b12d 100644
--- a/README.md
+++ b/README.md
@@ -28,9 +28,9 @@ flushed in a behavioral way.
composer require gedmo/doctrine-extensions
-* [Symfony](/doc/symfony.md)
-* [Laravel 5](https://www.laraveldoctrine.org/docs/1.3/extensions)
-* [Laminas](/doc/laminas.md)
+* [Symfony](/doc/frameworks/symfony.md)
+* [Laravel](/doc/frameworks/laravel.md)
+* [Laminas](/doc/frameworks/laminas.md)
### Upgrading
diff --git a/doc/annotations.md b/doc/annotations.md
index 92010c305c..f77ae52d5f 100644
--- a/doc/annotations.md
+++ b/doc/annotations.md
@@ -1,7 +1,7 @@
# Annotations Reference
> [!IMPORTANT]
-> To use annotations, you will need the deprecated [`doctrine/annotations`](https://www.doctrine-project.org/projects/annotations.html) library. PHP 8 users are encouraged to migrate and use [attributes](./attributes.md) as annotation support is deprecated in all supported Doctrine object managers.
+> Support for annotations is deprecated and will be removed in 4.0. PHP 8 users are encouraged to migrate and use [attributes](./attributes.md) instead of annotations. To use annotations, you will need the [`doctrine/annotations`](https://www.doctrine-project.org/projects/annotations.html) library.
Below you will a reference for annotations supported in this extensions library.
There will be introduction on usage with examples. For more detailed usage of each
diff --git a/doc/frameworks/laminas.md b/doc/frameworks/laminas.md
new file mode 100644
index 0000000000..562e6ad280
--- /dev/null
+++ b/doc/frameworks/laminas.md
@@ -0,0 +1,383 @@
+# Integrate the Doctrine Extensions in Laminas
+
+This guide will demonstrate how to integrate the Doctrine Extensions library into a Laminas application.
+
+## Index
+
+- [Getting Started](#getting-started)
+- [Registering Extension Listeners](#registering-extension-listeners)
+- [Registering Mapping Configuration](#registering-mapping-configuration)
+- [Registering Filters](#registering-filters)
+- [Configuring Extensions via Event Listeners](#configuring-extensions-via-event-listeners)
+
+## Getting Started
+
+> [!TIP]
+> This guide is written using the Laminas MVC quick start as the foundation.
+
+Assuming you have already [created your Laminas application](https://docs.laminas.dev/laminas-mvc/quick-start/),
+the next step will be to ensure you've installed this library and the Doctrine libraries you will need.
+
+For Doctrine MongoDB ODM users, this Composer command will install all required dependencies:
+
+```shell
+composer require doctrine/doctrine-module doctrine/doctrine-mongo-odm-module doctrine/mongodb-odm gedmo/doctrine-extensions
+```
+
+For Doctrine ORM users, this Composer command will install all required dependencies:
+
+```shell
+composer require doctrine/dbal doctrine/doctrine-module doctrine/doctrine-orm-module doctrine/orm gedmo/doctrine-extensions
+```
+
+## Registering Extension Listeners
+
+At the heart of the Doctrine Extensions library are the listeners which enable each extension. The below example demonstrates
+how to register and enable all listeners provided by this library.
+
+### Extensions Compatible with all Managers
+
+```php
+ [
+ 'invokables' => [
+ 'gedmo.mapping.driver.attribute' => AttributeReader::class,
+ ],
+ 'factories' => [
+ 'gedmo.listener.blameable' => function (ContainerInterface $container, string $requestedName): BlameableListener {
+ $listener = new BlameableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.ip_traceable' => function (ContainerInterface $container, string $requestedName): IpTraceableListener {
+ $listener = new IpTraceableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.loggable' => function (ContainerInterface $container, string $requestedName): LoggableListener {
+ $listener = new LoggableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.sluggable' => function (ContainerInterface $container, string $requestedName): SluggableListener {
+ $listener = new SluggableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.soft_deleteable' => function (ContainerInterface $container, string $requestedName): SoftDeleteableListener {
+ $listener = new SoftDeleteableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ // If your application uses a PSR-20 clock, you can provide it to this listener by uncommenting the below line
+ // $listener->setClock($container->get(ClockInterface::class));
+
+ return $listener;
+ },
+ 'gedmo.listener.sortable' => function (ContainerInterface $container, string $requestedName): SortableListener {
+ $listener = new SortableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.timestampable' => function (ContainerInterface $container, string $requestedName): TimestampableListener {
+ $listener = new TimestampableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ // If your application uses a PSR-20 clock, you can provide it to this listener by uncommenting the below line
+ // $listener->setClock($container->get(ClockInterface::class));
+
+ return $listener;
+ },
+ 'gedmo.listener.translatable' => function (ContainerInterface $container, string $requestedName): TranslatableListener {
+ $listener = new TranslatableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ // If your application uses a PSR-20 clock, you can provide it to this listener by uncommenting the below line
+ // $listener->setClock($container->get(ClockInterface::class));
+
+ return $listener;
+ },
+ ],
+ ],
+ 'doctrine' => [
+ 'eventmanager' => [
+ 'orm_default' => [
+ 'subscribers' => [
+ 'gedmo.listener.blameable',
+ 'gedmo.listener.ip_traceable',
+ 'gedmo.listener.loggable',
+ 'gedmo.listener.sluggable',
+ 'gedmo.listener.soft_deleteable',
+ 'gedmo.listener.sortable',
+ 'gedmo.listener.timestampable',
+ 'gedmo.listener.translatable',
+ 'gedmo.listener.tree',
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+### Extensions Compatible with MongoDB ODM Only
+
+```php
+ [
+ 'factories' => [
+ 'gedmo.listener.reference_integrity' => function (ContainerInterface $container, string $requestedName): ReferenceIntegrityListener {
+ $listener = new ReferenceIntegrityListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ 'gedmo.listener.references' => function (ContainerInterface $container, string $requestedName): ReferencesListener {
+ $listener = new ReferencesListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ ],
+ ],
+ 'doctrine' => [
+ 'eventmanager' => [
+ 'odm_default' => [
+ 'subscribers' => [
+ 'gedmo.listener.reference_integrity',
+ 'gedmo.listener.references',
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+### Extensions Compatible with ORM Only
+
+```php
+ [
+ 'factories' => [
+ 'gedmo.listener.uploadable' => function (ContainerInterface $container, string $requestedName): UploadableListener {
+ $listener = new UploadableListener();
+
+ // This call configures the listener to use the attribute driver service created above; if using annotations, you will need to provide the appropriate service instead
+ $listener->setAnnotationReader($container->get('gedmo.mapping.driver.attribute'));
+
+ return $listener;
+ },
+ ],
+ ],
+ 'doctrine' => [
+ 'eventmanager' => [
+ 'orm_default' => [
+ 'subscribers' => [
+ 'gedmo.listener.uploadable',
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+## Registering Mapping Configuration
+
+When using the [Loggable](../loggable.md), [Translatable](../translatable.md), or [Tree](../tree.md) extensions, you will
+need to register the mappings for these extensions to your object managers.
+
+> [!NOTE]
+> These extensions only provide mappings through annotations or attributes, with support for annotations being deprecated. If using annotations, you will need to ensure the [`doctrine/annotations`](https://www.doctrine-project.org/projects/annotations.html) library is installed and configured.
+
+### MongoDB ODM Mapping
+
+> [!IMPORTANT]
+> The tree extension does NOT have any objects to map when using the MongoDB ODM.
+
+The below example shows a configuration adding all available mappings to the default document manager.
+
+```php
+ [
+ 'driver' => [
+ 'gedmo.odm_driver' => [
+ 'class' => AttributeDriver::class, // If your application is using annotations, use the AnnotationDriver class instead
+ 'paths' => [
+ '/path/to/vendor/gedmo/doctrine-extensions/src/Loggable/Document',
+ '/path/to/vendor/gedmo/doctrine-extensions/src/Translatable/Document',
+ ],
+ ],
+ 'odm_default' => [
+ 'drivers' => [
+ 'gedmo.odm_driver', // Adds the mapping driver created above to the default mapping chain
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+### ORM Mapping
+
+The below example shows a configuration adding all available mappings to the default entity manager.
+
+```php
+ [
+ 'driver' => [
+ 'gedmo.orm_driver' => [
+ 'class' => AttributeDriver::class, // If your application is using annotations, use the AnnotationDriver class instead
+ 'paths' => [
+ '/path/to/vendor/gedmo/doctrine-extensions/src/Loggable/Entity',
+ '/path/to/vendor/gedmo/doctrine-extensions/src/Translatable/Entity',
+ '/path/to/vendor/gedmo/doctrine-extensions/src/Tree/Entity',
+ ],
+ ],
+ 'orm_default' => [
+ 'drivers' => [
+ 'gedmo.orm_driver', // Adds the mapping driver created above to the default mapping chain
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+To verify your configuration, you can use the `orm:info` command from the `doctrine-module` CLI tool to make sure the entities are registered.
+
+```sh
+$ vendor/bin/doctrine-module orm:info
+ Found X mapped entities:
+
+ [OK] Gedmo\Loggable\Entity\LogEntry
+ [OK] Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry
+ [OK] Gedmo\Translatable\Entity\Translation
+ [OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
+ [OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
+ [OK] Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure
+```
+
+## Registering Filters
+
+### Soft Deleteable Filter
+
+When using the [Soft Deleteable](../softdeleteable.md) extension, a filter is available which allows configuring whether
+soft-deleted objects are included in query results.
+
+> [!NOTE]
+> The default configuration in the Laminas modules does not enable the filters. To use these filters, you will need to enable them separately.
+
+#### MongoDB ODM Filter Configuration
+
+The below example shows a configuration adding the filter to the default document manager. To enable the filter,
+you can follow the [Filters documentation guide](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/filters.html#disabling-enabling-filters-and-setting-parameters).
+
+```php
+ [
+ 'configuration' => [
+ 'odm_default' => [
+ 'filters' => [
+ 'soft-deleteable' => SoftDeleteableFilter::class,
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+#### ORM Filter Configuration
+
+The below example shows a configuration adding the filter to the default entity manager. To enable the filter,
+you can follow the [Filters documentation guide](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/filters.html#disabling-enabling-filters-and-setting-parameters).
+
+```php
+ [
+ 'configuration' => [
+ 'orm_default' => [
+ 'filters' => [
+ 'soft-deleteable' => SoftDeleteableFilter::class,
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+## Configuring Extensions via Event Listeners
+
+When using the [Blameable](../blameable.md), [IP Traceable](../ip_traceable.md), [Loggable](../loggable.md), or
+[Translatable](../translatable.md) extensions, to work correctly, they require extra information that must be set
+at runtime.
+
+**Help Improve This Documentation**
+
+Pull requests are welcome to expand this section of the documentation.
diff --git a/doc/frameworks/laravel.md b/doc/frameworks/laravel.md
new file mode 100644
index 0000000000..0afe9e9834
--- /dev/null
+++ b/doc/frameworks/laravel.md
@@ -0,0 +1,5 @@
+# Integrate the Doctrine Extensions in Laravel
+
+When using the Laravel Doctrine package with the Doctrine ORM, you can use the [Laravel Doctrine Extensions](https://www.laraveldoctrine.org/docs/current/extensions)
+package to add this library to your application. Please review the extensions package documentation linked earlier for
+detailed instructions.
diff --git a/doc/frameworks/symfony.md b/doc/frameworks/symfony.md
new file mode 100644
index 0000000000..dd910318a8
--- /dev/null
+++ b/doc/frameworks/symfony.md
@@ -0,0 +1,481 @@
+# Integrate the Doctrine Extensions in Symfony
+
+This guide will demonstrate how to integrate the Doctrine Extensions library into a Symfony application.
+
+> [!TIP]
+> We recommend using the [`StofDoctrineExtensionsBundle`](https://symfony.com/bundles/StofDoctrineExtensionsBundle/current/index.html) which handles this integration for you.
+
+## Index
+
+- [Getting Started](#getting-started)
+- [Registering Extension Listeners](#registering-extension-listeners)
+- [Registering Mapping Configuration](#registering-mapping-configuration)
+- [Registering Filters](#registering-filters)
+- [Configuring Extensions via Event Subscribers](#configuring-extensions-via-event-subscribers)
+
+## Getting Started
+
+Assuming you have already [created your Symfony application](https://symfony.com/doc/current/getting_started/index.html),
+the next step will be to ensure you've installed this library and the Doctrine libraries you will need.
+
+For Doctrine MongoDB ODM users, this Composer command will install all required dependencies:
+
+```shell
+composer require doctrine/mongodb-odm doctrine/mongodb-odm-bundle gedmo/doctrine-extensions
+```
+
+For Doctrine ORM users, this Composer command will install all required dependencies:
+
+```shell
+composer require doctrine/dbal doctrine/doctrine-bundle doctrine/orm gedmo/doctrine-extensions
+```
+
+## Registering Extension Listeners
+
+At the heart of the Doctrine Extensions library are the listeners which enable each extension. The below example demonstrates
+how to register and enable all listeners provided by this library.
+
+### Extensions Compatible with all Managers
+
+> [!NOTE]
+> This example shows the configuration when using the ORM and `DoctrineBundle` with a single default entity manager. When using the MongoDB ODM and `DoctrineMongoDBBundle`, the tag name should be `doctrine_mongodb.odm.event_listener` instead of `doctrine.event_listener`. When using an application with multiple managers, a separate tag is needed with the `connection` attribute for each connection.
+
+```yaml
+services:
+ # Attribute mapping driver for the Doctrine Extension listeners
+ gedmo.mapping.driver.attribute:
+ class: Gedmo\Mapping\Driver\AttributeReader
+
+ # Gedmo Blameable Extension Listener
+ gedmo.listener.blameable:
+ class: Gedmo\Blameable\BlameableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'prePersist' }
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo IP Traceable Extension Listener
+ gedmo.listener.ip_traceable:
+ class: Gedmo\IpTraceable\IpTraceableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'prePersist' }
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo Loggable Extension Listener
+ gedmo.listener.loggable:
+ class: Gedmo\Loggable\LoggableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine.event_listener, event: 'postPersist' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo Sluggable Extension Listener
+ gedmo.listener.sluggable:
+ class: Gedmo\Sluggable\SluggableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine.event_listener, event: 'prePersist' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo Soft Deleteable Extension listener
+ gedmo.listener.soft_deleteable:
+ class: Gedmo\SoftDeleteable\SoftDeleteableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+ # The `clock` service was introduced in Symfony 6.2; if using an older Symfony version, you can either comment this call or provide your own PSR-20 Clock implementation
+ - [ setClock, [ '@clock' ] ]
+
+ # Gedmo Sortable Extension listener
+ gedmo.listener.sortable:
+ class: Gedmo\Sortable\SortableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine.event_listener, event: 'prePersist' }
+ - { name: doctrine.event_listener, event: 'postPersist' }
+ - { name: doctrine.event_listener, event: 'preUpdate' }
+ - { name: doctrine.event_listener, event: 'postRemove' }
+ - { name: doctrine.event_listener, event: 'postFlush' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo Timestampable Extension Listener
+ gedmo.listener.timestampable:
+ class: Gedmo\Timestampable\TimestampableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'prePersist' }
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+ # The `clock` service was introduced in Symfony 6.2; if using an older Symfony version, you can either comment this call or provide your own PSR-20 Clock implementation
+ - [ setClock, [ '@clock' ] ]
+
+ # Gedmo Translatable Extension Listener
+ gedmo.listener.translatable:
+ class: Gedmo\Translatable\TranslatableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'postLoad' }
+ - { name: doctrine.event_listener, event: 'postPersist' }
+ - { name: doctrine.event_listener, event: 'preFlush' }
+ - { name: doctrine.event_listener, event: 'onFlush' }
+ - { name: doctrine.event_listener, event: 'loadClassMetadata' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+ # The Kernel's `locale` parameter is used to configure the default locale for the extension
+ - [ setDefaultLocale, [ '%locale%' ] ]
+
+ # Gedmo Tree Extension Listener
+ gedmo.listener.tree:
+ class: Gedmo\Tree\TreeListener
+ tags:
+ - { name: doctrine.event_listener, event: 'prePersist'}
+ - { name: doctrine.event_listener, event: 'preUpdate'}
+ - { name: doctrine.event_listener, event: 'preRemove'}
+ - { name: doctrine.event_listener, event: 'onFlush'}
+ - { name: doctrine.event_listener, event: 'loadClassMetadata'}
+ - { name: doctrine.event_listener, event: 'postPersist'}
+ - { name: doctrine.event_listener, event: 'postUpdate'}
+ - { name: doctrine.event_listener, event: 'postRemove'}
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+```
+
+### Extensions Compatible with MongoDB ODM Only
+
+> [!NOTE]
+> This example shows the configuration when using the MongoDB ODM and `DoctrineMongoDBBundle` with a single default document manager. When using an application with multiple managers, a separate tag is needed with the `connection` attribute for each connection.
+
+```yaml
+services:
+ # Gedmo Reference Integrity Extension Listener
+ gedmo.listener.reference_integrity:
+ class: Gedmo\ReferenceIntegrity\ReferenceIntegrityListener
+ tags:
+ - { name: doctrine_mongodb.odm.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine_mongodb.odm.event_listener, event: 'preRemove' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+
+ # Gedmo References Extension Listener
+ gedmo.listener.references:
+ class: Gedmo\References\ReferencesListener
+ tags:
+ - { name: doctrine_mongodb.odm.event_listener, event: 'postLoad' }
+ - { name: doctrine_mongodb.odm.event_listener, event: 'loadClassMetadata' }
+ - { name: doctrine_mongodb.odm.event_listener, event: 'prePersist' }
+ - { name: doctrine_mongodb.odm.event_listener, event: 'preUpdate' }
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+```
+
+### Extensions Compatible with ORM Only
+
+> [!NOTE]
+> This example shows the configuration when using the ORM and `DoctrineBundle` with a single default entity manager. When using an application with multiple managers, a separate tag is needed with the `connection` attribute for each connection.
+
+```yaml
+services:
+ # Gedmo Uploadable Extension Listener
+ gedmo.listener.uploadable:
+ class: Gedmo\Uploadable\UploadableListener
+ tags:
+ - { name: doctrine.event_listener, event: 'loadClassMetadata'}
+ - { name: doctrine.event_listener, event: 'preFlush'}
+ - { name: doctrine.event_listener, event: 'onFlush'}
+ - { name: doctrine.event_listener, event: 'postFlush'}
+ calls:
+ # Uncomment the below call if using attributes, and comment the call for the annotation reader
+ # - [ setAnnotationReader, [ '@gedmo.mapping.driver.attribute' ] ]
+ # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
+ - [ setAnnotationReader, [ '@annotation_reader' ] ]
+```
+
+## Registering Mapping Configuration
+
+When using the [Loggable](../loggable.md), [Translatable](../translatable.md), or [Tree](../tree.md) extensions, you will
+need to register the mappings for these extensions to your object managers.
+
+> [!NOTE]
+> These extensions only provide mappings through annotations or attributes, with support for annotations being deprecated. If using annotations, you will need to ensure the [`doctrine/annotations`](https://www.doctrine-project.org/projects/annotations.html) library is installed and configured.
+
+### MongoDB ODM Mapping
+
+> [!IMPORTANT]
+> The tree extension does NOT have any objects to map when using the MongoDB ODM.
+
+The below example shows a configuration adding all available mappings to the default document manager.
+
+```yaml
+doctrine_mongodb:
+ document_managers:
+ default:
+ mappings:
+ loggable:
+ type: attribute # or annotation
+ alias: GedmoLoggable
+ prefix: Gedmo\Loggable\Document
+ dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Document"
+ is_bundle: false
+ translatable:
+ type: attribute # or annotation
+ alias: GedmoTranslatable
+ prefix: Gedmo\Translatable\Document
+ dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Document"
+ is_bundle: false
+```
+
+To verify your configuration, you can use the `doctrine:mongodb:mapping:info` command to make sure the entities are registered.
+
+```shell
+$ bin/console doctrine:mongodb:mapping:info
+ Found X documents mapped in document manager default:
+ [OK] Gedmo\Loggable\Document\LogEntry
+ [OK] Gedmo\Loggable\Document\MappedSuperclass\AbstractLogEntry
+ [OK] Gedmo\Translatable\Document\MappedSuperclass\AbstractPersonalTranslation
+ [OK] Gedmo\Translatable\Document\MappedSuperclass\AbstractTranslation
+ [OK] Gedmo\Translatable\Document\Translation
+```
+
+### ORM Mapping
+
+The below example shows a configuration adding all available mappings to the default entity manager.
+
+```yaml
+doctrine:
+ orm:
+ default:
+ mappings:
+ loggable:
+ type: attribute # or annotation
+ alias: GedmoLoggable
+ prefix: Gedmo\Loggable\Entity
+ dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Entity"
+ is_bundle: false
+ translatable:
+ type: attribute # or annotation
+ alias: GedmoTranslatable
+ prefix: Gedmo\Translatable\Entity
+ dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity"
+ is_bundle: false
+ tree:
+ type: attribute # or annotation
+ alias: GedmoTree
+ prefix: Gedmo\Tree\Entity
+ dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Tree/Entity"
+ is_bundle: false
+```
+
+To verify your configuration, you can use the `doctrine:mapping:info` command to make sure the entities are registered.
+
+```shell
+$ bin/console doctrine:mapping:info
+ Found X mapped entities:
+ [OK] Gedmo\Loggable\Entity\LogEntry
+ [OK] Gedmo\Loggable\Entity\MappedSuperclass\AbstractLogEntry
+ [OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
+ [OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
+ [OK] Gedmo\Translatable\Entity\Translation
+ [OK] Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure
+```
+
+## Registering Filters
+
+### Soft Deleteable Filter
+
+When using the [Soft Deleteable](../softdeleteable.md) extension, a filter is available which allows configuring whether
+soft-deleted objects are included in query results.
+
+> [!NOTE]
+> The default configuration in the Symfony bundles does not enable the filters. These examples show how to globally enable them.
+
+#### MongoDB ODM Filter Configuration
+
+The below example shows a configuration adding the filter to the default document manager.
+
+```yaml
+doctrine_mongodb:
+ document_managers:
+ default:
+ filters:
+ 'soft-deleteable':
+ class: Gedmo\SoftDeleteable\Filter\ODM\SoftDeleteableFilter
+ enabled: true
+```
+
+#### ORM Filter Configuration
+
+The below example shows a configuration adding the filter to the default entity manager.
+
+```yaml
+doctrine:
+ orm:
+ default:
+ filters:
+ 'soft-deleteable':
+ class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
+ enabled: true
+```
+
+## Configuring Extensions via Event Subscribers
+
+When using the [Blameable](../blameable.md), [IP Traceable](../ip_traceable.md), [Loggable](../loggable.md), or
+[Translatable](../translatable.md) extensions, to work correctly, they require extra information that must be set
+at runtime, typically during the `kernel.request` event. The below example is an event subscriber class which configures
+all of these extensions.
+
+```php
+ [
+ ['configureBlameableListener'], // Must run after the user is authenticated
+ ['configureIpTraceableListener', 512], // Runs early since this only requires the Request object
+ ['configureLoggableListener'], // Must run after the user is authenticated
+ ['configureTranslatableListener'], // Must run after the locale is configured
+ ],
+ ];
+ }
+
+ /**
+ * Configures the blameable listener using the currently authenticated user
+ */
+ public function configureBlameableListener(RequestEvent $event): void
+ {
+ // Only applies to the main request
+ if (!$event->isMainRequest()) {
+ return;
+ }
+
+ // If the required security component services weren't provided, there's nothing we can do
+ if (null === $this->authorizationChecker || null === $this->tokenStorage) {
+ return;
+ }
+
+ $token = $this->tokenStorage->getToken();
+
+ // Only set the user information if there is a token in storage and it represents an authenticated user
+ if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED')) {
+ $this->blameableListener->setUserValue($token->getUser());
+ }
+ }
+
+ /**
+ * Configures the IP traceable listener using the current request
+ */
+ public function configureIpTraceableListener(RequestEvent $event): void
+ {
+ // Only applies to the main request
+ if (!$event->isMainRequest()) {
+ return;
+ }
+
+ $ip = $event->getRequest()->getClientIp();
+
+ // Only set the IP address if available
+ if (null !== $ip) {
+ $this->ipTraceableListener->setIpValue($ip);
+ }
+ }
+
+ /**
+ * Configures the loggable listener using the currently authenticated user
+ */
+ public function configureLoggableListener(RequestEvent $event): void
+ {
+ // Only applies to the main request
+ if (!$event->isMainRequest()) {
+ return;
+ }
+
+ // If the required security component services weren't provided, there's nothing we can do
+ if (null === $this->authorizationChecker || null === $this->tokenStorage) {
+ return;
+ }
+
+ $token = $this->tokenStorage->getToken();
+
+ // Only set the user information if there is a token in storage and it represents an authenticated user
+ if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED')) {
+ $this->loggableListener->setUsername($token->getUser());
+ }
+ }
+
+ /**
+ * Configures the translatable listener using the request locale
+ */
+ public function configureTranslatableListener(RequestEvent $event): void
+ {
+ $this->translatableListener->setTranslatableLocale($event->getRequest()->getLocale());
+ }
+}
+```
diff --git a/doc/laminas.md b/doc/laminas.md
deleted file mode 100644
index 6f02884923..0000000000
--- a/doc/laminas.md
+++ /dev/null
@@ -1,85 +0,0 @@
-## Using Gedmo Doctrine Extensions in Laminas
-
-Assuming you are familiar with [DoctrineModule](https://github.com/doctrine/DoctrineModule) (if not, you should definitely start there!), integrating Doctrine Extensions with Laminas application is super-easy.
-
-### Composer
-
-Add `doctrine/doctrine-module`, `doctrine/doctrine-orm-module` or `doctrine/doctrine-mongo-odm-module` to composer.json file
-
-Then run `composer.phar update`.
-
-### Configuration
-
-Once libraries are installed, you can tell Doctrine which behaviors you want to use, by declaring appropriate subscribers in Event Manager settings. Together with [entity mapping options](https://github.com/doctrine/DoctrineORMModule#entities-settings), your module configuration file should look like following:
-
-```php
-return array(
- 'doctrine' => array(
- 'eventmanager' => array(
- 'orm_default' => array(
- 'subscribers' => array(
-
- // pick any listeners you need
- 'Gedmo\Tree\TreeListener',
- 'Gedmo\Timestampable\TimestampableListener',
- 'Gedmo\Sluggable\SluggableListener',
- 'Gedmo\Loggable\LoggableListener',
- 'Gedmo\Sortable\SortableListener'
- ),
- ),
- ),
- 'driver' => array(
- 'my_driver' => array(
- 'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
- 'cache' => 'array',
- 'paths' => array(__DIR__ . '/../src/MyModule/Entity')
- ),
- 'orm_default' => array(
- 'drivers' => array(
- 'MyModule\Entity' => 'my_driver'
- ),
- ),
- ),
- ),
-);
-```
-
-That's it! From now on you can use Gedmo annotations, just as it is described in [documentation](./annotations.md).
-
-#### Note: You may need to provide additional settings for some of the available listeners.
-
-For instance, `Translatable` requires additional metadata driver in order to manage translation tables:
-
-```php
-return array(
- 'doctrine' => array(
- 'eventmanager' => array(
- 'orm_default' => array(
- 'subscribers' => array(
- 'Gedmo\Translatable\TranslatableListener',
- ),
- ),
- ),
- 'driver' => array(
- 'my_driver' => array(
- 'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
- 'cache' => 'array',
- 'paths' => array(__DIR__ . '/../src/MyModule/Entity')
- ),
- 'translatable_metadata_driver' => array(
- 'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
- 'cache' => 'array',
- 'paths' => array(
- 'vendor/gedmo/doctrine-extensions/src/Translatable/Entity',
- ),
- ),
- 'orm_default' => array(
- 'drivers' => array(
- 'MyModule\Entity' => 'my_driver',
- 'Gedmo\Translatable\Entity' => 'translatable_metadata_driver',
- ),
- ),
- ),
- ),
-);
-```
diff --git a/doc/symfony.md b/doc/symfony.md
deleted file mode 100644
index 40acf432fb..0000000000
--- a/doc/symfony.md
+++ /dev/null
@@ -1,562 +0,0 @@
-# Install Gedmo Doctrine extensions in Symfony
-
-Configure full featured [Doctrine extensions](https://github.com/doctrine-extensions/DoctrineExtensions) for your Symfony project.
-This post will show you - how to create a simple configuration file to manage extensions with
-ability to use all features it provides.
-Interested? then bear with me! and don't be afraid, we're not diving into security component :)
-
-This post will put some light over the shed of extension installation and mapping configuration
-of Doctrine. It does not require any additional dependencies and gives you full power
-over management of extensions.
-
-Content:
-
-- [Symfony](#sf-app) application
-- Extensions metadata [mapping](#ext-mapping)
-- Extensions filters [filtering](#ext-filtering)
-- Extension [listeners](#ext-listeners)
-- Usage [example](#ext-example)
-- Some [tips](#more-tips)
-- [Alternative](#alternative) over configuration
-
-
-
-## Symfony application
-
-First of all, we will need a symfony startup application, let's say [symfony-standard edition
-with composer](https://symfony.com/doc/current/best_practices/creating-the-project.html)
-
-- `composer create-project symfony/skeleton [project name]`
-
-Now let's add the **gedmo/doctrine-extensions**
-
-You can find the doctrine-extensions project on packagist: https://packagist.org/packages/gedmo/doctrine-extensions
-
-To add it to your project:
-- `composer require gedmo/doctrine-extensions`
-
-
-
-## Mapping
-
-Let's start from the mapping. In case you use the **translatable**, **tree** or **loggable**
-extension you will need to map those abstract mapped superclasses for your ORM to be aware of.
-To do so, add some mapping info to your **doctrine.orm** configuration, edit **config/doctrine.yaml**:
-
-```yaml
-doctrine:
- dbal:
- # your dbal config here
-
- orm:
- auto_generate_proxy_classes: '%kernel.debug%'
- auto_mapping: true
- # only these lines are added additionally
- mappings:
- translatable:
- type: attribute # or annotation or xml
- alias: Gedmo
- prefix: Gedmo\Translatable\Entity
- # make sure vendor library location is correct
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity"
-```
-
-After that, running **php bin/console doctrine:mapping:info** you should see the output:
-
-```
-Found 3 entities mapped in entity manager default:
-[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
-[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
-[OK] Gedmo\Translatable\Entity\Translation
-```
-Well, we mapped only **translatable** for now, it really depends on your needs, which extensions
-your application uses.
-
-**Note:** there is **Gedmo\Translatable\Entity\Translation** which is not a super class, in that case
-if you create a doctrine schema, it will add **ext_translations** table, which might not be useful
-to you also. To skip mapping of these entities, you can map **only superclasses**
-
-```yaml
-mappings:
- translatable:
- type: attribute # or annotation or xml
- alias: Gedmo
- prefix: Gedmo\Translatable\Entity
- # make sure vendor library location is correct
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity/MappedSuperclass"
-```
-
-The configuration above, adds a **/MappedSuperclass** into directory depth, after running
-**php bin/console doctrine:mapping:info** you should only see now:
-
-```
-Found 2 entities mapped in entity manager default:
-[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
-[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
-```
-
-This is very useful for advanced requirements and quite simple to understand. So now let's map
-everything the extensions provide:
-
-```yaml
-# only orm config branch of doctrine
-orm:
- auto_generate_proxy_classes: '%kernel.debug%'
- auto_mapping: true
- # only these lines are added additionally
- mappings:
- translatable:
- type: attribute # or annotation or xml
- alias: Gedmo
- prefix: Gedmo\Translatable\Entity
- # make sure vendor library location is correct
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity"
- loggable:
- type: attribute # or annotation or xml
- alias: Gedmo
- prefix: Gedmo\Loggable\Entity
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Loggable/Entity"
- tree:
- type: attribute # or annotation or xml
- alias: Gedmo
- prefix: Gedmo\Tree\Entity
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Tree/Entity"
-```
-
-## Filters
-
-The **softdeleteable** ORM filter also needs to be configured, so that soft deleted records are filtered when querying.
-To do so, add this filter info to your **doctrine.orm** configuration, edit **config/doctrine.yaml**:
-```yaml
-doctrine:
- dbal:
- # your dbal config here
- orm:
- auto_generate_proxy_classes: '%kernel.debug%'
- auto_mapping: true
- # only these lines are added additionally
- filters:
- softdeleteable:
- class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
-```
-
-
-## Doctrine extension listener services
-
-Next, the heart of extensions are behavioral listeners which pours all the sugar. We will
-create a **yaml** service file in our config directory. The setup can be different, your config could be located
-in the bundle, it depends on your preferences. Edit **config/packages/doctrine_extensions.yaml**
-
-```yaml
-# services to handle doctrine extensions
-# import it in config/packages/doctrine_extensions.yaml
-services:
- # Attribute mapping driver for the Doctrine Extension listeners
- gedmo.mapping.driver.attribute:
- class: Gedmo\Mapping\Driver\AttributeReader
-
- # Doctrine Extension listeners to handle behaviors
- gedmo.listener.tree:
- class: Gedmo\Tree\TreeListener
- tags:
- - { name: doctrine.event_listener, event: 'prePersist'}
- - { name: doctrine.event_listener, event: 'preUpdate'}
- - { name: doctrine.event_listener, event: 'preRemove'}
- - { name: doctrine.event_listener, event: 'onFlush'}
- - { name: doctrine.event_listener, event: 'loadClassMetadata'}
- - { name: doctrine.event_listener, event: 'postPersist'}
- - { name: doctrine.event_listener, event: 'postUpdate'}
- - { name: doctrine.event_listener, event: 'postRemove'}
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- Gedmo\Translatable\TranslatableListener:
- tags:
- - { name: doctrine.event_listener, event: 'postLoad' }
- - { name: doctrine.event_listener, event: 'postPersist' }
- - { name: doctrine.event_listener, event: 'preFlush' }
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- - [ setDefaultLocale, [ "%locale%" ] ]
- - [ setTranslationFallback, [ false ] ]
-
- gedmo.listener.timestampable:
- class: Gedmo\Timestampable\TimestampableListener
- tags:
- - { name: doctrine.event_listener, event: 'prePersist' }
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- gedmo.listener.sluggable:
- class: Gedmo\Sluggable\SluggableListener
- tags:
- - { name: doctrine.event_listener, event: 'prePersist' }
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- gedmo.listener.sortable:
- class: Gedmo\Sortable\SortableListener
- tags:
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- - { name: doctrine.event_listener, event: 'prePersist' }
- - { name: doctrine.event_listener, event: 'postPersist' }
- - { name: doctrine.event_listener, event: 'preUpdate' }
- - { name: doctrine.event_listener, event: 'postRemove' }
- - { name: doctrine.event_listener, event: 'postFlush' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- gedmo.listener.softdeleteable:
- class: Gedmo\SoftDeleteable\SoftDeleteableListener
- tags:
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- Gedmo\Loggable\LoggableListener:
- tags:
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- - { name: doctrine.event_listener, event: 'postPersist' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- Gedmo\Blameable\BlameableListener:
- tags:
- - { name: doctrine.event_listener, event: 'prePersist' }
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
- Gedmo\IpTraceable\IpTraceableListener:
- tags:
- - { name: doctrine.event_listener, event: 'prePersist' }
- - { name: doctrine.event_listener, event: 'onFlush' }
- - { name: doctrine.event_listener, event: 'loadClassMetadata' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-
-```
-
-So what does it include in general? Well, it creates services for all extension listeners.
-You can remove some which you do not use, or change them as you need. **Translatable** for instance,
-sets the default locale to the value of your `%locale%` parameter, you can configure it differently.
-
-**Note:** In case you noticed, there is **EventSubscriber\DoctrineExtensionSubscriber**.
-You will need to create this subscriber class if you use **loggable** , **translatable** or **blameable**
-behaviors. This listener will set the **locale used** from request and **username** to
-loggable and blameable. So, to finish the setup create **EventSubscriber\DoctrineExtensionSubscriber**
-
-## Register event listener for [Symfony Doctrine MongoDB Bundle](https://github.com/doctrine/DoctrineMongoDBBundle)
-
-You also need to manually tag the listeners. Otherwise, the listeners will not be listening to the triggered events
-of Doctrine.
-
-```yaml
-services:
- Gedmo\Loggable\LoggableListener:
- tags:
- - { name: doctrine_mongodb.odm.event_listener, event: 'onFlush' }
- - { name: doctrine_mongodb.odm.event_listener, event: 'loadClassMetadata' }
- - { name: doctrine_mongodb.odm.event_listener, event: 'postPersist' }
- calls:
- # Uncomment the below call if using attributes, and comment the call for the annotation reader
- # - [ setAnnotationReader, [ "@gedmo.mapping.driver.attribute" ] ]
- # The `annotation_reader` service was deprecated in Symfony 6.4 and removed in Symfony 7.0
- - [ setAnnotationReader, [ "@annotation_reader" ] ]
-```
-
-```php
-blameableListener = $blameableListener;
- $this->tokenStorage = $tokenStorage;
- $this->translatableListener = $translatableListener;
- $this->loggableListener = $loggableListener;
- }
-
-
- public static function getSubscribedEvents(): array
- {
- return [
- KernelEvents::REQUEST => 'onKernelRequest',
- KernelEvents::FINISH_REQUEST => 'onLateKernelRequest'
- ];
- }
- public function onKernelRequest(): void
- {
- if (
- $this->tokenStorage->getToken() !== null &&
- $this->tokenStorage->getToken()->getUser() !== null
- ) {
- $this->blameableListener->setUserValue($this->tokenStorage->getToken()->getUser());
- }
- }
-
- public function onLateKernelRequest(FinishRequestEvent $event): void
- {
- $this->translatableListener->setTranslatableLocale($event->getRequest()->getLocale());
- }
-}
-```
-
-
-
-## Example
-
-After that, you have your extensions set up and ready to be used! Too easy right? Well,
-if you do not believe me, let's create a simple entity in our project:
-
-```php
-
-id;
- }
-
- public function setTitle(?string $title): void
- {
- $this->title = $title;
- }
-
- public function getTitle(): ?string
- {
- return $this->title;
- }
-
- public function getCreated(): ?DateTimeImmutable
- {
- return $this->created;
- }
-
- public function getUpdated(): ?DateTimeImmutable
- {
- return $this->updated;
- }
-
- public function getDeletedAt(): ?DateTimeImmutable
- {
- return $this->deletedAt;
- }
-
- public function setDeletedAt(?DateTimeImmutable $deletedAt): void
- {
- $this->deletedAt = $deletedAt;
- }
-}
-```
-
-Now, let's have some fun:
-
-- if you have not created the database yet, run `php bin/console doctrine:database:create`
-- create the schema `php bin/console doctrine:schema:create`
-
-Everything will work just fine, you can modify the **App\Controller\DemoController**
-and add an action to test how it works:
-
-```php
-// file: src/Controller/DemoController.php
-// include this code portion
-
-/**
- * @Route("/posts", name="_demo_posts")
- */
-public function postsAction(EntityManagerInterface $em): Response
-{
- $repository = $em->getRepository(App\Entity\BlogPost::class);
- // create some posts in case if there aren't any
- if (!$repository->find('hello_world')) {
- $post = new App\Entity\BlogPost();
- $post->setTitle('Hello world');
-
- $next = new App\Entity\BlogPost();
- $next->setTitle('Doctrine extensions');
-
- $em->persist($post);
- $em->persist($next);
- $em->flush();
- }
- $posts = $repository->findAll();
- dd($posts);
-}
-```
-
-Now if you follow the url: **http://your_virtual_host/demo/posts** you
-should see a print of posts, this is only an extension demo, we will not create a template.
-
-
-
-## More tips
-
-Regarding, the setup, I do not think it's too complicated to use, in general it is simple
-enough, and lets you understand at least small parts on how you can hook mappings into doctrine, and
-how easily extension services are added. This configuration does not hide anything behind
-curtains and allows you to modify the configuration as you require.
-
-### Multiple entity managers
-
-If you use more than one entity manager, you can simply tag the subscriber
-with other the manager name:
-
-
-Regarding, mapping of ODM mongodb, it's basically the same:
-
-```yaml
-doctrine_mongodb:
- default_database: 'my_database'
- default_connection: 'default'
- default_document_manager: 'default'
- connections:
- default: ~
- document_managers:
- default:
- connection: 'default'
- auto_mapping: true
- mappings:
- translatable:
- type: attribute # or annotation or xml
- alias: GedmoDocument
- prefix: Gedmo\Translatable\Document
- # make sure vendor library location is correct
- dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Document"
-```
-
-This also shows, how to make mappings based on single manager. All what differs is that **Document**
-instead of **Entity** is used. I haven't tested it with mongo though.
-
-**Note:** [extension repository](https://github.com/doctrine-extensions/DoctrineExtensions) contains all
-[documentation](../doc) you may need
-to understand how you can use it in your projects.
-
-
-
-## Alternative over configuration
-
-You can use [StofDoctrineExtensionsBundle](https://github.com/stof/StofDoctrineExtensionsBundle) which is a wrapper of these extensions
-
-## Troubleshooting
-
-- Make sure there are no *.orm.yml or *.orm.xml files for your Entities in your bundles Resources/config/doctrine directory. With those files in place the annotations won't be taken into account.