Получить все модули, контроллеры и действия из приложения Zend Framework - PullRequest
13 голосов
/ 20 мая 2009

Я хочу создать Zend Controller для управления ACL, поэтому моя проблема: Как я могу получить все имена модулей, элементов управления и имен действий в приложении Zend для создания элемента управления ACL?

Я использую Zend_Navigation, и если ресурс не существует в вашем ACL, Zend_Navigation является исключением. И я хочу использовать базу данных, чтобы запретить и разрешить доступ. Поэтому я должен сначала создать базу данных. И если я должен сделать это вручную, это боль.

Ответы [ 4 ]

25 голосов
/ 27 июля 2009

Это может быть старый вопрос, но вот как я это делаю ...

//        $front = Zend_Controller_Front::getInstance(); // use this line instead on a model class
    $front = $this->getFrontController(); // this in controller
    $acl   = array();

    foreach ($front->getControllerDirectory() as $module => $path) {
        foreach (scandir($path) as $file) {

            if (strstr($file, "Controller.php") !== false) {

                include_once $path . DIRECTORY_SEPARATOR . $file;
                $class = substr($file,0,strpos($file,".php"));

                if (is_subclass_of($class, 'Zend_Controller_Action')) {

                    $controller = strtolower(substr($file, 0, strpos($file, "Controller")));
                    $methods = array();

                    foreach (get_class_methods($class) as $method) {
                        if (strstr($method,"Action") != false) {
                            array_push($methods,substr($method,0,strpos($method,"Action")));
                        }
                    }
                }

                $acl[$module][$controller] = $methods;
            }
        }
    }
7 голосов
/ 22 мая 2009

Я создал функцию, которая может получать все действия, контроллеры и модули из приложения Zend. Вот оно:

$module_dir = substr(str_replace("\\","/",$this->getFrontController()->getModuleDirectory()),0,strrpos(str_replace("\\","/",$this->getFrontController()->getModuleDirectory()),'/'));
    $temp = array_diff( scandir( $module_dir), Array( ".", "..", ".svn"));
    $modules = array();
    $controller_directorys = array();
    foreach ($temp as $module) {
        if (is_dir($module_dir . "/" . $module)) {
            array_push($modules,$module);
            array_push($controller_directorys, str_replace("\\","/",$this->getFrontController()->getControllerDirectory($module)));
        }
    }

    foreach ($controller_directorys as $dir) {
        foreach (scandir($dir) as $dirstructure) {
            if (is_file($dir  . "/" . $dirstructure)) {
                if (strstr($dirstructure,"Controller.php") != false) {
                    include_once($dir . "/" . $dirstructure);
                }
            }

        }
    }

    $default_module = $this->getFrontController()->getDefaultModule();

    $db_structure = array();

    foreach(get_declared_classes() as $c){
        if(is_subclass_of($c, 'Zend_Controller_Action')){
            $functions = array();
            foreach (get_class_methods($c) as $f) {
                if (strstr($f,"Action") != false) {
                    array_push($functions,substr($f,0,strpos($f,"Action")));
                }
            }
            $c = strtolower(substr($c,0,strpos($c,"Controller")));

            if (strstr($c,"_") != false) {
                $db_structure[substr($c,0,strpos($c,"_"))][substr($c,strpos($c,"_") + 1)] = $functions;
            }else{
                $db_structure[$default_module][$c] = $functions;
            }
        }
    }       
}
1 голос
/ 17 января 2011

Я действительно нашел, что лучший способ получить легкодоступную ссылку на отражение - это рекурсивно маркировать правильные каталоги, а затем в результате создать документ XML. Кэширование XML-документа на скорость и использование xpath для извлечения данных.

Плагин строит рефлексию xml и кэширует ее на потом. Я взял этот код из его первоначальной реализации, так что это больше для того, чтобы дать вам ощущение, а не копировать и вставлять.

Конечно, база данных здесь работает так же хорошо. Но если вы пытаетесь ограничить количество запросов на страницу, кэшированный XML-документ работает очень хорошо.

class My_Reflection_Plugin extends My_Controller_Plugin_Abstract
{
    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {
        $cache = $this -> getCacheManager() -> getCache('general');

        if (!$xml = $cache->load("Reflection"))
        {
            $paths = array(
                PATH_APPLICATION . "/Core",
                PATH_SITE . "/Project"
            );

            foreach ($paths as $path)
            {
                $this -> inspectDir($path);
            }

            $cache -> save($this->getReflectionXML(), "Reflection");
        }
        else
        {
            $this -> getReflectionXML($xml);
        }
    }

    private function inspectDir($path)
    {
        $rdi = new RecursiveDirectoryIterator($path);
        $rii = new RecursiveIteratorIterator($rdi);
        $filtered = new My_Reflection_Filter($rii);

        iterator_apply($filtered, array($this, 'process'), array($filtered));
    }

    private function process($it = false)
    {
        $this -> getReflectionXML() -> addItem($it -> current());

        return true;
    }
}

Токенизация происходит внутри фильтра:

class My_Reflection_Filter extends FilterIterator
{
    public function accept()
    {
        $file = $this->getInnerIterator()->current();

        // If we somehow have something other than an SplFileInfo object, just
        // return false
        if (!$file instanceof SplFileInfo) {
            return false;
        }

        // If we have a directory, it's not a file, so return false
        if (!$file->isFile()) {
            return false;
        }

        // If not a PHP file, skip
        if ($file->getBasename('.php') == $file->getBasename()) {
            return false;
        }

        // Resource forks are no good either.
        if (substr($file->getBaseName(), 0, 2) == '._')
        {
            return false;
        }

        $contents = file_get_contents($file->getRealPath());
        $tokens   = token_get_all($contents);

        $file->className = NULL;
        $file->classExtends = NULL;
        $file->classImplements = array();

        $last = null;
        while (count($tokens) > 0)
        {
            $token = array_shift($tokens);

            if (!is_array($token))
            {
                continue;
            }

            list($id, $content, $line) = $token;

            switch ($id)
            {
                case T_ABSTRACT:
                case T_CLASS:
                case T_INTERFACE:
                        $last = 'object';
                    break;
                case T_EXTENDS:
                        $last = "extends";
                    break;
                case T_IMPLEMENTS:
                        $last = "implements";
                    break;
                case T_STRING:
                        switch ($last)
                        {
                            case "object":
                                    $file -> className = $content;
                                break;
                            case "extends":
                                    $file -> classExtends = $content;
                                break;
                            case "implements":
                                    $file -> classImplements[] = $content;
                                break;
                        }
                    break;
                case T_WHITESPACE:
                        // Do nothing, whitespace should be ignored but it shouldnt reset $last.
                    break;
                default:
                        // If its not directly following a keyword specified by $last, reset last to nothing.
                        $last = null;
                    break;
            }
        }

        return true;
    }
}

После того, как ваш xml-рефлексия будет заполнена любой необходимой вам информацией из класса, ваш плагин acl может следовать за ней и запрашивать эту информацию с помощью xpath.

0 голосов
/ 20 мая 2009

Я не думаю, что есть решение для этого в Zend. Тебе придется сделать это самому ...

Один из способов сделать это - перечислить все классы и проверить, расширяют ли классы (например) класс Zend_Controller_Action ...

проверка функций php get_declared_classes и is_subclass_of

foreach(get_declared_classes() as $c){
  if(is_subclass_of($c, 'Zend_Controller_Action')){
     ...
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...