pcz/deferred-kdyby-events

此包最新版本(v0.1)没有可用的许可证信息。

为doctrine2和nette提供的deferred kdyby事件助手

v0.1 2016-03-31 16:40 UTC

This package is not auto-updated.

Last update: 2024-09-20 19:25:59 UTC


README

Nette框架的deferred事件扩展(使用kdyby/events & kdyby/doctrineaneb kdyby až bude Bavorov...

此kdyby/events事件系统扩展为您的应用程序提供延迟事件的支撑。实现了以下两种基本类型的延迟事件:

  • 简单延迟事件 - 事件被持久化,并设置为在未来某个特定时间触发
  • 分组延迟事件 - 每个事件都有一个groupID属性。当一个新的事件被持久化时,所有等待的具有相同groupID的事件都会被取消。例如,您可以使用它们发送通知 - 当用户在10分钟内收到5条消息时,只有一条通知将通过此类型的事件发送。此外,还有一个类注解@Keeping,它改变分组策略的行为 - 最近的将保留,而后续的将被取消,因此最终的等待时间不会延长。

要求

安装

$ composer require pcz/deferred-kdyby-events
  • 在您的config neon文件中启用扩展
extensions:
	# add this line
	deferredEvents: pcz\DeferredKdybyEvents\DI\DeferredEventsExtension 
  • 其他扩展的配置也需要,请参阅以下依赖项的文档:Kdyby/DoctrineKdyby/EventsKdyby/Console

  • 在config中启用扩展后更新数据库模式(确保清除缓存并运行orm:schema-tool:update命令)

  • 差不多完成了,让我们设置一个cron作业

*/5 * * * * /path/to/php /path/to/your/app/www/index.php deferredEvents:fire

介绍

每个事件都由其事件类表示。它必须扩展以下基类之一:pcz\DeferredKdybyEvents\DeferredEventpcz\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 扩展热烈鼓掌