tao-test/app/tao/models/classes/controllerMap/Factory.php

173 lines
5.6 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2014 (original work) Open Assessment Technologies SA;
*
*
*/
namespace oat\tao\model\controllerMap;
use common_Logger;
use oat\tao\model\http\Controller;
use ReflectionClass;
use RecursiveDirectoryIterator;
use DirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
use RecursiveRegexIterator;
use helpers_PhpTools;
/**
* Fectory to create the description of the controllers and
* actions from the source code
*
* @author Joel Bout <joel@taotesting.com>
*/
class Factory
{
/**
*
* @param string $extensionId
* @return ControllerDescription[] array of controller descriptions
*/
public function getControllers($extensionId)
{
$ext = \common_ext_ExtensionsManager::singleton()->getExtensionById($extensionId);
$controllers = [];
foreach ($this->getControllerClasses($ext) as $className) {
$controllers[] = $this->getControllerDescription($className);
}
return $controllers;
}
/**
* Get a description of the controller
*
* @param string $controllerClassName
* @return ControllerDescription
*/
public function getControllerDescription($controllerClassName)
{
$reflector = new ReflectionClass($controllerClassName);
return new ControllerDescription($reflector);
}
/**
* Get a description of the action
*
* @param string $controllerClassName
* @param string $actionName
* @return ActionDescription
* @throws ActionNotFoundException
*/
public function getActionDescription($controllerClassName, $actionName)
{
if (!class_exists($controllerClassName) || !method_exists($controllerClassName, $actionName)) {
throw new ActionNotFoundException('Unknown ' . $controllerClassName . '@' . $actionName);
}
$reflector = new \ReflectionMethod($controllerClassName, $actionName);
return new ActionDescription($reflector);
}
/**
* Helper to find all controllers
*
* @param \common_ext_Extension $extension
* @return array
* @ignore
*/
private function getControllerClasses(\common_ext_Extension $extension)
{
$returnValue = [];
// routes
$namespaces = [];
foreach ($extension->getManifest()->getRoutes() as $mapedPath => $ns) {
if (is_string($ns)) {
$namespaces[] = trim($ns, '\\');
}
}
if (!empty($namespaces)) {
common_Logger::t('Namespace found in routes for extension ' . $extension->getId());
$classes = [];
$recDir = new RecursiveDirectoryIterator($extension->getDir());
$recIt = new RecursiveIteratorIterator($recDir);
$regexIt = new RegexIterator($recIt, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
foreach ($regexIt as $entry) {
$info = helpers_PhpTools::getClassInfo($entry[0]);
if (!empty($info['ns'])) {
$ns = trim($info['ns'], '\\');
if (!empty($info['ns']) && in_array($ns, $namespaces)) {
$returnValue[$info['class']] = $ns . '\\' . $info['class'];
}
}
}
}
// legacy
if ($extension->hasConstant('DIR_ACTIONS') && file_exists($extension->getConstant('DIR_ACTIONS'))) {
$dir = new DirectoryIterator($extension->getConstant('DIR_ACTIONS'));
foreach ($dir as $fileinfo) {
if (preg_match('/^class\.[^.]*\.php$/', $fileinfo->getFilename())) {
$module = substr($fileinfo->getFilename(), 6, -4);
$returnValue[$module] = $extension->getId() . '_actions_' . $module;
}
}
}
$returnValue = array_filter($returnValue, [$this, 'isControllerClassNameValid']);
return (array) $returnValue;
}
/**
* Validates controller class name to:
* - exist
* - have valid base class
* - be not abstract
*
* @param string $controllerClassName
*
* @return bool
*/
private function isControllerClassNameValid($controllerClassName)
{
$returnValue = true;
if (!class_exists($controllerClassName)) {
common_Logger::w($controllerClassName . ' not found');
$returnValue = false;
} elseif (!is_subclass_of($controllerClassName, 'Module') && !is_subclass_of($controllerClassName, Controller::class)) {
common_Logger::w($controllerClassName . ' is not a valid Controller.');
$returnValue = false;
} else {
// abstract so just move along
$reflection = new \ReflectionClass($controllerClassName);
if ($reflection->isAbstract()) {
common_Logger::i($controllerClassName . ' is abstract');
$returnValue = false;
}
}
return $returnValue;
}
}