391 lines
8.6 KiB
PHP
391 lines
8.6 KiB
PHP
<?php
|
|
|
|
/**
|
|
* NRE
|
|
*
|
|
* @author coderkun <olli@coderkun.de>
|
|
* @copyright 2013 coderkun (http://www.coderkun.de)
|
|
* @license http://www.gnu.org/licenses/gpl.html
|
|
* @link http://www.coderkun.de/projects/nre
|
|
*/
|
|
|
|
namespace nre\core;
|
|
|
|
|
|
/**
|
|
* Abstract class for implementing a Controller.
|
|
*
|
|
* @author coderkun <olli@coderkun.de>
|
|
*/
|
|
abstract class Controller
|
|
{
|
|
/**
|
|
* Corresponding Agent
|
|
*
|
|
* @var Agent
|
|
*/
|
|
protected $agent;
|
|
/**
|
|
* View of the Controller
|
|
*
|
|
* @var View
|
|
*/
|
|
private $view = null;
|
|
/**
|
|
* Data to pass to the View
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $viewData = array();
|
|
/**
|
|
* Current request
|
|
*
|
|
* @var Request
|
|
*/
|
|
protected $request = null;
|
|
/**
|
|
* Current response
|
|
*
|
|
* @var Response
|
|
*/
|
|
protected $response = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Load the class of a Controller.
|
|
*
|
|
* @throws ControllerNotFoundException
|
|
* @throws ControllerNotValidException
|
|
* @param string $controllerName Name of the Controller to load
|
|
*/
|
|
public static function load($controllerName)
|
|
{
|
|
// Determine full classname
|
|
$className = self::getClassName($controllerName);
|
|
|
|
try {
|
|
// Load class
|
|
ClassLoader::load($className);
|
|
|
|
// Validate class
|
|
ClassLoader::check($className, get_class());
|
|
}
|
|
catch(\nre\exceptions\ClassNotValidException $e) {
|
|
throw new \nre\exceptions\ControllerNotValidException($e->getClassName());
|
|
}
|
|
catch(\nre\exceptions\ClassNotFoundException $e) {
|
|
throw new \nre\exceptions\ControllerNotFoundException($e->getClassName());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Instantiate a Controller (Factory Pattern).
|
|
*
|
|
* @throws DatamodelException
|
|
* @throws DriverNotFoundException
|
|
* @throws DriverNotValidException
|
|
* @throws ModelNotValidException
|
|
* @throws ModelNotFoundException
|
|
* @throws ViewNotFoundException
|
|
* @param string $controllerName Name of the Controller to instantiate
|
|
* @param string $layoutName Name of the current Layout
|
|
* @param string $action Current Action
|
|
*/
|
|
public static function factory($controllerName, $layoutName, $action, $agent)
|
|
{
|
|
// Determine full classname
|
|
$className = self::getClassName($controllerName);
|
|
|
|
// Construct and return Controller
|
|
return new $className($layoutName, $action, $agent);
|
|
}
|
|
|
|
|
|
/**
|
|
* Determine the classname for the given Controller name.
|
|
*
|
|
* @param string $controllerName Controller name to get classname of
|
|
* @return string Classname for the Controller name
|
|
*/
|
|
private static function getClassName($controllerName)
|
|
{
|
|
$className = \nre\core\ClassLoader::concatClassNames($controllerName, \nre\core\ClassLoader::stripNamespace(get_class()));
|
|
|
|
|
|
return \nre\configs\AppConfig::$app['namespace']."controllers\\$className";
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Construct a new Controller.
|
|
*
|
|
* @throws DriverNotFoundException
|
|
* @throws DriverNotValidException
|
|
* @throws ModelNotValidException
|
|
* @throws ModelNotFoundException
|
|
* @throws ViewNotFoundException
|
|
* @param string $layoutName Name of the current Layout
|
|
* @param string $action Current Action
|
|
* @param Agent $agent Corresponding Agent
|
|
*/
|
|
protected function __construct($layoutName, $action, $agent)
|
|
{
|
|
// Store values
|
|
$this->agent = $agent;
|
|
|
|
// Load Models
|
|
$this->loadModels();
|
|
|
|
// Load View
|
|
$this->loadView($layoutName, $action);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Prefilter that is executed before running the Controller.
|
|
*
|
|
* @param Request $request Current request
|
|
* @param Response $response Current response
|
|
*/
|
|
public function preFilter(Request $request, Response $response)
|
|
{
|
|
// Request speichern
|
|
$this->request = $request;
|
|
|
|
// Response speichern
|
|
$this->response = $response;
|
|
|
|
|
|
// Linker erstellen
|
|
$this->set('linker', new \nre\core\Linker($request));
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Prefilter that is executed after running the Controller.
|
|
*
|
|
* @param Request $request Current request
|
|
* @param Response $response Current response
|
|
*/
|
|
public function postFilter(Request $request, Response $response)
|
|
{
|
|
}
|
|
|
|
|
|
/**
|
|
* Run the Controller.
|
|
*
|
|
* This method executes the Action of the Controller defined by
|
|
* the current Request.
|
|
*
|
|
* @throws ParamsNotValidException
|
|
* @throws IdNotFoundException
|
|
* @throws DatamodelException
|
|
* @throws ActionNotFoundException
|
|
* @param Request $request Current request
|
|
* @param Response $response Current response
|
|
*/
|
|
public function run(Request $request, Response $response)
|
|
{
|
|
// Determine Action
|
|
$action = $response->getParam(2, 'action');
|
|
if(!method_exists($this, $action)) {
|
|
throw new \nre\exceptions\ActionNotFoundException($action);
|
|
}
|
|
|
|
// Determine parameters
|
|
$params = $response->getParams(3);
|
|
if(empty($params)) {
|
|
$params = $request->getParams(3);
|
|
}
|
|
|
|
// Fill missing parameters
|
|
$rc = new \ReflectionClass($this);
|
|
$nullParamsCount = $rc->getMethod($action)->getNumberOfParameters() - count($params);
|
|
$nullParams = ($nullParamsCount > 0 ? array_fill(0, $nullParamsCount, NULL) : array());
|
|
|
|
|
|
// Call Action
|
|
call_user_func_array(
|
|
array(
|
|
$this,
|
|
$action
|
|
),
|
|
array_merge(
|
|
$params,
|
|
$nullParams
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Generate the output.
|
|
*
|
|
* @param array $viewData Data to pass to the View
|
|
* @return string Generated output
|
|
*/
|
|
public function render($viewData=null)
|
|
{
|
|
// Combine given data and data of this Controller
|
|
$data = $this->viewData;
|
|
if(!is_null($viewData)) {
|
|
$data = array_merge($viewData, $data);
|
|
}
|
|
|
|
// Rendern and return output
|
|
return $this->view->render($data);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Set data for the View.
|
|
*
|
|
* @param string $name Key
|
|
* @param mixed $data Value
|
|
*/
|
|
protected function set($name, $data)
|
|
{
|
|
$this->viewData[$name] = $data;
|
|
}
|
|
|
|
|
|
/**
|
|
* Redirect to the given URL.
|
|
*
|
|
* @param string $url Relative URL
|
|
*/
|
|
protected function redirect($url)
|
|
{
|
|
$url = 'http://'.$_SERVER['HTTP_HOST'].$url;
|
|
header('Location: '.$url);
|
|
exit;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if Models of this Controller are loaded and available.
|
|
*
|
|
* @param string $modelName Arbitrary number of Models to check
|
|
* @return bool All given Models are loaded and available
|
|
*/
|
|
protected function checkModels($modelName)
|
|
{
|
|
foreach(func_get_args() as $modelName)
|
|
{
|
|
if(!isset($this->$modelName) || !is_subclass_of($this->$modelName, 'Model')) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the View of the Controller
|
|
*
|
|
* @return View View of the Controller
|
|
*/
|
|
protected function getView()
|
|
{
|
|
return $this->view;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Load the Models of this Controller.
|
|
*
|
|
* @throws DatamodelException
|
|
* @throws DriverNotFoundException
|
|
* @throws DriverNotValidException
|
|
* @throws ModelNotValidException
|
|
* @throws ModelNotFoundException
|
|
*/
|
|
private function loadModels()
|
|
{
|
|
// Determine Models
|
|
$explicit = false;
|
|
$models = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class($this)));
|
|
if(property_exists($this, 'models'))
|
|
{
|
|
$models = $this->models;
|
|
$explicit = true;
|
|
}
|
|
if(!is_array($models)) {
|
|
$models = array($models);
|
|
}
|
|
// Models of parent classes
|
|
$parent = $this;
|
|
while($parent = get_parent_class($parent))
|
|
{
|
|
$properties = get_class_vars($parent);
|
|
if(array_key_exists('models', $properties)) {
|
|
$models = array_merge($models, $properties['models']);
|
|
}
|
|
}
|
|
|
|
// Load Models
|
|
foreach($models as &$model)
|
|
{
|
|
try {
|
|
// Load class
|
|
Model::load($model);
|
|
|
|
// Construct Model
|
|
$modelName = ucfirst(strtolower($model));
|
|
$this->$modelName = Model::factory($model);
|
|
}
|
|
catch(\nre\exceptions\ModelNotValidException $e) {
|
|
if($explicit) {
|
|
throw $e;
|
|
}
|
|
}
|
|
catch(\nre\exceptions\ModelNotFoundException $e) {
|
|
if($explicit) {
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Load the View of this Controller.
|
|
*
|
|
* @throws ViewNotFoundException
|
|
* @param string $layoutName Name of the current Layout
|
|
* @param string $action Current Action
|
|
*/
|
|
private function loadView($layoutName, $action)
|
|
{
|
|
// Check Layout name
|
|
if(is_null($layoutName)) {
|
|
return;
|
|
}
|
|
|
|
// Determine controller name
|
|
$controllerName = \nre\core\ClassLoader::getClassName(get_class($this));
|
|
|
|
|
|
// Load view
|
|
$isToplevel = is_subclass_of($this->agent, '\nre\agents\ToplevelAgent');
|
|
$this->view = View::loadAndFactory($layoutName, $controllerName, $action, $isToplevel);
|
|
}
|
|
|
|
}
|
|
|
|
?>
|