2009-05-20 25 views
12

Tôi muốn tạo Bộ điều khiển Zend cho quản lý ACL vì vậy vấn đề của tôi là: Làm thế nào tôi có thể nhận tất cả Tên mô-đun, Tên điều khiển và Tên hành động trong ứng dụng Zend để xây dựng Điều khiển ACL?Nhận tất cả các mô-đun, bộ điều khiển và hành động từ ứng dụng Zend Framework

Tôi sử dụng Zend_Navigation và nếu tài nguyên không tồn tại trong ACL Zend_Navigation của bạn sẽ bị loại trừ. Và tôi muốn sử dụng cơ sở dữ liệu để từ chối và cho phép truy cập. Vì vậy, tôi phải xây dựng cơ sở dữ liệu đầu tiên. Và nếu tôi phải làm điều đó bằng tay thì đó là một nỗi đau để làm điều đó.

+2

Tại sao cần phải có TẤT CẢ các hành động và tên bộ điều khiển? Chỉ cần nghĩ đến một danh sách trắng: chỉ các hành động hoặc bộ điều khiển nằm trong một nhóm đặc biệt mới được phép truy cập. Tất cả những người khác thì không. – powtac

+0

Bạn nên đặt câu trả lời này là đúng. Một danh sách trắng thực sự là cách tốt nhất để tiến hành với bộ điều khiển/hành động dựa trên ACL –

+2

Chỉ có một vấn đề nếu bạn sử dụng Zend_Navigation và tài nguyên không tồn tại trong ACL của bạn có ném một ngoại lệ. Và tôi muốn sử dụng cơ sở dữ liệu để từ chối và cho phép truy cập. Vì vậy, tôi phải xây dựng cơ sở dữ liệu đầu tiên. Và nếu tôi phải làm bằng tay thì đó là một nỗi đau để làm điều đó. –

Trả lời

7

tôi đã tạo ra một chức năng mà có thể nhận được tất cả những hành động, bộ điều khiển và mô-đun từ một ứng dụng zend. Ở đây là:

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

Tôi không nghĩ rằng có một giải pháp cho điều này trong Zend. Bạn sẽ phải làm điều đó cho mình ...

Một cách để làm điều đó, là để liệt kê tất cả các lớp học, và kiểm tra xem các lớp học mở rộng (ví dụ) lớp Zend_Controller_Action ...

kiểm tra các chức năng php get_declared_classesis_subclass_of

foreach(get_declared_classes() as $c){ 
    if(is_subclass_of($c, 'Zend_Controller_Action')){ 
    ... 
    } 
} 
24

Đây có thể là một câu hỏi cũ nhưng đây là cách tôi đang làm điều này ...

$front = $this->getFrontController(); 
    $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; 

       foreach (get_declared_classes() as $class) { 

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

         $controller = strtolower(substr($class, 0, strpos($class, "Controller"))); 
         $actions = array(); 

         foreach (get_class_methods($class) as $action) { 

          if (strstr($action, "Action") !== false) { 
           $actions[] = $action; 
          } 
         } 
        } 
       } 

       $acl[$module][$controller] = $actions; 
      } 
     } 
    } 
+0

hoạt động giống như một sự quyến rũ! – smoove

+0

Một tinh chỉnh nhỏ: "$ actions [] = $ action;" -> "$ actions [] = substr ($ action, 0, -6);" hữu ích trong trường hợp của tôi. Nó đã thoát khỏi "Hành động" từ chuỗi. – understack

+0

Có vẻ như nếu chức năng này được gọi từ một bộ điều khiển, thì bộ điều khiển đó và tất cả các hành động của nó bị thiếu từ $ acl. – understack

1

Tôi thực sự tìm thấy cách tốt nhất để có một tài liệu tham khảo phản ánh một cách dễ dàng có sẵn là đệ quy tokenise các thư mục chính xác và sau đó xây dựng một tài liệu xml như là một kết quả. Caching tài liệu xml cho tốc độ và sử dụng xpath để lấy dữ liệu.

Plugin xây dựng xml phản chiếu và lưu trữ nó sau này. Tôi đã lấy mã này ra khỏi triển khai ban đầu của nó, do đó, nó nhiều hơn để cung cấp cho bạn một cảm giác chứ không phải là sao chép và dán.

Tất nhiên, cơ sở dữ liệu cũng hoạt động tốt ở đây. Nhưng nếu bạn đang cố giới hạn truy vấn của mình trên mỗi trang, một tài liệu xml được lưu trong bộ nhớ cache hoạt động khá tốt.

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

Tokenisation xảy ra bên trong bộ lọc:

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

Một khi bạn đã xml phản ánh của bạn cư với bất kỳ thông tin bạn cần ra khỏi lớp, plugin acl bạn có thể đến sau khi nó và truy vấn thông tin đó với xpath .

Các vấn đề liên quan