dualmedia / symfony-doctrine-event-converter-bundle
一个用于从 Doctrine 变更创建 symfony 事件的 symfony 扩展包
Requires
- php: ^8.1
- doctrine/common: ^2|^3
- doctrine/doctrine-bundle: ^1.12|^2.0
- doctrine/orm: ^2.14|^3
- symfony/event-dispatcher: ^5.4|^6.2|^7
- symfony/framework-bundle: ^5.4|^6.2|^7
- symfony/http-kernel: ^5.4|^6.2|^7
- symfony/property-access: ^5.4|^6.2|^7
Requires (Dev)
- dama/doctrine-test-bundle: ^8|^7
- doctrine/doctrine-fixtures-bundle: ^3
- friendsofphp/php-cs-fixer: ^3
- jetbrains/phpstorm-attributes: ^1.0
- matthiasnoback/symfony-dependency-injection-test: ^5
- pedrotroller/php-cs-custom-fixer: ^2
- phpstan/phpstan: ^1
- phpunit/phpunit: ^10
- pkly/phpunit-service-create-trait: ^1.0
- vimeo/psalm: ^5
README
此扩展包旨在无缝地在 Doctrine 和 symfony 事件之间进行转换,同时允许创建具有自己需求和检查的子事件
它允许您直接使用 symfony 简化 Doctrine 操作,而无需实现 Doctrine 的监听器和事件逻辑。
所有的工作都已经完成,只需声明您的实体,在它们上实现 EntityInterface
,然后创建一个抽象事件类。
安装
简单地运行 composer require dualmedia/symfony-doctrine-event-converter-bundle
然后按照以下方式将扩展包添加到您的 config/bundles.php
文件中
return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], // other bundles ... DualMedia\DoctrineEventDistributorBundle\DoctrineEventConverterBundle::class => ['all' => true], ];
使用方法
实体
创建一个由 Doctrine 管理的实体,同时实现 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; } }
事件
创建一个事件类(非最终),然后在某个时刻扩展 DualMedia\DoctrineEventDistributorBundle\Event\AbstractEntityEvent
,使用适当的注解标记此类,可以是基本注解之一或子事件
use DualMedia\DoctrineEventDistributorBundle\Attributes\PrePersistEvent; use DualMedia\DoctrineEventDistributorBundle\Event\AbstractEntityEvent; #[PrePersistEvent] abstract class ItemEvent extends AbstractEntityEvent { public static function getEntityClass(): ?string { return Item::class; } }
该扩展包将自动为适当的事件生成代理类。
每个代理类的命名空间开头可见于 此处 的 PROXY_NS
常量值下。
以下类名将始终包含父事件的完整命名空间。此命名空间由扩展包中的自动加载器加载,不应以其他方式(除订阅者和一般使用外)与之交互。
子事件
假设以下场景:您希望在 Item
的状态从 pending
变更为 complete
时触发事件,在这种情况下,您需要在您的 ItemEvent
(上面)中添加以下属性。
子事件可以是应用于变量先前和当前状态(或其中之一)的检查,或者仅应用于一个(从 OR 到)。
重要
由于 Doctrine 的传递方式,遗憾的是目前尚不知道集合的变化。
从和到
以下将生成一个 ItemPendingToCompleteEvent
类(在默认代理命名空间下)。
use \DualMedia\DoctrineEventConverterBundle\Attributes\SubEvent; use \DualMedia\DoctrineEventConverterBundle\Model\Change; #[SubEvent("PendingToComplete", changes: [new Change('status', ItemStatusEnum::Pending, ItemStatusEnum::Complete)])]
当然,假设存在可以传递给 Change
模型的枚举或其他值。
一次可能需要多个更改,或者根据 SubEvent::$allMode
是任何更改。
从
以下将生成一个 ItemFromPendingEvent
。
#[SubEvent("FromPending", changes: [new Change('status', ItemStatusEnum::Pending)])]
到
以下将生成一个 ItemCompleteEvent
。
#[SubEvent("Complete", changes: [new Change('status', to: ItemStatusEnum::Complete)])]
PHPStan 和 Psalm 问题忽略
以下提供了一些现成的模板,以使您的工作更加容易。
将来可能提供插件,但尚未确定。
PHPStan
注意:将来将提供 phpstan.neon 文件以忽略这些问题,目前只需将以下行添加到您的文件中。
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\\_]+.#'
我还建议在您的配置中禁用 reportUnmatchedIgnoredErrors
,但这不是强制性的。
Psalm
需要将此配置复制过来,因为 Psalm 不允许包含文件。
<issueHandlers> <UndefinedClass> <errorLevel type="suppress"> <referencedClass name="DualMedia\DoctrineEventConverterProxy\*"/> </errorLevel> </UndefinedClass> <UndefinedDocblockClass> <errorLevel type="suppress"> <referencedClass name="DualMedia\DoctrineEventConverterProxy\*"/> </errorLevel> </UndefinedDocblockClass> </issueHandlers>