mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Merge remote-tracking branch 'origin/feature/classloader-10614'
This commit is contained in:
commit
202b493c10
@ -349,28 +349,23 @@ abstract class ApplicationBootstrap
|
|||||||
|
|
||||||
$this->loader = new ClassLoader();
|
$this->loader = new ClassLoader();
|
||||||
$this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga');
|
$this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga');
|
||||||
|
$this->loader->registerNamespace('Icinga', $this->libDir . '/Icinga', $this->appDir);
|
||||||
$this->loader->register();
|
$this->loader->register();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the Zend Autoloader
|
* Register the Zend Autoloader - compat only - does nothing
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setupZendAutoloader()
|
public function setupZendAutoloader()
|
||||||
{
|
{
|
||||||
require_once 'Zend/Loader/Autoloader.php';
|
|
||||||
|
|
||||||
\Zend_Loader_Autoloader::getInstance();
|
|
||||||
|
|
||||||
\Zend_Paginator::addScrollingStylePrefixPath(
|
|
||||||
'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle'
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup module manager
|
* Setup module manager
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
namespace Icinga\Application;
|
namespace Icinga\Application;
|
||||||
|
|
||||||
|
use Zend_Loader_Autoloader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PSR-4 class loader
|
* PSR-4 class loader
|
||||||
*/
|
*/
|
||||||
@ -13,6 +15,40 @@ class ClassLoader
|
|||||||
*/
|
*/
|
||||||
const NAMESPACE_SEPARATOR = '\\';
|
const NAMESPACE_SEPARATOR = '\\';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icinga Web 2 module namespace prefix
|
||||||
|
*/
|
||||||
|
const MODULE_PREFIX = 'Icinga\\Module\\';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icinga Web 2 module namespace prefix length
|
||||||
|
*
|
||||||
|
* Helps to make substr/strpos operations even faster
|
||||||
|
*/
|
||||||
|
const MODULE_PREFIX_LENGTH = 14;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A hardcoded class/subdir map for application ns prefixes
|
||||||
|
*
|
||||||
|
* When a module registers with an application directory, those
|
||||||
|
* namespace prefixes (after the module prefix) will be looked up
|
||||||
|
* in the corresponding application subdirectories
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $applicationPrefixes = array(
|
||||||
|
'Clicommands' => 'clicommands',
|
||||||
|
'Controllers' => 'controllers',
|
||||||
|
'Forms' => 'forms'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we already instantiated the ZF autoloader
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $gotZend = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespaces
|
* Namespaces
|
||||||
*
|
*
|
||||||
@ -20,18 +56,33 @@ class ClassLoader
|
|||||||
*/
|
*/
|
||||||
private $namespaces = array();
|
private $namespaces = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application directories
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $applicationDirectories = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a base directory for a namespace prefix
|
* Register a base directory for a namespace prefix
|
||||||
*
|
*
|
||||||
|
* Application directory is optional and provides additional lookup
|
||||||
|
* logic for hardcoded namespaces like "Forms"
|
||||||
|
*
|
||||||
* @param string $namespace
|
* @param string $namespace
|
||||||
* @param string $directory
|
* @param string $directory
|
||||||
|
* @param string $appDirectory
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function registerNamespace($namespace, $directory)
|
public function registerNamespace($namespace, $directory, $appDirectory = null)
|
||||||
{
|
{
|
||||||
$this->namespaces[$namespace] = $directory;
|
$this->namespaces[$namespace] = $directory;
|
||||||
|
|
||||||
|
if ($appDirectory !== null) {
|
||||||
|
$this->applicationDirectories[$namespace] = $appDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,21 +107,177 @@ class ClassLoader
|
|||||||
*/
|
*/
|
||||||
public function getSourceFile($class)
|
public function getSourceFile($class)
|
||||||
{
|
{
|
||||||
|
if ($file = $this->getModuleSourceFile($class)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->namespaces as $namespace => $dir) {
|
foreach ($this->namespaces as $namespace => $dir) {
|
||||||
if ($class === strstr($class, $namespace)) {
|
if ($class === strstr($class, $namespace)) {
|
||||||
$classPath = str_replace(
|
return $this->buildClassFilename($class, $namespace);
|
||||||
self::NAMESPACE_SEPARATOR,
|
|
||||||
DIRECTORY_SEPARATOR,
|
|
||||||
substr($class, strlen($namespace))
|
|
||||||
) . '.php';
|
|
||||||
if (file_exists($file = $dir . $classPath)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the source file of the given module class or interface
|
||||||
|
*
|
||||||
|
* @param string $class Module class or interface name
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
protected function getModuleSourceFile($class)
|
||||||
|
{
|
||||||
|
if (! $this->classBelongsToModule($class)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$modules = Icinga::app()->getModuleManager();
|
||||||
|
$namespace = $this->extractModuleNamespace($class);
|
||||||
|
|
||||||
|
if ($this->hasNamespace($namespace)) {
|
||||||
|
|
||||||
|
return $this->buildClassFilename($class, $namespace);
|
||||||
|
|
||||||
|
} elseif (! $modules->loadedAllEnabledModules()) {
|
||||||
|
|
||||||
|
$moduleName = $this->extractModuleName($class);
|
||||||
|
|
||||||
|
if ($modules->hasEnabled($moduleName)) {
|
||||||
|
$modules->loadModule($moduleName);
|
||||||
|
|
||||||
|
return $this->buildClassFilename($class, $namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the Icinga module namespace from a given namespaced class name
|
||||||
|
*
|
||||||
|
* Does no validation, prefix must have been checked before
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function extractModuleNamespace($class)
|
||||||
|
{
|
||||||
|
return substr(
|
||||||
|
$class,
|
||||||
|
0,
|
||||||
|
strpos($class, self::NAMESPACE_SEPARATOR, self::MODULE_PREFIX_LENGTH + 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the Icinga module name from a given namespaced class name
|
||||||
|
*
|
||||||
|
* Does no validation, prefix must have been checked before
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function extractModuleName($class)
|
||||||
|
{
|
||||||
|
return lcfirst(
|
||||||
|
substr(
|
||||||
|
$class,
|
||||||
|
self::MODULE_PREFIX_LENGTH,
|
||||||
|
strpos(
|
||||||
|
$class,
|
||||||
|
self::NAMESPACE_SEPARATOR,
|
||||||
|
self::MODULE_PREFIX_LENGTH + 1
|
||||||
|
) - self::MODULE_PREFIX_LENGTH
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the given class name belongs to a module namespace
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function classBelongsToModule($class)
|
||||||
|
{
|
||||||
|
return substr($class, 0, self::MODULE_PREFIX_LENGTH) === self::MODULE_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a filename string for the given class
|
||||||
|
*
|
||||||
|
* Expects the given namespace to be registered with a path name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function buildClassFilename($class, $namespace)
|
||||||
|
{
|
||||||
|
$relNs = substr($class, strlen($namespace) + 1);
|
||||||
|
|
||||||
|
if ($this->namespaceHasApplictionDirectory($namespace)) {
|
||||||
|
$prefixSeparator = strpos($relNs, self::NAMESPACE_SEPARATOR);
|
||||||
|
$prefix = substr($relNs, 0, $prefixSeparator);
|
||||||
|
|
||||||
|
if ($this->isApplicationPrefix($prefix)) {
|
||||||
|
return $this->applicationDirectories[$namespace]
|
||||||
|
. DIRECTORY_SEPARATOR
|
||||||
|
. $this->applicationPrefixes[$prefix]
|
||||||
|
. $this->classToRelativePhpFilename(substr($relNs, $prefixSeparator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->namespaces[$namespace] . DIRECTORY_SEPARATOR . $this->classToRelativePhpFilename($relNs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the relative file name for the given (namespaces) class
|
||||||
|
*
|
||||||
|
* @param string $class
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function classToRelativePhpFilename($class)
|
||||||
|
{
|
||||||
|
return str_replace(
|
||||||
|
self::NAMESPACE_SEPARATOR,
|
||||||
|
DIRECTORY_SEPARATOR,
|
||||||
|
$class
|
||||||
|
) . '.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether given prefix (Forms, Controllers...) makes part of "application"
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function isApplicationPrefix($prefix)
|
||||||
|
{
|
||||||
|
return array_key_exists($prefix, $this->applicationPrefixes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the given namespace registered an application directory
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function namespaceHasApplictionDirectory($namespace)
|
||||||
|
{
|
||||||
|
return array_key_exists($namespace, $this->applicationDirectories);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require ZF autoloader
|
||||||
|
*
|
||||||
|
* @return Zend_Loader_Autoloader
|
||||||
|
*/
|
||||||
|
protected function requireZendAutoloader()
|
||||||
|
{
|
||||||
|
require_once 'Zend/Loader/Autoloader.php';
|
||||||
|
$this->gotZend = true;
|
||||||
|
return Zend_Loader_Autoloader::getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the given class or interface
|
* Load the given class or interface
|
||||||
*
|
*
|
||||||
@ -80,10 +287,22 @@ class ClassLoader
|
|||||||
*/
|
*/
|
||||||
public function loadClass($class)
|
public function loadClass($class)
|
||||||
{
|
{
|
||||||
if ($file = $this->getSourceFile($class)) {
|
// We are aware of the Zend_ prefix and lazyload it's autoloader.
|
||||||
require $file;
|
// Return as fast as possible if we already did so.
|
||||||
return true;
|
if (substr($class, 0, 5) === 'Zend_') {
|
||||||
|
if (! $this->gotZend) {
|
||||||
|
$this->requireZendAutoloader();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($file = $this->getSourceFile($class)) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
require $file;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,13 @@ class Manager
|
|||||||
*/
|
*/
|
||||||
private $modulePaths = array();
|
private $modulePaths = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we loaded all enabled modules
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $loadedAllEnabledModules = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of the module manager
|
* Create a new instance of the module manager
|
||||||
*
|
*
|
||||||
@ -177,12 +184,28 @@ class Manager
|
|||||||
*/
|
*/
|
||||||
public function loadEnabledModules()
|
public function loadEnabledModules()
|
||||||
{
|
{
|
||||||
foreach ($this->listEnabledModules() as $name) {
|
if (! $this->loadedAllEnabledModules) {
|
||||||
$this->loadModule($name);
|
foreach ($this->listEnabledModules() as $name) {
|
||||||
|
$this->loadModule($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->loadedAllEnabledModules = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we loaded all enabled modules
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function loadedAllEnabledModules()
|
||||||
|
{
|
||||||
|
return $this->loadedAllEnabledModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to load the module and register it in the application
|
* Try to load the module and register it in the application
|
||||||
*
|
*
|
||||||
@ -245,6 +268,8 @@ class Manager
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->loadedAllEnabledModules = false;
|
||||||
|
|
||||||
if (file_exists($link) && is_link($link)) {
|
if (file_exists($link) && is_link($link)) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,13 @@ class Module
|
|||||||
*/
|
*/
|
||||||
private $cssdir;
|
private $cssdir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base application directory
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $appdir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Library directory
|
* Library directory
|
||||||
*
|
*
|
||||||
@ -244,6 +251,7 @@ class Module
|
|||||||
$this->jsdir = $basedir . '/public/js';
|
$this->jsdir = $basedir . '/public/js';
|
||||||
$this->libdir = $basedir . '/library';
|
$this->libdir = $basedir . '/library';
|
||||||
$this->configdir = $app->getConfigDir('modules/' . $name);
|
$this->configdir = $app->getConfigDir('modules/' . $name);
|
||||||
|
$this->appdir = $basedir . '/application';
|
||||||
$this->localedir = $basedir . '/application/locale';
|
$this->localedir = $basedir . '/application/locale';
|
||||||
$this->formdir = $basedir . '/application/forms';
|
$this->formdir = $basedir . '/application/forms';
|
||||||
$this->controllerdir = $basedir . '/application/controllers';
|
$this->controllerdir = $basedir . '/application/controllers';
|
||||||
@ -739,6 +747,16 @@ class Module
|
|||||||
return $this->basedir;
|
return $this->basedir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the module's application directory
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getApplicationDir()
|
||||||
|
{
|
||||||
|
return $this->appdir;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the module's library directory
|
* Get the module's library directory
|
||||||
*
|
*
|
||||||
@ -1043,18 +1061,13 @@ class Module
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$loader = $this->app->getLoader();
|
|
||||||
$moduleName = ucfirst($this->getName());
|
$moduleName = ucfirst($this->getName());
|
||||||
|
|
||||||
$moduleLibraryDir = $this->getLibDir(). '/'. $moduleName;
|
$this->app->getLoader()->registerNamespace(
|
||||||
if (is_dir($moduleLibraryDir)) {
|
'Icinga\\Module\\' . $moduleName,
|
||||||
$loader->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir);
|
$this->getLibDir() . '/'. $moduleName,
|
||||||
}
|
$this->getApplicationDir()
|
||||||
|
);
|
||||||
$moduleFormDir = $this->getFormDir();
|
|
||||||
if (is_dir($moduleFormDir)) {
|
|
||||||
$loader->registerNamespace('Icinga\\Module\\' . $moduleName. '\\Forms', $moduleFormDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->registeredAutoloader = true;
|
$this->registeredAutoloader = true;
|
||||||
|
|
||||||
@ -1118,21 +1131,10 @@ class Module
|
|||||||
if (! $this->app->isWeb()) {
|
if (! $this->app->isWeb()) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
$moduleControllerDir = $this->getControllerDir();
|
|
||||||
if (is_dir($moduleControllerDir)) {
|
return $this
|
||||||
$this->app->getfrontController()->addControllerDirectory(
|
|
||||||
$moduleControllerDir,
|
|
||||||
$this->getName()
|
|
||||||
);
|
|
||||||
$this->app->getLoader()->registerNamespace(
|
|
||||||
'Icinga\\Module\\' . ucfirst($this->getName()) . '\\' . Dispatcher::CONTROLLER_NAMESPACE,
|
|
||||||
$moduleControllerDir
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$this
|
|
||||||
->registerLocales()
|
->registerLocales()
|
||||||
->registerRoutes();
|
->registerRoutes();
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1143,6 +1145,13 @@ class Module
|
|||||||
protected function registerRoutes()
|
protected function registerRoutes()
|
||||||
{
|
{
|
||||||
$router = $this->app->getFrontController()->getRouter();
|
$router = $this->app->getFrontController()->getRouter();
|
||||||
|
|
||||||
|
// TODO: We should not be required to do this. Please check dispatch()
|
||||||
|
$this->app->getfrontController()->addControllerDirectory(
|
||||||
|
$this->getControllerDir(),
|
||||||
|
$this->getName()
|
||||||
|
);
|
||||||
|
|
||||||
/** @var \Zend_Controller_Router_Rewrite $router */
|
/** @var \Zend_Controller_Router_Rewrite $router */
|
||||||
foreach ($this->routes as $name => $route) {
|
foreach ($this->routes as $name => $route) {
|
||||||
$router->addRoute($name, $route);
|
$router->addRoute($name, $route);
|
||||||
|
@ -91,7 +91,6 @@ class Web extends EmbeddedWeb
|
|||||||
->setupLogger()
|
->setupLogger()
|
||||||
->setupInternationalization()
|
->setupInternationalization()
|
||||||
->setupZendMvc()
|
->setupZendMvc()
|
||||||
->setupNamespaces()
|
|
||||||
->setupModuleManager()
|
->setupModuleManager()
|
||||||
->loadSetupModuleIfNecessary()
|
->loadSetupModuleIfNecessary()
|
||||||
->loadEnabledModules()
|
->loadEnabledModules()
|
||||||
@ -346,6 +345,7 @@ class Web extends EmbeddedWeb
|
|||||||
'layoutPath' => $this->getApplicationDir('/layouts/scripts')
|
'layoutPath' => $this->getApplicationDir('/layouts/scripts')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->setupFrontController();
|
$this->setupFrontController();
|
||||||
$this->setupViewRenderer();
|
$this->setupViewRenderer();
|
||||||
return $this;
|
return $this;
|
||||||
@ -492,24 +492,4 @@ class Web extends EmbeddedWeb
|
|||||||
}
|
}
|
||||||
return Translator::DEFAULT_LOCALE;
|
return Translator::DEFAULT_LOCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup class loader namespaces for Icinga\Controllers and Icinga\Forms
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
private function setupNamespaces()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->getLoader()
|
|
||||||
->registerNamespace(
|
|
||||||
'Icinga\\' . Dispatcher::CONTROLLER_NAMESPACE,
|
|
||||||
$this->getApplicationDir('controllers')
|
|
||||||
)
|
|
||||||
->registerNamespace(
|
|
||||||
'Icinga\\Forms',
|
|
||||||
$this->getApplicationDir('forms')
|
|
||||||
);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user