在PwBaseController 裏面,會有這個方法的存在php
/** * action Hook 註冊 * * @param string $registerKey 擴展點別名 * @param PwBaseHookService $bp * @throws PwException * @return void */ protected function runHook($registerKey, $bp) { if (!$registerKey) return; if (!$bp instanceof PwBaseHookService) { throw new PwException('class.type.fail', array( '{parm1}' => 'src.library.base.PwBaseController.runHook', '{parm2}' => 'PwBaseHookService', '{parm3}' => get_class($bp))); } if (!$filters = PwHook::getRegistry($registerKey)) return; if (!$filters = PwHook::resolveActionHook($filters, $bp)) return; $args = func_get_args(); $_filters = array(); foreach ($filters as $key => $value) { $args[0] = isset($value['method']) ? $value['method'] : ''; $_filters[] = array('class' => $value['class'], 'args' => $args); } $this->resolveActionFilter($_filters); }
咱們先不理這個東西是什麼,看它究竟是怎樣調用的數據庫
/** * 發帖 */ public function doaddAction() { list($title, $content, $topictype, $subtopictype, $reply_notice, $hide) = $this->getInput(array('atc_title', 'atc_content', 'topictype', 'sub_topictype', 'reply_notice', 'hide'), 'post'); $pwPost = $this->post; $this->runHook('c_post_doadd', $pwPost); $postDm = $pwPost->getDm(); $postDm->setTitle($title) ->setContent($content) ->setHide($hide) ->setReplyNotice($reply_notice); //set topic type $topictype_id = $subtopictype ? $subtopictype : $topictype; $topictype_id && $postDm->setTopictype($topictype_id); if (($result = $pwPost->execute($postDm)) !== true) { $data = $result->getData(); $data && $this->addMessage($data, 'data'); $this->showError($result->getError()); } $tid = $pwPost->getNewId(); $this->showMessage('success', 'bbs/read/run/?tid=' . $tid . '&fid=' . $pwPost->forum->fid, true); }
$this->runHook('c_post_doadd', $pwPost);
以前發帖的時候發現頁面有添加話題的內容,可是在控制器入面卻沒有發現有這種邏輯的操做,後來才知道是經過注入去操做的,咱們看看數據庫入面的紀錄
再看看它們是怎樣定義的
/** * 帖子發佈 - 話題相關 * * @author jinlong.panjl <jinlong.panjl@aliyun-inc.com> * @copyright ©2003-2103 phpwind.com * @license http://www.phpwind.com * @version $Id$ * @package wind */ class PwPostDoTagInjector extends PwBaseHookInjector { public function doadd() { $tagNames = (array)$this->getInput('tagnames', 'post'); if (!is_array($tagNames) || !count($tagNames)) return; Wind::import('SRV:forum.srv.post.do.PwPostDoTag'); return new PwPostDoTag($this->bp,$tagNames); } public function domodify() { $tagNames = (array)$this->getInput('tagnames', 'post'); Wind::import('SRV:forum.srv.post.do.PwPostDoTag'); return new PwPostDoTag($this->bp,$tagNames); } }
doadd 這個方法就算添加標籤的
它的父類是什麼玩意express
<?php defined('WEKIT_VERSION') || exit('Forbidden'); Wind::import('WIND:filter.WindActionFilter'); /** * PwHook action攔截過濾器抽象接口定義 * * 經過繼承該接口,能夠實如今Controller層注入擴展實現.該接口默認調用'run'方法. * 支持多參數擴展. * @author Qiong Wu <papa0924@gmail.com> 2011-12-2 * @copyright ©2003-2103 phpwind.com * @license http://www.windframework.com * @version $Id: PwBaseHookInjector.php 8692 2012-04-24 05:56:29Z jieyin $ * @package src * @subpackage library.filter */ abstract class PwBaseHookInjector extends WindActionFilter { private $callback = 'run'; private $args = array(); /** * @var PwBaseHookService */ protected $bp = null; /** * @param WindForward $forward * @param WindErrorMessage $errorMessage * @param WindRouter $router * @param array $args */ public function __construct($forward, $errorMessage, $router, $args = array()) { parent::__construct($forward, $errorMessage, $router); !empty($args[0]) && $this->callback = $args[0]; isset($args[1]) && $this->bp = $args[1]; if (count($args) > 2) { unset($args[0], $args[1]); $this->args = $args; } } /* (non-PHPdoc) * @see WindHandlerInterceptor::preHandle() */ public function preHandle() { if (!method_exists($this, $this->callback)) return; $injector = call_user_func_array(array($this, $this->callback), $this->args); if ($injector) $this->bp->appendDo($injector); } /* (non-PHPdoc) * @see WindHandlerInterceptor::postHandle() */ public function postHandle() {} } ?>
原來是繼承了過濾器,呵呵,因此這個比較強大啊,能夠這樣用app
咱們在看看上面控制器的這個方法 resolveActionFilterdom
/** * action過濾鏈策略部署 * * @example <pre> * $filters = array(array('expression'=>'', 'class'=>'', * args=array())); * </pre> * @param array $filters * @return void */ protected function resolveActionFilter($filters) { if (!$filters) return; $chain = WindFactory::createInstance('WindHandlerInterceptorChain'); $args = array($this->getForward(), $this->getErrorMessage(), null); foreach ((array) $filters as $value) { $chain->addInterceptors( WindFactory::createInstance(Wind::import($value['class']), (empty($value['args']) ? $args : array_merge($args, array($value['args']))))); } $chain->getHandler()->handle(); }
流程是這樣的,先創建過濾鏈 ,把過濾器一一添加實例化,哈哈,跟咱們以前的沒什麼區別ide
可是事情尚未結速post
class PwPostDoTag extends PwPostDoBase { private $loginUser; private $defaultType = 'threads'; private $tagNames = array(); private $typeId = ''; public function __construct(PwPost $pwpost,$tagNames) { $this->loginUser = $pwpost->user; $tagNames = $tagNames ? $tagNames : array(); $this->tagNames = array_unique($tagNames); $this->typeId = $this->_getService()->getTypeIdByTypeName($this->defaultType); } public function addThread($tid) { $this->_getService()->addTags($this->_buildTagDm($tid)); } public function updateThread($tid) { $this->_getService()->updateTags($this->typeId,$tid,$this->_buildTagDm($tid)); } public function getDm() { return new PwTagDm(); } public function dataProcessing($postDm) { if (!is_array($this->tagNames) || !$this->tagNames) return $postDm; $postDm->setTags(implode(',',$this->tagNames)); return $postDm; } private function _buildTagDm($tid) { if (!is_array($this->tagNames) || !$this->tagNames) return false; $dmArray = array(); foreach ($this->tagNames as $value) { $value = trim($value); $dm = $this->getDm(); $dmArray[$value] = $dm->setName($value) ->setTypeId($this->typeId) ->setParamId($tid) ->setIfhot(1) ->setCreateUid($this->loginUser->uid) ; } return $dmArray; } public function check($postDm) { if (!is_array($this->tagNames) || !$this->tagNames) return true; $count = count($this->tagNames); foreach ($this->tagNames as $v) { $dm = $this->getDm(); $dm->setName($v); if(($return = $dm->beforeAdd()) instanceof PwError) return $return; } if ($count > 5) { return new PwError("Tag:tagnum.exceed"); } if ($count && $this->loginUser->getPermission('tag_allow_add') < 1) { return new PwError("TAG:right.tag_allow_add.error"); } return true; } /** * Enter description here ... * * @return PwTagService */ protected function _getService() { return Wekit::load('tag.srv.PwTagService'); } }
那麼 addThread 是在何時調用的呢,又是怎樣調用的呢 看這裏ui
/** * @see PwPostAction.afterRun */ public function afterRun() { $this->runDo('addThread', $this->tid); }
這個類是 PwTopicPost 也正是咱們在控制器裏面剛剛實例化的 ,咱們斷點調式下看看 this
關鍵在這裏插件
/* (non-PHPdoc) * @see WindHandlerInterceptor::preHandle() */ public function preHandle() { if (!method_exists($this, $this->callback)) return; $injector = call_user_func_array(array($this, $this->callback), $this->args); if ($injector) $this->bp->appendDo($injector); }
把過濾器又加入到_do裏面,不知道爲何要這樣呢
$this->bp的值是多少呢
原來是這個pwPost
class PwPost extends PwBaseHookService { public $action; public $forum; public $user; public $special; // 帖子類型 public function __construct(PwPostAction $action) { $this->action = $action; $this->forum = $action->forum; $this->user = $action->user; $this->special = $action->getSpecial(); /** hook **/ $this->action->setSrv($this); } /** * 發帖以前檢測 * * @return bool */ public function check() { if (($result = $this->isInit()) !== true) { return new PwError('data.error'); } if (($result = $this->checkForum()) !== true) { return $result; } if (($result = $this->checkPost()) !== true) { return $result; } if ($this->isBan()) { return new PwError('ban'); } if (($result = $this->action->check()) !== true) { return $result; } return true; } /** * 初始化信息是否知足要求 * * @return bool */ public function isInit() { return $this->action->isInit(); } /** * 檢測是否擁有該版操做權限 * * @return bool */ public function checkForum() { if (!$this->forum->isForum()) { return new PwError('BBS:post.forum.not.exists'); } if (($result = $this->forum->allowVisit($this->user)) !== true) { return new PwError('BBS:forum.permissions.visit.allow', array('{grouptitle}' => $this->user->getGroupInfo('name'))); } return true; } /** * 檢測是否容許發帖 * * @return bool */ public function checkPost() { if ($this->user->groupid == 7) { return new PwError('REG_CHECK'); } /* $config = Wekit::C('bbs'); if ($config['post.timing.open'] && !$this->user->inGroup($config['post.timing.groups']) && !self::inTime($config['post.timing.start_hour'], $config['post.timing.start_min'], $config['post.timing.end_hour'], $config['post.timing.end_min'])) { return new PwError('BBS:post.timing'); } */ return true; } /** * 檢測用戶是否被禁言 * * @return bool */ public function isBan() { if ($this->user->gid == 6) { Wind::import('SRV:user.srv.PwBanBp'); $banBp = new PwBanBp($this->user->uid); $memberid = 0; if (false === $banBp->checkIfBanSpeak()) { $memberid = $banBp->recoveryBanSpeaKError(); } elseif ($banBp->endDateTimeBanSpeak()) { $memberid = $banBp->callEndDateTimeBanSpeak(); } if ($memberid) { $this->user->info['groups'] = ''; $this->user->info['groupid'] = 0; $this->user->info['memberid'] = $memberid; $this->user->groups = array($memberid); $this->user->resetGid($memberid); return false; } return true; } return false; } public function getDm() { return $this->action->getDm(); } /** * 各應用獲取該用戶dm來設置,以達到更新用戶信息的目的 * * @return object PwUserInfoDm */ public function getUserDm() { return $this->action->getUserDm(); } public function getAttachs() { return $this->action->getAttachs(); } /** * 發佈 * * @param object $postDm 帖子數據模型 * @return bool */ public function execute(PwPostDm $postDm) { if (($result = $this->action->beforeRun($postDm)) instanceof PwError) { return $result; } if (($result = $this->action->dataProcessing($postDm)) !== true) { return $result; } if (($result = $this->action->execute()) !== true) { return $result; } $this->action->afterRun(); $this->updateUser(); return true; } public function getInfo() { return $this->action->getInfo(); } public function getNewId() { return $this->action->getNewId(); } public function getDisabled() { return $this->action->isDisabled(); } /** * 更新用戶信息 /積分/發帖數/等 */ public function updateUser() { Wind::import('SRV:credit.bo.PwCreditBo'); $credit = PwCreditBo::getInstance(); if ($operation = $this->action->getCreditOperate()) { $credit->operate($operation, $this->user, true, array('forumname' => $this->forum->foruminfo['name']), $this->forum->getCreditSet($operation)); } $credit->execute(); $this->action->updateUser(); if ($userDm = $this->action->getUserDm(false)) { Wekit::load('user.PwUser')->editUser($userDm, PwUser::FETCH_DATA); } } public function appendDo($do) { $this->action->appendDo($do); } public function runDo($method) { $args = func_get_args(); call_user_func_array(array($this->action, 'runDo'), $args); }
原來是這樣,看到這裏基本明白啦
基本上發帖中就要牽涉到這裏操做了,若是第三方插件要加入的話就要加上服務當中
話題對應的hook 是 c_post_doadd
而發帖自己的hook是 m_PwTopicPost
來看看它是怎樣定義的
<?php defined('WEKIT_VERSION') || exit('Forbidden'); Wind::import('SRV:forum.srv.post.do.PwPostDoBase'); /** * 帖子發佈 - 話題 * * @author jinlong.panjl <jinlong.panjl@aliyun-inc.com> * @copyright ©2003-2103 phpwind.com * @license http://www.phpwind.com * @version $Id$ * @package wind */ class PwReplyDoRemind extends PwPostDoBase { private $loginUser; private $_reminds = array(); private $_atc_title; private $_maxNum; public function __construct(PwPost $pwpost) { $this->loginUser = $pwpost->user; $this->_maxNum = $this->loginUser->getPermission('remind_max_num'); } public function addPost($pid, $tid) { $this->_addRemind($pid, $tid); } public function updatePost($pid, $tid) { $this->_addRemind($pid, $tid); } public function dataProcessing($postDm) { if ($this->_check() !== true) return $postDm; $atc_content = $postDm->getField('content'); $atc_content = preg_replace('/\[quote(=.+?\,\d+)?\].*?\[\/quote\]/is', '', $atc_content); $this->_atc_title = Pw::substrs(trim(Pw::stripWindCode($atc_content,true)),20); $reminds = $this->_getRemindService()->bulidRemind($atc_content); $this->_reminds = $this->_getRemindService()->buildUsers($this->loginUser->uid,$reminds,$this->_maxNum); $reminds = $this->_getRemindService()->formatReminds($this->_reminds); $postDm->setReminds($reminds); return $postDm; } private function _addRemind($pid, $tid) { if ($this->_check() !== true) return false; if (!$this->_reminds) return false; $reminds = ($this->_maxNum && count($this->_reminds) > $this->_maxNum) ? array_slice($this->_reminds, 0, $this->_maxNum) : $this->_reminds; $remindUids = array_keys($reminds); $this->_getRemindService()->addRemind($this->loginUser->uid, $remindUids); //發送通知 $extendParams = array( 'remindUid' => $this->loginUser->uid, 'title' => $this->_atc_title, 'remindUsername' => $this->loginUser->username, 'notice' => '在回帖 <a href="' . WindUrlHelper::createUrl('bbs/read/run', array('tid'=>$tid), $pid) . '" target="_blank">' . $this->_atc_title . '</a> @了您', ); // 是否黑名單 $remindUids = $this->_checkBlack($remindUids); foreach ($remindUids as $uid) { $this->_getPwNoticeService()->sendNotice($uid,'remind',$pid,$extendParams); } } private function _check() { if ($this->loginUser->getPermission('remind_open') < 1) { return new PwError("bbs:remind.remind_open.error"); } return true; } /** * 是否開啓權限 * * @param array $remindUids * @return bool */ private function _checkBlack($remindUids) { $result = Wekit::load('user.PwUserBlack')->checkUserBlack($this->loginUser->uid, $remindUids); if ($result) { $remindUids = array_diff($remindUids,$result); } return $remindUids; } /** * @return PwNoticeService */ protected function _getPwNoticeService(){ return Wekit::load('message.srv.PwNoticeService'); } /** * PwRemindService * * @return PwRemindService */ private function _getRemindService(){ return Wekit::load('remind.srv.PwRemindService'); } }
不一樣的類有不一樣的方法,可能就是調用時機不一樣,責任不一樣,總之就比較複雜