philippgrashoff / handlerforatk
该软件包的最新版本(5.0.0)没有可用的许可证信息。
5.0.0
2023-11-11 19:49 UTC
Requires
- php: 8.*
- atk4/data: 5.*
Requires (Dev)
- phpstan/phpstan: 1.*
- phpunit/phpunit: ^9.5.5
README
为什么要有这个仓库?
当模型保存时,我需要处理很多操作。我的代码通常是这样的
//after save implementation in a Tour Model $this->onHook( Model::HOOK_AFTER_SAVE, function (self $tour) { CalendarCacheController::handleTourChange($tour); StockController::handleTourChange($tour); } );
我对这一点真的很不喜欢
- 模型本身需要知道在保存/删除时应该发生哪些额外的操作。
- 这意味着模型需要处理其他模型的控制流。我喜欢我的模型更“笨”,专注于属性管理、合理的辅助函数以及它们与其他模型的关系。
- 由于模型需要调用在插入/更新/删除之后应该发生的所有操作,这也意味着这些额外操作的代码需要位于同一仓库中。这可能会导致一个巨大的单体。我更愿意将更大的应用程序拆分成几个仓库。这强制实施良好的结构化和清晰的API。
这个简单的仓库就是为了改变这些缺点。它是 atk4/data 的一个实现。这个非常棒的框架没有实现MVC模式,但它有非常强大的模型。然而,这个仓库的逻辑可以简单地调整。它是一种单例(也可以通过DI完成)和钩子模式的组合。
这个仓库是如何工作的
模型经纪人有点像MQTT经纪人:模型可以“发布”事件,如after insert
、after update
或after delete
。其他类可以“订阅”这些事件并对它们作出反应。结果是
- 模型本身不需要知道在
after insert
等事件之后执行哪些额外操作。 - 模型本身不处理这些额外操作的流程控制。
- 由于这是通过钩子实现的,因此可以从不在模型所在的仓库中添加额外的操作。
该仓库中有两个文件实现了逻辑
InvokeModelBrokerTrait
:一个要添加到想要发布事件的Model
的特质ModelBroker
:当注册的事件被调用时,会调用模型经纪人。其他类可以订阅经纪人,以便在这些事件发生时被调用。
如何使用它
- 您只需要两个方法:
InvokeModelBrokerTrait::publish()
和ModelBroker::subscribe()
! - 每个
Model
都可以在Model::save()
中调用的任何事件(钩子位置)发布。为了这样做,必须将InvokeModelBrokerTrait
添加到模型中。如果是这样,只需调用publish()
方法并告诉该方法要发布哪个钩子位置,例如$this->publish(Model::HOOK_AFTER_SAVE)
。 - 任何其他类现在都可以订阅模型发布的任何事件。为此,它们只需调用
ModelBroker::subscribe()
并告诉该方法要订阅哪个事件以及事件发生时要做什么。
//A model that publishes an event class SomeModel extends Model { use InvokeModelBrokerTrait; protected function init(): void { $this->publish(Model::HOOK_AFTER_SAVE); //in here we only want to publish the after save spot } //other init() code like adding fields } //this Class wants to act to the after save event class SomeController { public static function registerModelBrokerHooks(): void { ModelBroker::getInstance()->subscribe( Model::HOOK_AFTER_SAVE, function (Model $entity, bool $isUpdate) { //the same parameters are available as on Model::HOOK_AFTER_SAVE hook spot //some logic that should be performed when the after save event takes place } ); } );
当然,这意味着所有额外操作都需要在模型保存执行之前注册。因此,例如,在 App::init()
中,需要添加一些这样的代码
SomeController::registerModelBrokerHooks(); SomeOtherController::registerModelBrokerHooks(); YetAnotherController::registerModelBrokerHooks();
模型和模型经纪人的耦合
模型经纪人在 Model::save()
的钩子位置被调用。这意味着所有额外操作都将与本身的 save()
在同一事务中。因此,如果其中一个额外操作失败,则整个 save()
将回滚。
多个模型发布相同的事件
如果有多个模型调用publish()
发布相同的事件,任何订阅者都会从这些模型接收到这个事件。
class ModelA extends Model { use InvokeModelBrokerTrait; protected function init(): void { $this->publish(Model::HOOK_AFTER_SAVE); } } class ModelB extends Model { use InvokeModelBrokerTrait; protected function init(): void { $this->publish(Model::HOOK_AFTER_SAVE); } } //inside some other class. This subscription will receive the after save event from both ModelA and ModelB. ModelBroker::getInstance()->subscribe( Model::HOOK_AFTER_SAVE, function (Model $entity, bool $isUpdate) { //only act on ModelA if($entity instanceof ModelA) { //do something } } );
将来可能会增加在subscribe()
中直接过滤事件的功能。
安装
使用此存储库的最简单方法是将其添加到您的composer.json文件中的'require'部分。
{ "require": { "philippgrashoff/atkdatamodelbroker": "5.0.*" } }
版本控制
此存储库的版本号与atk4\data的版本号相对应。因此,5.0.x版本与atk4\data 5.0.x版本兼容,依此类推。