【问题标题】:wordpress-like model to view api event system (MVC)类似于 wordpress 的模型来查看 api 事件系统 (MVC)
【发布时间】:2010-01-18 19:05:46
【问题描述】:

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。

【问题讨论】:

  • 你想在你的视图中过滤什么?在渲染期间(或之前)调用 WordPress 过滤器。
  • @infamouse:任何东西都可以成为候选人。
  • 这对伴侣没有帮助。你需要给出一个更具体的例子来说明你想要做什么。不过,我会尽力回答你的问题。
  • 示例是 getItemName() 执行 wp_title() 的操作:创建过滤器事件。插件可以订阅该事件并具有过滤标题字符串的更改。
  • 我的答案或多或少是他们所做的。这是 wp 代码库中的相关行: $title = apply_filters('single_cat_title', $cat->name);然后这样做: $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));等等等等。您需要在代码中跳动一下才能遵循它。

标签: php model-view-controller api


【解决方案1】:

好的,

我不是 100% 完全符合您的要求,但我有一个想法。

也许你的意思是这样的:

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;
}

它还有一些其他的功能,比如 has_filter 等等...

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;
}

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

apply_filters,所有类似插件的函数在代码渲染时都会被程序调用,这里是一个例子

    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>

【讨论】:

  • 你可能想把它分解成一个插件类,这样你就可以使用它,以便插件可以挂接到任何东西。而不仅仅是过滤,你也可以为方法做......
  • jolierouge,感谢您的努力。首先,我认为您的 eventDispatcher 解决方案更有意义,因为调度事件/过滤器似乎超出了视图的职责。
    我看到的问题是它似乎不允许在循环中对某些内容进行过滤器.例如,回到 wordpress,一个类别循环显示多个帖子。在循环中,它具有过滤事件。我不知道如何在循环中也有这些: $view->posts = $latestTenPostsInCategoryX; foreach 这些帖子: echo $post->title(); // 并且标题被过滤
  • 以下是我的总体目标的更多背景:stackoverflow.com/questions/2074317/…
猜你喜欢
  • 2013-05-12
  • 1970-01-01
  • 1970-01-01
  • 2016-01-01
  • 1970-01-01
  • 2015-12-28
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
相关资源
最近更新 更多