开发者

wordpress-like model to view api event system (MVC)

Wordpress has a nice api system. I'm struggling in creating an equal flexible one using a more traditional MVC interpretation. A typical view class could be like this:

class View
{
    public function set($name, $value)
    {
         $this->data[$name] = $value
    }

    public function __get($name) ... you know how it works
}

A use case would be a controller adding an order contain order lines:

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

Then the template file could have something like

foreach ($this->order->getOrde开发者_开发知识库rLines() as $orderLine)
{
    ?><div><?php echo $orderLine->getItemName(); ?><div><?php
}

At least this is what is commonly seen in many PHP MVC frameworks. I'm open to alternative implementations that solve the question:

How to add an event system like wordpress has? Eg a filter OrderLineItemName.


Okay,

I am not 100% exactly what you want to do, but I have an idea.

Maybe you mean something like this:

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;

or you can use this method, which is more event like. Again sample code, but you should be able to cannabalize it.

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;

This is just some sample code, I don't do it this way at all, but it seems like it may be what you are talking about.

Cheers, Jason

Addendum:

Most of this stuff is about the WP codebase.

WP accesses variables set in the global scope that are modified like so:

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

It has some other functions like, has_filter etc...

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

This is not an event driven system, it's a method lookup table which is just a giant hash that looks up the user defined functions to call.

apply_filters, and all plugin like functions are called procedurally as the code is rendered, here is an example

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

Or for actions, in an actual template view like so:

<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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜