pcz /deferred-kdyby-events
为doctrine2和nette提供的deferred kdyby事件助手
Requires
- kdyby/console: >=2.4
- kdyby/doctrine: >=2.3
- kdyby/events: >=2.4
This package is not auto-updated.
Last update: 2024-09-20 19:25:59 UTC
README
Nette框架的deferred事件扩展(使用kdyby/events & kdyby/doctrine)aneb kdyby až bude Bavorov...
此kdyby/events事件系统扩展为您的应用程序提供延迟事件的支撑。实现了以下两种基本类型的延迟事件:
- 简单延迟事件 - 事件被持久化,并设置为在未来某个特定时间触发
- 分组延迟事件 - 每个事件都有一个groupID属性。当一个新的事件被持久化时,所有等待的具有相同groupID的事件都会被取消。例如,您可以使用它们发送通知 - 当用户在10分钟内收到5条消息时,只有一条通知将通过此类型的事件发送。此外,还有一个类注解@Keeping,它改变分组策略的行为 - 最近的将保留,而后续的将被取消,因此最终的等待时间不会延长。
要求
- PHP 5.4或更高版本。
- Nette框架
- kdyby/doctrine
- kdyby/events
- kdyby/console
安装
- 使用Composer安装此扩展
$ composer require pcz/deferred-kdyby-events
- 在您的config neon文件中启用扩展
extensions: # add this line deferredEvents: pcz\DeferredKdybyEvents\DI\DeferredEventsExtension
-
其他扩展的配置也需要,请参阅以下依赖项的文档:Kdyby/Doctrine,Kdyby/Events 和 Kdyby/Console。
-
在config中启用扩展后更新数据库模式(确保清除缓存并运行
orm:schema-tool:update
命令) -
差不多完成了,让我们设置一个cron作业
*/5 * * * * /path/to/php /path/to/your/app/www/index.php deferredEvents:fire
介绍
每个事件都由其事件类表示。它必须扩展以下基类之一:pcz\DeferredKdybyEvents\DeferredEvent
或 pcz\DeferredKdybyEvents\GroupedDeferredEvent
。实际上,每个事件类都是一个ORM实体,因此不要忘记在类属性上使用ORM注解。使用MTI(多表继承)继承类型会导致每个事件在数据库模式中由1个表表示。在添加新事件类后,也需要更新数据库模式。
示例
让我们从简单的延迟事件类型开始,以下示例显示了产品价格计划更改的实现
事件类
use Doctrine\ORM\Mapping as ORM; /** @ORM\Entity */ class ChangeProductPriceEvent extends \pcz\DeferredKdybyEvents\DeferredEvent { const EVENT_NAME = 'ChangeProductPrice'; /** * @var Product * @ORM\ManyToOne(targetEntity="Product") */ protected $product; /** * @var integer * @ORM\Column(type="integer") */ protected $new_price; public function __construct(\DateTime $execution_date, Product $product, $new_price) { parent::__construct($execution_date); $this->product = $product; $this->new_price = $new_price; } public function getEventName() { return self::EVENT_NAME; } public function getProduct() { return $this->product; } public function getNewPrice() { return $this->new_price; } }
事件创建
/** @var $em Kdyby\Doctrine\EntityManager */ /** @var $product Product */ $event = new ChangeProductPriceEvent( new \DateTime('2016-04-01 00:00:00'), $product, 10 ); $em->persist($event); $em->flush();
事件处理
class ChangeProductEventListener implements Kdyby\Events\Subscriber { // this listener must be registered in config, with 'kdyby.subscriber' tag of course /** @var Kdyby\Doctrine\EntityManager */ protected $em; public function getSubscribedEvents() { return [ChangeProductPriceEvent::EVENT_NAME => 'changePrice']; } public function changePrice(ChangeProductPriceEvent $e) { // don't use this in production, some locking should be implemented $product = $e->getProduct(); $product->setPrice($e->getNewPrice()); $this->em->persist($product)->flush(); } }
.. 就这么多:-) 现在,让我们看看一些更有趣的场景。一个内部消息系统是您优秀应用程序的一部分,您想在用户收到消息时发送通知。但是您不想垃圾邮件用户的邮箱,因此通知将被延迟。如果在延迟期间收到另一条消息,用户仍然会收到单一的通知。
/** @pcz\DeferredKdybyEvents\Annotations\Keeping */ class NewMessageNotificationEvent extends pcz\DeferredKdybyEvents\GroupedDeferredEvent { // ... protected $user; public function __construct(\DateTime $execution_date, User $user) { parent::__construct($execution_date); $this->user = $user; } public function getGroupKey() { return $this->user->getId(); } // ... }
注意getGroupKey()
方法,当重写GroupedDeferredEvent
类时必须实现此方法。这是必要的,因为它定义了分组键。另外,@Keeping
注解也很重要,它将在后面讨论。另一个示例是从聊天室中删除不活跃的聊天成员。注意缺少@Keeping
注解和getGroupKey()
方法。
class RemoveUserFromRoomEvent extends pcz\DeferredKdybyEvents\GroupedDeferredEvent { // ... public function getGroupKey() { return $this->user->getId() . '_' . $this->room->getId(); } // ... }
每当用户发送聊天消息时,就会创建新的事件。如果延迟时间为例如48小时(例如使用$event = new RemoveUserFromRoomEvent((new \DateTime())->add(new \DateInterval('PT48H')), ...)
),那么48小时未参与聊天室的用户将被移除。当新事件持久化时,所有具有相同groupKey
的其他等待事件将被暂停。
但这可能不是第一种情况(通知示例)的正确行为。如果有人每5分钟给我发一条消息,我就永远收不到通知,因为创建的事件总是会“覆盖”最后一个等待的事件。在这种情况下,请使用@Keeping
注解。它改变了分组策略 - 保留最近的事件,所有后续的事件将被暂停。
谢谢并享受 并为Kdyby 扩展热烈鼓掌