dualmedia/dynamic-orm-value-bundle
Installation
composer require dualmedia/dynamic-orm-value-bundle
Register the bundle in config/bundles.php:
DualMedia\DynamicORMValueBundle\DynamicORMValueBundle::class => ['all' => true],
Configure Entity Paths
Create config/packages/dm_dynamic_orm.yaml:
dm_dynamic_orm:
entity_paths:
- '%kernel.project_dir%/src/Entity'
Annotate Your Entity
Use the #[DynamicValue] attribute on a property to mark it for dynamic generation:
use DualMedia\DynamicORMValueBundle\Attribute\DynamicValue;
#[ORM\Entity]
class Order
{
#[DynamicValue]
private string $userFriendlyId;
}
First Use Case Persist an entity to auto-generate the dynamic value:
$order = new Order();
$entityManager->persist($order);
$entityManager->flush(); // $order->userFriendlyId is now populated
Marking Dynamic Fields
Use #[DynamicValue] on properties that should be auto-generated during persist()/flush():
#[DynamicValue(strategy: 'uuid')] // Optional: specify generation strategy
private string $trackingCode;
Custom Strategies
Extend the default strategies (e.g., uuid, incremental) by implementing DynamicValueStrategyInterface:
class CustomStrategy implements DynamicValueStrategyInterface
{
public function generate(): string
{
return 'CUSTOM-' . time();
}
}
Register it in dm_dynamic_orm.yaml:
dm_dynamic_orm:
strategies:
custom: DualMedia\DynamicORMValueBundle\Strategy\CustomStrategy
Use it in your entity:
#[DynamicValue(strategy: 'custom')]
private string $customField;
Conditional Generation
Use the #[DynamicValue] if option to control when a value is generated:
#[DynamicValue(if: 'this->isActive()')]
private string $activeToken;
Integration with Events
Listen to prePersist/preUpdate to inject dynamic values manually:
$entityManager->getEventManager()->addEventListener(
ORMEvents::prePersist,
function (PrePersistEventArgs $args) {
$entity = $args->getObject();
if ($entity instanceof Order && $entity->isReadyForFriendlyId()) {
$entity->setUserFriendlyId('MANUAL-' . uniqid());
}
}
);
Bulk Operations
For batch inserts, leverage EntityManager::flush() after setting dynamic values in a loop:
foreach ($orders as $order) {
$order->setUserFriendlyId('BATCH-' . $order->getId());
}
$entityManager->flush();
Circular Dependencies
Avoid annotating properties that rely on other dynamic values in the same entity. The bundle processes fields in declaration order, which may lead to incomplete data if A depends on B and both are dynamic.
Configuration Overrides
If entity_paths is misconfigured, the bundle silently ignores annotated entities. Verify paths in dm_dynamic_orm.yaml and check for #[DynamicValue] attributes not triggering.
Strategy Conflicts
Custom strategies must implement DynamicValueStrategyInterface exactly. Missing methods (e.g., generate()) will throw BadMethodCallException at runtime.
Doctrine Lifecycle Events
Dynamic values generated in prePersist may not reflect in postPersist if the entity is modified afterward. Use postPersist for final adjustments:
$entityManager->getEventManager()->addEventListener(
ORMEvents::postPersist,
function (PostPersistEventArgs $args) {
$entity = $args->getObject();
if ($entity instanceof Order) {
$entity->setGeneratedAt(new \DateTime());
}
}
);
Performance with Large Batches
Generating dynamic values for thousands of entities in a single flush() can cause delays. Consider:
incremental instead of uuid).Enable Logging
Add this to config/packages/monolog.yaml to log dynamic value generation:
handlers:
dynamic_orm:
type: stream
path: "%kernel.logs_dir%/dynamic_orm.log"
level: debug
channels: ["dynamic_orm"]
Then configure the bundle to use the channel:
dm_dynamic_orm:
logging_channel: dynamic_orm
Check Event Subscribers
Ensure no other subscribers are overriding dynamic values. Inspect EventManager listeners:
$listeners = $entityManager->getEventManager()->getListeners();
print_r($listeners[ORMEvents::prePersist]);
Validate Strategies Test strategies in isolation:
$strategy = new \DualMedia\DynamicORMValueBundle\Strategy\UuidStrategy();
var_dump($strategy->generate()); // Should output a UUID
Custom Value Sources
Implement DynamicValueSourceInterface to fetch values from external systems (e.g., APIs):
class ApiValueSource implements DynamicValueSourceInterface
{
public function getValue(): string
{
return file_get_contents('https://api.example.com/value');
}
}
Use it in dm_dynamic_orm.yaml:
dm_dynamic_orm:
sources:
api: DualMedia\DynamicORMValueBundle\Source\ApiValueSource
Annotate the entity:
#[DynamicValue(source: 'api')]
private string $externalValue;
Post-Generation Hooks
Extend the bundle’s DynamicValueGenerator to add logic after value generation:
$generator = $container->get('dm_dynamic_orm.generator');
$generator->addPostGenerateListener(
Order::class,
function (Order $order) {
$order->setGeneratedAt(new \DateTime());
}
);
Override Default Strategies
Replace default strategies (e.g., uuid) by binding your implementation as a service:
services:
DualMedia\DynamicORMValueBundle\Strategy\UuidStrategy:
class: App\Strategy\CustomUuidStrategy
How can I help you explore Laravel packages today?