hostnet / entity-mutation-component
监听事件以进行突变
Requires
- php: ^7.3||^8.0
- doctrine/orm: ^2.7.4
- hostnet/entity-tracker-component: ^2.0.1
Requires (Dev)
- hostnet/database-test-lib: ^2.0.2
- hostnet/phpcs-tool: ^9.1.0
- phpunit/phpunit: ^9.5.6
- symfony/cache: ^5.3
README
文档
实体突变组件是什么?
实体突变组件是一个库,它利用实体跟踪组件,并允许您挂钩到实体变更事件。
该组件允许您根据两种不同的策略自动存储突变:复制当前状态和复制上一个状态。第一种将当前状态复制到突变实体中,而后者将上一个状态复制到突变实体中。
要求
实体突变组件需要至少php 7.3,并运行在Doctrine2上。对于具体要求,请检查composer.json。
安装
安装非常简单,此软件包可在packagist上获取。您可以注册软件包并将其锁定到主要版本,因为我们遵循语义版本化2.0.0。
示例
$ composer require hostnet/entity-mutation-component
文档
它是如何工作的?
它通过在您的实体上放置@Mutation
注解并在实体变更事件上注册监听器来实现,假设您已经配置了实体跟踪组件。
以下是一个使用示例。
设置
- 您必须在您的实体上添加
@Mutation
- 您必须创建您的突变实体
- 可选地,如果您您的实体知道自己的突变,您可以添加
MutationAwareInterface
注册事件
以下是一个非常基本的设置示例。如果您使用具有依赖注入容器的框架,设置将会更容易。
设置可能看起来有点复杂,但实际上大部分是设置跟踪组件。如果您在框架中使用它,建议为此创建一个特定于框架的配置软件包以自动化此过程。
注意:如果您使用Symfony,可以查看hostnet/entity-tracker-bundle。此捆绑包旨在为您配置服务。
use Hostnet\Component\EntityMutation\Resolver\MutationResolver; use Hostnet\Component\EntityTracker\Listener\EntityChangedListener; use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider; use Hostnet\Component\EntityTracker\Provider\EntityMutationMetadataProvider; /* @var $em \Doctrine\ORM\EntityManager */ $event_manager = $em->getEventManager(); // default doctrine annotation reader $annotation_reader = new AnnotationReader(); // setup required providers $annotation_metadata_provider = new EntityAnnotationMetadataProvider($annotation_reader); $mutation_metadata_provider = new EntityMutationMetadataProvider($annotation_reader); // pre flush event listener that uses the @Mutation annotation $entity_changed_listener = new EntityChangedListener( $annotation_metadata_provider, $mutation_metadata_provider ); // the resolver is used to find the correct annotation, which // fields are considered to be tracked and stored as mutation // and which entity represents your Mutation entity. $mutation_resolver = new MutationResolver($annotation_metadata_provider); // creating the mutation listener $mutation_listener = new MutationListener($mutation_resolver); // register the events $event_manager->addEventListener('prePersist', $entity_changed_listener); $event_manager->addEventListener('preFlush', $entity_changed_listener); $event_manager->addEventListener('entityChanged', $mutation_listener);
配置实体
现在我们只需要在实体上放置@Mutation
注解。注解有2个选项
- 策略;这将确定是存储当前状态还是上一个状态在突变中
- 类;您的突变类的完整命名空间。默认情况下,它是当前类名后缀为Mutation(即
Acme\MyEntity
默认为Acme\MyEntityMutation
)。
此外,您还可以配置实体以成为MutationAware,这是可选的。
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Mapping as ORM; use Hostnet\Component\EntityMutation\Mutation; use Hostnet\Component\EntityMutation\MutationAwareInterface; /** * @ORM\Entity * @ORM\Table(name="users") * @Mutation( * class = "MyUserEntityMutation", * strategy = "previous" * ) * The above values are equal to the defaults. They are only * here to show how you can use them outside of this example */ class MyUserEntity implements MutationAwareInterface { ... private $id; /** * @ORM\... */ private $city; /** * @ORM\... */ private $name; /** * @ORM\OneToMany... * @var ArrayCollection */ private $mutations; public function setName($name) { ... } public function getName() { ... } public function addMutation($element) { $this->mutations->add($element); } public function getMutations() { return $this->mutations; } /** * Used to get the last mutation stored, you might want to change * it to return the one before that if your strategy is current. */ public function getPreviousMutation() { $criteria = (new Criteria()) ->orderBy(['id' => Criteria::DESC]) ->setMaxResults(1); return $this->mutations->matching($criteria)->current() ? : null; } }
创建突变实体
变异本身就是一个实体。在当前版本中,MutationResolver 仅会在实体和实体变异之间共享字段时返回变异字段。这可以通过添加一个包含共享字段的特性来轻松完成。在这个例子中,将用于存储变异的唯一属性是 $name
。
构造函数是您应该遵循的少数实际约定之一,以便使用变异。第一个参数是当前管理与实体,其中原始数据是上一个状态(如 doctrine 上次检索时那样处理)并且不受 doctrine 管理。
这样做是为了让您完全控制要存储的哪些字段以及如何存储变异。例如,在某些情况下,您可能想要总结或转换某些字段,如果自动完成而不使用复杂的数据转换器系统,则可能无法完成。
注意:$original_data 是一个非管理实体,仅应用于读取属性。使用第一个参数进行连接。
use Doctrine\ORM\Mapping as ORM; class MyUserEntityMutation { ... /** * @ORM\ManyToOne(targetEntity="MyUserEntity", inversedBy="mutations") */ private $user; /** * @ORM\... */ private $name; public function setName($name) { ... } public function getName() { ... } public function __construct(MyUserEntity $user, MyUserEntity $original_data) { // link our user to the mutation $this->user = $user; // populate the mutation with data from the previous state $this->name = $original_data->getName(); } }
一个完整的工作示例可以在我们的测试中找到,请参见:链接
接下来是什么?
$my_user_entity->setName('Henk'); // was Hans before $em->flush(); var_dump($my_user_entity->getPreviousMutation()); // shows the state it had with Hans