This bundle is meant to convert between doctrine and symfony events seamlessly, as well as allow for creation of sub-events with their own requirements and checks
It allows you to streamline doctrine actions using symfony directly, without need of implementing doctrine's listeners and event logic.
All of the hard work is already done, just declare your entities, implement EntityInterface
on them, and create an abstract event class.
Simply composer require dualmedia/symfony-doctrine-event-converter-bundle
Then add the bundle to your config/bundles.php
file like so
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
// other bundles ...
DualMedia\DoctrineEventDistributorBundle\DoctrineEventConverterBundle::class => ['all' => true],
];
Make a Doctrine-managed entity, that also implements the DualMedia\DoctrineEventDistributorBundle\Interfaces\EntityInterface
use Doctrine\ORM\Mapping as ORM;
use DualMedia\DoctrineEventDistributorBundle\Interfaces\EntityInterface;
#[ORM\Entity]
class Item implements EntityInterface
{
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'smallint')]
private ?int $status = null;
public function getId()
{
return $this->id;
}
public function getStatus(): ?int
{
return $this->status;
}
public function setStatus(
int $status
): self {
$this->status = $status;
return $this;
}
}
Create an event class (not final), and then at some point extend DualMedia\DoctrineEventDistributorBundle\Event\AbstractEntityEvent
,
mark this class with your appropriate event annotation, either one of the base ones or SubEvent
use DualMedia\DoctrineEventDistributorBundle\Attributes\PrePersistEvent;
use DualMedia\DoctrineEventDistributorBundle\Event\AbstractEntityEvent;
#[PrePersistEvent]
abstract class ItemEvent extends AbstractEntityEvent
{
public static function getEntityClass(): ?string
{
return Item::class;
}
}
The bundle will then automatically generate proxy classes for appropriate events.
Each proxy class starts with the proxy namespace visible here under the PROXY_NS
constant value.
The following class name will always contain the full namespace of the parent event. This namespace is loaded via the autoloader in the bundle and should not be interacted with in ways other than subscribers and general use.
Let's assume the following scenario: You wish to have an event fired when the status of the Item
changes from pending
to complete
,
in this case you'd add the following attribute on your ItemEvent
(above).
SubEvents can take form of checks which apply to the previous and current state of variable, or only one (from OR to).
Because of how Doctrine passes changes unfortunately changes to collections are not known at this time.
The following will generate an ItemPendingToCompleteEvent
class (under the default proxy namespace).
use \DualMedia\DoctrineEventConverterBundle\Attributes\SubEvent;
use \DualMedia\DoctrineEventConverterBundle\Model\Change;
#[SubEvent("PendingToComplete", changes: [new Change('status', ItemStatusEnum::Pending, ItemStatusEnum::Complete)])]
Assuming of course the existence of an enum or other value which can be passed to the Change
model.
More than one change can be required at a time, or any change, depending on SubEvent::$allMode
.
The following will generate an ItemFromPendingEvent
.
#[SubEvent("FromPending", changes: [new Change('status', ItemStatusEnum::Pending)])]
The following will generate an ItemCompleteEvent
.
#[SubEvent("Complete", changes: [new Change('status', to: ItemStatusEnum::Complete)])]
Ready-to-use templates are available below to make your lives a bit easier.
Plugins may be provided at a later time, but it's not certain.
Note: in future a phpstan.neon file will be provided to ignore these issues, for the time being simply add the following lines into your file.
parameters:
ignoreErrors:
- '#Class DualMedia\\DoctrineEventConverterProxy\\[a-zA-Z0-9\\_]+ not found#'
- '#Parameter \$[a-zA-Z0-9\\_]+ of method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\) has invalid type DualMedia\\DoctrineEventConverterProxy\\[a-zA-Z0-9\\_]+#'
- '#Instantiated class DualMedia\\DoctrineEventConverterProxy\\[a-zA-Z0-9\\_]+ not found.#'
- '#Call to method [a-zA-Z0-9\\_]+\(\) on an unknown class DualMedia\\DoctrineEventConverterProxy\\[a-zA-Z0-9\\_]+.#'
I also suggest disabling reportUnmatchedIgnoredErrors
in your config, but it's not strictly necessary.
This configuration needs to be copied over as psalm does not allow including files.
<issueHandlers>
<UndefinedClass>
<errorLevel type="suppress">
<referencedClass name="DualMedia\DoctrineEventConverterProxy\*"/>
</errorLevel>
</UndefinedClass>
<UndefinedDocblockClass>
<errorLevel type="suppress">
<referencedClass name="DualMedia\DoctrineEventConverterProxy\*"/>
</errorLevel>
</UndefinedDocblockClass>
</issueHandlers>