2010-01-18 3 views
1

Wordpress a un système d'api sympa. J'ai du mal à en créer un aussi flexible en utilisant une interprétation MVC plus traditionnelle. Une classe de vue typique pourrait ressembler à ceci:modèle wordpress-like pour visualiser le système d'événements api (MVC)

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

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

Un cas d'utilisation serait un contrôleur en ajoutant une commande contient des lignes de commande:

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

Ensuite, le fichier modèle pourrait avoir quelque chose comme

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

Au moins c'est ce qui est souvent vu dans de nombreux frameworks PHP MVC. Je suis ouvert à d'autres implémentations qui résolvent la question:

Comment ajouter un système d'événement comme wordpress a? Par exemple, un filtre OrderLineItemName.

+1

Que essayez-vous de filtrer dans votre vue? Les filtres WordPress sont appelés pendant (ou juste avant) le rendu. – funwhilelost

+0

@infamouse: Tout peut être un candidat. – koen

+0

Cela n'aide pas vraiment le compagnon. Vous auriez besoin de donner un exemple plus concret de ce que vous voulez faire. Néanmoins, je vais essayer de répondre à votre question. –

Répondre

2

D'accord,

Je ne suis pas 100% exactement ce que vous voulez faire, mais j'ai une idée.

Peut-être que vous voulez dire quelque chose comme ceci:

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; 

ou vous pouvez utiliser cette méthode, qui est plus comme événement. Encore un exemple de code, mais vous devriez être capable de le cannabaliser.

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; 

Ceci est juste un exemple de code, je fais, mais il ne semble pas le faire de cette façon du tout comme il peut être ce que vous parlez.

Cheers, Jason

Addendum:

La plupart de ce genre de choses est sur le WP codebase.

WP accède aux variables définies dans la portée globale qui sont modifiées comme ceci:

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

Il a d'autres fonctions telles que, 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; 
} 

Ce n'est pas un événement conduit système, c'est une table de consultation de méthode qui est juste un hachage géant qui recherche les fonctions définies par l'utilisateur à appeler.

apply_filters, et tous les plugins comme fonctions sont appelées la procédure que le code est rendu, voici un exemple

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

Ou pour les actions, dans une vue de modèle réel comme ceci:

<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

Vous voudriez probablement décomposer cela en classe de plugin, de cette façon vous pouvez l'utiliser pour que les plugins puissent s'accrocher à n'importe quoi. et pas seulement filtrer, vous pouvez le faire aussi pour les méthodes ... –

+0

jolierouge, merci pour votre effort. Tout d'abord, je pense que votre solution eventDispatcher a plus de sens car la répartition des événements/filtres semble hors de la responsabilité de la vue.
Le problème que je vois avec les deux est qu'il ne semble pas permettre d'avoir un filtre sur quelque chose dans une boucle. Par exemple, pour revenir à wordpress, une catégorie affiche plusieurs messages dans une boucle. Dans la boucle, il a des événements de filtrage. Je ne vois pas comment je peux les avoir dans une boucle: $ view-> posts = $ latestTenPostsInCategoryX; pour chacun de ces messages: echo $ post-> title(); // et le titre est filtré – koen

+0

Voici un peu plus de fond à mon objectif global: http://stackoverflow.com/questions/2074317/viewhelper-newable-injectable-dilemma – koen