typecho插件开发小结
in php with 0 comment

typecho插件开发小结

in php with 0 comment

这周推翻了之前写的框架,有些代码的确写的lowB了一点。所以打算拿typecho二开做APP的底层。

这几天晚上粗略的看了下typecho的插件开发文档,真tm.....少啊,文档少的可怜。

所以只能四处阅读残缺的文档,结合晚上的一些实验,做些记录

Helper类的应用

Helper类是typecho官方提供的插件脚手架,可以获取系统配置、添加/删除插件,面板,action,和菜单(菜单经测试似乎加不上)

主要的用法

    //注册面板
    Helper::addPanel(index[索引], '插件名/xxx.php', _t('标题'), _t('标题2'), 'contributor[用户权限]');

    //注册路由
    Helper::addRoute('路由别名','/xxx/','调用的类名','调用的方法名');

    //注册动作  绑定之后 url中带有xxx时,会映射到指定的类上
    Helper::addAction('xxx', '调用的类名');

注:
1.关于用户权限可以点此了解
2.Helper还有一个addMenu的方法,但多次测试无效后就不在此推出了,有兴趣的朋友可以自行浏览官方文档
3.以上的方法都有对应的removeAction/removeRoute/removePanel方法,使用方法在此也不过多描述


插件Action的坑

    //参考如下代码
    //假设我们有一个插件是显示一些物品信息 url为/item/xx(物品id)
    //此时该url会触发Item_Action类的action方法,但新手们可能会发现无法获取到id的值
    Helper::addRoute('show','/item/[id:digital]','Item_Action','action');

昨天晚上遇到这个问题,无论输出$_GET(结果为空数组)也好,还是使用Typecho_Request::get()也好,都获取不到id的值。

于是仔细查看typecho的源码,追踪到了 /var/Typecho/Route.php

    try {
        /** 载入参数 */
        $params = NULL;

        if (!empty($route['params'])) {
            unset($matches[0]);
            $params = array_combine($route['params'], $matches);
        }

        //$params被传送到了这里
        //大概的语句应该是这样
        //Typecho_Widget::widget('xxx_Action',NULL, ['id'=>7]);
        //
        //那我们去看看 Typecho_Widget::widget 到底做了什么

        $widget = Typecho_Widget::widget($route['widget'], NULL, $params);

        if (isset($route['action'])) {
            $widget->{$route['action']}();
        }

        return;

   } catch (Exception $e) {
        if (404 == $e->getCode()) {
            Typecho_Widget::destory($route['widget']);
            continue;
        }

        throw $e;
   }

打开 /var/Typecho/Widget.php


    public static function widget($alias, $params = NULL, $request = NULL, $enableResponse = true)
    {
        $parts = explode('@', $alias);
        $className = $parts[0];
        $alias = empty($parts[1]) ? $className : $parts[1];

        if (isset(self::$_widgetAlias[$className])) {
            $className = self::$_widgetAlias[$className];
        }

        if (!isset(self::$_widgetPool[$alias])) {
            /** 如果类不存在 */
            if (!class_exists($className)) {
                throw new Typecho_Widget_Exception($className);
            }

            /** 初始化request */
            if (!empty($request)) {
                $requestObject = new Typecho_Request();
                $requestObject->setParams($request);
            } else {
                $requestObject = Typecho_Request::getInstance();
            }

            /** 初始化response */
            $responseObject = $enableResponse ? Typecho_Response::getInstance()
            : Typecho_Widget_Helper_Empty::getInstance();

            /** 初始化组件 */
            
            //看这里,widget方法创建了一个新的组件,并且传入request对象,response对象和参数
            //request和response都是对应基类的实例,所以可以直接调用对应的方法

            $widget = new $className($requestObject, $responseObject, $params);

            $widget->execute();
            self::$_widgetPool[$alias] = $widget;
        }

        return self::$_widgetPool[$alias];
    }

那么到此整个疑问就已经解开了,我们在xxx_Action类中创建一个构造方法接收对应的对象即可

class Shop_Action implements Widget_Interface_Do
{

    private $request;
    private $response;
    private $params;

    public function __construct($request,$response,$params){
        $this->request = $request;
        $this->response = $response;
        $this->params = $params;
    }

    public function action(){}
}

到此我们就可以使用 $this->request->id 接收对应的值了。


数据库查询如何使用IS NULL

也不知道是不是我的需求太小众,居然在typecho的文档和问题中找不到我想要的答案,于是只能自己翻源码

需求:查询文章中不带访问密码的文章
方法:数据库查询时查询 password字段为空 的文章

因为这个问题的关注点在于where()方法上,于是根据类层层找where()所处的文件(别问我为什么不用phpstorm直接找,用的在线编辑器 心塞)

首先找到 Typecho_Db 基类的位置 /var/Typecho/Db.php 因为查询用的是select方法,所以查看该类的select().

    public function select()
    {
        $args = func_get_args();
        //select用到了本类中sql()方法,去看下sql()
        return call_user_func_array(array($this->sql(), 'select'), $args ? $args : array('*'));
    }

    //sql方法又返回一个Typecho_Db_Query类实例,那么我们再去看下Typecho_Db_Query
    public function sql()
    {
        return new Typecho_Db_Query($this->_adapter, $this->_prefix);
    }

Typecho_Db_Query 在 /var/Typecho/Db/Query.php,嗯,找到where方法了


public function where()
    {
        $condition = func_get_arg(0);
        $condition = str_replace('?', "%s", $this->filterColumn($condition));
        $operator = empty($this->_sqlPreBuild['where']) ? ' WHERE ' : ' AND';
        
        if (func_num_args() <= 1) {
            //注意这里,当where只有一个参数时,则直接当成字符串拼接
            $this->_sqlPreBuild['where'] .= $operator . ' (' . $condition . ')';
        } else {
            $args = func_get_args();
            array_shift($args);
            $this->_sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, $this->quoteValues($args)) . ')';
        }

        return $this;
    }

到了这里一切都很明了了,我们对于使用IS NULL方法,直接使用where('xxx IS NULL')即可

使用where('xxx = ?',NULL) 或 使用where('xxx IS ?',NULL)都会报错!

Comments are closed.