Skip to content

Instantly share code, notes, and snippets.

@Aurielle
Forked from fprochazka/PresenterInfo.php
Created November 19, 2010 17:32
Show Gist options
  • Save Aurielle/706828 to your computer and use it in GitHub Desktop.
Save Aurielle/706828 to your computer and use it in GitHub Desktop.
PresenterTree - fixed verze
service.PHPin-Tools-PresenterTree.factory = "\PHPin\Tools\PresenterTree::createPresenterTree"
<?php
require LIBS_DIR . '/Nette/loader.php';
Nette\Environment::loadConfig();
$pt = Nette\Environment::getApplication->getContext()->getService('PHPin\Tools\PresenterTree');
# presenters
dump($pt->presenters); // all of them!
dump($pt->getPresenters('Front')); // directry in front
dump($pt->getPresenters('Front', TRUE)); // even those in submodules!
dump($pt->getPresenters('Front:Forum')); // wanna have a nice menu in forum ? :)
# modules
dump($pt->modules); // root modules
dump($pt->getModules('Front')); // directry in front
dump($pt->getModules('Front:Client')); // avalaible submodules?
# actions
dump($pt->getActions('Front:Homepage')); // homepage actions?
dump($pt->getActions('Front:Client')); // damn that's a module... too bad, returns NULL
foreach ($pt->getPresenters('Front') as $presenter) {
dump($presenter->actions); //
}
# excluding presenters & actions
abstract class BasePresenter extends Nette\Application\Presenter { } // one
/** @hideInTree */
abstract class BasePresenter extends Nette\Application\Presenter { } // two
abstract class BasePresenter extends Nette\Application\Presenter
{
/** @hideInTree */
public function actionDefault() { } // three
/** @hideInTree */
public function renderSomethink() { } // three
}
<?php
namespace PHPin\Tools;
use Nette;
use Nette\Reflection\ClassReflection;
/**
* @author Filip Procházka <[email protected]>
*/
class PresenterInfo extends Nette\Object
{
/** @var string */
private $name;
/** @var string */
private $module;
/** @var string */
private $class;
/** @var array */
private $actions;
/** @var PHPin\Tools\PresenterTree */
private $tree;
/**
* @param string $name
* @param string $module
* @param string $class
*/
public function __construct($name, $module, $class)
{
$this->name = $name;
$this->module = $module;
$this->class = $class;
}
/**
* @return bool
*/
public function isPublic()
{
$ref = $this->getPresenterReflection();
return !$ref->hasAnnotation('hideInTree');
}
/**
* @return Nette\Reflection\ClassReflection
*/
public function getPresenterReflection()
{
return new ClassReflection($this->getPresenterClass());
}
/**
* @return array
*/
public function getActions()
{
if ($this->actions === NULL) {
$this->actions = $this->getTree()->getPresenterActions($this);
}
return $this->actions;
}
/**
* @return string
*/
public function getName($full = FALSE)
{
return ($full ? ':' . $this->module . ':' : NULL) . $this->name;
}
/**
* @return string
*/
public function getPresenterClass()
{
return $this->class;
}
/**
* @return string
*/
public function getModule()
{
return $this->module;
}
public function __toString()
{
return $this->getName(TRUE);
}
/**
* @return Kdyby\PresenterTree
*/
public function getTree()
{
if ($this->tree === NULL) {
$this->tree = $this->getContext()->getService("PHPin\\Tools\\PresenterTree");
}
return $this->tree;
}
/**
* @return Nette\context
*/
public function getContext()
{
return Nette\Environment::getApplication()->getContext();
}
public function __sleep()
{
$properties = (array)$this;
unset($properties['tree'], $properties['actions']);
return array_keys($properties);
}
}
<?php
namespace PHPin\Tools;
use Nette;
use Nette\Caching\Cache;
use Nette\Reflection\MethodReflection;
use Nette\String;
/**
* @author Filip Procházka <[email protected]>
*/
class PresenterTree extends Nette\Object
{
const ALL = TRUE;
const DIRECT = FALSE;
// const TREE = 'tree'; // what does this mean? bad memmory :(
/** @var Nette\Caching\Cache */
private $cache;
public function __construct()
{
$cache = $this->getCache();
if (!$this->isActual($cache)) {
$cache->save('presenters', $this->buildPresenterTree());
$cache->save('modules', $this->buildModuleTree($cache['presenters']));
$cache->save('actions', $this->buildActionTree($cache['presenters']));
$this->isActual(TRUE);
}
}
/**
* @param Nette\Caching\Cache|bool $cache
* @return bool
*/
private function isActual($cache = NULL)
{
$classes = $this->getRobotLoader()->getIndexedClasses();
$hash = md5(serialize($classes));
if ($cache === TRUE) {
return $this->getCache()->save('hash', $hash);
}
if ($cache['hash'] != $hash) {
return FALSE;
}
return TRUE;
}
/**
* @return array
*/
private function buildPresenterTree()
{
$classes = array_keys($this->getRobotLoader()->getIndexedClasses());
$tree = array();
foreach ($i = new \RegexIterator(new \ArrayIterator($classes), "~.*Presenter$~") as $class) {
$nettePath = String::split(substr($class, 0, -9), '~Module\\\\~i');
$presenter = array_pop($nettePath);
$module = strlen($module = $this->formatNettePath($nettePath)) ? substr($module, 1) : NULL;
$presenterInfo = new PresenterInfo($presenter, $module, $class);
$ref = $presenterInfo->getPresenterReflection();
if (!$ref->isAbstract() && $presenterInfo->isPublic()) {
$t =& $tree['byModule'];
foreach ($nettePath as $step) {
$t[$step] = isset($t[$step]) ? $t[$step] : array();
$t =& $t[$step];
}
$t[$presenter] = $presenterInfo;
$steps = array();
foreach ($nettePath as $step) {
$steps[] = $step;
$module = substr($this->formatNettePath($steps), 1);
$relative = substr($this->formatNettePath(array_diff($nettePath, $steps), $presenter), 1);
$tree['all'][NULL][':'.$module.':'.$relative] = $presenterInfo;
$tree['all'][$module][$relative] = $presenterInfo;
}
}
}
ksort($tree['all']);
return $tree;
}
/**
* @return array
*/
private function buildModuleTree($presenters)
{
$tree = array();
$modules = array();
foreach ($presenters['all'][NULL] as $fullPath => $presenter) {
if (!in_array($presenter->module, $modules)) {
$modules[] = $presenter->module;
}
}
foreach ($modules as $module) {
$nettePath = explode(':', $module);
$module = array_pop($nettePath);
$t =& $tree['byModule'];
foreach ($nettePath as $step) {
$t[$step] = isset($t[$step]) ? $t[$step] : array();
$t =& $t[$step];
}
$t = is_array($t) ? $t : array();
$t[] = $module;
}
return $tree;
}
/**
* @return array
*/
private function buildActionTree($presenters)
{
$tree = array();
foreach ($presenters['all'][NULL] as $fullPath => $presenter) {
$ref = $presenter->getPresenterReflection();
$views = array();
$methods = array();
foreach($ref->getMethods() as $k => $v) {
if(!$v->hasAnnotation('hideInTree') && $v->isPublic())
$methods[] = $v->name;
}
foreach($i = new \RegexIterator(new \ArrayIterator($methods), '~^(action|render)(.*)~i', \RegexIterator::GET_MATCH) as $view) {
$views[] = $view[2];
}
$actions = array();
foreach ($views as $view) {
$view = lcfirst($view);
$actions[$view] = $fullPath.':'.$view;
}
if ($actions) {
$tree['all'][$presenter->presenterClass] = array_flip($actions);
$t =& $tree['byPresenter'];
foreach (String::split($presenter->module, '~:~') as $step) {
$t[$step] = isset($t[$step]) ? $t[$step] : array();
$t =& $t[$step];
}
$t[$presenter->name] = array_flip($actions);
}
}
return $tree;
}
/**
* @param string $nettePath
* @param bool $all
* @return array
*/
public function getPresenters($nettePath = NULL, $all = FALSE)
{
if (strpos($nettePath, ':') === 0) {
$nettePath = substr($nettePath, 1);
}
if (strpos($nettePath, ':') === strlen($nettePath)) {
$nettePath = substr($nettePath, 0, -1);
}
if ($all || $nettePath === NULL) {
return isset($this->cache['presenters']['all'][$nettePath]) ? $this->cache['presenters']['all'][$nettePath] : NULL;
}
$tree = $this->cache['presenters']['byModule'];
foreach (String::split($nettePath, '~:~') as $step) {
if (!isset($tree[$step])) {
return NULL;
}
$tree =& $tree[$step];
}
return array_filter($tree, function($item) { return !is_array($item); });
}
/**
* @param PHPin\Tools\PresenterInfo $presenter
* @return array
*/
public function getPresenterActions(PresenterInfo $presenter)
{
return $this->cache['actions']['all'][$presenter->class];
}
/**
* @param string $nettePath
* @return array
*/
public function getActions($nettePath)
{
if (strpos($nettePath, ':') === 0) {
$nettePath = substr($nettePath, 1);
}
if (strpos($nettePath, ':') === strlen($nettePath)) {
$nettePath = substr($nettePath, 0, -1);
}
if (!$nettePath) {
return NULL;
}
$presenters = array();
$tree = $this->cache['actions']['byPresenter'];
foreach (String::split($nettePath, '~:~') as $step) {
if (!isset($tree[$step])) {
return NULL;
}
$tree =& $tree[$step];
}
return array_filter($tree, function($item) { return !is_array($item); });
}
/**
* @param string $nettePath
* @param bool $all
* @return array
*/
public function getModules($nettePath = NULL)
{
if (strpos($nettePath, ':') === 0) {
$nettePath = substr($nettePath, 1);
}
if (strpos($nettePath, ':') === strlen($nettePath)) {
$nettePath = substr($nettePath, 0, -1);
}
if (!$nettePath) {
return array_filter($this->cache['modules']['byModule'], function($item) { return !is_array($item); });
}
$presenters = array();
$tree = $this->cache['modules']['byModule'];
foreach (String::split($nettePath, '~:~') as $step) {
if (!isset($tree[$step])) {
return NULL;
}
$tree =& $tree[$step];
}
return array_filter($tree, function($item) { return !is_array($item); });
}
/**
* @param array $steps
* @param string $presenter
* @return string
*/
private function formatNettePath($steps, $presenter = NULL)
{
return "" . ($steps ? ':'.implode(':', $steps) : NULL) . ($presenter ? ':'.$presenter : NULL);
}
/**
* @return Nette\Caching\Cache
*/
private function getCache()
{
if ($this->cache === NULL) {
$this->cache = Nette\Environment::getCache('PHPin.PresenterTree');
}
return $this->cache;
}
/**
* @return Nette\Loaders\RobotLoader
*/
private function getRobotLoader()
{
return $this->getContext()->getService("Nette\\Loaders\\RobotLoader");
}
/**
* @return Nette\Context
*/
public function getContext()
{
return Nette\Environment::getApplication()->getContext();
}
/**
* @return PHPin\Tools\PresenterTree
*/
public static function createPresenterTree()
{
return new static;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment