代码之家  ›  专栏  ›  技术社区  ›  koen

类似wordpress的模型来查看api事件系统(mvc)

  •  1
  • koen  · 技术社区  · 15 年前

    wordpress有一个很好的api系统。我正在努力使用更传统的mvc解释来创建一个同样灵活的版本。典型的视图类可能是这样的:

    class View
    {
        public function set($name, $value)
        {
             $this->data[$name] = $value
        }
    
        public function __get($name) ... you know how it works
    }
    

    一个用例将是一个控制器,添加一个包含订单行的订单:

    $view->add('order', $orderModel);
    

    然后模板文件可能有如下内容

    foreach ($this->order->getOrderLines() as $orderLine)
    {
        ?><div><?php echo $orderLine->getItemName(); ?><div><?php
    }
    

    至少这是在许多php mvc框架中常见的。我对解决问题的其他实现持开放态度:

    如何添加像wordpress那样的事件系统?例如过滤器orderlineitemname。

    1 回复  |  直到 15 年前
        1
  •  2
  •   J. Martin    15 年前

    可以,

    我不是百分之百的你想做的,但我有个主意。

    也许你的意思是这样的:

    class View {
        public $hooks = array('getsomeVar');
        public $hooks_functions = array();
        public $attributes = array();
        public function __set($k,$v) {
            $this->attributes[$k] = $v;
        }
        public function __get($k) {
            if (isset($this->attributes[$k])){
                $hooks = $this->get_functions_by_hook('get' . $k);
                if (!empty($hooks)){
                    foreach ($hooks as $klass=>$methods) {
                        if (class_exists($klass)){
                            $class = new $klass();
                            foreach ($methods as $method) {
                                if (method_exists($class,$method)){
                                    $this->attributes[$k] = $class->$method($this->attributes[$k]);
                                } 
                            }
                        }
                    }
                }
                return $this->attributes[$k];
            } else {
                throw new Exception($k . " is not a view variable");
            }
        }
    
        public function register_filter($name,$class,$method) {
            if (in_array($name,$this->hooks)){
                $this->hooks_functions[$name][$class][] = $method;
            } else {
                throw new Exception($name . ' is not a valid hook');
            }
        }
    
        public function get_functions_by_hook($name) {
            if (array_key_exists($name,$this->hooks_functions)){
                return $this->hooks_functions[$name];
            }
            return array();
        }
    }
    class MyPlugin {
        public function fix_string($str) {
            return str_replace("ruby",'php',$str);
        }
    }
    
    $v = new View();
    $v->someVar = 'ruby is great';
    $v->register_filter('getsomeVar','MyPlugin','fix_string');
    echo $v->someVar;
    

    或者你可以使用这种方法,它更像事件。同样是示例代码,但是您应该能够对其进行解压。

    class EventDispatcher {
        public static $listeners = array();
        public static function registerListener(&$instance) {
            if (!in_array($isntance,self::$listeners)){
                array_push(self::$listeners,$instance);
            }
        }
        public static function dispatchEvent($name,&$value) {
            foreach (self::$listeners as $listener) {
                if (method_exists($listener,'interests')){
                    $funcs = $listener->interests();
                    if (array_key_exists($name,$funcs)){
                        foreach ($funcs as $f) {
                            $value = $listener->$f($value);
                        }
                    }
                }
            }
        }
    }
    class Plugin {
        public static function registerPlugin($class_name) {
            if (class_exists($class_name)){
                EventDispatcher::registerListener(new $class_name());
            }
        }
    }
    class Model {
        public function __construct() {
            EventDispatcher::registerListener($this);
        }
        public function special($value) {
            echo "I got called too!\n\n";
            return $value;
        }
        public function interests() {
            return array(
                "getsomeVar" => "special",
            );
        }
    }
    class View {
        public $attributes = array();
        public function __set($k,$v) {
            $this->attributes[$k] = $v;
        }
        public function __get($k) {
            if (isset($this->attributes[$k])){
                EventDispatcher::dispatchEvent('get' . $k,$this->attributes[$k]);
                return $this->attributes[$k];
            } else {
                throw new Exception($k . " is not a view variable");
            }
        }
    }
    class MyPlugin {
        public function fix_string($str) {
            return str_replace("ruby",'php',$str);
        }
        public function interests() {
            return array(
                "getsomeVar" => "fix_string",
            );
        }
    }
    Plugin::registerPlugin('MyPlugin');
    $model = new Model();
    $v = new View();
    $v->someVar = 'ruby is great';
    echo $v->someVar;
    

    这只是一些示例代码,我完全不是这样做的,但似乎这就是您所说的。

    干杯, 杰森

    补遗:

    大部分内容都是关于wp代码库的。

    wp访问全局范围中设置的变量,这些变量的修改如下:

    function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
        global $wp_filter, $merged_filters;
    
        $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
        $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
        unset( $merged_filters[ $tag ] );
        return true;
    }
    

    它还有其他一些功能,如,有滤波器等。

    function apply_filters($tag, $value) {
        global $wp_filter, $merged_filters, $wp_current_filter;
    
        $args = array();
        $wp_current_filter[] = $tag;
    
        // Do 'all' actions first
        if ( isset($wp_filter['all']) ) {
            $args = func_get_args();
            _wp_call_all_hook($args);
        }
    
        if ( !isset($wp_filter[$tag]) ) {
            array_pop($wp_current_filter);
            return $value;
        }
    
        // Sort
        if ( !isset( $merged_filters[ $tag ] ) ) {
            ksort($wp_filter[$tag]);
            $merged_filters[ $tag ] = true;
        }
    
        reset( $wp_filter[ $tag ] );
    
        if ( empty($args) )
            $args = func_get_args();
    
        do {
            foreach( (array) current($wp_filter[$tag]) as $the_ )
                if ( !is_null($the_['function']) ){
                    $args[1] = $value;
                    $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
                }
    
        } while ( next($wp_filter[$tag]) !== false );
    
        array_pop( $wp_current_filter );
    
        return $value;
    }
    

    这不是一个事件驱动的系统,而是一个方法查找表,它只是一个查找要调用的用户定义函数的巨大散列。

    应用过滤器,当代码被呈现时,所有类似插件的函数都被称为过程性函数,下面是一个例子

        if ( $prefixed ) {
            $value = apply_filters("pre_$field", $value);
            $value = apply_filters("${field_no_prefix}_save_pre", $value);
        } else {
            $value = apply_filters("pre_post_$field", $value);
            $value = apply_filters("${field}_pre", $value);
        }
    

    或者对于操作,在实际的模板视图中,如下所示:

    <p class="submit"><input type="submit" class="button" name="submit" value="<?php esc_attr_e('Add Category'); ?>" /></p>
    <?php do_action('edit_link_category_form', $category); ?>
    </form>
    
    推荐文章