| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- <?php
- //事件分发服务
- namespace services\common;
- use Closure;
- use common\components\BaseEvent;
- use common\enums\RedisKeyEnum;
- use common\enums\StatusEnum;
- use common\helpers\ArrayHelper;
- use common\helpers\StringHelper;
- use common\interfaces\ListenerInterface;
- use common\models\common\AddonsEvent;
- use common\models\mall\Mall;
- use common\models\mall\MallAddons;
- use common\traits\ErrorTrait;
- use Exception;
- use ReflectionClass;
- use Yii;
- use yii\base\Component;
- use yii\helpers\Json;
- class EventService extends Component
- {
- use ErrorTrait;
- protected $listen = [];
- public function init(){
- parent::init();
- }
- /**
- * 获取listen数组
- * @Author bing
- * @DateTime 2021-03-01 10:36:55
- * @copyright: Copyright (c) 2020 广东七件事集团
- * @return array|mixed
- */
- public function getListen(){
- return $this->listen;
- }
- /**
- * 设置listen数组
- * @Author bing
- * @DateTime 2021-03-01 10:37:27
- * @copyright: Copyright (c) 2020 广东七件事集团
- * @param array $listen
- * @return void
- */
- public function setListen(array $listen){
- $this->listen = $listen;
- }
- /**
- * 事件调度器
- * @Author bing
- * @DateTime 2021-03-01 10:35:25
- * @copyright: Copyright (c) 2020 广东七件事集团
- * @param \yii\base\Event $event
- * @param [type] $data
- * @param [type] $listeners
- * @return void
- */
- public function dispatch(BaseEvent $event, $data = null, $listeners = null){
- $listeners = is_object($listeners) ? [$listeners] : (array) $listeners;
- $addons_listeners = $this->addonsEventBind($event->name, $event->mall_id ?? 0);
- asort($addons_listeners);//将插件监听数据进行排序
- $listeners = array_unique(
- array_merge(
- isset($this->listen[get_class($event)]) ? $this->listen[get_class($event)] : [],
- $listeners,
- $addons_listeners
- )
- );
- foreach ($listeners as $listener) {
- if ($listener instanceof Closure || function_exists($listener)) {
- $this->on($event->name, $listener, $data);
- continue;
- }
- if(!class_exists($listener)) continue;
- if(empty($event->name)){
- $reflect_class = new ReflectionClass($event);
- $event->name = $reflect_class->name;
- }
- $listener = Yii::createObject($listener);
- if (! $listener instanceof ListenerInterface) {
- throw new Exception(sprintf('The %s muse be implement %s.', get_class($listener), ListenerInterface::class));
- }
- $this->on($event->name, [$listener, 'handle'], $data);
- }
- $this->trigger($event->name, $event);
- $this->off($event->name);//常驻内存,内存泄漏处理
- }
- /**
- * 获取事件对应的插件
- * @Author: lun
- * @DateTime: 2022/3/17 0017 17:54
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $event_name
- * @param $mall_id
- * @return array|mixed
- */
- public function addonsEventBind($event_name, $mall_id){
- // 获取该商城所有有效的插件
- $mall_addons = MallAddons::getValidAddons($mall_id);
- if (empty($mall_addons)) return [];
- // 根据事件名称获取所有属于该事件的所有插件
- $redis = Yii::$app->redis;
- $redis_key = RedisKeyEnum::suffix(RedisKeyEnum::EVENT_LISTENERS, '',true) .':'. $event_name;
- $event_addons = $redis->hgetall($redis_key);// 获取缓存中的事件数据
- if (empty($event_addons)) $event_addons = $this->getEventsByMysql($event_name);
- // 处理返回的hash数组,$event_addons数组的hash返回格式['Agent','addons\Agent\common\listeners\OrderPaidListener','Boss','addons\Boss\common\listeners\OrderPaidListener']
- $event_addons_arr = $event_addons_keys = $event_addons_values = [];
- foreach ($event_addons as $key => $value) {
- if ($key % 2 == 0) {
- $event_addons_keys[] = $value;// 获取该事件的所有key
- } else {
- $event_addons_values[] = $value;// 获取该事件的所有value
- }
- }
- // 组合为简直相对的数组
- foreach ($event_addons_values as $key => $value) {
- $event_addons_arr[$event_addons_keys[$key]] = $value;
- }
- $intersect = array_intersect($mall_addons, $event_addons_keys);// 获取应用名称交集
- $listener = '';
- foreach($event_addons_arr as $addons_name => $listener_str) {
- // 将商城所有属于此事件名称的方法进行字符串组合
- if (in_array($addons_name, $intersect)) $listener .= $listener_str . ',';
- }
- if (empty($listener)) return [];
- // 移除右边逗号,再组合成数组返回
- return explode(',', rtrim($listener, ','));
- }
- /**
- * 从数据库中读取事件对应的listeners
- * @param $event_name
- * @return array
- */
- public function getEventsByMysql($event_name)
- {
- // 事件为空时,则直接读取数据库
- $event_list = AddonsEvent::find()->select('addons_name,event_name,listeners')->where(['event_name' => $event_name, 'status' => StatusEnum::ENABLED])->asArray()->all();
- $event_addons = [];
- foreach ($event_list as $item) {
- $event_addons[] = $item['addons_name'];
- $event_addons[] = implode(',', json_decode($item['listeners'], true));
- }
- return $event_addons;
- }
- /**
- * 创建链接菜单
- * @Author: lun
- * @DateTime: 2021/10/14 0014 14:16
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param string $addons_name
- * @throws \yii\db\Exception
- */
- public function create(string $addons_name, array $eventsMenu)
- {
- try {
- // 重组数组
- foreach ($eventsMenu as $key => $menu) {
- $allMenu[$key] = ArrayHelper::regroupMapToArr($menu);
- }
- $time = time();
- $event_addons = [];
- foreach ($allMenu as $key => $item) {
- foreach ($item as $k => $value) {
- // 根据事件名保存为数组
- $event_addons[$value['event_name']] = implode(',', $value['listeners']);
- $listeners = Json::encode($value['listeners']);
- $event = AddonsEvent::findOne(['addons_name' => $addons_name, 'event_name' => $value['event_name'], 'status' => StatusEnum::ENABLED]);
- if ($event) {
- if (Json::encode($event['listeners']) != $listeners) {
- $event->listeners = $value['listeners'];
- $event->save();
- }
- } else {
- $row = [];
- $row['addons_name'] = $addons_name;
- $row['event_name'] = $value['event_name'] ?? [];
- $row['listeners'] = $listeners;
- $row['created_at'] = $time;
- $row['updated_at'] = $time;
- $rows[] = $row;
- }
- }
- }
- if (!empty($rows)) {
- $field = ['addons_name', 'event_name', 'listeners', 'created_at', 'updated_at'];
- // 批量插入数据
- $res = Yii::$app->db->createCommand()->batchInsert(AddonsEvent::tableName(), $field, $rows)->execute();
- if (!$res) throw new \yii\base\Exception("事件创建失败");
- }
- // 获取所有事件再进行组合
- $list = AddonsEvent::find()->where(['status' => StatusEnum::ENABLED])->asArray()->all();
- $addons_event = [];
- foreach ($list as $item) {
- $addons_event[$item['event_name']][$item['addons_name']] = implode(',', Json::decode($item['listeners'], true));
- }
- // 将组合后的事件入存入redis中
- $redis = Yii::$app->redis;
- foreach ($addons_event as $event_name => $item) {
- $redis_key = RedisKeyEnum::suffix(RedisKeyEnum::EVENT_LISTENERS, '',true) .':'. $event_name;
- // 删除对应事件名称hash
- $redis->del($redis_key);
- foreach ($item as $name => $value) {
- $redis->hset($redis_key, $name, $value);// 存入hash
- }
- }
- return true;
- } catch (Exception $e) {
- $this->setError($e->getMessage());
- return false;
- }
- }
- /**
- * 商城安装插件绑定事件
- * @Author: lun
- * @DateTime: 2022/1/15 0015 19:07
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $addons_name
- * @param $mall_id
- * @return array|mixed
- */
- public function mallEventBind($addons_name, $mall_id){
- $cache = Yii::$app->cache;
- // 缓存无数据则对表进行查询
- $cond[] = ['addons_name' => $addons_name, 'status' => StatusEnum::ENABLED];
- $event_list = AddonsEvent::getAddonsEvent($cond,[],true,'listeners,event_name');
- if ($event_list) {
- // 循环组合对应事件的监听地址
- foreach ($event_list as $listeners) {
- $cache_key = RedisKeyEnum::suffix(RedisKeyEnum::EVENT, $listeners['event_name'],true);
- $cache_key .= $mall_id;
- $listenerArr = Json::decode($listeners['listeners'], true);
- $event = [];
- foreach ($listenerArr as $listener) {
- $event[] = $listener;
- }
- if ($event) {
- $cache_data = $cache->get($cache_key);
- if ($cache_data) {
- $event = array_unique(array_merge($cache_data, $event));
- }
- $cache->set($cache_key, $event);// 保存至缓存
- }
- }
- }
- }
- /**
- * 所有商城重新对应应用的事件绑定
- * @Author: lun
- * @DateTime: 2022/3/8 0008 17:44
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $addons_name
- * @return bool
- */
- public function allMallEventBind($addons_name)
- {
- try {
- // 获取已购买了该应用的商城
- $list = MallAddons::getMallAddons([['addons_name' => $addons_name]], [],true, 'mall_id');
- foreach ($list as $item) {
- $this->mallEventBind($addons_name, $item['mall_id']);
- }
- return true;
- } catch (Exception $e) {
- $this->setError($e->getMessage());
- return false;
- }
- }
- }
|