kabiroman / adaptive-entity-manager-bundle
Symfony bundle for kabiroman/adaptive-entity-manager integration
Installs: 12
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.1
- kabiroman/adaptive-entity-manager: ^1.2
- psr/event-dispatcher: ^1.0
- psr/log: ^1.0 || ^2.0 || ^3.0
- symfony/event-dispatcher: ^6.0 || ^7.0
- symfony/framework-bundle: ^6.0 || ^7.0
Requires (Dev)
- phpunit/phpunit: ^10.5
- symfony/monolog-bundle: ^3.0 || ^4.0
- symfony/phpunit-bridge: ^6.4
README
Introduction
This bundle provides flexible entity management for Symfony applications, integrating with Doctrine ORM to handle entities dynamically from YAML configurations. In version 2.0.0, it introduces enhanced support for multiple EntityManagers, allowing for more complex and adaptable database interactions. It enables automated loading of entity definitions and supports various EntityManagers for improved flexibility.
Installation
To install the bundle, use Composer:
composer require kabiroman/adaptive-entity-manager-bundle
Add the bundle to your config/bundles.php
:
return [ // ... Kabiroman\AdaptiveEntityManagerBundle\AdaptiveEntityManagerBundle::class => ['all' => true], ];
Configuration (Version 2.0.0 and above)
With version 2.0.0, the bundle now supports multiple entity managers. You must explicitly define each manager under the entity_managers
key.
Configure the bundle in config/packages/adaptive_entity_manager.yaml
. Example:
adaptive_entity_manager: entity_managers: default: entities_dir: '%kernel.project_dir%/src/Entity/Adaptive' entities_namespace: 'App\Entity\Adaptive\' connection: default # Assuming 'default' is configured in doctrine.yaml metadata_cache: 'cache.app' # Optional: PSR-6 cache service ID for metadata caching use_optimized_metadata: true # Optional: Enable optimized metadata system (default: true) custom: entities_dir: '%kernel.project_dir%/src/Entity/Adaptive/Custom' entities_namespace: 'App\Entity\Adaptive\Custom\' connection: custom # Assuming 'custom' is configured in doctrine.yaml metadata_cache: 'cache.custom' # Optional: Different cache service for this manager use_optimized_metadata: false # Optional: Disable optimization for this manager
Important Note on Entity Metadata Paths (Version 2.0.0+)
In versions prior to 2.0.0, the entities_dir
was a top-level configuration. With the introduction of multiple entity managers in 2.0.0, the entities_dir
(and entities_namespace
) are now configured per entity manager within the entity_managers
section. This allows each manager to define its own specific directory for YAML entity metadata files and their corresponding namespace.
Performance Configuration Options (Version 2.3.0+)
Starting from version 2.3.0, the bundle supports additional performance optimization options:
metadata_cache
(optional)
- Type: string (PSR-6 cache service ID)
- Default: null (no caching)
- Description: Specifies a PSR-6 cache service to use for caching entity metadata. This significantly improves performance by avoiding re-parsing of YAML entity definitions on every request.
- Example values:
'cache.app'
,'cache.redis'
,'cache.custom'
use_optimized_metadata
(optional)
- Type: boolean
- Default: true
- Description: Enables the optimized metadata system which provides better performance for metadata operations. When enabled, uses
OptimizedEntityMetadataFactory
instead of the standardEntityMetadataFactory
. - Recommendation: Keep enabled (true) for production environments unless you have specific compatibility requirements.
Performance Impact: Using both metadata_cache
and use_optimized_metadata: true
can significantly reduce application startup time and improve overall performance, especially in applications with many entity definitions.
Entity Metadata Paths and Automatic Discovery
Hardcoded Automatic Discovery Path:
The bundle includes an automatic discovery mechanism that searches for entity YAML files in a hardcoded directory: %kernel.project_dir%/config/aem/entities/
.
* For each defined entity manager (e.g., `default`, `custom`), the bundle will look for YAML files named `[manager_name].*.yaml` within this hardcoded directory. For instance, for the `default` manager, it will search for `default.user.yaml`, `default.product.yaml`, etc.
* Entities found via this automatic discovery are merged with entities configured via the `entities_dir` for that specific manager.
Configuring Adaptive Entity Metadata
Adaptive entities allow dynamic definition of entity metadata via YAML files. Each YAML file in the entities_dir
for a specific manager should define the structure of an entity, including fields, types, and other metadata.
Example YAML for an Entity
# user.yaml (For automatic discovery, name it `default.user.yaml` and place it in `%kernel.project_dir%/config/aem/entities/`.) App\Entity\User: dataAdapterClass: App\DataAdapter\UserDataAdapter id: id: column: id type: integer nullable: false fields: login: column: login type: string nullable: false hasOne: role: targetEntity: App\Entity\User\Role joinColumn: name: role_id referencedColumnName: id hasMany: posts: targetEntity: App\Entity\User\Post mappedBy: author fetch: LAZY lifecycleCallbacks: prePersist: - setCreatedAt
For automated entity loading, place individual YAML files in the configured entities_dir
for each manager.
Registering the entity data adapter
This section covers how to properly register and configure the data adapter for entities, including custom adapters, to integrate with your Doctrine setup via the EntityDataAdapterProvider.
Steps to Register Custom Adapters:
- Create a custom adapter class that implements the required interface (e.g., based on Kabiroman\AEM\DataAdapter\EntityDataAdapter).
- Register your custom adapter as a service in Symfony's services.yaml or via autowiring, tagging it appropriately for the provider.
- In your configuration (e.g., config/packages/adaptive_entities/user.yaml), reference the custom adapter in the EntityDataAdapter setup.
- Test the custom adapter by injecting it into your code and verifying entity operations without altering database schemas.
Example Service Registration in services.yaml:
services: App\CustomAdapter: class: App\CustomEntityDataAdapter tags: ['adaptive_entity_manager.adapter'] # Assuming a tag for the provider arguments: ['@doctrine'] # Inject dependencies as needed
Usage (Version 2.0.0 and above)
With the introduction of multiple entity managers, you now interact with a ManagerRegistry
to retrieve specific entity managers by name.
use Kabiroman\AdaptiveEntityManagerBundle\Service\ManagerRegistryInterface; use App\Entity\Adaptive\User; // Example entity, adjust namespace as per your config // In your controller or service, inject ManagerRegistryInterface class MyService { private $managerRegistry; public function __construct(ManagerRegistryInterface $managerRegistry) { $this->managerRegistry = $managerRegistry; } public function doSomething() { // Get the default entity manager $defaultManager = $this->managerRegistry->getManager('adaptive_entity_manager.default_entity_manager'); $userRepository = $defaultManager->getRepository(User::class); $user = $userRepository->find(1); // Or get a custom entity manager $customManager = $this->managerRegistry->getManager('adaptive_entity_manager.custom_entity_manager'); // ... use customManager // Example of persisting a new entity with the default manager $newUser = new User(); // Set properties of newUser $defaultManager->persist($newUser); $defaultManager->flush(); } }
Event Handling (Version 2.1.0 and above)
With the introduction of PSR-14 event support, the bundle now dispatches various lifecycle events, allowing you to react to different operations. These events are native Symfony events and can be subscribed to using Symfony's event dispatcher mechanism.
UnitOfWork Events (Version 2.2.0 and above)
In addition to ManagerRegisteredEvent
, the bundle also dispatches events related to the UnitOfWork
lifecycle. These events wrap the core UnitOfWork
events from kabiroman/adaptive-entity-manager
and are dispatched as native Symfony events, allowing you to hook into the persist, update, and remove operations.
PrePersistEntityEvent
: Dispatched before an entity is persisted.PostPersistEntityEvent
: Dispatched after an entity has been persisted.PreUpdateEntityEvent
: Dispatched before an entity is updated.PostUpdateEntityEvent
: Dispatched after an entity has been updated.PreRemoveEntityEvent
: Dispatched before an entity is removed.PostRemoveEntityEvent
: Dispatched after an entity has been removed.
To subscribe to these events, you can create a Symfony event subscriber. The events are Symfony\Contracts\EventDispatcher\Event
objects and can be stopped using StoppableEventInterface
.
Breaking Changes in 2.0.0
- Default
EntityManager
removed: You must now explicitly specify a manager name when retrieving anEntityManager
. Direct access to a defaultEntityManager
service (e.g.,Kabiroman\AEM\EntityManagerInterface::class
) is no longer supported directly without using theManagerRegistry
.
Migration Guide from 1.x to 2.0.0
-
Update Configuration: Your
adaptive_entity_manager
configuration inconfig/packages/adaptive_entity_manager.yaml
must be updated to use theentity_managers
key.Before (1.x):
adaptive_entity_manager: entities_dir: '%kernel.project_dir%/src/Entity/Adaptive' entities_namespace: 'App\Entity\Adaptive\' connection: default
After (2.0.0+):
adaptive_entity_manager: entity_managers: default: entities_dir: '%kernel.project_dir%/src/Entity/Adaptive' entities_namespace: 'App\Entity\Adaptive\' connection: default # Performance options (available since 2.3.0): metadata_cache: 'cache.app' # Optional: PSR-6 cache for metadata use_optimized_metadata: true # Optional: Enable optimizations
-
Replace
EntityManagerInterface
calls: Instead of directly injectingKabiroman\AEM\EntityManagerInterface
, you should now injectKabiroman\AdaptiveEntityManagerBundle\Service\ManagerRegistryInterface
and retrieve managers by name.Before (1.x):
use Kabiroman\AEM\EntityManagerInterface; // ... $manager = $container->get(EntityManagerInterface::class);
After (2.0.0):
use Kabiroman\AdaptiveEntityManagerBundle\Service\ManagerRegistryInterface; // ... $defaultManager = $container->get(ManagerRegistryInterface::class)->getManager('adaptive_entity_manager.default_entity_manager'); $customManager = $container->get(ManagerRegistryInterface::class)->getManager('adaptive_entity_manager.custom_entity_manager');
Changelog
See CHANGELOG.md for detailed changes.
Contributing
Contributions are welcome! Please submit pull requests or issues via the repository.
License
This bundle is open-source and licensed under the MIT License.