De hecho, me pareció que la mejor manera de tener una referencia de reflexión era fácilmente disponibles a Conversar de forma recurrente los directorios correctos y luego crear un documento xml como resultado. Almacenamiento en caché del documento xml para mayor velocidad y uso de xpath para recuperar los datos.
El complemento crea el reflejo xml y lo almacena en caché para más adelante. He sacado este código de su implementación original, así que es más para darle una idea en lugar de copiar y pegar.
Por supuesto, una base de datos funciona igual de bien aquí. Pero si intenta limitar sus consultas por página, un documento XML en caché funciona bastante bien.
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;
}
}
Estandarización de fichas que sucede en el interior del filtro:
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;
}
}
vez que tenga su xml reflexión poblada de toda la información que necesita salir de la clase, su plugin ACL puede venir después de él y consultar esa información con XPath .
¿Por qué es necesario tener TODAS las acciones y nombres de controlador? Solo piense en una lista blanca: solo se permite el acceso a acciones o controladores que están en un grupo especial. Todos los demás no son – powtac
Deberías haber hecho esta una respuesta, ya que estás en lo correcto. Una lista blanca es realmente la mejor manera de proceder con la ACL basada en controlador/acción –
. Solo hay un problema si utiliza Zend_Navigation y el recurso no existe en su ACL. Se produce una excepción. Y quiero usar una base de datos para denegar y permitir el acceso. Entonces debo construir la base de datos primero. Y si debo hacerlo a mano, es un dolor hacer eso. –