在PwBaseController 里面,会有这个方法的存在
/**
* 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 这个方法就算添加标签的
它的父类是什么玩意
<?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() {}
}
?>
原来是继承了过滤器,呵呵,所以这个比较强大啊,可以这样用
我们在看看上面控制器的这个方法 resolveActionFilter
/**
* 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();
}
流程是这样的,先建立过滤链 ,把过滤器一一添加实例化,哈哈,跟我们之前的没什么区别
但是事情还没有结速
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 是在什么时候调用的呢,又是怎样调用的呢 看这里
/**
* @see PwPostAction.afterRun
*/
public function afterRun() {
$this->runDo('addThread', $this->tid);
}
这个类是 PwTopicPost 也正是我们在控制器里面刚刚实例化的 ,我们断点调式下看看
关键在这里
/* (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');
}
}
不同的类有不同的方法,可能就是调用时机不同,责任不同,总之就比较复杂