From 3fca3cab9b49a2ae4934ddc738839fb8c4534e62 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 02:19:53 +0100
Subject: [PATCH 001/213] add framework and basic application files
---
.htaccess | 30 +
agents/BottomlevelAgent.inc | 25 +
agents/IntermediateAgent.inc | 48 ++
agents/ToplevelAgent.inc | 382 +++++++++++++
agents/bottomlevel/epmty | 0
agents/intermediate/ErrorAgent.inc | 35 ++
agents/toplevel/FaultAgent.inc | 35 ++
agents/toplevel/HtmlAgent.inc | 35 ++
apis/WebApi.inc | 250 +++++++++
app/empty | 0
bootstrap.inc | 33 ++
configs/AppConfig.inc | 75 +++
configs/CoreConfig.inc | 167 ++++++
controllers/ErrorController.inc | 48 ++
controllers/FaultController.inc | 37 ++
controllers/HtmlController.inc | 58 ++
controllers/components/empty | 0
core/Agent.inc | 607 +++++++++++++++++++++
core/Api.inc | 163 ++++++
core/Autoloader.inc | 98 ++++
core/ClassLoader.inc | 129 +++++
core/Component.inc | 85 +++
core/Config.inc | 49 ++
core/Controller.inc | 424 ++++++++++++++
core/Driver.inc | 96 ++++
core/Exception.inc | 65 +++
core/Linker.inc | 322 +++++++++++
core/Logger.inc | 132 +++++
core/Model.inc | 141 +++++
core/Request.inc | 64 +++
core/Response.inc | 158 ++++++
core/View.inc | 124 +++++
core/WebUtils.inc | 75 +++
drivers/DatabaseDriver.inc | 87 +++
drivers/MysqliDriver.inc | 167 ++++++
exceptions/AccessDeniedException.inc | 51 ++
exceptions/ActionNotFoundException.inc | 77 +++
exceptions/AgentNotFoundException.inc | 67 +++
exceptions/AgentNotValidException.inc | 67 +++
exceptions/ClassNotFoundException.inc | 77 +++
exceptions/ClassNotValidException.inc | 77 +++
exceptions/ComponentNotFoundException.inc | 67 +++
exceptions/ComponentNotValidException.inc | 67 +++
exceptions/ControllerNotFoundException.inc | 67 +++
exceptions/ControllerNotValidException.inc | 67 +++
exceptions/DatamodelException.inc | 99 ++++
exceptions/DriverNotFoundException.inc | 68 +++
exceptions/DriverNotValidException.inc | 68 +++
exceptions/FatalDatamodelException.inc | 96 ++++
exceptions/IdNotFoundException.inc | 77 +++
exceptions/LayoutNotFoundException.inc | 68 +++
exceptions/LayoutNotValidException.inc | 67 +++
exceptions/ModelNotFoundException.inc | 67 +++
exceptions/ModelNotValidException.inc | 68 +++
exceptions/ParamsNotValidException.inc | 77 +++
exceptions/ServiceUnavailableException.inc | 77 +++
exceptions/ViewNotFoundException.inc | 77 +++
logs/empty | 0
models/DatabaseModel.inc | 83 +++
requests/WebRequest.inc | 401 ++++++++++++++
responses/WebResponse.inc | 250 +++++++++
views/error.tpl | 13 +
views/fault/error/index.tpl | 2 +
views/fault/fault.tpl | 16 +
views/html/error/index.tpl | 2 +
views/html/html.tpl | 16 +
views/inlineerror.tpl | 1 +
www/.htaccess | 8 +
www/error403.html | 14 +
www/error404.html | 14 +
www/error500.html | 14 +
www/index.php | 45 ++
72 files changed, 6716 insertions(+)
create mode 100644 .htaccess
create mode 100644 agents/BottomlevelAgent.inc
create mode 100644 agents/IntermediateAgent.inc
create mode 100644 agents/ToplevelAgent.inc
create mode 100644 agents/bottomlevel/epmty
create mode 100644 agents/intermediate/ErrorAgent.inc
create mode 100644 agents/toplevel/FaultAgent.inc
create mode 100644 agents/toplevel/HtmlAgent.inc
create mode 100644 apis/WebApi.inc
create mode 100644 app/empty
create mode 100644 bootstrap.inc
create mode 100644 configs/AppConfig.inc
create mode 100644 configs/CoreConfig.inc
create mode 100644 controllers/ErrorController.inc
create mode 100644 controllers/FaultController.inc
create mode 100644 controllers/HtmlController.inc
create mode 100644 controllers/components/empty
create mode 100644 core/Agent.inc
create mode 100644 core/Api.inc
create mode 100644 core/Autoloader.inc
create mode 100644 core/ClassLoader.inc
create mode 100644 core/Component.inc
create mode 100644 core/Config.inc
create mode 100644 core/Controller.inc
create mode 100644 core/Driver.inc
create mode 100644 core/Exception.inc
create mode 100644 core/Linker.inc
create mode 100644 core/Logger.inc
create mode 100644 core/Model.inc
create mode 100644 core/Request.inc
create mode 100644 core/Response.inc
create mode 100644 core/View.inc
create mode 100644 core/WebUtils.inc
create mode 100644 drivers/DatabaseDriver.inc
create mode 100644 drivers/MysqliDriver.inc
create mode 100644 exceptions/AccessDeniedException.inc
create mode 100644 exceptions/ActionNotFoundException.inc
create mode 100644 exceptions/AgentNotFoundException.inc
create mode 100644 exceptions/AgentNotValidException.inc
create mode 100644 exceptions/ClassNotFoundException.inc
create mode 100644 exceptions/ClassNotValidException.inc
create mode 100644 exceptions/ComponentNotFoundException.inc
create mode 100644 exceptions/ComponentNotValidException.inc
create mode 100644 exceptions/ControllerNotFoundException.inc
create mode 100644 exceptions/ControllerNotValidException.inc
create mode 100644 exceptions/DatamodelException.inc
create mode 100644 exceptions/DriverNotFoundException.inc
create mode 100644 exceptions/DriverNotValidException.inc
create mode 100644 exceptions/FatalDatamodelException.inc
create mode 100644 exceptions/IdNotFoundException.inc
create mode 100644 exceptions/LayoutNotFoundException.inc
create mode 100644 exceptions/LayoutNotValidException.inc
create mode 100644 exceptions/ModelNotFoundException.inc
create mode 100644 exceptions/ModelNotValidException.inc
create mode 100644 exceptions/ParamsNotValidException.inc
create mode 100644 exceptions/ServiceUnavailableException.inc
create mode 100644 exceptions/ViewNotFoundException.inc
create mode 100644 logs/empty
create mode 100644 models/DatabaseModel.inc
create mode 100644 requests/WebRequest.inc
create mode 100644 responses/WebResponse.inc
create mode 100644 views/error.tpl
create mode 100644 views/fault/error/index.tpl
create mode 100644 views/fault/fault.tpl
create mode 100644 views/html/error/index.tpl
create mode 100644 views/html/html.tpl
create mode 100644 views/inlineerror.tpl
create mode 100644 www/.htaccess
create mode 100644 www/error403.html
create mode 100644 www/error404.html
create mode 100644 www/error500.html
create mode 100644 www/index.php
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 00000000..e5c5c191
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,30 @@
+Allow From All
+Options -Indexes -MultiViews
+
+ErrorDocument 403 /www/error403.html
+ErrorDocument 404 /www/error404.html
+ErrorDocument 500 /www/error500.html
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+
+ RewriteEngine On
+
+ RewriteBase /
+ RewriteRule ^(.*)$ www/$1 [L]
+
diff --git a/agents/BottomlevelAgent.inc b/agents/BottomlevelAgent.inc
new file mode 100644
index 00000000..37816614
--- /dev/null
+++ b/agents/BottomlevelAgent.inc
@@ -0,0 +1,25 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The BottomlevelAgent is the standard Agent and can have indefinite
+ * SubAgents.
+ *
+ * @author coderkun
+ */
+ abstract class BottomlevelAgent extends \nre\core\Agent
+ {
+ }
+
+?>
diff --git a/agents/IntermediateAgent.inc b/agents/IntermediateAgent.inc
new file mode 100644
index 00000000..7139653d
--- /dev/null
+++ b/agents/IntermediateAgent.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The IntermediateAgent assumes the task of a module. There is only one
+ * IntermediateAgent per request.
+ *
+ * @author coderkun
+ */
+ abstract class IntermediateAgent extends \nre\core\Agent
+ {
+
+
+
+
+ /**
+ * Get the layout if it was explicitly defined.
+ *
+ * @return string Layout of the IntermediateAgent
+ */
+ public static function getLayout($agentName)
+ {
+ // Determine classname
+ $className = Autoloader::concatClassNames($agentName, 'Agent');
+
+ // Check property
+ if(isset($className::$layout)) {
+ return $className::$layout;
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
diff --git a/agents/ToplevelAgent.inc b/agents/ToplevelAgent.inc
new file mode 100644
index 00000000..c545975a
--- /dev/null
+++ b/agents/ToplevelAgent.inc
@@ -0,0 +1,382 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The ToplevelAgent assumes the task of a FrontController. There is
+ * only one per request.
+ *
+ * @author coderkun
+ */
+ class ToplevelAgent extends \nre\core\Agent
+ {
+ /**
+ * Stage: Load
+ *
+ * @var string
+ */
+ const STAGE_LOAD = 'load';
+ /**
+ * Stage: Run
+ *
+ * @var string
+ */
+ const STAGE_RUN = 'run';
+
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+ /**
+ * Layout instace
+ *
+ * @var Layout
+ */
+ private $layout = null;
+ /**
+ * IntermediateAgent instance
+ *
+ * @var IntermediateAgent
+ */
+ private $intermediateAgent = null;
+
+
+
+
+ /**
+ * Construct a ToplevelAgent.
+ *
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+
+
+ // Create response
+ $response = clone $response;
+ $response->clearParams(1);
+ $response->addParams(
+ null,
+ \nre\configs\CoreConfig::$defaults['action']
+ );
+
+ // Call parent constructor
+ parent::__construct($request, $response, $log, true);
+
+
+ // Load IntermediateAgent
+ $this->loadIntermediateAgent();
+ }
+
+
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws ServiceUnavailableException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ public function run(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ try {
+ return $this->_run($request, $response);
+ }
+ catch(\nre\exceptions\AccessDeniedException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_FORBIDDEN, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\ParamsNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ }
+
+
+ /**
+ * Generate output of the Controller of this Agent and its
+ * SubAgents.
+ *
+ * @param array $data View data
+ * @return string Generated output
+ */
+ public function render($data=array())
+ {
+ // Render IntermediateAgent
+ $data = array();
+ $data['intermediate'] = $this->intermediateAgent->render();
+
+
+ // Render ToplevelAgent
+ return parent::render($data);
+ }
+
+
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws FatalDatamodelException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function addSubAgent($agentName)
+ {
+ try {
+ call_user_func_array(
+ array(
+ $this,
+ '_addSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ throw new \nre\exceptions\FatalDatamodelException($e->getDatamodelMessage(), $e->getDatamodelErrorNumber());
+ }
+ }
+
+
+
+
+ /**
+ * Load IntermediateAgent defined by the current request.
+ *
+ * @throws ServiceUnavailableException
+ */
+ private function loadIntermediateAgent()
+ {
+ try {
+ $this->_loadIntermediateAgent();
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ }
+
+
+ /**
+ * Load IntermediateAgent defined by the current request.
+ *
+ * @throws ServiceUnavailableException
+ */
+ private function _loadIntermediateAgent()
+ {
+ // Determine IntermediateAgent
+ $agentName = $this->response->getParam(1);
+ if(is_null($agentName)) {
+ $agentName = $this->request->getParam(1, 'intermediate');
+ $this->response->addParam($agentName);
+ }
+
+ // Load IntermediateAgent
+ IntermediateAgent::load($agentName);
+
+
+ // Determine Action
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+ // Construct IntermediateAgent
+ $this->intermediateAgent = \nre\agents\IntermediateAgent::factory(
+ $agentName,
+ $this->request,
+ $this->response,
+ $this->log
+ );
+ }
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws IdNotFoundException
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ private function _run(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ // Run IntermediateAgent
+ $this->runIntermediateAgent();
+
+
+ // TODO Request instead of response?
+ $response = clone $response;
+ $response->clearParams(2);
+ $response->addParam(\nre\configs\CoreConfig::$defaults['action']);
+
+
+ // Run ToplevelAgent
+ return parent::run($request, $response);
+ }
+
+
+ /**
+ * Run IntermediateAgent.
+ *
+ * @throws ParamsNotValidException
+ * @throws IdNotFoundException
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ */
+ private function runIntermediateAgent()
+ {
+ $this->intermediateAgent->run(
+ $this->request,
+ $this->response
+ );
+ }
+
+
+ /**
+ * Handle an error that occurred during
+ * loading/cnostructing/running of the IntermediateAgent.
+ *
+ * @throws ServiceUnavailableException
+ * @param Exception $exception Occurred exception
+ * @param int $httpStatusCode HTTP-statuscode
+ * @param string $stage Stage of execution
+ */
+ private function error($exception, $httpStatusCode, $stage=self::STAGE_LOAD)
+ {
+ // Log error
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+
+ try {
+ // Define ErrorAgent
+ $this->response->clearParams(1);
+ $this->response->addParams(
+ \nre\configs\AppConfig::$defaults['intermediate-error'],
+ \nre\configs\CoreConfig::$defaults['action'],
+ $httpStatusCode
+ );
+
+ // Load ErrorAgent
+ $this->_loadIntermediateAgent();
+
+ // Run ErrorAgent
+ if($stage == self::STAGE_RUN) {
+ $this->_run($this->request, $this->response);
+ }
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(Exception $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ }
+
+
+ }
+
+?>
diff --git a/agents/bottomlevel/epmty b/agents/bottomlevel/epmty
new file mode 100644
index 00000000..e69de29b
diff --git a/agents/intermediate/ErrorAgent.inc b/agents/intermediate/ErrorAgent.inc
new file mode 100644
index 00000000..1067e8e1
--- /dev/null
+++ b/agents/intermediate/ErrorAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to show an error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class ErrorAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/FaultAgent.inc b/agents/toplevel/FaultAgent.inc
new file mode 100644
index 00000000..0d098fe4
--- /dev/null
+++ b/agents/toplevel/FaultAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display a toplevel error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class FaultAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/HtmlAgent.inc b/agents/toplevel/HtmlAgent.inc
new file mode 100644
index 00000000..e6bc8d61
--- /dev/null
+++ b/agents/toplevel/HtmlAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display a HTML-page.
+ *
+ * @author Oliver Hanraths
+ */
+ class HtmlAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/apis/WebApi.inc b/apis/WebApi.inc
new file mode 100644
index 00000000..6851ee2d
--- /dev/null
+++ b/apis/WebApi.inc
@@ -0,0 +1,250 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\apis;
+
+
+ /**
+ * WebApi-implementation.
+ *
+ * This class runs and renders an web-applictaion.
+ *
+ * @author coderkun
+ */
+ class WebApi extends \nre\core\Api
+ {
+
+
+
+
+ /**
+ * Construct a new WebApi.
+ */
+ public function __construct()
+ {
+ parent::__construct(
+ new \nre\requests\WebRequest(),
+ new \nre\responses\WebResponse()
+ );
+
+ // Add routes
+ $this->addRoutes();
+
+ // Disable screen logging for AJAX requests
+ if($this->request->getParam(0, 'toplevel') == 'ajax') {
+ $this->log->disableAutoLogToScreen();
+ }
+ }
+
+
+
+
+ /**
+ * Run application.
+ *
+ * This method runs the application and handles all errors.
+ */
+ public function run()
+ {
+ try {
+ $exception = parent::run();
+
+ if(!is_null($exception)) {
+ $this->errorService($exception);
+ }
+ }
+ catch(\nre\exceptions\ServiceUnavailableException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\FatalDatamodelException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\AgentNoaatValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ $this->errorService($e);
+ }
+ }
+
+
+ /**
+ * Render output.
+ */
+ public function render()
+ {
+ // Generate output
+ parent::render();
+
+
+ // Set HTTP-header
+ $this->response->header();
+
+ // Show output
+ echo $this->response->getOutput();
+ }
+
+
+
+
+ /**
+ * Add routes (normal and reverse) defined in the AppConfig.
+ */
+ private function addRoutes()
+ {
+ // Normal routes
+ if(property_exists('\nre\configs\AppConfig', 'routes')) {
+ foreach(\nre\configs\AppConfig::$routes as &$route) {
+ $this->request->addRoute($route[0], $route[1], $route[2]);
+ }
+ }
+
+ // Reverse routes
+ if(property_exists('\nre\configs\AppConfig', 'reverseRoutes')) {
+ foreach(\nre\configs\AppConfig::$reverseRoutes as &$route) {
+ $this->request->addReverseRoute($route[0], $route[1], $route[2]);
+ }
+ }
+
+ // Revalidate request
+ $this->request->revalidate();
+ }
+
+
+ /**
+ * Handle an error that orrcurred during the
+ * loading/constructing/running of the ToplevelAgent.
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $httpStatusCode HTTP-statuscode
+ */
+ private function error(\nre\core\Exception $exception, $httpStatusCode)
+ {
+ // Log error message
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+ try {
+ // Set agent for handling errors
+ $this->response->clearParams();
+ $this->response->addParams(
+ \nre\configs\AppConfig::$defaults['toplevel-error'],
+ \nre\configs\AppConfig::$defaults['intermediate-error'],
+ \nre\configs\CoreConfig::$defaults['action'],
+ $httpStatusCode
+ );
+
+ // Run this agent
+ parent::run();
+ }
+ catch(\nre\exceptions\ServiceUnavailableException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(Exception $e) {
+ $this->errorService($e);
+ }
+ }
+
+
+ /**
+ * Handle a error which cannot be handles by the system (and
+ * HTTP 503).
+ *
+ * $param Exception $exception Occurred exception
+ */
+ private function errorService($exception)
+ {
+ // Log error message
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+ // Set HTTP-rtatuscode
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader(503));
+
+
+ // Read and print static error file
+ $fileName = ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['errorFile'].\nre\configs\CoreConfig::getFileExt('views');
+ ob_start();
+ include($fileName);
+ $this->response->setOutput(ob_get_clean());
+
+
+ // Prevent further execution
+ $this->response->setExit();
+ }
+
+ }
+
+?>
diff --git a/app/empty b/app/empty
new file mode 100644
index 00000000..e69de29b
diff --git a/bootstrap.inc b/bootstrap.inc
new file mode 100644
index 00000000..55647ac0
--- /dev/null
+++ b/bootstrap.inc
@@ -0,0 +1,33 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ // Include required classes
+ require_once(ROOT.DS.'configs'.DS.'CoreConfig.inc');
+ require_once(ROOT.DS.\nre\configs\CoreConfig::getClassDir('core').DS.'Autoloader.inc');
+
+
+ // Set PHP-logging
+ ini_set('error_log', ROOT.DS.\nre\configs\CoreConfig::getClassDir('logs').DS.'php'.\nre\configs\CoreConfig::getFileExt('logs'));
+
+ // Register autoloader
+ \nre\core\Autoloader::register();
+
+
+ // Initialize WebApi
+ $webApi = new \nre\apis\WebApi();
+
+ // Run WebApi
+ $webApi->run();
+
+ // Render output
+ $webApi->render();
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
new file mode 100644
index 00000000..7524f7b2
--- /dev/null
+++ b/configs/AppConfig.inc
@@ -0,0 +1,75 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace nre\configs;
+
+
+ /**
+ * Application configuration.
+ *
+ * This class contains static variables with configuration values for
+ * the specific application.
+ *
+ * @author Oliver Hanraths
+ */
+ final class AppConfig
+ {
+
+ /**
+ * Application values
+ *
+ * @static
+ * @var array
+ */
+ public static $app = array(
+ 'namespace' => 'hhu\\z\\',
+ 'timeZone' => 'Europe/Berlin'
+ );
+
+
+ /**
+ * Default values
+ *
+ * @static
+ * @var array
+ */
+ public static $defaults = array(
+ 'toplevel' => 'html',
+ 'toplevel-error' => 'fault',
+ 'intermediate' => 'introduction',
+ 'intermediate-error' => 'error'
+ );
+
+
+ /**
+ * Routes
+ *
+ * @static
+ * @var array
+ */
+ public static $routes = array(
+ //array('', '', '')
+ );
+
+
+ /**
+ * Reverse routes
+ *
+ * @static
+ * @var array
+ */
+ public static $reverseRoutes = array(
+ //array('', '', '')
+ );
+
+ }
+
+?>
diff --git a/configs/CoreConfig.inc b/configs/CoreConfig.inc
new file mode 100644
index 00000000..a28b6dbc
--- /dev/null
+++ b/configs/CoreConfig.inc
@@ -0,0 +1,167 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\configs;
+
+
+ /**
+ * Core configuration.
+ *
+ * This class contains static variables with configuration values.
+ *
+ * @author coderkun
+ */
+ final class CoreConfig
+ {
+
+ /**
+ * Core values
+ *
+ * @static
+ * @var array
+ */
+ public static $core = array(
+ 'namespace' => 'nre\\',
+ );
+
+
+ /**
+ * Directories
+ *
+ * @static
+ * @var array
+ */
+ public static $dirs = array(
+ 'core' => 'core',
+ 'publicDir' => 'www'
+ );
+
+
+ /**
+ * File extensions
+ *
+ * @static
+ * @var array
+ */
+ public static $fileExts = array(
+ 'default' => 'inc',
+ 'views' => 'tpl',
+ 'logs' => 'log',
+ );
+
+
+ /**
+ * Default values
+ *
+ * @static
+ * @var array
+ */
+ public static $defaults = array(
+ 'action' => 'index',
+ 'errorFile' => 'error',
+ 'inlineErrorFile' => 'inlineerror'
+ );
+
+
+ /**
+ * Miscellaneous settings
+ *
+ * @static
+ * @var array
+ */
+ public static $misc = array(
+ 'fileExtDot' => '.'
+ );
+
+
+ /**
+ * Logging settings
+ *
+ * @static
+ * @var array
+ */
+ public static $log = array(
+ 'filename' => 'errors',
+ 'format' => 'Fehler %d: %s in %s, Zeile %d'
+ );
+
+
+ /**
+ * Class-specific settings
+ *
+ * @static
+ * @var array
+ */
+ public static $classes = array(
+ 'linker' => array(
+ 'url' => array(
+ 'length' => 50,
+ 'delimiter' => '-'
+ )
+ )
+ );
+
+
+
+
+ /**
+ * Determine the directory for a specific classtype.
+ *
+ * @param string $classType Classtype to get directory of
+ * @return string Directory of given classtype
+ */
+ public static function getClassDir($classType)
+ {
+ // Default directory (for core classes)
+ $classDir = self::$dirs['core'];
+
+ // Configurable directory
+ if(array_key_exists($classType, self::$dirs)) {
+ $classDir = self::$dirs[$classType];
+ }
+ else
+ {
+ // Default directory for classtype
+ if(is_dir(ROOT.DS.$classType)) {
+ $classDir = $classType;
+ }
+ }
+
+
+ // Return directory
+ return $classDir;
+ }
+
+
+ /**
+ * Determine the file extension for a specific filetype.
+ *
+ * @param string $fileType Filetype to get file extension of
+ * @return string File extension of given filetype
+ */
+ public static function getFileExt($fileType)
+ {
+ // Default file extension
+ $fileExt = self::$fileExts['default'];
+
+ // Configurable file extension
+ if(array_key_exists($fileType, self::$fileExts)) {
+ $fileExt = self::$fileExts[$fileType];
+ }
+
+
+ // Return file extension
+ return self::$misc['fileExtDot'].$fileExt;
+ }
+
+ }
+
+?>
diff --git a/controllers/ErrorController.inc b/controllers/ErrorController.inc
new file mode 100644
index 00000000..8cb308b5
--- /dev/null
+++ b/controllers/ErrorController.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to show an error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class ErrorController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Set HTTP-header and print an error message.
+ *
+ * @param int $httpStatusCode HTTP-statuscode of the error that occurred
+ */
+ public function index($httpStatusCode)
+ {
+ // Set HTTP-header
+ if(!array_key_exists($httpStatusCode, \nre\core\WebUtils::$httpStrings)) {
+ $httpStatusCode = 200;
+ }
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader($httpStatusCode));
+
+ // Display statuscode and message
+ $this->set('code', $httpStatusCode);
+ $this->set('string', \nre\core\WebUtils::$httpStrings[$httpStatusCode]);
+ }
+
+ }
+
+?>
diff --git a/controllers/FaultController.inc b/controllers/FaultController.inc
new file mode 100644
index 00000000..be01fea7
--- /dev/null
+++ b/controllers/FaultController.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to display a toplevel error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class FaultController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show the error message.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/HtmlController.inc b/controllers/HtmlController.inc
new file mode 100644
index 00000000..3c33d732
--- /dev/null
+++ b/controllers/HtmlController.inc
@@ -0,0 +1,58 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the HtmlAgent to display a HTML-page.
+ *
+ * @author Oliver Hanraths
+ */
+ class HtmlController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Prefilter.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+
+ // Set content-type
+ $this->response->addHeader("Content-type: text/html; charset=utf-8");
+
+ // Start session
+ session_start();
+ }
+
+
+ /**
+ * Action: index.
+ *
+ * Create the HTML-structure.
+ */
+ public function index()
+ {
+ // Set the name of the current IntermediateAgent as page title
+ $this->set('title', $this->request->getParam(1, 'intermediate'));
+ }
+
+ }
+
+?>
diff --git a/controllers/components/empty b/controllers/components/empty
new file mode 100644
index 00000000..e69de29b
diff --git a/core/Agent.inc b/core/Agent.inc
new file mode 100644
index 00000000..00ec1a90
--- /dev/null
+++ b/core/Agent.inc
@@ -0,0 +1,607 @@
+
+ * @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 the implementation af an Agent.
+ *
+ * @author coderkun
+ */
+ abstract class Agent
+ {
+ /**
+ * Name of BottomlevelAgent for showing inline errors
+ *
+ * @var string
+ */
+ const INLINEERROR_AGENT = 'inlineerror';
+
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+ /**
+ * Log-system
+ *
+ * @var Logger
+ */
+ protected $log;
+ /**
+ * SubAgents
+ *
+ * @var array
+ */
+ protected $subAgents = array();
+ /**
+ * Controller of this Agent
+ *
+ * @var Controller
+ */
+ public $controller = null;
+
+
+
+
+ /**
+ * Load the class of an Agent.
+ *
+ * @static
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ */
+ public static function load($agentName)
+ {
+ // Determine full classname
+ $agentType = self::getAgentType();
+ $className = self::getClassName($agentName, $agentType);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ $parentAgentClassName = ClassLoader::concatClassNames($agentType, 'agent');
+ $parentAgentClassName = "\\nre\\agents\\$parentAgentClassName";
+ ClassLoader::check($className, $parentAgentClassName);
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\AgentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\AgentNotFoundException($e->getClassName());
+ }
+ }
+
+
+
+ /**
+ * Instantiate an Agent (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param string $agentName Name of the Agent to instantiate
+ * @param Request $request Current request
+ * @param Response $respone Current respone
+ * @param Logger $log Log-system
+ */
+ public static function factory($agentName, Request $request, Response $response, Logger $log=null)
+ {
+ // Determine full classname
+ $agentType = self::getAgentType();
+ $className = self::getClassName($agentName, $agentType);
+
+
+ // Construct and return Agent
+ return new $className($request, $response, $log);
+ }
+
+
+ /**
+ * Determine the type of an Agent.
+ *
+ * @static
+ * @return string Agent type
+ */
+ private static function getAgentType()
+ {
+ return strtolower(ClassLoader::getClassName(get_called_class()));
+ }
+
+
+ /**
+ * Determine the classname for the given Agent name.
+ *
+ * @static
+ * @param string $agentName Agent name to get classname of
+ * @param string $agentType Agent type of given Agent name
+ * @return string Classname for the Agent name
+ */
+ private static function getClassName($agentName, $agentType)
+ {
+ $className = ClassLoader::concatClassNames($agentName, 'agent');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."agents\\$agentType\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(Request $request, Response $response, Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+ $this->log = $log;
+
+ // Construct SubAgent
+ $this->actionConstruct();
+
+ // Load corresponding Controller
+ $this->loadController();
+ }
+
+
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws ParamsNotValidException
+ * @throws IdNotFoundException
+ * @throws DatamodelException
+ * @throws ActionNotFoundException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ public function run(Request $request, Response $response)
+ {
+ // Check Controller
+ if(!is_null($this->controller))
+ {
+ // Call prefilter
+ $this->controller->preFilter($request, $response);
+
+ // Run controller
+ $this->controller->run($request, $response);
+
+ // Call postfilter
+ $this->controller->postFilter($request, $response);
+ }
+
+
+ // Run SubAgents
+ $exception = null;
+ foreach($this->subAgents as &$subAgent)
+ {
+ try {
+ $subAgent['object']->run(
+ $request,
+ $subAgent['response']
+ );
+ }
+ catch(ParamsNotValidException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(IdNotFoundException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(DatamodelException $e) {
+ $exception = $e;
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(ActionNotFoundException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ }
+
+
+ // Return last occurred exception
+ return $exception;
+ }
+
+
+ /**
+ * Generate output of the Controller of this Agent and its
+ * SubAgents.
+ *
+ * @param array $data View data
+ * @return string Generated output
+ */
+ public function render($data=array())
+ {
+ // Check Controller
+ if(!is_null($this->controller))
+ {
+ // Render SubAgents
+ foreach($this->subAgents as $subAgent)
+ {
+ $label = array_key_exists('label', $subAgent) ? $subAgent['label'] : $subAgent['name'];
+ $data[$label] = $this->renderSubAgent($subAgent);
+ }
+
+ // Render the Controller of this agent
+ return $this->controller->render($data);
+ }
+ }
+
+
+
+
+ /**
+ * Construct SubAgents (per Action).
+ */
+ protected function actionConstruct()
+ {
+ // Action ermitteln
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+ // Initialisierungsmethode für diese Action ausführen
+ if(method_exists($this, $action))
+ {
+ call_user_func_array(
+ array(
+ $this,
+ $action
+ ),
+ array(
+ $this->request,
+ $this->response
+ )
+ );
+ }
+ }
+
+
+ /**
+ * Load the Controller of this Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ */
+ protected function loadController()
+ {
+ // Determine Controller name
+ $controllerName = ClassLoader::getClassName(get_class($this));
+
+ // Determine ToplevelAgent
+ $toplevelAgentName = $this->response->getParam(0);
+ if(is_null($toplevelAgentName)) {
+ $toplevelAgentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($toplevelAgentName);
+ }
+
+ // Determine Action
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+
+ // Load Controller
+ Controller::load($controllerName);
+
+ // Construct Controller
+ $this->controller = Controller::factory($controllerName, $toplevelAgentName, $action, $this);
+ }
+
+
+ /**
+ * Log an error.
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $logMode Log mode
+ */
+ protected function log($exception, $logMode)
+ {
+ if(is_null($this->log)) {
+ return;
+ }
+
+ $this->log->log(
+ $exception->getMessage(),
+ $logMode
+ );
+ }
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function addSubAgent($agentName)
+ {
+ try {
+ call_user_func_array(
+ array(
+ $this,
+ '_addSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(DatamodelException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ }
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function _addSubAgent($agentName)
+ {
+ try {
+ // Load Agent
+ \nre\agents\BottomlevelAgent::load($agentName);
+
+ // Construct Agent
+ $this->subAgents[] = call_user_func_array(
+ array(
+ $this,
+ 'newSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(ViewNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(DriverNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(DriverNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ModelNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ModelNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ControllerNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ControllerNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(AgentNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(AgentNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ }
+
+
+
+
+ /**
+ * Create a new SubAgent.
+ *
+ * @throws DatamodelException
+ * @param string $agentName Agent name
+ * @return array SubAgent
+ */
+ private function newSubAgent($agentName)
+ {
+ // Response
+ $response = clone $this->response;
+ $response->clearParams(1);
+ $params = func_get_args();
+ if(count($params) < 2 || empty($params[1])) {
+ $params[1] = \nre\configs\CoreConfig::$defaults['action'];
+ }
+ call_user_func_array(
+ array(
+ $response,
+ 'addParams'
+ ),
+ $params
+ );
+
+ return array(
+ 'name' => strtolower($agentName),
+ 'response' => $response,
+ 'object' => \nre\agents\BottomlevelAgent::factory(
+ $agentName,
+ $this->request,
+ $response,
+ $this->log
+ )
+ );
+ }
+
+
+ /**
+ * Render a SubAgent.
+ *
+ * @param array $subAgent SubAgent to render
+ * @return string Generated output
+ */
+ private function renderSubAgent(&$subAgent)
+ {
+ // Check for InlineError
+ if(array_key_exists('inlineerror', $subAgent) && !empty($subAgent['inlineerror'])) {
+ return file_get_contents($subAgent['inlineerror']);
+ }
+
+
+ // Rendern SubAgent and return its output
+ return $subAgent['object']->render();
+ }
+
+
+ /**
+ * Handle the exception of a SubAgent.
+ *
+ * @param string $label Name of the original Agent
+ * @param Excepiton $exception Occurred exception
+ * @return array InlineError-SubAgent
+ */
+ private function errorInline($subAgent, $request, $exception)
+ {
+ // Create the SubAgent for the exception
+ $subAgent = $this->newInlineError($subAgent['name'], $exception);
+
+
+ // Run the InlineError-SubAgent
+ try {
+ $subAgent['object']->run(
+ $request,
+ $subAgent['response']
+ );
+ }
+ catch(ActionNotFoundException $e) {
+ $this->log($e, Logger::LOGMODE_AUTO);
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+
+
+ // Return the InlineError-SubAgent
+ return $subAgent;
+ }
+
+
+ /**
+ * Create a new InlineError.
+ *
+ * @param string $label Name of the original Agent
+ * @param Exception $exception Occurred exception
+ */
+ private function newInlineError($label, $exception)
+ {
+ // Log error
+ $this->log($exception, Logger::LOGMODE_AUTO);
+
+ // Determine Agent name
+ $agentName = self::INLINEERROR_AGENT;
+
+ // Create SugAgent
+ $subAgent = array();
+
+
+ try {
+ // Load Agenten
+ \nre\agents\BottomlevelAgent::load($agentName);
+
+ // Construct Agent
+ $subAgent = $this->newSubAgent($agentName);
+ $subAgent['label'] = $label;
+ $subAgent['response']->addParam($exception);
+ }
+ catch(ViewNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DatamodelException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DriverNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DriverNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ModelNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ModelNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ControllerNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ControllerNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(AgentNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(AgentNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+
+
+ // Return SubAgent
+ return $subAgent;
+ }
+
+
+ /**
+ * Handle a hardcore error that could not be handled by the
+ * system.
+ */
+ private function newInlineErrorService()
+ {
+ // Read and return static error file
+ return ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['inlineErrorFile'].\nre\configs\Config::getFileExt('views');
+ }
+
+ }
+
+?>
diff --git a/core/Api.inc b/core/Api.inc
new file mode 100644
index 00000000..b89b12e7
--- /dev/null
+++ b/core/Api.inc
@@ -0,0 +1,163 @@
+
+ * @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 to implement an API.
+ *
+ * The API is the center of each application and specifies how and what
+ * to run and render.
+ *
+ * @author coderkun
+ */
+ abstract class Api
+ {
+ /**
+ * Die aktuelle Anfrage
+ *
+ * @var Request
+ */
+ protected $request;
+ /**
+ * Der Toplevelagent
+ *
+ * @var ToplevelAgent
+ */
+ private $toplevelAgent = null;
+ /**
+ * Die aktuelle Antwort
+ *
+ * @var Response
+ */
+ protected $response;
+ /**
+ * Log-System
+ *
+ * @var Logger
+ */
+ protected $log;
+
+
+
+
+ /**
+ * Construct a new API.
+ *
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ */
+ public function __construct(Request $request, Response $response)
+ {
+ // Store request
+ $this->request = $request;
+
+ // Store response
+ $this->response = $response;
+
+ // Init logging
+ $this->log = new \nre\core\Logger();
+ }
+
+
+
+
+ /**
+ * Run the application.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @throws AgentNotValidException
+ * @throws AgentNotFoundException
+ * @return Exception Last occurred exception of an subagent
+ */
+ public function run()
+ {
+ // Load ToplevelAgent
+ $this->loadToplevelAgent();
+
+ // Run ToplevelAgent
+ return $this->toplevelAgent->run($this->request, $this->response);
+ }
+
+
+ /**
+ * Render the output.
+ */
+ public function render()
+ {
+ // Check exit-status
+ if($this->response->getExit()) {
+ return;
+ }
+
+ // Render ToplevelAgent
+ $this->response->setOutput($this->toplevelAgent->render());
+ }
+
+
+
+
+ /**
+ * Log an exception
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $logMode Log-mode
+ */
+ protected function log($exception, $logMode)
+ {
+ $this->log->log(
+ $exception->getMessage(),
+ $logMode
+ );
+ }
+
+
+
+
+ /**
+ * Load the ToplevelAgent specified by the request.
+ *
+ * @throws ServiceUnavailableException
+ * @throws AgentNotValidException
+ * @throws AgentNotFoundException
+ */
+ private function loadToplevelAgent()
+ {
+ // Determine agent
+ $agentName = $this->response->getParam(0);
+ if(is_null($agentName)) {
+ $agentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($agentName);
+ }
+
+ // Load agent
+ \nre\agents\ToplevelAgent::load($agentName);
+
+ // Construct agent
+ $this->toplevelAgent = \nre\agents\ToplevelAgent::factory(
+ $agentName,
+ $this->request,
+ $this->response,
+ $this->log
+ );
+ }
+
+ }
+
+?>
diff --git a/core/Autoloader.inc b/core/Autoloader.inc
new file mode 100644
index 00000000..020b61f7
--- /dev/null
+++ b/core/Autoloader.inc
@@ -0,0 +1,98 @@
+
+ * @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;
+
+
+ /**
+ * Autoloader.
+ *
+ * This class tries to load not yet used classes.
+ *
+ * @author coderkun
+ */
+ class Autoloader
+ {
+ /**
+ * Private construct().
+ */
+ private function __construct() {}
+
+ /**
+ * Private clone().
+ */
+ private function __clone() {}
+
+
+
+
+ /**
+ * Register load-method.
+ */
+ public static function register()
+ {
+ spl_autoload_register(
+ array(
+ get_class(),
+ 'load'
+ )
+ );
+ }
+
+
+ /**
+ * Look for the given class and try to load it.
+ *
+ * @param string $fullClassName Die zu ladende Klasse
+ */
+ public static function load($fullClassName)
+ {
+ $fullClassNameA = explode('\\', $fullClassName);
+
+ if(strpos($fullClassName, \nre\configs\CoreConfig::$core['namespace']) !== 0)
+ {
+ // App
+ $className = array_slice($fullClassNameA, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
+ array_unshift($className, \nre\configs\CoreConfig::getClassDir('app'));
+ $filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
+ if(file_exists($filename)) {
+ require_once($filename);
+ }
+ }
+ else
+ {
+ // Core
+ $className = array_slice($fullClassNameA, substr_count(\nre\configs\CoreConfig::$core['namespace'], '\\'));
+ $filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
+ if(file_exists($filename)) {
+ require_once($filename);
+ }
+ }
+
+
+ }
+
+
+ /**
+ * Determine classtype of a class.
+ *
+ * @param string $className Name of the class to determine the classtype of
+ * @return string Classtype of the given class
+ */
+ public static function getClassType($className)
+ {
+ // CamelCase
+ return strtolower(preg_replace('/^.*([A-Z][^A-Z]+)$/', '$1', $className));
+ }
+
+ }
+
+?>
diff --git a/core/ClassLoader.inc b/core/ClassLoader.inc
new file mode 100644
index 00000000..81cf537a
--- /dev/null
+++ b/core/ClassLoader.inc
@@ -0,0 +1,129 @@
+
+ * @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;
+
+
+ /**
+ * Class for safely loading classes.
+ *
+ * @author coderkun
+ */
+ class ClassLoader
+ {
+
+
+
+
+ /**
+ * Load a class.
+ *
+ * @throws ClassNotFoundException
+ * @param string $className Name of the class to load
+ */
+ public static function load($fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_slice($className, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
+
+ // Determine filename
+ $fileName = ROOT.DS.implode(DS, $className). \nre\configs\CoreConfig::getFileExt('includes');
+
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of a class.
+ *
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function check($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+ /**
+ * Strip the namespace from a class name.
+ *
+ * @param string $class Name of a class including its namespace
+ * @return Name of the given class without its namespace
+ */
+ public static function stripNamespace($class)
+ {
+ return array_slice(explode('\\', $class), -1)[0];
+ }
+
+
+ /**
+ * Strip the class type from a class name.
+ *
+ * @param string $className Name of a class
+ * @return Name of the given class without its class type
+ */
+ public static function stripClassType($className)
+ {
+ return preg_replace('/^(.*)[A-Z][^A-Z]+$/', '$1', $className);
+ }
+
+
+ /**
+ * Strip the namespace and the class type of a full class name
+ * to get only its name.
+ *
+ * @param string $class Full name of a class
+ * @return Only the name of the given class
+ */
+ public static function getClassName($class)
+ {
+ return self::stripClassType(self::stripNamespace($class));
+ }
+
+
+ /**
+ * Concatenate strings to a class name following the CamelCase
+ * pattern.
+ *
+ * @param string $className1 Arbitrary number of strings to concat
+ * @return string Class name as CamelCase
+ */
+ public static function concatClassNames($className1)
+ {
+ return implode('', array_map(
+ function($arg) {
+ return ucfirst(strtolower($arg));
+ },
+ func_get_args()
+ ));
+ }
+
+ }
+
+?>
diff --git a/core/Component.inc b/core/Component.inc
new file mode 100644
index 00000000..a93363dc
--- /dev/null
+++ b/core/Component.inc
@@ -0,0 +1,85 @@
+
+ * @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 to implement a (Controller) Component.
+ *
+ * @author coderkun
+ */
+ abstract class Component
+ {
+
+
+
+
+ /**
+ * Load the class of a Component.
+ *
+ * @throws ComponentNotFoundException
+ * @throws ComponentNotValidException
+ * @param string $componentName Name of the Component to load
+ */
+ public static function load($componentName)
+ {
+ // Determine full classname
+ $className = self::getClassName($componentName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\ComponentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\ComponentNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Component (Factory Pattern).
+ *
+ * @param string $componentName Name of the Component to instantiate
+ */
+ public static function factory($componentName)
+ {
+ // Determine full classname
+ $className = self::getClassName($componentName);
+
+ // Construct and return Controller
+ return new $className();
+ }
+
+
+ /**
+ * Determine the classname for the given Component name.
+ *
+ * @param string $componentName Component name to get classname of
+ * @return string Classname for the Component name
+ */
+ private static function getClassName($componentName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($componentName, \nre\core\ClassLoader::stripNamespace(get_class()));
+
+
+ return \nre\configs\AppConfig::$app['namespace']."controllers\\components\\$className";
+ }
+
+ }
+
+?>
diff --git a/core/Config.inc b/core/Config.inc
new file mode 100644
index 00000000..b51f1e47
--- /dev/null
+++ b/core/Config.inc
@@ -0,0 +1,49 @@
+
+ * @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;
+
+
+ /**
+ * Configuration.
+ *
+ * This class does not hold any configuration value but helps to
+ * determine values that can be hold by AppConfig or CoreConfig.
+ *
+ * @author coderkun
+ */
+ final class Config
+ {
+
+
+
+
+ /**
+ * Get a default value.
+ *
+ * @param string $index Index of value to get
+ */
+ public static function getDefault($index)
+ {
+ if(array_key_exists($index, \nre\configs\AppConfig::$defaults)) {
+ return \nre\configs\AppConfig::$defaults[$index];
+ }
+ if(array_key_exists($index, \nre\configs\CoreConfig::$defaults)) {
+ return \nre\configs\CoreConfig::$defaults[$index];
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
diff --git a/core/Controller.inc b/core/Controller.inc
new file mode 100644
index 00000000..55a7675a
--- /dev/null
+++ b/core/Controller.inc
@@ -0,0 +1,424 @@
+
+ * @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
+ */
+ 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 Components
+ $this->loadComponents();
+
+ // 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 Components of this Controller.
+ *
+ * @throws ComponentNotValidException
+ * @throws ComponentNotFoundException
+ */
+ private function loadComponents()
+ {
+ // Determine components
+ $components = array();
+ if(property_exists($this, 'components')) {
+ $components = $this->components;
+ }
+ if(!is_array($components)) {
+ $components = array($components);
+ }
+
+ // Load components
+ foreach($components as &$component)
+ {
+ // Load class
+ Component::load($component);
+
+ // Construct component
+ $componentName = ucfirst(strtolower($component));
+ $this->$componentName = Component::factory($component);
+ }
+ }
+
+
+ /**
+ * 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);
+ }
+
+ }
+
+?>
diff --git a/core/Driver.inc b/core/Driver.inc
new file mode 100644
index 00000000..eec59143
--- /dev/null
+++ b/core/Driver.inc
@@ -0,0 +1,96 @@
+
+ * @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 Driver.
+ *
+ * @author coderkun
+ */
+ abstract class Driver
+ {
+
+
+
+
+ /**
+ * Load the class of a Driver.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $driverName Name of the Driver to load
+ */
+ public static function load($driverName)
+ {
+ // Determine full classname
+ $className = self::getClassName($driverName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\DriverNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\DriverNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Driver (Factory Pattern).
+ *
+ * @param string $driverName Name of the Driver to instantiate
+ */
+ public static function factory($driverName, $config)
+ {
+ // Determine full classname
+ $className = self::getClassName($driverName);
+
+
+ // Construct and return Driver
+ return $className::singleton($config);
+ }
+
+
+ /**
+ * Determine the classname for the given Driver name.
+ *
+ * @param string $driverName Driver name to get classname of
+ * @return string Classname fore the Driver name
+ */
+ private static function getClassName($driverName)
+ {
+ $className = ClassLoader::concatClassNames($driverName, ClassLoader::stripNamespace(get_class()));
+
+
+ return "\\nre\\drivers\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Driver.
+ */
+ protected function __construct()
+ {
+ }
+
+ }
+
+?>
diff --git a/core/Exception.inc b/core/Exception.inc
new file mode 100644
index 00000000..a17a700f
--- /dev/null
+++ b/core/Exception.inc
@@ -0,0 +1,65 @@
+
+ * @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;
+
+
+ /**
+ * Exception class.
+ *
+ * @author coderkun
+ */
+ class Exception extends \Exception
+ {
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $message Error message
+ * @param int $code Error code
+ * @param string $name Name to insert
+ */
+ function __construct($message, $code, $name=null)
+ {
+ parent::__construct(
+ $this->concat(
+ $message,
+ $name
+ ),
+ $code
+ );
+ }
+
+
+
+
+ /**
+ * Insert the name in a message
+ *
+ * @param string $message Error message
+ * @param string $name Name to insert
+ */
+ private function concat($message, $name)
+ {
+ if(is_null($name)) {
+ return $message;
+ }
+
+
+ return "$message: $name";
+ }
+
+ }
+
+?>
diff --git a/core/Linker.inc b/core/Linker.inc
new file mode 100644
index 00000000..5496d2b9
--- /dev/null
+++ b/core/Linker.inc
@@ -0,0 +1,322 @@
+
+ * @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;
+
+
+ /**
+ * Class to create web links based on the current request.
+ *
+ * @author coderkun
+ */
+ class Linker
+ {
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+
+
+
+
+ /**
+ * Construct a new linker.
+ *
+ * @param Request $request Current request
+ */
+ function __construct(\nre\requests\WebRequest $request)
+ {
+ $this->request = $request;
+ }
+
+
+
+
+ /**
+ * Process a title and optional a date to create link parameters.
+ *
+ * @param string $title Titel
+ * @param string $date Date
+ * @return string Created link parameters
+ */
+ public static function getLinkParams($title, $date=null)
+ {
+ // Parameters
+ $param = '';
+
+ // Mask special sign seperately
+ $specials = array('/', '?', '&');
+ foreach($specials as &$special) {
+ $title = str_replace($special, rawurlencode(rawurlencode($special)), $title);
+ }
+
+ // Process title
+ $param .= str_replace(
+ ' ',
+ '-',
+ substr(
+ $title,
+ 0,
+ \nre\configs\CoreConfig::$classes['linker']['url']['length']
+ )
+ );
+
+ // Process date
+ if(!empty($date)) {
+ $param = substr($date, 0, 10).\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'].$param;
+ }
+
+
+ // Mask and return parameters
+ return array(rawurlencode($param));
+ }
+
+
+ /**
+ * Extract date and title from a parameter string.
+ *
+ * @param string $dateTitle Parameter string with date and title
+ * @return array Extracted date and title as associative array
+ */
+ public static function extractDateTitle($dateTitle)
+ {
+ // Get delimiter
+ $delimiter = \nre\configs\CoreConfig::$classes[strtolower(get_class())]['url']['delimiter'];
+
+ // Split
+ $dateTitle = explode($delimiter, $dateTitle);
+ if(count($dateTitle) < 4) {
+ throw new IdNotFoundException(implode($delimiter, $dateTitle));
+ }
+
+ // Get parts
+ $date = urldecode(implode($delimiter, array_slice($dateTitle, 0, 3)));
+ $title = urldecode(implode($delimiter, array_slice($dateTitle, 3)));
+
+
+ // Return date and title
+ return array(
+ 'date' => $date,
+ 'title' => $title
+ );
+ }
+
+
+
+
+ /**
+ * Create a web link.
+ *
+ * @param array $params Parameters to use
+ * @param int $offset Ignore first parameters
+ * @param bool $exclusiveParams Use only the given parameters
+ * @param array $getParams GET-parameter to use
+ * @param bool $exclusiveGetParams Use only the given GET-parameters
+ * @param string $anchor Target anchor
+ * @param bool $absolute Include hostname etc. for an absolute URL
+ * @return string Created link
+ */
+ public function link($params=null, $offset=0, $exclusiveParams=true, $getParams=null, $exclusiveGetParams=true, $anchor=null, $absolute=false)
+ {
+ // Make current request to response
+ $response = new \nre\responses\WebResponse();
+
+
+ // Check parameters
+ if(is_null($params)) {
+ $params = array();
+ }
+ elseif(!is_array($params)) {
+ $params = array($params);
+ }
+
+ // Set parameters from request
+ $reqParams = array_slice($this->request->getParams(), 1, $offset);
+ if(count($reqParams) < $offset && $offset > 0) {
+ $reqParams[] = $this->request->getParam(1, 'intermediate');
+ }
+ if(count($reqParams) < $offset && $offset > 1) {
+ $reqParams[] = $this->request->getParam(2, 'action');
+ }
+ $params = array_map('rawurlencode', $params);
+ $params = array_merge($reqParams, $params);
+
+ // Use Layout
+ $layout = \nre\configs\AppConfig::$defaults['toplevel'];
+ if(!empty($getParams) && array_key_exists('layout', $getParams)) {
+ $layout = $getParams['layout'];
+ }
+ array_unshift($params, $layout);
+
+ // Use parameters from request only
+ if(!$exclusiveParams)
+ {
+ $params = array_merge(
+ $params,
+ array_slice(
+ $this->request->getParams(),
+ count($params)
+ )
+ );
+ }
+
+ // Set parameters
+ call_user_func_array(
+ array(
+ $response,
+ 'addParams'
+ ),
+ $params
+ );
+
+
+ // Check GET-parameters
+ if(is_null($getParams)) {
+ $getParams = array();
+ }
+ elseif(!is_array($params)) {
+ $params = array($params);
+ }
+ if(!$exclusiveGetParams)
+ {
+ $getParams = array_merge(
+ $this->request->getGetParams(),
+ $getParams
+ );
+ }
+
+ // Set GET-parameters
+ $response->addGetParams($getParams);
+
+
+ // Create and return link
+ return self::createLink($this->request, $response, $anchor, $absolute);
+ }
+
+
+ /**
+ * Create a link from an URL.
+ *
+ * @param string $url URL to create link from
+ * @param bool $absolute Create absolute URL
+ * @return string Created link
+ */
+ public function hardlink($url, $absolute=false)
+ {
+ return $this->createUrl($url, $this->request, $absolute);
+ }
+
+
+
+
+ /**
+ * Create a link.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @param bool $absolute Create absolute link
+ * @param string $anchor Anchor on target
+ * @return string Created link
+ */
+ private static function createLink(Request $request, Response $response, $anchor=null, $absolute=false)
+ {
+ // Check response
+ if(is_null($response)) {
+ return null;
+ }
+
+
+ // Get parameters
+ $params = $response->getParams(1);
+
+ // Check Action
+ if(count($params) == 2 && $params[1] == \nre\configs\CoreConfig::$defaults['action']) {
+ array_pop($params);
+ }
+
+ // Set parameters
+ $link = implode('/', $params);
+
+ // Apply reverse-routes
+ $link = $request->applyReverseRoutes($link);
+
+
+ // Get GET-parameters
+ $getParams = $response->getGetParams();
+
+ // Layout überprüfen
+ if(array_key_exists('layout', $getParams) && $getParams['layout'] == \nre\configs\AppConfig::$defaults['toplevel']) {
+ unset($getParams['layout']);
+ }
+
+ // Set GET-parameters
+ if(array_key_exists('url', $getParams)) {
+ unset($getParams['url']);
+ }
+ if(count($getParams) > 0) {
+ $link .= '?'.http_build_query($getParams);
+ }
+
+ // Add anchor
+ if(!is_null($anchor)) {
+ $link .= "#$anchor";
+ }
+
+
+ // Create URL
+ $url = self::createUrl($link, $request, $absolute);
+
+
+ return $url;
+ }
+
+
+ /**
+ * Adapt a link to the environment.
+ *
+ * @param string $url URL
+ * @param Request $request Current request
+ * @param bool $absolute Create absolute URL
+ * @return string Adapted URL
+ */
+ private static function createUrl($url, Request $request, $absolute=false)
+ {
+ // Variables
+ $server = $_SERVER['SERVER_NAME'];
+ $uri = $_SERVER['REQUEST_URI'];
+ $prefix = '';
+
+
+ // Determine prefix
+ $ppos = array(strlen($uri));
+ if(($p = strpos($uri, '/'.$request->getParam(1, 'intermediate'))) !== false) {
+ $ppos[] = $p;
+ }
+ $prefix = substr($uri, 0, min($ppos));
+
+ // Create absolute URL
+ if($absolute) {
+ $prefix = "http://$server/".trim($prefix, '/');
+ }
+
+ // Put URL together
+ $url = rtrim($prefix, '/').'/'.ltrim($url, '/');
+
+
+ // Return URL
+ return $url;
+ }
+
+ }
+
+?>
diff --git a/core/Logger.inc b/core/Logger.inc
new file mode 100644
index 00000000..b5ac7dc9
--- /dev/null
+++ b/core/Logger.inc
@@ -0,0 +1,132 @@
+
+ * @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;
+
+
+ /**
+ * Class to log messages to different targets.
+ *
+ * @author coderkun
+ */
+ class Logger
+ {
+ /**
+ * Log mode: Detect automatic
+ *
+ * @var int
+ */
+ const LOGMODE_AUTO = 0;
+ /**
+ * Log mode: Print to screen
+ *
+ * @var int
+ */
+ const LOGMODE_SCREEN = 1;
+ /**
+ * Log mode: Use PHP-logging mechanism
+ *
+ * @var int
+ */
+ const LOGMODE_PHP = 2;
+
+ /**
+ * Do not auto-log to screen
+ *
+ * @var boolean
+ */
+ private $autoLogToScreenDisabled = false;
+
+
+
+
+ /**
+ * Construct a new logger.
+ */
+ public function __construct()
+ {
+ }
+
+
+
+
+ /**
+ * Log a message.
+ *
+ * @param string $message Message to log
+ * @param int $logMode Log mode to use
+ */
+ public function log($message, $logMode=self::LOGMODE_SCREEN)
+ {
+ // Choose log mode automatically
+ if($logMode == self::LOGMODE_AUTO) {
+ $logMode = $this->getAutoLogMode();
+ }
+
+ // Print message to screen
+ if($logMode & self::LOGMODE_SCREEN) {
+ $this->logToScreen($message);
+ }
+
+ // Use PHP-logging mechanism
+ if($logMode & self::LOGMODE_PHP) {
+ $this->logToPhp($message);
+ }
+ }
+
+
+ /**
+ * Disable logging to screen when the log mode is automatically
+ * detected.
+ */
+ public function disableAutoLogToScreen()
+ {
+ $this->autoLogToScreenDisabled = true;
+ }
+
+
+
+ /**
+ * Print a message to screen.
+ *
+ * @param string $message Message to print
+ */
+ private function logToScreen($message)
+ {
+ echo "$message \n";
+ }
+
+
+ /**
+ * Log a message by using PHP-logging mechanism.
+ *
+ * @param string $message Message to log
+ */
+ private function logToPhp($message)
+ {
+ error_log($message, 0);
+ }
+
+
+ /**
+ * Detect log mode automatically by distinguishing between
+ * production and test environment.
+ *
+ * @return int Automatically detected log mode
+ */
+ private function getAutoLogMode()
+ {
+ return ($_SERVER['SERVER_ADDR'] == '127.0.0.1' && !$this->autoLogToScreenDisabled) ? self::LOGMODE_SCREEN : self::LOGMODE_PHP;
+ }
+
+ }
+
+?>
diff --git a/core/Model.inc b/core/Model.inc
new file mode 100644
index 00000000..c0475b4a
--- /dev/null
+++ b/core/Model.inc
@@ -0,0 +1,141 @@
+
+ * @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 Model.
+ *
+ * @author coderkun
+ */
+ abstract class Model
+ {
+
+
+
+
+ /**
+ * Load the class of a Model.
+ *
+ * @throws ModelNotFoundException
+ * @throws ModelNotValidException
+ * @param string $modelName Name of the Model to load
+ */
+ public static function load($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\ModelNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\ModelNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Model (Factory Pattern).
+ *
+ * @param string $modelName Name of the Model to instantiate
+ */
+ public static function factory($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ // Construct and return Model
+ return new $className();
+ }
+
+
+ /**
+ * Determine the classname for the given Model name.
+ *
+ * @param string $modelName Model name to get classname of
+ * @return string Classname fore the Model name
+ */
+ private static function getClassName($modelName)
+ {
+ $className = ClassLoader::concatClassNames($modelName, ClassLoader::stripNamespace(get_class()));
+
+
+ return \nre\configs\AppConfig::$app['namespace']."models\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Model.
+ *
+ * TODO Catch exception
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ protected function __construct()
+ {
+ // Load Models
+ $this->loadModels();
+ }
+
+
+
+
+ /**
+ * Load the Models of this Model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ private function loadModels()
+ {
+ // Determine Models
+ $models = array();
+ if(property_exists($this, 'models')) {
+ $models = $this->models;
+ }
+ if(!is_array($models)) {
+ $models = array($models);
+ }
+
+
+ // Load Models
+ foreach($models as $model)
+ {
+ // Load class
+ Model::load($model);
+
+ // Construct Model
+ $modelName = ucfirst(strtolower($model));
+ $this->$modelName = Model::factory($model);
+ }
+ }
+
+ }
+
+?>
diff --git a/core/Request.inc b/core/Request.inc
new file mode 100644
index 00000000..5fda187e
--- /dev/null
+++ b/core/Request.inc
@@ -0,0 +1,64 @@
+
+ * @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;
+
+
+ /**
+ * Base class to represent a request.
+ *
+ * @author coderkun
+ */
+ class Request
+ {
+ /**
+ * Passed parameters
+ *
+ * @var array
+ */
+ protected $params = array();
+
+
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ // Return parameter
+ if(count($this->params) > $index) {
+ return $this->params[$index];
+ }
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ return array_slice($this->params, $offset);
+ }
+
+ }
+
+?>
diff --git a/core/Response.inc b/core/Response.inc
new file mode 100644
index 00000000..4781b2ab
--- /dev/null
+++ b/core/Response.inc
@@ -0,0 +1,158 @@
+
+ * @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;
+
+
+ /**
+ * Base class to represent a response.
+ *
+ * @author coderkun
+ */
+ class Response
+ {
+ /**
+ * Applied parameters
+ *
+ * @var array
+ */
+ protected $params = array();
+ /**
+ * Generated output
+ *
+ * @var string
+ */
+ private $output = '';
+ /**
+ * Abort futher execution
+ *
+ * @var bool
+ */
+ private $exit = false;
+
+
+
+
+ /**
+ * Add a parameter.
+ *
+ * @param mixed $value Value of parameter
+ */
+ public function addParam($value)
+ {
+ $this->params[] = $value;
+ }
+
+
+ /**
+ * Add multiple parameters.
+ *
+ * @param mixed $value1 Value of first parameter
+ * @param mixed … Values of further parameters
+ */
+ public function addParams($value1)
+ {
+ $this->params = array_merge(
+ $this->params,
+ func_get_args()
+ );
+ }
+
+
+ /**
+ * Delete all stored parameters (from offset on).
+ *
+ * @param int $offset Offset-index
+ */
+ public function clearParams($offset=0)
+ {
+ $this->params = array_slice($this->params, 0, $offset);
+ }
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ // Return parameter
+ if(count($this->params) > $index) {
+ return $this->params[$index];
+ }
+
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ return array_slice($this->params, $offset);
+ }
+
+
+ /**
+ * Set output.
+ *
+ * @param string $output Generated output
+ */
+ public function setOutput($output)
+ {
+ $this->output = $output;
+ }
+
+
+ /**
+ * Get generated output.
+ *
+ * @return string Generated output
+ */
+ public function getOutput()
+ {
+ return $this->output;
+ }
+
+
+ /**
+ * Set exit-state.
+ *
+ * @param bool $exit Abort further execution
+ */
+ public function setExit($exit=true)
+ {
+ $this->exit = $exit;
+ }
+
+
+ /**
+ * Get exit-state.
+ *
+ * @return bool Abort further execution
+ */
+ public function getExit()
+ {
+ return $this->exit;
+ }
+
+ }
+
+?>
diff --git a/core/View.inc b/core/View.inc
new file mode 100644
index 00000000..513bd953
--- /dev/null
+++ b/core/View.inc
@@ -0,0 +1,124 @@
+
+ * @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;
+
+
+ /**
+ * View.
+ *
+ * Class to encapsulate a template file and to provide rendering methods.
+ *
+ * @author coderkun
+ */
+ class View
+ {
+ /**
+ * Template filename
+ *
+ * @var string
+ */
+ private $templateFilename;
+
+
+
+
+ /**
+ * Load and instantiate the View of an Agent.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ public static function loadAndFactory($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ return new View($layoutName, $agentName, $action, $isToplevel);
+ }
+
+
+
+
+ /**
+ * Construct a new View.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ private function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ // Create template filename
+ // LayoutName
+ $fileName = ROOT.DS. \nre\configs\CoreConfig::getClassDir('views').DS. strtolower($layoutName).DS;
+ // AgentName and Action
+ if(strtolower($agentName) != $layoutName || !$isToplevel) {
+ $fileName .= strtolower($agentName).DS.strtolower($action);
+ }
+ else {
+ $fileName .= strtolower($layoutName);
+ }
+ // File extension
+ $fileName .= \nre\configs\CoreConfig::getFileExt('views');
+
+
+ // Check template file
+ if(!file_exists($fileName)) {
+ throw new \nre\exceptions\ViewNotFoundException($fileName);
+ }
+
+ // Save filename
+ $this->templateFilename = $fileName;
+ }
+
+
+
+
+ /**
+ * Generate output
+ *
+ * @param array $data Data to have available in the template file
+ */
+ public function render($data)
+ {
+ // Extract data
+ if(!is_null($data)) {
+ extract($data, EXTR_SKIP);
+ }
+
+ // Buffer output
+ ob_start();
+
+ // Include template
+ include($this->templateFilename);
+
+
+ // Return buffered output
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Get template filename.
+ *
+ * @return string Template filename
+ */
+ public function getTemplateFilename()
+ {
+ return $this->templateFilename;
+ }
+
+ }
+
+?>
diff --git a/core/WebUtils.inc b/core/WebUtils.inc
new file mode 100644
index 00000000..5a4bb6f0
--- /dev/null
+++ b/core/WebUtils.inc
@@ -0,0 +1,75 @@
+
+ * @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;
+
+
+ /**
+ * Class that holds several web-specific methods and properties.
+ *
+ * @author coderkun
+ */
+ class WebUtils
+ {
+ /**
+ * HTTP-statuscode 403: Forbidden
+ *
+ * @var int
+ */
+ const HTTP_FORBIDDEN = 403;
+ /**
+ * HTTP-statuscode 404: Not Found
+ *
+ * @var int
+ */
+ const HTTP_NOT_FOUND = 404;
+ /**
+ * HTTP-statuscode 503: Service Unavailable
+ *
+ * @var int
+ */
+ const HTTP_SERVICE_UNAVAILABLE = 503;
+
+ /**
+ * HTTP-header strings
+ *
+ * @var array
+ */
+ public static $httpStrings = array(
+ 200 => 'OK',
+ 304 => 'Not Modified',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 503 => 'Service Unavailable'
+ );
+
+
+
+
+ /**
+ * Get the HTTP-header of a HTTP-statuscode
+ *
+ * @param int $httpStatusCode HTTP-statuscode
+ * @return string HTTP-header of HTTP-statuscode
+ */
+ public static function getHttpHeader($httpStatusCode)
+ {
+ if(!array_key_exists($httpStatusCode, self::$httpStrings)) {
+ $httpStatusCode = 200;
+ }
+
+
+ return sprintf("HTTP/1.1 %d %s\n", $httpStatusCode, self::$httpStrings[$httpStatusCode]);
+ }
+
+ }
+
+?>
diff --git a/drivers/DatabaseDriver.inc b/drivers/DatabaseDriver.inc
new file mode 100644
index 00000000..dfd5c0fd
--- /dev/null
+++ b/drivers/DatabaseDriver.inc
@@ -0,0 +1,87 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\drivers;
+
+
+ /**
+ * Abstract class for implementing a database driver.
+ *
+ * @author coderkun
+ */
+ abstract class DatabaseDriver extends \nre\core\Driver
+ {
+ /**
+ * Driver class instance
+ *
+ * @static
+ * @var DatabaseDriver
+ */
+ protected static $driver = null;
+ /**
+ * Connection resource
+ *
+ * @var resource
+ */
+ protected $connection = null;
+
+
+
+
+ /**
+ * Singleton-pattern.
+ *
+ * @param array $config Database driver configuration
+ * @return DatabaseDriver Singleton-instance of database driver class
+ */
+ public static function singleton($config)
+ {
+ // Singleton
+ if(self::$driver !== null) {
+ return self::$driver;
+ }
+
+ // Construct
+ $className = get_called_class();
+ self::$driver = new $className($config);
+
+
+ return self::$driver;
+ }
+
+
+ /**
+ * Construct a new database driver.
+ *
+ * @param array $config Connection and login settings
+ */
+ protected function __construct($config)
+ {
+ parent::__construct();
+
+ // Establish connection
+ $this->connect($config);
+ }
+
+
+
+
+ /**
+ * Establish a connect to a MqSQL-database.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ protected abstract function connect($config);
+
+ }
+
+?>
diff --git a/drivers/MysqliDriver.inc b/drivers/MysqliDriver.inc
new file mode 100644
index 00000000..9520fa1e
--- /dev/null
+++ b/drivers/MysqliDriver.inc
@@ -0,0 +1,167 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\drivers;
+
+
+ /**
+ * Implementation of a database driver for MySQL-databases.
+ *
+ * @author coderkun
+ */
+ class MysqliDriver extends \nre\drivers\DatabaseDriver
+ {
+
+
+
+
+ /**
+ * Construct a MySQL-driver.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ function __construct($config)
+ {
+ parent::__construct($config);
+ }
+
+
+
+
+ /**
+ * Execute a SQL-query.
+ *
+ * @throws DatamodelException
+ * @param string $query Query to run
+ * @param mixed … Params
+ * @return array Result
+ */
+ public function query($query)
+ {
+ // Prepare statement
+ if(!($stmt = $this->connection->prepare($query))) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+
+ try {
+ // Prepare data
+ $data = array();
+
+ // Bind parameters
+ $p = array_slice(func_get_args(), 1);
+ $params = array();
+ foreach($p as $key => $value) {
+ $params[$key] = &$p[$key];
+ }
+ if(count($params) > 0)
+ {
+ if(!(call_user_func_array(array($stmt, 'bind_param'), $params))) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+ }
+
+ // Execute query
+ if(!$stmt->execute()) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+
+ // Fetch result
+ if($result = $stmt->get_result()) {
+ while($row = $result->fetch_assoc()) {
+ $data[] = $row;
+ }
+ }
+
+
+ return $data;
+ }
+ finally {
+ $stmt->close();
+ }
+ }
+
+
+ /**
+ * Return the last insert id (of the last insert-query).
+ *
+ * @return int Last insert id
+ */
+ public function getInsertId()
+ {
+ return $this->connection->insert_id;
+ }
+
+
+ /**
+ * Enable/disable autocommit feature.
+ *
+ * @param boolean $autocommit Enable/disable autocommit
+ */
+ public function setAutocommit($autocommit)
+ {
+ $this->connection->autocommit($autocommit);
+ }
+
+
+ /**
+ * Rollback the current transaction.
+ */
+ public function rollback()
+ {
+ $this->connection->rollback();
+ }
+
+
+ /**
+ * Commit the current transaction.
+ */
+ public function commit()
+ {
+ $this->connection->commit();
+ }
+
+
+
+
+ /**
+ * Establish a connect to a MqSQL-database.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ protected function connect($config)
+ {
+ // Connect
+ $con = @new \mysqli(
+ $config['host'],
+ $config['user'],
+ $config['password'],
+ $config['db']
+ );
+
+ // Check connection
+ if($con->connect_error) {
+ throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
+ }
+
+ // Set character encoding
+ if(!$con->set_charset('utf8')) {
+ throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
+ }
+
+ // Save connection
+ $this->connection = $con;
+ }
+
+ }
+
+?>
diff --git a/exceptions/AccessDeniedException.inc b/exceptions/AccessDeniedException.inc
new file mode 100644
index 00000000..31bba929
--- /dev/null
+++ b/exceptions/AccessDeniedException.inc
@@ -0,0 +1,51 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Access denied.
+ *
+ * @author coderkun
+ */
+ class AccessDeniedException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'access denied';
+
+
+
+
+ /**
+ * Consturct a new exception.
+ */
+ function __construct()
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+ }
+
+?>
diff --git a/exceptions/ActionNotFoundException.inc b/exceptions/ActionNotFoundException.inc
new file mode 100644
index 00000000..418dd49c
--- /dev/null
+++ b/exceptions/ActionNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ActionNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 70;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'action not found';
+
+ /**
+ * Name of the action that was not found
+ *
+ * @var string
+ */
+ private $action;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $action Name of the action that was not found
+ */
+ function __construct($action)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $action
+ );
+
+ // Store values
+ $this->action = $action;
+ }
+
+
+
+
+ /**
+ * Get the name of the action that was not found.
+ *
+ * @return string Name of the action that was not found
+ */
+ public function getAction()
+ {
+ return $this->action;
+ }
+
+ }
+
+?>
diff --git a/exceptions/AgentNotFoundException.inc b/exceptions/AgentNotFoundException.inc
new file mode 100644
index 00000000..f0b3a2a7
--- /dev/null
+++ b/exceptions/AgentNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Agent not found.
+ *
+ * @author coderkun
+ */
+ class AgentNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 66;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'agent not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $agentName Name of the Agent that was not found
+ */
+ function __construct($agentName)
+ {
+ parent::__construct(
+ $agentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Agent that was not found.
+ *
+ * @return string Name of the Agent that was not found
+ */
+ public function getAgentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/AgentNotValidException.inc b/exceptions/AgentNotValidException.inc
new file mode 100644
index 00000000..1c752051
--- /dev/null
+++ b/exceptions/AgentNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Agent not valid.
+ *
+ * @author coderkun
+ */
+ class AgentNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 76;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'agent not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $agentName Name of the invalid Agent
+ */
+ function __construct($agentName)
+ {
+ parent::__construct(
+ $agentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Agent.
+ *
+ * @return string Name of the invalid Agent
+ */
+ public function getAgentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ClassNotFoundException.inc b/exceptions/ClassNotFoundException.inc
new file mode 100644
index 00000000..070f383f
--- /dev/null
+++ b/exceptions/ClassNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Class not found.
+ *
+ * @author coderkun
+ */
+ class ClassNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 64;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'class not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $className;
+
+
+
+
+ /**
+ * Construct a new exception
+ *
+ * @param string $className Name of the class that was not found
+ */
+ function __construct($className, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $className
+ );
+
+ // Store values
+ $this->className = $className;
+ }
+
+
+
+
+ /**
+ * Get the name of the class that was not found.
+ *
+ * @return string Name of the class that was not found
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ClassNotValidException.inc b/exceptions/ClassNotValidException.inc
new file mode 100644
index 00000000..bdd36d5e
--- /dev/null
+++ b/exceptions/ClassNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Class not valid.
+ *
+ * @author coderkun
+ */
+ class ClassNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 74;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'class not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $className;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $className Name of the invalid class
+ */
+ function __construct($className, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $className
+ );
+
+ // Store value
+ $this->className = $className;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid class.
+ *
+ * @return string Name of the invalid class
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ComponentNotFoundException.inc b/exceptions/ComponentNotFoundException.inc
new file mode 100644
index 00000000..5e75de44
--- /dev/null
+++ b/exceptions/ComponentNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Component not found.
+ *
+ * @author coderkun
+ */
+ class ComponentNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 67;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'component not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $componentName Name of the Component that was not found
+ */
+ function __construct($componentName)
+ {
+ parent::__construct(
+ $componentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Component that was not found.
+ *
+ * @return string Name of the Component that was not found
+ */
+ public function getComponentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ComponentNotValidException.inc b/exceptions/ComponentNotValidException.inc
new file mode 100644
index 00000000..a03b0c0d
--- /dev/null
+++ b/exceptions/ComponentNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Component not valid.
+ *
+ * @author coderkun
+ */
+ class ComponentNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 77;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'component not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $componentName Name of the invalid Component
+ */
+ function __construct($componentName)
+ {
+ parent::__construct(
+ $componentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Component.
+ *
+ * @return string Name of the invalid Component
+ */
+ public function getComponentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ControllerNotFoundException.inc b/exceptions/ControllerNotFoundException.inc
new file mode 100644
index 00000000..90859c49
--- /dev/null
+++ b/exceptions/ControllerNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Controller not found.
+ *
+ * @author coderkun
+ */
+ class ControllerNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 67;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'controller not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $controllerName Name of the Controller that was not found
+ */
+ function __construct($controllerName)
+ {
+ parent::__construct(
+ $controllerName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Controller that was not found.
+ *
+ * @return string Name of the Controller that was not found
+ */
+ public function getControllerName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ControllerNotValidException.inc b/exceptions/ControllerNotValidException.inc
new file mode 100644
index 00000000..0c945bcb
--- /dev/null
+++ b/exceptions/ControllerNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Controller not valid.
+ *
+ * @author coderkun
+ */
+ class ControllerNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 77;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'controller not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $controllerName Name of the invalid Controller
+ */
+ function __construct($controllerName)
+ {
+ parent::__construct(
+ $controllerName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Controller.
+ *
+ * @return string Name of the invalid Controller
+ */
+ public function getControllerName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/DatamodelException.inc b/exceptions/DatamodelException.inc
new file mode 100644
index 00000000..7785cd21
--- /dev/null
+++ b/exceptions/DatamodelException.inc
@@ -0,0 +1,99 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Datamodel.
+ *
+ * This exception is thrown when an error occurred during the execution
+ * of a datamodel.
+ *
+ * @author coderkun
+ */
+ class DatamodelException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 84;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'datamodel error';
+
+ /**
+ * Error message of datamodel
+ *
+ * @var string
+ */
+ private $datamodelMessage;
+ /**
+ * Error code of datamodel
+ *
+ * @var int
+ */
+ private $datamodelErrorNumber;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param string $datamodelMessage Error message of datamodel
+ * @param int $datamodelErrorNumber Error code of datamodel
+ */
+ function __construct($datamodelMessage, $datamodelErrorNumber)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $datamodelMessage." ($datamodelErrorNumber)"
+ );
+
+ // Store values
+ $this->datamodelMessage = $datamodelMessage;
+ $this->datamodelErrorNumber = $datamodelErrorNumber;
+ }
+
+
+
+
+ /**
+ * Get the error message of datamodel.
+ *
+ * @return string Error message of datamodel
+ */
+ public function getDatamodelMessage()
+ {
+ return $this->datamodelMessage;
+ }
+
+
+ /**
+ * Get the error code of datamodel.
+ *
+ * @return string Error code of datamodel
+ */
+ public function getDatamodelErrorNumber()
+ {
+ return $this->datamodelErrorNumber;
+ }
+
+ }
+
+?>
diff --git a/exceptions/DriverNotFoundException.inc b/exceptions/DriverNotFoundException.inc
new file mode 100644
index 00000000..9b218f29
--- /dev/null
+++ b/exceptions/DriverNotFoundException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Driver not found.
+ *
+ * @author coderkun
+ */
+ class DriverNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 71;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'driver not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $driverName Name of the driver that was not found
+ */
+ function __construct($driverName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $driverName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the driver that was not found.
+ *
+ * @return string Name of the driver that was not found
+ */
+ public function getDriverName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/DriverNotValidException.inc b/exceptions/DriverNotValidException.inc
new file mode 100644
index 00000000..fa9022e8
--- /dev/null
+++ b/exceptions/DriverNotValidException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Driver not valid.
+ *
+ * @author coderkun
+ */
+ class DriverNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 81;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'driver not valid';
+
+
+
+
+ /**
+ * Konstruktor.
+ *
+ * @param string $driverName Name of the invalid driver
+ */
+ function __construct($driverName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $driverName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid driver.
+ *
+ * @return string Name of the invalid driver
+ */
+ public function getDriverName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/FatalDatamodelException.inc b/exceptions/FatalDatamodelException.inc
new file mode 100644
index 00000000..afd80b86
--- /dev/null
+++ b/exceptions/FatalDatamodelException.inc
@@ -0,0 +1,96 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Datamodel exception that is fatal for the application.
+ *
+ * @author coderkun
+ */
+ class FatalDatamodelException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'fatal datamodel error';
+
+ /**
+ * Error message of datamodel
+ *
+ * @var string
+ */
+ private $datamodelMessage;
+ /**
+ * Error code of datamodel
+ *
+ * @var int
+ */
+ private $datamodelErrorNumber;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param string $datamodelMessage Error message of datamodel
+ * @param int $datamodelErrorNumber Error code of datamodel
+ */
+ function __construct($datamodelMessage, $datamodelErrorNumber)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $datamodelMessage." ($datamodelErrorNumber)"
+ );
+
+ // Store values
+ $this->datamodelMessage = $datamodelMessage;
+ $this->datamodelErrorNumber = $datamodelErrorNumber;
+ }
+
+
+
+
+ /**
+ * Get the error message of datamodel.
+ *
+ * @return string Error message of datamodel
+ */
+ public function getDatamodelMessage()
+ {
+ return $this->datamodelMessage;
+ }
+
+
+ /**
+ * Get the error code of datamodel.
+ *
+ * @return string Error code of datamodel
+ */
+ public function getDatamodelErrorNumber()
+ {
+ return $this->datamodelErrorNumber;
+ }
+
+ }
+
+?>
diff --git a/exceptions/IdNotFoundException.inc b/exceptions/IdNotFoundException.inc
new file mode 100644
index 00000000..fc3315c3
--- /dev/null
+++ b/exceptions/IdNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: ID not found.
+ *
+ * @author coderkun
+ */
+ class IdNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'id not found';
+
+ /**
+ * ID that was not found
+ *
+ * @var mixed
+ */
+ private $id;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param mixed $id ID that was not found
+ */
+ function __construct($id)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $id
+ );
+
+ // Store values
+ $this->id = $id;
+ }
+
+
+
+
+ /**
+ * Get the ID that was not found.
+ *
+ * @return mixed ID that was not found
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ }
+
+?>
diff --git a/exceptions/LayoutNotFoundException.inc b/exceptions/LayoutNotFoundException.inc
new file mode 100644
index 00000000..0eb8c89c
--- /dev/null
+++ b/exceptions/LayoutNotFoundException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Layout not found.
+ *
+ * @author coderkun
+ */
+ class LayoutNotFoundException extends \nre\exceptions\AgentNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 65;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'layout not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $layoutName Name of the Layout that was not found
+ */
+ function __construct($layoutName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $layoutName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Layout that was not found.
+ *
+ * @return string Name of the Layout that was not found
+ */
+ public function getLayoutName()
+ {
+ return $this->getAgentName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/LayoutNotValidException.inc b/exceptions/LayoutNotValidException.inc
new file mode 100644
index 00000000..b3af184f
--- /dev/null
+++ b/exceptions/LayoutNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Layout not valid.
+ *
+ * @author coderkun
+ */
+ class LayoutNotValidException extends \nre\exceptions\AgentNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 75;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'layout not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $layoutName Name of the invalid Layout
+ */
+ function __construct($layoutName)
+ {
+ parent::__construct(
+ $layoutName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Layout.
+ *
+ * @return string Name of the invalid Layout
+ */
+ public function getLayoutName()
+ {
+ return $this->getAgentName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ModelNotFoundException.inc b/exceptions/ModelNotFoundException.inc
new file mode 100644
index 00000000..48e8c0df
--- /dev/null
+++ b/exceptions/ModelNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ModelNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 68;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'model not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $modelName Name of the Model that was not found
+ */
+ function __construct($modelName)
+ {
+ parent::__construct(
+ $modelName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Model that was not found
+ *
+ * @return string Name of the Model that was not found
+ */
+ public function getModelName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ModelNotValidException.inc b/exceptions/ModelNotValidException.inc
new file mode 100644
index 00000000..267e460e
--- /dev/null
+++ b/exceptions/ModelNotValidException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ModelNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 78;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'model not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $modelName Name of the invalid Model
+ */
+ function __construct($modelName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $modelName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Model
+ *
+ * @return string Name of the invalid Model
+ */
+ public function getModelName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ParamsNotValidException.inc b/exceptions/ParamsNotValidException.inc
new file mode 100644
index 00000000..be650ce2
--- /dev/null
+++ b/exceptions/ParamsNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception Parameters not valid.
+ *
+ * @author coderkun
+ */
+ class ParamsNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 86;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'parameters not valid';
+
+ /**
+ * Invalid parameters.
+ *
+ * @var array
+ */
+ private $params;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param mixed $param1 Invalid parameters as argument list
+ */
+ function __construct($param1)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ implode(', ', func_get_args())
+ );
+
+ // Store values
+ $this->params = func_get_args();
+ }
+
+
+
+
+ /**
+ * Get invalid parameters.
+ *
+ * @return array Invalid parameters
+ */
+ public function getParams()
+ {
+ return $this->params;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ServiceUnavailableException.inc b/exceptions/ServiceUnavailableException.inc
new file mode 100644
index 00000000..bafc297f
--- /dev/null
+++ b/exceptions/ServiceUnavailableException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Service is unavailable.
+ *
+ * @author coderkun
+ */
+ class ServiceUnavailableException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 84;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'service unavailable';
+
+ /**
+ * Throws exception
+ *
+ * @var Exception
+ */
+ private $exception;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param Exception $exception Exception that has occurred
+ */
+ function __construct($exception)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $exception->getMessage()
+ );
+
+ // Store values
+ $this->exception = $exception;
+ }
+
+
+
+
+ /**
+ * Get the exception that hat occurred
+ *
+ * @return Exception Exception that has occurred
+ */
+ public function getException()
+ {
+ return $this->exception;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ViewNotFoundException.inc b/exceptions/ViewNotFoundException.inc
new file mode 100644
index 00000000..30366201
--- /dev/null
+++ b/exceptions/ViewNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: View not found.
+ *
+ * @author coderkun
+ */
+ class ViewNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 69;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'view not found';
+
+ /**
+ * Filename of the view that was not found
+ *
+ * @var string
+ */
+ private $fileName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $fileName Filename of the view that was not found
+ */
+ function __construct($fileName)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $fileName
+ );
+
+ // Save values
+ $this->fileName = $fileName;
+ }
+
+
+
+
+ /**
+ * Get the filename of the view that was not found.
+ *
+ * @return string Filename of the view that was not found
+ */
+ public function getFileName()
+ {
+ return $this->fileName;
+ }
+
+ }
+
+?>
diff --git a/logs/empty b/logs/empty
new file mode 100644
index 00000000..e69de29b
diff --git a/models/DatabaseModel.inc b/models/DatabaseModel.inc
new file mode 100644
index 00000000..51259f4f
--- /dev/null
+++ b/models/DatabaseModel.inc
@@ -0,0 +1,83 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\models;
+
+
+ /**
+ * Default implementation of a database model.
+ *
+ * @author coderkun
+ */
+ class DatabaseModel extends \nre\core\Model
+ {
+ /**
+ * Database connection
+ *
+ * @static
+ * @var DatabaseDriver
+ */
+ protected $db = NULL;
+
+
+
+
+ /**
+ * Construct a new datamase model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $type Database type
+ * @param array $config Connection settings
+ */
+ function __construct($type, $config)
+ {
+ parent::__construct();
+
+ // Load database driver
+ $this->loadDriver($type);
+
+ // Establish database connection
+ $this->connect($type, $config);
+ }
+
+
+
+
+ /**
+ * Load the database driver.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $driverName Name of the database driver
+ */
+ private function loadDriver($driverName)
+ {
+ \nre\core\Driver::load($driverName);
+ }
+
+
+ /**
+ * Establish a connection to the database.
+ *
+ * @throws DatamodelException
+ * @param string $driverName Name of the database driver
+ * @param array $config Connection settings
+ */
+ private function connect($driverName, $config)
+ {
+ $this->db = \nre\core\Driver::factory($driverName, $config);
+ }
+
+ }
+
+?>
diff --git a/requests/WebRequest.inc b/requests/WebRequest.inc
new file mode 100644
index 00000000..2e0f19b9
--- /dev/null
+++ b/requests/WebRequest.inc
@@ -0,0 +1,401 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\requests;
+
+
+ /**
+ * Representation of a web-request.
+ *
+ * @author coderkun
+ */
+ class WebRequest extends \nre\core\Request
+ {
+ /**
+ * Passed GET-parameters
+ *
+ * @var array
+ */
+ private $getParams = array();
+ /**
+ * Passed POST-parameters
+ *
+ * @var array
+ */
+ private $postParams = array();
+ /**
+ * Stored routes
+ *
+ * @var array
+ */
+ private $routes = array();
+ /**
+ * Stored reverse-routes
+ *
+ * @var array
+ */
+ private $reverseRoutes = array();
+
+
+
+
+ /**
+ * Construct a new web-request.
+ */
+ public function __construct()
+ {
+ // Detect current request
+ $this->detectRequest();
+
+ // Load GET-parameters
+ $this->loadGetParams();
+
+ // Load POST-parameters
+ $this->loadPostParams();
+
+ // Detect AJAX
+ $this->detectAJAX();
+ }
+
+
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ if($index == 0) {
+ return $this->getGetParam('layout', $defaultIndex);
+ }
+ else {
+ return parent::getParam($index-1, $defaultIndex);
+ }
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameters
+ */
+ public function getParams($offset=0)
+ {
+ if($offset == 0)
+ {
+ return array_merge(
+ array(
+ $this->getGetParam('layout', 'toplevel')
+ ),
+ parent::getParams()
+ );
+ }
+
+
+ return array_slice($this->params, $offset-1);
+ }
+
+
+ /**
+ * Get a GET-parameter.
+ *
+ * @param string $key Key of GET-parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of GET-parameter
+ */
+ public function getGetParam($key, $defaultIndex=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->getParams))
+ {
+ // Return value
+ return $this->getParams[$key];
+ }
+
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all GET-parameters.
+ *
+ * @return array GET-Parameters
+ */
+ public function getGetParams()
+ {
+ return $this->getParams;
+ }
+
+
+ /**
+ * Get a POST-parameter.
+ *
+ * @param string $key Key of POST-parameter
+ * @param string $defaultValue Default value for this parameter
+ * @return string Value of POST-parameter
+ */
+ public function getPostParam($key, $defaultValue=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->postParams))
+ {
+ // Return value
+ return $this->postParams[$key];
+ }
+
+
+ // Return default value
+ return $defaultValue;
+ }
+
+
+ /**
+ * Get all POST-parameters.
+ *
+ * @return array POST-parameters
+ */
+ public function getPostParams()
+ {
+ return $this->postParams;
+ }
+
+
+ /**
+ * Get the method of the current request.
+ *
+ * @return string Current request method
+ */
+ public function getRequestMethod()
+ {
+ return $_SERVER['REQUEST_METHOD'];
+ }
+
+
+ /**
+ * Add a URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ */
+ public function addRoute($pattern, $replacement, $isLast=false)
+ {
+ // Store route
+ $this->routes[] = $this->newRoute($pattern, $replacement, $isLast);
+ }
+
+
+ /**
+ * Add a reverse URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the reverse routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ */
+ public function addReverseRoute($pattern, $replacement, $isLast=false)
+ {
+ // Store reverse route
+ $this->reverseRoutes[] = $this->newRoute($pattern, $replacement, $isLast);
+ }
+
+
+ /**
+ * Apply stored reverse-routes to an URL
+ *
+ * @param string $url URL to apply reverse-routes to
+ * @return string Reverse-routed URL
+ */
+ public function applyReverseRoutes($url)
+ {
+ return $this->applyRoutes($url, $this->reverseRoutes);
+ }
+
+
+ /**
+ * Revalidate the current request
+ */
+ public function revalidate()
+ {
+ $this->detectRequest();
+ }
+
+
+ /**
+ * Get a SERVER-parameter.
+ *
+ * @param string $key Key of SERVER-parameter
+ * @return string Value of SERVER-parameter
+ */
+ public function getServerParam($key)
+ {
+ if(array_key_exists($key, $_SERVER)) {
+ return $_SERVER[$key];
+ }
+
+
+ return null;
+ }
+
+
+
+
+ /**
+ * Detect the current HTTP-request.
+ */
+ private function detectRequest()
+ {
+ // URL ermitteln
+ $url = isset($_GET) && array_key_exists('url', $_GET) ? $_GET['url'] : '';
+ $url = trim($url, '/');
+
+ // Routes anwenden
+ $url = $this->applyRoutes($url, $this->routes);
+
+ // URL splitten
+ $params = explode('/', $url);
+ if(empty($params[0])) {
+ $params = array();
+ }
+
+
+ // Parameter speichern
+ $this->params = $params;
+ }
+
+
+ /**
+ * Determine parameters passed by GET.
+ */
+ private function loadGetParams()
+ {
+ if(isset($_GET)) {
+ $this->getParams = $_GET;
+ }
+ }
+
+
+ /**
+ * Determine parameters passed by POST.
+ */
+ private function loadPostParams()
+ {
+ if(isset($_POST)) {
+ $this->postParams = $_POST;
+ }
+ }
+
+
+ /**
+ * Detect an AJAX-request by checking the X-Requested-With
+ * header and set the layout to 'ajax' in this case.
+ */
+ private function detectAjax()
+ {
+ // Get request headers
+ $headers = apache_request_headers();
+
+ // Check X-Requested-With header and set layout
+ if(array_key_exists('X-Requested-With', $headers) && $headers['X-Requested-With'] == 'XMLHttpRequest') {
+ if(!array_key_exists('layout', $this->getParams)) {
+ $this->getParams['layout'] = 'ajax';
+ }
+ }
+ }
+
+
+ /**
+ * Create a new URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the reverse routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ * @return array New URL-route
+ */
+ private function newRoute($pattern, $replacement, $isLast=false)
+ {
+ return array(
+ 'pattern' => $pattern,
+ 'replacement' => $replacement,
+ 'isLast' => $isLast
+ );
+ }
+
+
+ /**
+ * Apply given routes to an URL
+ *
+ * @param string $url URL to apply routes to
+ * @param array $routes Routes to apply
+ * @return string Routed URL
+ */
+ private function applyRoutes($url, $routes)
+ {
+ // Traverse given routes
+ foreach($routes as &$route)
+ {
+ // Create and apply Regex
+ $urlR = preg_replace(
+ '>'.$route['pattern'].'>i',
+ $route['replacement'],
+ $url
+ );
+
+ // Split URL
+ $get = '';
+ if(($gpos = strrpos($urlR, '?')) !== false) {
+ $get = substr($urlR, $gpos+1);
+ $urlR = substr($urlR, 0, $gpos);
+ }
+
+ // Has current route changed anything?
+ if($urlR != $url || !empty($get))
+ {
+ // Extract GET-parameters
+ if(strlen($get) > 0)
+ {
+ $gets = explode('&', $get);
+ foreach($gets as $get)
+ {
+ $get = explode('=', $get);
+ if(!array_key_exists($get[0], $this->getParams)) {
+ $this->getParams[$get[0]] = $get[1];
+ }
+ }
+ }
+
+
+ // Stop when route “isLast”
+ if($route['isLast']) {
+ $url = $urlR;
+ break;
+ }
+ }
+
+
+ // Set new URL
+ $url = $urlR;
+ }
+
+
+ // Return routed URL
+ return $url;
+ }
+
+ }
+
+?>
diff --git a/responses/WebResponse.inc b/responses/WebResponse.inc
new file mode 100644
index 00000000..2ca25079
--- /dev/null
+++ b/responses/WebResponse.inc
@@ -0,0 +1,250 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\responses;
+
+
+ /**
+ * Representation of a web-response.
+ *
+ * @author coderkun
+ */
+ class WebResponse extends \nre\core\Response
+ {
+ /**
+ * Applied GET-parameters
+ *
+ * @var array
+ */
+ private $getParams = array();
+ /**
+ * Changed header lines
+ *
+ * @var array
+ */
+ private $headers = array();
+
+
+
+
+ /**
+ * Add a parameter.
+ *
+ * @param mixed $value Value of parameter
+ */
+ public function addParam($value)
+ {
+ if(array_key_exists('layout', $this->getParams)) {
+ parent::addParam($value);
+ }
+ else {
+ $this->addGetParam('layout', $value);
+ }
+ }
+
+
+ /**
+ * Add multiple parameters.
+ *
+ * @param mixed $value1 Value of first parameter
+ * @param mixed … Values of further parameters
+ */
+ public function addParams($value1)
+ {
+ $this->addParam($value1);
+
+ $this->params = array_merge(
+ $this->params,
+ array_slice(
+ func_get_args(),
+ 1
+ )
+ );
+ }
+
+
+ /**
+ * Delete all stored parameters (from offset on).
+ *
+ * @param int $offset Offset-index
+ */
+ public function clearParams($offset=0)
+ {
+ if($offset == 0) {
+ unset($this->getParams['layout']);
+ }
+
+ parent::clearParams(max(0, $offset-1));
+ }
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ if($index == 0) {
+ return $this->getGetParam('layout', $defaultIndex);
+ }
+ else {
+ return parent::getParam($index-1, $defaultIndex);
+ }
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ if($offset == 0)
+ {
+ if(!array_key_exists('layout', $this->getParams)) {
+ return array();
+ }
+
+ return array_merge(
+ array(
+ $this->getParams['layout']
+ ),
+ $this->params
+ );
+ }
+
+
+ return array_slice($this->params, $offset-1);
+ }
+
+
+ /**
+ * Add a GET-parameter.
+ *
+ * @param string $key Key of GET-parameter
+ * @param mixed $value Value of GET-parameter
+ */
+ public function addGetParam($key, $value)
+ {
+ $this->getParams[$key] = $value;
+ }
+
+
+ /**
+ * Add multiple GET-parameters.
+ *
+ * @param array $params Associative arary with key-value GET-parameters
+ */
+ public function addGetParams($params)
+ {
+ $this->getParams = array_merge(
+ $this->getParams,
+ $params
+ );
+ }
+
+
+ /**
+ * Get a GET-parameter.
+ *
+ * @param int $index Index of GET-parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of GET-parameter
+ */
+ public function getGetParam($key, $defaultIndex=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->getParams))
+ {
+ // Return value
+ return $this->getParams[$key];
+ }
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all GET-parameters.
+ *
+ * @return array All GET-parameters
+ */
+ public function getGetParams()
+ {
+ return $this->getParams;
+ }
+
+
+ /**
+ * Add a line to the response header.
+ *
+ * @param string $headerLine Header line
+ * @param bool $replace Replace existing header line
+ * @param int $http_response_code HTTP-response code
+ */
+ public function addHeader($headerLine, $replace=true, $http_response_code=null)
+ {
+ $this->headers[] = $this->newHeader($headerLine, $replace, $http_response_code);
+ }
+
+
+ /**
+ * Clear all stored headers.
+ */
+ public function clearHeaders()
+ {
+ $this->headers = array();
+ }
+
+
+ /**
+ * Send stored headers.
+ */
+ public function header()
+ {
+ foreach($this->headers as $header)
+ {
+ header(
+ $header['string'],
+ $header['replace'],
+ $header['responseCode']
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Create a new header line.
+ *
+ * @param string $headerLine Header line
+ * @param bool $replace Replace existing header line
+ * @param int $http_response_code HTTP-response code
+ */
+ private function newHeader($headerLine, $replace=true, $http_response_code=null)
+ {
+ return array(
+ 'string' => $headerLine,
+ 'replace' => $replace,
+ 'responseCode' => $http_response_code
+ );
+ }
+
+ }
+
+?>
diff --git a/views/error.tpl b/views/error.tpl
new file mode 100644
index 00000000..f45b01a0
--- /dev/null
+++ b/views/error.tpl
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Service Unavailable
+
+
+
+ Die Anwendung steht zur Zeit leider nicht zur Verfügung.
+
+
+
diff --git a/views/fault/error/index.tpl b/views/fault/error/index.tpl
new file mode 100644
index 00000000..f7e42500
--- /dev/null
+++ b/views/fault/error/index.tpl
@@ -0,0 +1,2 @@
+Fehler
+=$code?>: =$string?>
diff --git a/views/fault/fault.tpl b/views/fault/fault.tpl
new file mode 100644
index 00000000..307b772d
--- /dev/null
+++ b/views/fault/fault.tpl
@@ -0,0 +1,16 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+
+ =$intermediate?>
+
+
+
+
diff --git a/views/html/error/index.tpl b/views/html/error/index.tpl
new file mode 100644
index 00000000..f7e42500
--- /dev/null
+++ b/views/html/error/index.tpl
@@ -0,0 +1,2 @@
+Fehler
+=$code?>: =$string?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
new file mode 100644
index 00000000..307b772d
--- /dev/null
+++ b/views/html/html.tpl
@@ -0,0 +1,16 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+
+ =$intermediate?>
+
+
+
+
diff --git a/views/inlineerror.tpl b/views/inlineerror.tpl
new file mode 100644
index 00000000..87a2b222
--- /dev/null
+++ b/views/inlineerror.tpl
@@ -0,0 +1 @@
+Dieser Teil der Anwendung steht zur Zeit leider nicht zur Verfügung.
diff --git a/www/.htaccess b/www/.htaccess
new file mode 100644
index 00000000..63163a80
--- /dev/null
+++ b/www/.htaccess
@@ -0,0 +1,8 @@
+
+ RewriteEngine On
+
+ RewriteBase /
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^(.*)$ index.php?url=$1 [QSA,L,NE]
+
diff --git a/www/error403.html b/www/error403.html
new file mode 100644
index 00000000..c8867377
--- /dev/null
+++ b/www/error403.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+ Access denied.
+
+
+
diff --git a/www/error404.html b/www/error404.html
new file mode 100644
index 00000000..874106f4
--- /dev/null
+++ b/www/error404.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+ Not found.
+
+
+
diff --git a/www/error500.html b/www/error500.html
new file mode 100644
index 00000000..b7afa5c0
--- /dev/null
+++ b/www/error500.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+ Internal server error.
+
+
+
diff --git a/www/index.php b/www/index.php
new file mode 100644
index 00000000..2faa32fd
--- /dev/null
+++ b/www/index.php
@@ -0,0 +1,45 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ /**
+ * Define constants
+ */
+ // Directory separator
+ if(!defined('DS')) {
+ define('DS', DIRECTORY_SEPARATOR);
+ }
+ // Root directory
+ if(!defined('ROOT')) {
+ define('ROOT', dirname(dirname(__FILE__)));
+ }
+
+
+ /**
+ * De-/Activate error messages
+ */
+ if($_SERVER['SERVER_ADDR'] == '127.0.0.1') {
+ error_reporting(E_ALL);
+ ini_set('display_errors', 1);
+ ini_set('log_errors', 0);
+ }
+ else {
+ error_reporting(E_ALL);
+ ini_set('display_errors', 0);
+ ini_set('log_errors', 1);
+ }
+
+
+ /**
+ * Run application
+ */
+ require ROOT.DS.'bootstrap.inc';
+
+?>
From 24f97d7c94e7ce86ce3c210da65347ce22098d04 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 02:34:29 +0100
Subject: [PATCH 002/213] add application Controller
---
app/Controller.inc | 85 +++++++++++++++++++++++++++++++++
app/empty | 0
controllers/ErrorController.inc | 2 +-
3 files changed, 86 insertions(+), 1 deletion(-)
create mode 100644 app/Controller.inc
delete mode 100644 app/empty
diff --git a/app/Controller.inc b/app/Controller.inc
new file mode 100644
index 00000000..55509fbb
--- /dev/null
+++ b/app/Controller.inc
@@ -0,0 +1,85 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Controller.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class Controller extends \nre\core\Controller
+ {
+ /**
+ * Linker instance
+ *
+ * @var Linker
+ */
+ protected $linker = null;
+
+
+
+
+ /**
+ * Construct a new application 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
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+
+ // Set timezone
+ date_default_timezone_set(\nre\configs\AppConfig::$app['timeZone']);
+ }
+
+
+
+ /**
+ * Prefilter that is executed before running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Create linker
+ $this->linker = new \nre\core\Linker($this->request);
+ }
+
+
+ /**
+ * Prefilter that is executed after running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::postFilter($request, $response);
+
+ // Set title
+ $this->set('title', $this->request->getParam(1, 'intermediate'));
+ }
+
+ }
+
+?>
diff --git a/app/empty b/app/empty
deleted file mode 100644
index e69de29b..00000000
diff --git a/controllers/ErrorController.inc b/controllers/ErrorController.inc
index 8cb308b5..efdae4f4 100644
--- a/controllers/ErrorController.inc
+++ b/controllers/ErrorController.inc
@@ -17,7 +17,7 @@
*
* @author Oliver Hanraths
*/
- class ErrorController extends \nre\core\Controller
+ class ErrorController extends \hhu\z\Controller
{
From b0a83f4cc9de981f79cd3ff6d0eec515a63e6252 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 02:37:08 +0100
Subject: [PATCH 003/213] add Stylesheet- and CssAgent and add it to
HTML-layout
---
agents/intermediate/CssAgent.inc | 35 +++++++++
agents/toplevel/StylesheetAgent.inc | 35 +++++++++
configs/AppConfig.inc | 2 +-
controllers/CssController.inc | 103 +++++++++++++++++++++++++++
controllers/StylesheetController.inc | 37 ++++++++++
views/html/html.tpl | 2 +
views/stylesheet/css/desktop.tpl | 0
views/stylesheet/error/index.tpl | 1 +
views/stylesheet/stylesheet.tpl | 4 ++
9 files changed, 218 insertions(+), 1 deletion(-)
create mode 100644 agents/intermediate/CssAgent.inc
create mode 100644 agents/toplevel/StylesheetAgent.inc
create mode 100644 controllers/CssController.inc
create mode 100644 controllers/StylesheetController.inc
create mode 100644 views/stylesheet/css/desktop.tpl
create mode 100644 views/stylesheet/error/index.tpl
create mode 100644 views/stylesheet/stylesheet.tpl
diff --git a/agents/intermediate/CssAgent.inc b/agents/intermediate/CssAgent.inc
new file mode 100644
index 00000000..8d8de32f
--- /dev/null
+++ b/agents/intermediate/CssAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to show CSS-stylesheets.
+ *
+ * @author Oliver Hanraths
+ */
+ class CssAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/StylesheetAgent.inc b/agents/toplevel/StylesheetAgent.inc
new file mode 100644
index 00000000..07eefea0
--- /dev/null
+++ b/agents/toplevel/StylesheetAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display stylesheets.
+ *
+ * @author Oliver Hanraths
+ */
+ class StylesheetAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 7524f7b2..599b4cac 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -56,7 +56,7 @@
* @var array
*/
public static $routes = array(
- //array('', '', '')
+ array('css/?(.*)', 'css/$1?layout=stylesheet', false)
);
diff --git a/controllers/CssController.inc b/controllers/CssController.inc
new file mode 100644
index 00000000..38e4a474
--- /dev/null
+++ b/controllers/CssController.inc
@@ -0,0 +1,103 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the CssAgent to show CSS-stylesheets.
+ *
+ * @author Oliver Hanraths
+ */
+ class CssController extends \hhu\z\Controller
+ {
+
+
+
+ /**
+ * Prefilter that is executed before running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Set content-type for CSS-stylesheets
+ $response->addHeader('Content-type: text/css');
+
+ // Set expires-header for caching
+ $response->addHeader("Pragma: public");
+ $response->addHeader("Expires: ".gmdate('r', time()+(60*60*24)));
+ $response->addHeader("Date: ".gmdate(\DateTime::RFC822));
+ }
+
+
+ /**
+ * Action: desktop.
+ *
+ * Show CSS for desktops.
+ */
+ public function desktop()
+ {
+ // Set HTTP-header
+ $this->setHeader();
+ }
+
+
+ /**
+ * Action: adds.
+ *
+ * Show additional CSS for desktops.
+ */
+ public function desktop_adds()
+ {
+ // Set HTTP-header
+ $this->setHeader();
+ }
+
+
+
+
+ /**
+ * Set HTTP-header for caching.
+ */
+ private function setHeader()
+ {
+ // Determine filename of template
+ $templateFilename = $this->getView()->getTemplateFilename();
+
+ // Determine date of last change
+ $templateLastModified = gmdate('r', filemtime($templateFilename));
+
+ // Create E-tag
+ $templateEtag = hash('sha256', $templateLastModified.$templateFilename);
+
+
+ // Set header
+ $this->response->addHeader("Last-Modified: ".$templateLastModified);
+ $this->response->addHeader("Etag: ".$templateEtag);
+ // HTTP-status
+ $headerModifiedSince = $this->request->getServerParam('HTTP_IF_MODIFIED_SINCE');
+ $headerNoneMatch = $this->request->getServerParam('HTTP_IF_NONE_MATCH');
+ if(
+ !is_null($headerModifiedSince) && $templateLastModified < strtotime($headerModifiedSince) &&
+ !is_null($headerNoneMatch) && $headerNoneMatch == $templateEtag
+ ) {
+ $this->response->setExit(true);
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader(304));
+ }
+ }
+
+ }
+
+?>
diff --git a/controllers/StylesheetController.inc b/controllers/StylesheetController.inc
new file mode 100644
index 00000000..d9bbfc3d
--- /dev/null
+++ b/controllers/StylesheetController.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the StylesheetAgent to display stylesheets.
+ *
+ * @author Oliver Hanraths
+ */
+ class StylesheetController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show the stylesheet-structure
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 307b772d..6adf05e5 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -4,6 +4,8 @@
The Legend of Z
+
+
diff --git a/views/stylesheet/css/desktop.tpl b/views/stylesheet/css/desktop.tpl
new file mode 100644
index 00000000..e69de29b
diff --git a/views/stylesheet/error/index.tpl b/views/stylesheet/error/index.tpl
new file mode 100644
index 00000000..f6ceec9b
--- /dev/null
+++ b/views/stylesheet/error/index.tpl
@@ -0,0 +1 @@
+Fehler: =$code?> =$string?>
diff --git a/views/stylesheet/stylesheet.tpl b/views/stylesheet/stylesheet.tpl
new file mode 100644
index 00000000..c796c127
--- /dev/null
+++ b/views/stylesheet/stylesheet.tpl
@@ -0,0 +1,4 @@
+@charset "UTF-8";
+
+
+=$intermediate?>
From d205864dd4010ba3602310c4f0fe115390b1ef37 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 03:28:18 +0100
Subject: [PATCH 004/213] add IntroductionAgent
---
agents/intermediate/IntroductionAgent.inc | 35 +++++++++++++++++++++++
controllers/IntroductionController.inc | 35 +++++++++++++++++++++++
views/html/introduction/index.tpl | 14 +++++++++
3 files changed, 84 insertions(+)
create mode 100644 agents/intermediate/IntroductionAgent.inc
create mode 100644 controllers/IntroductionController.inc
create mode 100644 views/html/introduction/index.tpl
diff --git a/agents/intermediate/IntroductionAgent.inc b/agents/intermediate/IntroductionAgent.inc
new file mode 100644
index 00000000..0ec5e706
--- /dev/null
+++ b/agents/intermediate/IntroductionAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to show an introduction page.
+ *
+ * @author Oliver Hanraths
+ */
+ class IntroductionAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/IntroductionController.inc b/controllers/IntroductionController.inc
new file mode 100644
index 00000000..5fead9cf
--- /dev/null
+++ b/controllers/IntroductionController.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to show an introduction page.
+ *
+ * @author Oliver Hanraths
+ */
+ class IntroductionController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/views/html/introduction/index.tpl b/views/html/introduction/index.tpl
new file mode 100644
index 00000000..2f36cff2
--- /dev/null
+++ b/views/html/introduction/index.tpl
@@ -0,0 +1,14 @@
+
+
+ Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de >
+
+
+ Daniel Miskovic <daniel.miskovic@uni-duesseldorf.de >
+
+
+ Leitung: Kathrin Knautz , B.A., M.A. <kathrin.knautz@uni-duesseldorf.de >
+
+
+
+ Heinrich-Heine-Universität Düsseldorf
+
From 99a1d525a7994ac12d11e5501c265f7b8683ce31 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 13:12:02 +0100
Subject: [PATCH 005/213] add MenuAgent
---
agents/bottomlevel/MenuAgent.inc | 35 ++++++++++++++++++++++++++++++++
agents/bottomlevel/epmty | 0
agents/toplevel/HtmlAgent.inc | 2 ++
controllers/MenuController.inc | 35 ++++++++++++++++++++++++++++++++
views/html/html.tpl | 5 ++++-
views/html/menu/index.tpl | 2 ++
6 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 agents/bottomlevel/MenuAgent.inc
delete mode 100644 agents/bottomlevel/epmty
create mode 100644 controllers/MenuController.inc
create mode 100644 views/html/menu/index.tpl
diff --git a/agents/bottomlevel/MenuAgent.inc b/agents/bottomlevel/MenuAgent.inc
new file mode 100644
index 00000000..835a8831
--- /dev/null
+++ b/agents/bottomlevel/MenuAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\bottomlevel;
+
+
+ /**
+ * Agent to display a menu.
+ *
+ * @author Oliver Hanraths
+ */
+ class MenuAgent extends \nre\agents\BottomlevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/bottomlevel/epmty b/agents/bottomlevel/epmty
deleted file mode 100644
index e69de29b..00000000
diff --git a/agents/toplevel/HtmlAgent.inc b/agents/toplevel/HtmlAgent.inc
index e6bc8d61..43090112 100644
--- a/agents/toplevel/HtmlAgent.inc
+++ b/agents/toplevel/HtmlAgent.inc
@@ -28,6 +28,8 @@
*/
public function index()
{
+ // Add menu
+ $this->addSubAgent('Menu');
}
}
diff --git a/controllers/MenuController.inc b/controllers/MenuController.inc
new file mode 100644
index 00000000..51aedd25
--- /dev/null
+++ b/controllers/MenuController.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to display a menu.
+ *
+ * @author Oliver Hanraths
+ */
+ class MenuController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 6adf05e5..63c9e041 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -9,7 +9,10 @@
- The Legend of Z
+
+ The Legend of Z
+ =$menu?>
+
=$intermediate?>
diff --git a/views/html/menu/index.tpl b/views/html/menu/index.tpl
new file mode 100644
index 00000000..88d03d48
--- /dev/null
+++ b/views/html/menu/index.tpl
@@ -0,0 +1,2 @@
+
+
From 978ce5156d6e66210ddf0bf39be0a5a8ab4b8ee9 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 13:13:32 +0100
Subject: [PATCH 006/213] correct parameters for Agent-actions
---
agents/bottomlevel/MenuAgent.inc | 2 +-
agents/intermediate/CssAgent.inc | 2 +-
agents/intermediate/ErrorAgent.inc | 2 +-
agents/intermediate/IntroductionAgent.inc | 2 +-
agents/toplevel/FaultAgent.inc | 2 +-
agents/toplevel/HtmlAgent.inc | 2 +-
agents/toplevel/StylesheetAgent.inc | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/agents/bottomlevel/MenuAgent.inc b/agents/bottomlevel/MenuAgent.inc
index 835a8831..77d60d8d 100644
--- a/agents/bottomlevel/MenuAgent.inc
+++ b/agents/bottomlevel/MenuAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
diff --git a/agents/intermediate/CssAgent.inc b/agents/intermediate/CssAgent.inc
index 8d8de32f..860a75a5 100644
--- a/agents/intermediate/CssAgent.inc
+++ b/agents/intermediate/CssAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
diff --git a/agents/intermediate/ErrorAgent.inc b/agents/intermediate/ErrorAgent.inc
index 1067e8e1..85bb6f95 100644
--- a/agents/intermediate/ErrorAgent.inc
+++ b/agents/intermediate/ErrorAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
diff --git a/agents/intermediate/IntroductionAgent.inc b/agents/intermediate/IntroductionAgent.inc
index 0ec5e706..3a06fdff 100644
--- a/agents/intermediate/IntroductionAgent.inc
+++ b/agents/intermediate/IntroductionAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
diff --git a/agents/toplevel/FaultAgent.inc b/agents/toplevel/FaultAgent.inc
index 0d098fe4..1ceb682e 100644
--- a/agents/toplevel/FaultAgent.inc
+++ b/agents/toplevel/FaultAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
diff --git a/agents/toplevel/HtmlAgent.inc b/agents/toplevel/HtmlAgent.inc
index 43090112..e131fdf2 100644
--- a/agents/toplevel/HtmlAgent.inc
+++ b/agents/toplevel/HtmlAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
// Add menu
$this->addSubAgent('Menu');
diff --git a/agents/toplevel/StylesheetAgent.inc b/agents/toplevel/StylesheetAgent.inc
index 07eefea0..6231b066 100644
--- a/agents/toplevel/StylesheetAgent.inc
+++ b/agents/toplevel/StylesheetAgent.inc
@@ -26,7 +26,7 @@
/**
* Action: index.
*/
- public function index()
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
{
}
From f618a2869a6df006912ec4a16a848b6f565ada11 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 16:22:43 +0100
Subject: [PATCH 007/213] create application model
---
app/Model.inc | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 app/Model.inc
diff --git a/app/Model.inc b/app/Model.inc
new file mode 100644
index 00000000..32835d04
--- /dev/null
+++ b/app/Model.inc
@@ -0,0 +1,42 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Model.
+ *
+ * @author Oliver Hanraths
+ */
+ class Model extends \nre\models\DatabaseModel
+ {
+
+
+
+
+ /**
+ * Construct a new application Model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ public function __construct()
+ {
+ parent::__construct('mysqli', \nre\configs\AppConfig::$database);
+ }
+
+ }
+
+?>
From 1e426803673240009c725f3cd8cb680748a349a0 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 16:22:56 +0100
Subject: [PATCH 008/213] create application Utils
---
app/Utils.inc | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 app/Utils.inc
diff --git a/app/Utils.inc b/app/Utils.inc
new file mode 100644
index 00000000..3ef93670
--- /dev/null
+++ b/app/Utils.inc
@@ -0,0 +1,32 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Class for implementing utility methods.
+ *
+ * @author Oliver Hanraths
+ */
+ class Utils
+ {
+
+ /**
+ * Format for printing the date
+ *
+ * @var string
+ */
+ const DATEFORMAT = 'm.d.Y';
+
+ }
+
+?>
From fed2fec0c9ad0cb88dda7ed01ce91b9225e1940c Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 16:25:26 +0100
Subject: [PATCH 009/213] change link parameter masking of framework
---
configs/CoreConfig.inc | 2 +-
core/Linker.inc | 89 ++++++++++++++++++------------------------
2 files changed, 40 insertions(+), 51 deletions(-)
diff --git a/configs/CoreConfig.inc b/configs/CoreConfig.inc
index a28b6dbc..45bc7e4a 100644
--- a/configs/CoreConfig.inc
+++ b/configs/CoreConfig.inc
@@ -103,7 +103,7 @@
public static $classes = array(
'linker' => array(
'url' => array(
- 'length' => 50,
+ 'length' => 128,
'delimiter' => '-'
)
)
diff --git a/core/Linker.inc b/core/Linker.inc
index 5496d2b9..f5b30b13 100644
--- a/core/Linker.inc
+++ b/core/Linker.inc
@@ -43,72 +43,61 @@
/**
- * Process a title and optional a date to create link parameters.
+ * Mask parameters to be used in an URL.
*
- * @param string $title Titel
- * @param string $date Date
- * @return string Created link parameters
+ * @param string $param1 First parameter
+ * @return string Masked parameters as string
*/
- public static function getLinkParams($title, $date=null)
+ public static function createLinkParam($param1)
{
- // Parameters
- $param = '';
-
- // Mask special sign seperately
- $specials = array('/', '?', '&');
- foreach($specials as &$special) {
- $title = str_replace($special, rawurlencode(rawurlencode($special)), $title);
- }
-
- // Process title
- $param .= str_replace(
- ' ',
- '-',
- substr(
- $title,
- 0,
- \nre\configs\CoreConfig::$classes['linker']['url']['length']
+ return implode(
+ \nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
+ call_user_func_array(
+ Utils::createLinkParams,
+ func_get_args()
)
);
-
- // Process date
- if(!empty($date)) {
- $param = substr($date, 0, 10).\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'].$param;
- }
-
-
- // Mask and return parameters
- return array(rawurlencode($param));
}
/**
- * Extract date and title from a parameter string.
+ * Mask parameters to be used in an URL.
*
- * @param string $dateTitle Parameter string with date and title
- * @return array Extracted date and title as associative array
+ * @param string $param1 First parameter
+ * @return string Masked parameters as array
*/
- public static function extractDateTitle($dateTitle)
+ public static function createLinkParams($param1)
{
- // Get delimiter
- $delimiter = \nre\configs\CoreConfig::$classes[strtolower(get_class())]['url']['delimiter'];
+ // Parameters
+ $linkParams = array();
+ $params = func_get_args();
- // Split
- $dateTitle = explode($delimiter, $dateTitle);
- if(count($dateTitle) < 4) {
- throw new IdNotFoundException(implode($delimiter, $dateTitle));
+ foreach($params as $param)
+ {
+ // Mask special signs seperately
+ $specials = array('/', '?', '&');
+ foreach($specials as &$special) {
+ $param = str_replace($special, rawurlencode(rawurlencode($special)), $param);
+ }
+
+ // Process parameter
+ $param = str_replace(
+ ' ',
+ \nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
+ substr(
+ $title,
+ 0,
+ \nre\configs\CoreConfig::$classes['linker']['url']['length']
+ )
+ );
+
+ // Encode parameter
+ $linkParams[] = rawurlencode($param);
}
-
- // Get parts
- $date = urldecode(implode($delimiter, array_slice($dateTitle, 0, 3)));
- $title = urldecode(implode($delimiter, array_slice($dateTitle, 3)));
- // Return date and title
- return array(
- 'date' => $date,
- 'title' => $title
- );
+ // Return link parameters
+ return $linkParams;
}
From 150aa2d1b559df2b24c1f9e6d6ba7a38e862e3fd Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 17 Jan 2014 16:26:49 +0100
Subject: [PATCH 010/213] add basic Users- and SeminariesAgent
---
agents/intermediate/SeminariesAgent.inc | 35 ++++++++
agents/intermediate/UsersAgent.inc | 35 ++++++++
configs/AppConfig.inc | 21 ++++-
controllers/SeminariesController.inc | 75 +++++++++++++++++
controllers/UsersController.inc | 61 ++++++++++++++
models/SeminariesModel.inc | 104 +++++++++++++++++++++++
models/UsersModel.inc | 105 ++++++++++++++++++++++++
views/html/html.tpl | 5 +-
views/html/menu/index.tpl | 6 +-
views/html/seminaries/index.tpl | 10 +++
views/html/seminaries/seminary.tpl | 4 +
views/html/users/index.tpl | 10 +++
views/html/users/user.tpl | 4 +
13 files changed, 470 insertions(+), 5 deletions(-)
create mode 100644 agents/intermediate/SeminariesAgent.inc
create mode 100644 agents/intermediate/UsersAgent.inc
create mode 100644 controllers/SeminariesController.inc
create mode 100644 controllers/UsersController.inc
create mode 100644 models/SeminariesModel.inc
create mode 100644 models/UsersModel.inc
create mode 100644 views/html/seminaries/index.tpl
create mode 100644 views/html/seminaries/seminary.tpl
create mode 100644 views/html/users/index.tpl
create mode 100644 views/html/users/user.tpl
diff --git a/agents/intermediate/SeminariesAgent.inc b/agents/intermediate/SeminariesAgent.inc
new file mode 100644
index 00000000..53f08124
--- /dev/null
+++ b/agents/intermediate/SeminariesAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/UsersAgent.inc b/agents/intermediate/UsersAgent.inc
new file mode 100644
index 00000000..7b929586
--- /dev/null
+++ b/agents/intermediate/UsersAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 599b4cac..8f5ab347 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -56,7 +56,9 @@
* @var array
*/
public static $routes = array(
- array('css/?(.*)', 'css/$1?layout=stylesheet', false)
+ array('css/?(.*)', 'css/$1?layout=stylesheet', false),
+ array('users/(.+)', 'users/user/$1', false),
+ array('seminaries/(.+)', 'seminaries/seminary/$1', false)
);
@@ -67,7 +69,22 @@
* @var array
*/
public static $reverseRoutes = array(
- //array('', '', '')
+ array('users/user/(.*)', 'users/$1', false),
+ array('seminaries/seminary/(.*)', 'seminaries/$1', false)
+ );
+
+
+ /**
+ * Database connection settings
+ *
+ * @static
+ * @var array
+ */
+ public static $database = array(
+ 'user' => 'z',
+ 'host' => 'localhost',
+ 'password' => 'legendofZ',
+ 'db' => 'z'
);
}
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
new file mode 100644
index 00000000..85867cbb
--- /dev/null
+++ b/controllers/SeminariesController.inc
@@ -0,0 +1,75 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesController extends \hhu\z\Controller
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'users');
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * List registered seminaries.
+ */
+ public function index()
+ {
+ // Get seminaries
+ $seminaries = $this->Seminaries->getSeminaries();
+
+ // Get additional data
+ foreach($seminaries as &$seminary)
+ {
+ // Created user
+ $seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
+ }
+
+
+ // Pass data to view
+ $this->set('seminaries', $seminaries);
+ }
+
+
+ /**
+ * Action: seminary.
+ *
+ * Show a seminary and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function seminary($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ }
+
+ }
+
+?>
diff --git a/controllers/UsersController.inc b/controllers/UsersController.inc
new file mode 100644
index 00000000..0a3ce645
--- /dev/null
+++ b/controllers/UsersController.inc
@@ -0,0 +1,61 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ // Get registered users
+ $users = $this->Users->getUsers();
+
+
+ // Pass data to view
+ $this->set('users', $users);
+ }
+
+
+ /**
+ * Action: user.
+ *
+ * Show a user and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function user($userUrl)
+ {
+ // Get user
+ $user = $this->Users->getUserByUrl($userUrl);
+
+
+ // Pass data to view
+ $this->set('user', $user);
+ }
+
+
+ }
+
+?>
diff --git a/models/SeminariesModel.inc b/models/SeminariesModel.inc
new file mode 100644
index 00000000..c4ae7954
--- /dev/null
+++ b/models/SeminariesModel.inc
@@ -0,0 +1,104 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the SeminariesAgent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new SeminariesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get registered seminaries.
+ *
+ * @return array Seminaries
+ */
+ public function getSeminaries()
+ {
+ // Get seminaries
+ return $this->db->query(
+ 'SELECT id, created, created_user_id, title, url '.
+ 'FROM seminaries '.
+ 'ORDER BY created DESC'
+ );
+ }
+
+
+ /**
+ * Get a seminary and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryId ID of a seminary
+ * @return array Seminary
+ */
+ public function getSeminaryById($seminaryId)
+ {
+ $seminary = $this->db->query(
+ 'SELECT id, created, created_user_id, title, url '.
+ 'FROM seminaries '.
+ 'WHERE id = ?',
+ 'i',
+ $seminaryId
+ );
+ if(empty($seminary)) {
+ throw new \nre\exceptions\IdNotFoundException($seminaryId);
+ }
+
+
+ return $seminary[0];
+ }
+
+
+ /**
+ * Get a seminary and its data by its URL-title.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ * @return array Seminary
+ */
+ public function getSeminaryByUrl($seminaryUrl)
+ {
+ $seminary = $this->db->query(
+ 'SELECT id, created, created_user_id, title, url '.
+ 'FROM seminaries '.
+ 'WHERE url = ?',
+ 's',
+ $seminaryUrl
+ );
+ if(empty($seminary)) {
+ throw new \nre\exceptions\IdNotFoundException($seminaryUrl);
+ }
+
+
+ return $seminary[0];
+ }
+
+ }
+
+?>
diff --git a/models/UsersModel.inc b/models/UsersModel.inc
new file mode 100644
index 00000000..2a9bb6a3
--- /dev/null
+++ b/models/UsersModel.inc
@@ -0,0 +1,105 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the UsersAgent to list users and get their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new UsersModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get registered users.
+ *
+ * @return array Users
+ */
+ public function getUsers()
+ {
+ return $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'ORDER BY username ASC'
+ );
+ }
+
+
+ /**
+ * Get a user and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param int $userId ID of an user
+ * @return array Userdata
+ */
+ public function getUserById($userId)
+ {
+ // Get user
+ $user = $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'WHERE id = ?',
+ 'i',
+ $userId
+ );
+ if(empty($user)) {
+ throw new \nre\exceptions\IdNotFoundException($userId);
+ }
+
+
+ return $user[0];
+ }
+
+
+ /**
+ * Get a user and its data by its URL-username.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ * @return array Userdata
+ */
+ public function getUserByUrl($userUrl)
+ {
+ // Get user
+ $user = $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'WHERE url = ?',
+ 's',
+ $userUrl
+ );
+ if(empty($user)) {
+ throw new \nre\exceptions\IdNotFoundException($userUrl);
+ }
+
+
+ return $user[0];
+ }
+
+ }
+
+?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 63c9e041..404d0edc 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -11,9 +11,12 @@
The Legend of Z
- =$menu?>
+
+ =$menu?>
+
+ =$title?>
=$intermediate?>
diff --git a/views/html/menu/index.tpl b/views/html/menu/index.tpl
index 88d03d48..d7c91883 100644
--- a/views/html/menu/index.tpl
+++ b/views/html/menu/index.tpl
@@ -1,2 +1,4 @@
-
-
+
+ ">Users
+ ">Seminaries
+
diff --git a/views/html/seminaries/index.tpl b/views/html/seminaries/index.tpl
new file mode 100644
index 00000000..267a561c
--- /dev/null
+++ b/views/html/seminaries/index.tpl
@@ -0,0 +1,10 @@
+
+
+
+
+
+ erstellt von =$seminary['creator']['username']?>
+
+
+
+
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
new file mode 100644
index 00000000..5566aba2
--- /dev/null
+++ b/views/html/seminaries/seminary.tpl
@@ -0,0 +1,4 @@
+=$seminary['title']?>
+
+ erstellt am =date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created']))?>
+
diff --git a/views/html/users/index.tpl b/views/html/users/index.tpl
new file mode 100644
index 00000000..347743bb
--- /dev/null
+++ b/views/html/users/index.tpl
@@ -0,0 +1,10 @@
+
+
+
+
+
+ registriert seit =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+
+
+
+
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
new file mode 100644
index 00000000..f89d38b7
--- /dev/null
+++ b/views/html/users/user.tpl
@@ -0,0 +1,4 @@
+=$user['username']?>
+
+ registriert seit =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+
From 22618f7985ac4ca935ea138bd4bfac0fa0abac59 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 19 Jan 2014 13:38:40 +0100
Subject: [PATCH 011/213] update introduction page a little
---
views/html/introduction/index.tpl | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/views/html/introduction/index.tpl b/views/html/introduction/index.tpl
index 2f36cff2..b7633b2f 100644
--- a/views/html/introduction/index.tpl
+++ b/views/html/introduction/index.tpl
@@ -1,14 +1,20 @@
+Ein Projekt zum Thema „Gamification im Lehrumfeld“ – basierend auf Die Legende von Zyren .
+Entwickler:
- Oliver Hanraths <oliver.hanraths@uni-duesseldorf.de >
+ Oliver Hanraths <oliver(DOT)hanraths(AT)uni-duesseldorf(DOT)de >
+ Programmierung und Datenbank
- Daniel Miskovic <daniel.miskovic@uni-duesseldorf.de >
+ Daniel Miskovic <daniel(DOT)miskovic(AT)uni-duesseldorf(DOT)de >
+ GUI und Webdesign
- Leitung: Kathrin Knautz , B.A., M.A. <kathrin.knautz@uni-duesseldorf.de >
+ Kathrin Knautz , B.A., M.A. <kathrin(DOT)knautz(AT)uni-duesseldorf(DOT)de >
+ Leitung
+
Heinrich-Heine-Universität Düsseldorf
From df074f5a01edc6f65d4dc7a70ecf2a740f1a52cf Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 19 Jan 2014 13:38:59 +0100
Subject: [PATCH 012/213] link css-file and headline correctly
---
views/html/html.tpl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 404d0edc..9401a5e5 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -5,12 +5,12 @@
The Legend of Z
-
+
- The Legend of Z
+
=$menu?>
From da7cda02f95893e33f46e131f74494bd43f53fa1 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 19 Jan 2014 23:03:55 +0100
Subject: [PATCH 013/213] add localization and move timezone selection to the
right place
---
agents/toplevel/HtmlAgent.inc | 32 +++++++++++++-
app/Controller.inc | 3 --
app/ToplevelAgent.inc | 36 ++++++++++++++++
configs/AppConfig.inc | 15 ++++++-
controllers/SeminariesController.inc | 3 ++
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 0 -> 744 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 45 ++++++++++++++++++++
views/html/error/index.tpl | 2 +-
views/html/html.tpl | 1 -
views/html/introduction/index.tpl | 1 +
views/html/menu/index.tpl | 4 +-
views/html/seminaries/index.tpl | 3 +-
views/html/seminaries/seminary.tpl | 3 +-
views/html/users/index.tpl | 3 +-
views/html/users/user.tpl | 3 +-
15 files changed, 141 insertions(+), 13 deletions(-)
create mode 100644 app/ToplevelAgent.inc
create mode 100644 locale/de_DE/LC_MESSAGES/The Legend of Z.mo
create mode 100644 locale/de_DE/LC_MESSAGES/The Legend of Z.po
diff --git a/agents/toplevel/HtmlAgent.inc b/agents/toplevel/HtmlAgent.inc
index e131fdf2..63ed4525 100644
--- a/agents/toplevel/HtmlAgent.inc
+++ b/agents/toplevel/HtmlAgent.inc
@@ -17,12 +17,21 @@
*
* @author Oliver Hanraths
*/
- class HtmlAgent extends \nre\agents\ToplevelAgent
+ class HtmlAgent extends \hhu\z\ToplevelAgent
{
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ parent::__construct($request, $response, $log);
+
+
+ $this->setLanguage($request);
+ }
+
+
/**
* Action: index.
*/
@@ -32,6 +41,27 @@
$this->addSubAgent('Menu');
}
+
+
+
+ private function setLanguage(\nre\core\Request $request)
+ {
+ // Set domain
+ $domain = \nre\configs\AppConfig::$app['name'];
+
+ // Get language
+ $locale = $request->getGetParam('lang', 'language');
+ if(is_null($locale)) {
+ return;
+ }
+
+ // Load translation
+ putenv("LC_ALL=$locale");
+ setlocale(LC_ALL, $locale);
+ bindtextdomain($domain, ROOT.DS.\nre\configs\AppConfig::$dirs['locale']);
+ textdomain($domain);
+ }
+
}
?>
diff --git a/app/Controller.inc b/app/Controller.inc
index 55509fbb..4403407b 100644
--- a/app/Controller.inc
+++ b/app/Controller.inc
@@ -44,9 +44,6 @@
public function __construct($layoutName, $action, $agent)
{
parent::__construct($layoutName, $action, $agent);
-
- // Set timezone
- date_default_timezone_set(\nre\configs\AppConfig::$app['timeZone']);
}
diff --git a/app/ToplevelAgent.inc b/app/ToplevelAgent.inc
new file mode 100644
index 00000000..97aea57b
--- /dev/null
+++ b/app/ToplevelAgent.inc
@@ -0,0 +1,36 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Controller.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class ToplevelAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ parent::__construct($request, $response, $log);
+
+
+ // Set timezone
+ date_default_timezone_set(\nre\configs\AppConfig::$app['timeZone']);
+ }
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 8f5ab347..3467c3be 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -30,6 +30,7 @@
* @var array
*/
public static $app = array(
+ 'name' => 'The Legend of Z',
'namespace' => 'hhu\\z\\',
'timeZone' => 'Europe/Berlin'
);
@@ -45,7 +46,19 @@
'toplevel' => 'html',
'toplevel-error' => 'fault',
'intermediate' => 'introduction',
- 'intermediate-error' => 'error'
+ 'intermediate-error' => 'error',
+ 'language' => 'de_DE.utf8'
+ );
+
+
+ /**
+ * Directories
+ *
+ * @static
+ * @var array
+ */
+ public static $dirs = array(
+ 'locale' => 'locale'
);
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
index 85867cbb..4f026f41 100644
--- a/controllers/SeminariesController.inc
+++ b/controllers/SeminariesController.inc
@@ -65,6 +65,9 @@
// Get seminary
$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+ // Created user
+ $seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
+
// Pass data to view
$this->set('seminary', $seminary);
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
new file mode 100644
index 0000000000000000000000000000000000000000..ec51389a69bdbf4ffb9b427614d53912f88b5c08
GIT binary patch
literal 744
zcmZvaPm9w)7{*6k{}2^K@wSKYASg23r0UX5>1DgE6uVe#R>X_UCU29Gbf(Nqs_SR)
z>e-tgz|#tXh*$4>((m9W&?gOA55DA=Xa2nJGjEvuxVrI{A=_s}~31M~v)7O+KD_=IS)>t;u-kPjRy)v3jX|A-iiX1y|WF1Q_NlzI+JmNPUHyUqdDOb*u
z#WG4J*1Vw9i%}+?paL#2PYU8=%1I+*#-9a~M~UdyPS_QDFpPOSjP8jr644HCx8wWU
zcfu$PktiP1Qq?a1&+9aKW9hs|tkkZQ-q@H2W2y5><|Go5^MB?s&*=HyAlM)657rGv
ztuW{t?McJtXn}q_z4BX&QYzi$X(6p6-#bW#qO;DckDHMd1D%>o={)A0L*;{~;sI&0
zO&=3OnesepZMW`Xr1ZK+5%X3sDJv^WF*J7WVy+jfsq3}7yczaxX?~-}qubqe
z{nS)8rGC>^%$vUcx=%^kw3xtOggBwK)jUf@FI~WfRFq`dKFehler
+=_('Error')?>
=$code?>: =$string?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 9401a5e5..0f46493c 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -16,7 +16,6 @@
- =$title?>
=$intermediate?>
diff --git a/views/html/introduction/index.tpl b/views/html/introduction/index.tpl
index b7633b2f..1d3fa615 100644
--- a/views/html/introduction/index.tpl
+++ b/views/html/introduction/index.tpl
@@ -1,3 +1,4 @@
+=_('Introduction')?>
Ein Projekt zum Thema „Gamification im Lehrumfeld“ – basierend auf Die Legende von Zyren .
Entwickler:
diff --git a/views/html/menu/index.tpl b/views/html/menu/index.tpl
index d7c91883..ad0fbe39 100644
--- a/views/html/menu/index.tpl
+++ b/views/html/menu/index.tpl
@@ -1,4 +1,4 @@
- ">Users
- ">Seminaries
+ ">=_('Users')?>
+ ">=_('Seminaries')?>
diff --git a/views/html/seminaries/index.tpl b/views/html/seminaries/index.tpl
index 267a561c..037f718e 100644
--- a/views/html/seminaries/index.tpl
+++ b/views/html/seminaries/index.tpl
@@ -1,9 +1,10 @@
+=_('Seminaries')?>
- erstellt von =$seminary['creator']['username']?>
+ =sprintf(_('created by %s on %s'), $seminary['creator']['username'], date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created'])))?>
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 5566aba2..094fbf3b 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -1,4 +1,5 @@
+=_('Seminaries')?>
=$seminary['title']?>
- erstellt am =date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created']))?>
+ =sprintf(_('created by %s on %s'), $seminary['creator']['username'], date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created'])))?>
diff --git a/views/html/users/index.tpl b/views/html/users/index.tpl
index 347743bb..3b94e6a0 100644
--- a/views/html/users/index.tpl
+++ b/views/html/users/index.tpl
@@ -1,9 +1,10 @@
+=_('Users')?>
- registriert seit =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+ =_('registered on')?> =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
index f89d38b7..91591dd3 100644
--- a/views/html/users/user.tpl
+++ b/views/html/users/user.tpl
@@ -1,4 +1,5 @@
+=_('Users')?>
=$user['username']?>
- registriert seit =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+ =_('registered on')?> =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
From 63766773a062a8371775b0237a899c5db0486b0a Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 22 Jan 2014 16:28:32 +0100
Subject: [PATCH 014/213] create AuthComponent with basic functionality
---
controllers/components/AuthComponent.inc | 80 ++++++++++++++++++++++++
1 file changed, 80 insertions(+)
create mode 100644 controllers/components/AuthComponent.inc
diff --git a/controllers/components/AuthComponent.inc b/controllers/components/AuthComponent.inc
new file mode 100644
index 00000000..fe0cb139
--- /dev/null
+++ b/controllers/components/AuthComponent.inc
@@ -0,0 +1,80 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers\components;
+
+
+ /**
+ * Component to handle authentication and authorization
+ *
+ * @author Oliver Hanraths
+ */
+ class AuthComponent extends \nre\core\Component
+ {
+ /**
+ * Key to save a user-ID as
+ *
+ * @var string
+ */
+ const KEY_USER_ID = 'user_id';
+
+
+
+
+ /**
+ * Construct a new Auth-component.
+ */
+ public function __construct()
+ {
+ // Start session
+ if(session_id() === '') {
+ session_start();
+ session_regenerate_id(true);
+ }
+ }
+
+
+
+
+ /**
+ * Set the ID of the user that is currently logged in.
+ *
+ * @param int $userId ID of the currently logged in user
+ */
+ public function setUserId($userId)
+ {
+ if(is_null($userId)) {
+ unset($_SESSION[self::KEY_USER_ID]);
+ }
+ else {
+ $_SESSION[self::KEY_USER_ID] = $userId;
+ }
+ }
+
+
+ /**
+ * Get the ID of the user that is currently logged in.
+ *
+ * @return int ID of the currently logged in user
+ */
+ public function getUserId()
+ {
+ if(array_key_exists(self::KEY_USER_ID, $_SESSION)) {
+ return $_SESSION[self::KEY_USER_ID];
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
From 011c9d8ed5653308c1e76a9ff4f8ed5fdd5e10a4 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 22 Jan 2014 16:31:25 +0100
Subject: [PATCH 015/213] integrate AuthComponent and implement CRUD for users
---
agents/ToplevelAgent.inc | 2 +
app/Controller.inc | 65 ++++++-
configs/AppConfig.inc | 10 +-
controllers/HtmlController.inc | 8 +-
controllers/SeminariesController.inc | 9 +
controllers/UsersController.inc | 160 ++++++++++++++++++
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 744 -> 1407 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 75 +++++++-
models/UsersModel.inc | 132 +++++++++++++++
views/html/html.tpl | 5 +
views/html/menu/index.tpl | 5 +
views/html/users/create.tpl | 14 ++
views/html/users/delete.tpl | 8 +
views/html/users/edit.tpl | 14 ++
views/html/users/index.tpl | 3 +
views/html/users/login.tpl | 12 ++
.../empty => views/html/users/logout.tpl | 0
views/html/users/user.tpl | 3 +
18 files changed, 509 insertions(+), 16 deletions(-)
create mode 100644 views/html/users/create.tpl
create mode 100644 views/html/users/delete.tpl
create mode 100644 views/html/users/edit.tpl
create mode 100644 views/html/users/login.tpl
rename controllers/components/empty => views/html/users/logout.tpl (100%)
diff --git a/agents/ToplevelAgent.inc b/agents/ToplevelAgent.inc
index c545975a..eee33450 100644
--- a/agents/ToplevelAgent.inc
+++ b/agents/ToplevelAgent.inc
@@ -265,6 +265,7 @@
/**
* Run the Controller of this Agent and its SubAgents.
*
+ * @throws AccessDeniedException
* @throws IdNotFoundException
* @throws ServiceUnavailableException
* @throws DatamodelException
@@ -292,6 +293,7 @@
/**
* Run IntermediateAgent.
*
+ * @throws AccessDeniedException
* @throws ParamsNotValidException
* @throws IdNotFoundException
* @throws ServiceUnavailableException
diff --git a/app/Controller.inc b/app/Controller.inc
index 4403407b..24301a88 100644
--- a/app/Controller.inc
+++ b/app/Controller.inc
@@ -19,12 +19,30 @@
*/
abstract class Controller extends \nre\core\Controller
{
+ /**
+ * Required components
+ *
+ * @var array
+ */
+ public $components = array('auth');
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('users');
/**
* Linker instance
*
* @var Linker
*/
protected $linker = null;
+ /**
+ * Data of currently logged in user if any
+ *
+ * @var array
+ */
+ protected static $user = null;
@@ -58,13 +76,19 @@
{
parent::preFilter($request, $response);
+ // Check rights
+ $this->checkPermission();
+
// Create linker
$this->linker = new \nre\core\Linker($this->request);
+
+ // Set userdata
+ $this->set('loggedUser', static::$user);
}
/**
- * Prefilter that is executed after running the Controller.
+ * Postfilter that is executed after running the Controller.
*
* @param Request $request Current request
* @param Response $response Current response
@@ -72,9 +96,44 @@
public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
{
parent::postFilter($request, $response);
+ }
+
+
+
+
+ /**
+ * Check user permissions.
+ *
+ * @throws AccessDeniedException
+ */
+ private function checkPermission()
+ {
+ // Determine user
+ try {
+ $userId = $this->Auth->getUserId();
+ if(!is_null($userId)) {
+ static::$user = $this->Users->getUserById($this->Auth->getUserId());
+ }
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ }
- // Set title
- $this->set('title', $this->request->getParam(1, 'intermediate'));
+
+ // Determine permissions
+ $action = $this->request->getParam(2, 'action');
+ if(!property_exists($this, 'permissions')) {
+ return; // Allow if nothing is specified
+ }
+ if(!array_key_exists($action, $this->permissions)) {
+ return; // Allow if Action is not specified
+ }
+ $permissions = $this->permissions[$action];
+
+
+ // Check permissions
+ if(is_null(static::$user)) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
}
}
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 3467c3be..c4ef5929 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -69,9 +69,10 @@
* @var array
*/
public static $routes = array(
- array('css/?(.*)', 'css/$1?layout=stylesheet', false),
- array('users/(.+)', 'users/user/$1', false),
- array('seminaries/(.+)', 'seminaries/seminary/$1', false)
+ array('css/?(.*)', 'css/$1?layout=stylesheet', false),
+ array('users/([^/]+)/(edit|delete)', 'users/$2/$1', true),
+ array('users/(?!(index|login|logout|create|edit|delete))', 'users/user/$1', true),
+ array('seminaries/(.+)', 'seminaries/seminary/$1', false)
);
@@ -82,7 +83,8 @@
* @var array
*/
public static $reverseRoutes = array(
- array('users/user/(.*)', 'users/$1', false),
+ array('users/user/(.*)', 'users/$1', true),
+ array('users/([^/]+)/(.*)', 'users/$2/$1', true),
array('seminaries/seminary/(.*)', 'seminaries/$1', false)
);
diff --git a/controllers/HtmlController.inc b/controllers/HtmlController.inc
index 3c33d732..a2659898 100644
--- a/controllers/HtmlController.inc
+++ b/controllers/HtmlController.inc
@@ -17,7 +17,7 @@
*
* @author Oliver Hanraths
*/
- class HtmlController extends \nre\core\Controller
+ class HtmlController extends \hhu\z\Controller
{
@@ -36,9 +36,6 @@
// Set content-type
$this->response->addHeader("Content-type: text/html; charset=utf-8");
-
- // Start session
- session_start();
}
@@ -51,6 +48,9 @@
{
// Set the name of the current IntermediateAgent as page title
$this->set('title', $this->request->getParam(1, 'intermediate'));
+
+ // Set userdata
+ $this->set('loggedUser', static::$user);
}
}
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
index 4f026f41..4a9581bf 100644
--- a/controllers/SeminariesController.inc
+++ b/controllers/SeminariesController.inc
@@ -25,6 +25,15 @@
* @var array
*/
public $models = array('seminaries', 'users');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array(),
+ 'seminary' => array()
+ );
diff --git a/controllers/UsersController.inc b/controllers/UsersController.inc
index 0a3ce645..aea5ffbb 100644
--- a/controllers/UsersController.inc
+++ b/controllers/UsersController.inc
@@ -19,6 +19,19 @@
*/
class UsersController extends \hhu\z\Controller
{
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array(),
+ 'user' => array(),
+ 'create' => array(),
+ 'edit' => array(),
+ 'delete' => array()
+ );
+
@@ -56,6 +69,153 @@
}
+ /**
+ * Action: login.
+ *
+ * Log in a user.
+ */
+ public function login()
+ {
+ $username = '';
+
+ // Log the user in
+ if($this->request->getRequestMethod() == 'POST' && !empty($this->request->getPostParam('login')))
+ {
+ $username = $this->request->getPostParam('username');
+ $userId = $this->Users->login(
+ $username,
+ $this->request->getPostParam('password')
+ );
+
+ if(!is_null($userId))
+ {
+ $this->Auth->setUserId($userId);
+ $user = $this->Users->getUserById($userId);
+
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+ }
+
+
+ // Pass data to view
+ $this->set('username', $username);
+ $this->set('failed', ($this->request->getRequestMethod() == 'POST'));
+ }
+
+
+ /**
+ * Action: logout.
+ *
+ * Log out a user.
+ */
+ public function logout()
+ {
+ // Unset the currently logged in user
+ $this->Auth->setUserId(null);
+
+ // Redirect
+ $this->redirect($this->linker->link(array()));
+ }
+
+
+ /**
+ * Action: create.
+ *
+ * Create a new user.
+ */
+ public function create()
+ {
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
+ {
+ // Create new user
+ $userId = $this->Users->createUser(
+ $this->request->getPostParam('username'),
+ $this->request->getPostParam('email'),
+ $this->request->getPostParam('password')
+ );
+
+ // Redirect to user
+ $user = $this->Users->getUserById($userId);
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+ }
+
+
+ /**
+ * Action: edit.
+ *
+ * Edit a user.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function edit($userUrl)
+ {
+ // User
+ $user = $this->Users->getUserByUrl($userUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Save changes
+ if(!empty($this->request->getPostParam('save')))
+ {
+ // Edit user
+ $this->Users->editUser(
+ $user['id'],
+ $this->request->getPostParam('username'),
+ $this->request->getPostParam('email'),
+ $this->request->getPostParam('password')
+ );
+ }
+
+
+ // Redirect to user
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+
+
+ // Pass data to view
+ $this->set('user', $user);
+ }
+
+
+ /**
+ * Action: delete.
+ *
+ * Delete a user.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function delete($userUrl)
+ {
+ // User
+ $user = $this->Users->getUserByUrl($userUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Check confirmation
+ if($this->request->getPostParam('delete') == 'delete')
+ {
+ // Delete user
+ $this->Users->deleteUser($user['id']);
+
+ // Redirect to overview
+ $this->redirect($this->linker->link(null, 1));
+ }
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array('user', $user['url']), 1));
+ }
+
+
+ // Show confirmation
+ $this->set('user', $user);
+ }
+
+
}
?>
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index ec51389a69bdbf4ffb9b427614d53912f88b5c08..a8dd7d2c500d170581bcd7b63409bb2c2e4438c8 100644
GIT binary patch
literal 1407
zcmZvbJ!lj`6vxMJJ-@#|P+=?r5!v(Z6p0&xXmXKYqK9{ih#+&jFSo06vted7XKYL(
zHZ~$weu0ghjbIh95IYO41;Jn?SX&AHXLoZK#NlRt^XB8d|C@RDZO{5A3~e9!A@n8m
z!{|5G;Dh!V+zEaGw}RinE#NP31Na-<1^xlIfjidb^9R9=u#bS7!Qp~cumsx&D`35t
zp9h`4d!Rdazu-e~FYL#K{Tkd3`wjRKF_*vtuy3qqY&V#KZvO+&`FRRDeXl^L|1Id^
zyf4;2f;(V;0-esU#rhA>hy4?Dc@5!^Td#pG|IvbVa6jxz#X5m5o&q5+YtD9UQ;tlR
z^Wpr#eWustw9?#t<9PNaZqCJD=LSV{_vdm!>REI8UG96FHLgim;);4aHKf@DNrIh?
z>tSq*k=BW3_2tD!Ga{DW*)Y^(44YC`Ct(`cI8kgm>BQMLNiDm$;;$i$=_NX3P3p!<
z=$H&^MoB6|ZlgR7UtWARWR@47^Wh
z1w!6l;6sKd3SX9=WSTm$v7{-)JZtFW76sOu3cahO4K(|_1r5{GA%z{Y{CcTzspVx?
zf>mzsG&40*9|)|LE2Z&7SyFJbFb6%B?%3mVQp9SM2a(W*?AVpo
zq&G6y=fcgB_UbA~!dP{DKGKeD>6&+*6zNKkuhF9IyyMtOi~@tcrMH5xvswVCJ7xx4fyveh)_PB
z|K?-rnG$LyCB@H?O6^_J98Y9PN>Z#pB|p3~L9}|N4UcV#aXoC3B8dWCRiv&)iPd8@
z`(Y{4sp|Y&qbb6yIA=wrT6Q7Dow8;kC0=B(0cHBamFcs*Onb4uE#n~K9m-`{-Xk57
qI@8yim2BU?XtyIaz>Bg^Nry5*wls<)qJUcdOyXv+<IEh#Qz!{_}zaQcII{veg&P+nc@whMqvStU>vT&R}TVsgb8?o5Z=M}
z`!EY1FbUsqn1HRA}3!_a;S5-MqmZLa{{_a&CN`)l1xW(-=7OH7;`u5zG%(Q4H
a6U(&0CUaLT-Q8e*diXayNu08*9sK~{9Zhxs
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
index e216dbb5..0f2a598c 100644
--- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
-"POT-Creation-Date: 2014-01-19 22:56+0100\n"
-"PO-Revision-Date: 2014-01-19 22:58+0100\n"
+"POT-Creation-Date: 2014-01-22 16:28+0100\n"
+"PO-Revision-Date: 2014-01-22 16:29+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -15,8 +15,10 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-SearchPath-0: ../../../views\n"
-#: ../../../views/html/menu/index.tpl:2 ../../../views/html/users/user.tpl:1
-#: ../../../views/html/users/index.tpl:1
+#: ../../../views/html/menu/index.tpl:2 ../../../views/html/users/login.tpl:1
+#: ../../../views/html/users/user.tpl:1 ../../../views/html/users/index.tpl:1
+#: ../../../views/html/users/edit.tpl:1 ../../../views/html/users/delete.tpl:1
+#: ../../../views/html/users/create.tpl:1
msgid "Users"
msgstr "Benutzer"
@@ -26,10 +28,73 @@ msgstr "Benutzer"
msgid "Seminaries"
msgstr "Kurse"
-#: ../../../views/html/users/user.tpl:4 ../../../views/html/users/index.tpl:7
+#: ../../../views/html/menu/index.tpl:5 ../../../views/html/users/login.tpl:2
+#: ../../../views/html/users/login.tpl:11
+msgid "Login"
+msgstr "Login"
+
+#: ../../../views/html/menu/index.tpl:7
+msgid "Logout"
+msgstr "Logout"
+
+#: ../../../views/html/users/login.tpl:6 ../../../views/html/users/login.tpl:7
+#: ../../../views/html/users/edit.tpl:6 ../../../views/html/users/edit.tpl:7
+#: ../../../views/html/users/create.tpl:6
+#: ../../../views/html/users/create.tpl:7
+msgid "Username"
+msgstr "Benutzername"
+
+#: ../../../views/html/users/login.tpl:8 ../../../views/html/users/login.tpl:9
+#: ../../../views/html/users/edit.tpl:10 ../../../views/html/users/edit.tpl:11
+#: ../../../views/html/users/create.tpl:10
+#: ../../../views/html/users/create.tpl:11
+msgid "Password"
+msgstr "Passwort"
+
+#: ../../../views/html/users/user.tpl:4 ../../../views/html/users/delete.tpl:2
+msgid "Delete user"
+msgstr "Benutzer löschen"
+
+#: ../../../views/html/users/user.tpl:7 ../../../views/html/users/index.tpl:10
msgid "registered on"
msgstr "registriert seit"
+#: ../../../views/html/users/index.tpl:3
+msgid "Create new user"
+msgstr "Neuen Benutzer erstellen"
+
+#: ../../../views/html/users/edit.tpl:2
+msgid "Edit user"
+msgstr "Benutzer bearbeiten"
+
+#: ../../../views/html/users/edit.tpl:8 ../../../views/html/users/edit.tpl:9
+#: ../../../views/html/users/create.tpl:8
+#: ../../../views/html/users/create.tpl:9
+msgid "E‑Mail-Address"
+msgstr "E‑Mail-Adresse"
+
+#: ../../../views/html/users/edit.tpl:13
+#: ../../../views/html/users/create.tpl:13
+msgid "create"
+msgstr "erstellen"
+
+#: ../../../views/html/users/delete.tpl:4
+#, php-format
+msgid "Should the user “%s” (%s) really be deleted?"
+msgstr "Soll der Benutzer „%s“ (%s) wirklich gelöscht werden?"
+
+#: ../../../views/html/users/delete.tpl:6
+msgid "delete"
+msgstr "löschen"
+
+#: ../../../views/html/users/delete.tpl:7
+msgid "cancel"
+msgstr "abbrechen"
+
+#: ../../../views/html/users/create.tpl:2
+msgid "New user"
+msgstr "Neuer Benutzer"
+
#: ../../../views/html/error/index.tpl:1
msgid "Error"
msgstr "Fehler"
diff --git a/models/UsersModel.inc b/models/UsersModel.inc
index 2a9bb6a3..576bc1a2 100644
--- a/models/UsersModel.inc
+++ b/models/UsersModel.inc
@@ -100,6 +100,138 @@
return $user[0];
}
+
+ /**
+ * Log a user in if its credentials are valid.
+ *
+ * @throws DatamodelException
+ * @param string $username The name of the user to log in
+ * @param string $password Plaintext password of the user to log in
+ */
+ public function login($username, $password)
+ {
+ $data = $this->db->query('SELECT id, password FROM users WHERE username = ?', 's', $username);
+ if(!empty($data))
+ {
+ $data = $data[0];
+ if($this->verify($password, $data['password'])) {
+ return $data['id'];
+ }
+ }
+
+
+ return null;
+ }
+
+
+ /**
+ * Create a new user.
+ *
+ * @param string $username Username of the user to create
+ * @param string $email E‑Mail-Address of the user to create
+ * @param string $password Password of the user to create
+ * @return int ID of the newly created user
+ */
+ public function createUser($username, $email, $password)
+ {
+ $this->db->query(
+ 'INSERT INTO users '.
+ '(username, url, email, password) '.
+ 'VALUES '.
+ '(?, ?, ?, ?)',
+ 'ssss',
+ $username,
+ \nre\core\Linker::createLinkParam($username),
+ $email,
+ $this->hash($password)
+ );
+
+
+ return $this->db->getInsertId();
+ }
+
+
+ /**
+ * Edit a user.
+ *
+ * @throws DatamodelException
+ * @param string $username New name of user
+ * @param string $email Changed e‑mail-address of user
+ * @param string $password Changed plaintext password of user
+ */
+ public function editUser($userId, $username, $email, $password)
+ {
+ try {
+ // Update user data
+ $this->db->query(
+ 'UPDATE users '.
+ 'SET username = ?, email = ? '.
+ 'WHERE id = ?',
+ 'ssi',
+ $sername, $email,
+ $userId
+ );
+
+ // Set new password
+ if(!empty($password))
+ {
+ $this->db->query(
+ 'UPDATE users '.
+ 'SET password = ? '.
+ 'WHERE id = ?',
+ 'si',
+ $this->hash($password),
+ $userId
+ );
+ }
+ }
+ catch(Exception $e) {
+ $this->db->rollback();
+ throw $e;
+ }
+ finally {
+ $this->db->setAutocommit(true);
+ }
+ }
+
+
+ /**
+ * Delete a user.
+ *
+ * @param int $userId ID of the user to delete
+ */
+ public function deleteUser($userId)
+ {
+ $this->db->query('DELETE FROM users WHERE id = ?', 'i', $userId);
+ }
+
+
+
+
+ /**
+ * Hash a password.
+ *
+ * @param string $password Plaintext password
+ * @return string Hashed password
+ */
+ private function hash($password)
+ {
+ return password_hash($password, PASSWORD_DEFAULT);
+ }
+
+
+ /**
+ * Verify a password.
+ *
+ * @param string $password Plaintext password to verify
+ * @param string $hash Hashed password to match with
+ * @return boolean Verified
+ */
+ private function verify($password, $hash)
+ {
+ return password_verify($password, $hash);
+ }
+
}
?>
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 0f46493c..a9f5c842 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -14,6 +14,11 @@
=$menu?>
+
+
+
=$intermediate?>
diff --git a/views/html/menu/index.tpl b/views/html/menu/index.tpl
index ad0fbe39..f9f8246c 100644
--- a/views/html/menu/index.tpl
+++ b/views/html/menu/index.tpl
@@ -1,4 +1,9 @@
">=_('Users')?>
">=_('Seminaries')?>
+
+ =_('Login')?>
+
+ =_('Logout')?>
+
diff --git a/views/html/users/create.tpl b/views/html/users/create.tpl
new file mode 100644
index 00000000..caffac41
--- /dev/null
+++ b/views/html/users/create.tpl
@@ -0,0 +1,14 @@
+=_('Users')?>
+=_('New user')?>
+
+
diff --git a/views/html/users/delete.tpl b/views/html/users/delete.tpl
new file mode 100644
index 00000000..10f280ab
--- /dev/null
+++ b/views/html/users/delete.tpl
@@ -0,0 +1,8 @@
+=_('Users')?>
+=_('Delete user')?>
+
+=sprintf(_('Should the user “%s” (%s) really be deleted?'), $user['username'], $user['email'])?>
+
diff --git a/views/html/users/edit.tpl b/views/html/users/edit.tpl
new file mode 100644
index 00000000..d3d1c2e0
--- /dev/null
+++ b/views/html/users/edit.tpl
@@ -0,0 +1,14 @@
+=_('Users')?>
+=_('Edit user')?>
+
+
diff --git a/views/html/users/index.tpl b/views/html/users/index.tpl
index 3b94e6a0..9a5b525e 100644
--- a/views/html/users/index.tpl
+++ b/views/html/users/index.tpl
@@ -1,4 +1,7 @@
=_('Users')?>
+
+ =_('Create new user')?>
+
diff --git a/views/html/users/login.tpl b/views/html/users/login.tpl
new file mode 100644
index 00000000..36c13da4
--- /dev/null
+++ b/views/html/users/login.tpl
@@ -0,0 +1,12 @@
+=_('Users')?>
+=_('Login')?>
+
+
diff --git a/controllers/components/empty b/views/html/users/logout.tpl
similarity index 100%
rename from controllers/components/empty
rename to views/html/users/logout.tpl
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
index 91591dd3..1e8466b5 100644
--- a/views/html/users/user.tpl
+++ b/views/html/users/user.tpl
@@ -1,5 +1,8 @@
=_('Users')?>
=$user['username']?>
+
+ =_('Delete user')?>
+
=_('registered on')?> =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
From 34e304ded1815ef0be70bddfed735e5a4e538d78 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 22 Jan 2014 16:31:49 +0100
Subject: [PATCH 016/213] correct little mistakes in Linker-class
---
core/Linker.inc | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/Linker.inc b/core/Linker.inc
index f5b30b13..00c5846b 100644
--- a/core/Linker.inc
+++ b/core/Linker.inc
@@ -53,7 +53,7 @@
return implode(
\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
call_user_func_array(
- Utils::createLinkParams,
+ '\nre\core\Linker::createLinkParams',
func_get_args()
)
);
@@ -85,7 +85,7 @@
' ',
\nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
substr(
- $title,
+ $param,
0,
\nre\configs\CoreConfig::$classes['linker']['url']['length']
)
From 3bebc9a35fba318c3543dca0c3387569d8893226 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sat, 25 Jan 2014 20:22:54 +0100
Subject: [PATCH 017/213] add IntlDateFormatter for formatting locale-dependent
date and time
---
app/Controller.inc | 14 +++++++++
app/Utils.inc | 8 -----
configs/AppConfig.inc | 3 +-
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 1407 -> 1544 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 32 +++++++++++++++++---
views/html/seminaries/index.tpl | 2 +-
views/html/seminaries/seminary.tpl | 2 +-
views/html/users/index.tpl | 2 +-
views/html/users/user.tpl | 2 +-
9 files changed, 47 insertions(+), 18 deletions(-)
diff --git a/app/Controller.inc b/app/Controller.inc
index 24301a88..5594ac31 100644
--- a/app/Controller.inc
+++ b/app/Controller.inc
@@ -82,6 +82,20 @@
// Create linker
$this->linker = new \nre\core\Linker($this->request);
+ // Create date and time formatter
+ $this->set('dateFormatter', new \IntlDateFormatter(
+ \nre\core\Config::getDefault('locale'),
+ \IntlDateFormatter::MEDIUM,
+ \IntlDateFormatter::NONE,
+ NULL
+ ));
+ $this->set('timeFormatter', new \IntlDateFormatter(
+ \nre\core\Config::getDefault('locale'),
+ \IntlDateFormatter::NONE,
+ \IntlDateFormatter::SHORT,
+ NULL
+ ));
+
// Set userdata
$this->set('loggedUser', static::$user);
}
diff --git a/app/Utils.inc b/app/Utils.inc
index 3ef93670..1e3527c1 100644
--- a/app/Utils.inc
+++ b/app/Utils.inc
@@ -19,14 +19,6 @@
*/
class Utils
{
-
- /**
- * Format for printing the date
- *
- * @var string
- */
- const DATEFORMAT = 'm.d.Y';
-
}
?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index c4ef5929..12624ab0 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -47,7 +47,8 @@
'toplevel-error' => 'fault',
'intermediate' => 'introduction',
'intermediate-error' => 'error',
- 'language' => 'de_DE.utf8'
+ 'language' => 'de_DE.utf8',
+ 'locale' => 'de-DE'
);
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index a8dd7d2c500d170581bcd7b63409bb2c2e4438c8..cb455ec186be0d5ee691003275f56b08f9b65462 100644
GIT binary patch
delta 654
zcmYk3J4gdT5QaCo%hM!ke1ne@6hRR}K*eAq0YL<9#3E{uVwJ!pMIHpJU?*aC*lKBI
zWv5_cDWafamUEG*S;l8ZRp?6tx%P>g1-(*c4G6}Qbzyv&ja^ZdRfO>Z0
zI+TlEUA{pP_UXocqbVQ?PZ2*1yV<`smFkC&uoJ#R`R^P0RZXcl*+lsOl*%Td2$*G%
zgbPpvreO@OLaAUI@~It$6tvy=3`z&ip`5#f(y1Glcd&=}MfS=hn=~HQIK@d>j63o{Q8k!JA11
delta 531
zcmXxhD@X)E9LMpweR$`2o_Z<>-hmecqqo7wnhaYkhSPR+gGB@%b3i(_k_P7L%5%
z2PT_AgFysAFbQUp==Zlb{$chr|DB!3fA*yETh88U!MP!(Xmwhj)}VC?Jcvge!zUcU
zcO1qq4DlPs@dqnd^#<=}afrN$C0uZ}uuLA~qA{6C+`tiP!3;IA>paCta_jPI93{WS
zOE&G}40$IoWgU-yfsaxj-H83ROT4wa;BXo*8pbr^<^5)Jb362Ok)df1)azXO_kz
z)D5gT6PzaBbmJ*%!(HTjc_>#D2jmCS8l^T5*3VC@s{TV)&iwqh=$#JWtK&jfsA?!a
z4;7&5YcyN;I=1U=*k>=X4S&5D&9#=|XvL;})Ad(-XZ~`*z65)AD{R}Fa68;jcMi-S
Di
- =sprintf(_('created by %s on %s'), $seminary['creator']['username'], date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created'])))?>
+ =sprintf(_('created by %s on %s'), $seminary['creator']['username'], $dateFormatter->format(new \DateTime($seminary['created'])))?>
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 094fbf3b..3c5f1aba 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -1,5 +1,5 @@
=_('Seminaries')?>
=$seminary['title']?>
- =sprintf(_('created by %s on %s'), $seminary['creator']['username'], date(\hhu\z\Utils::DATEFORMAT, strtotime($seminary['created'])))?>
+ =sprintf(_('created by %s on %s'), $seminary['creator']['username'], $dateFormatter->format(new \DateTime($seminary['created'])))?>
diff --git a/views/html/users/index.tpl b/views/html/users/index.tpl
index 9a5b525e..5d2883af 100644
--- a/views/html/users/index.tpl
+++ b/views/html/users/index.tpl
@@ -7,7 +7,7 @@
- =_('registered on')?> =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+ =sprintf(_('registered on %s'), $dateFormatter->format(new \DateTime($user['created'])))?>
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
index 1e8466b5..e3a037af 100644
--- a/views/html/users/user.tpl
+++ b/views/html/users/user.tpl
@@ -4,5 +4,5 @@
=_('Delete user')?>
- =_('registered on')?> =date(\hhu\z\Utils::DATEFORMAT, strtotime($user['created']))?>
+ =sprintf(_('registered on %s'), $dateFormatter->format(new \DateTime($user['created'])))?>
From 297c56e29d75506ef00b4bc01641cfed102f1d60 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sat, 25 Jan 2014 20:55:10 +0100
Subject: [PATCH 018/213] implement CRUD for seminaries and correct typos for
users
---
configs/AppConfig.inc | 3 +-
controllers/SeminariesController.inc | 97 ++++++++++++++++++++
controllers/UsersController.inc | 5 +-
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 1544 -> 1805 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 57 ++++++++----
models/SeminariesModel.inc | 57 ++++++++++++
models/UsersModel.inc | 11 ++-
views/html/seminaries/create.tpl | 10 ++
views/html/seminaries/delete.tpl | 8 ++
views/html/seminaries/edit.tpl | 10 ++
views/html/seminaries/index.tpl | 3 +
views/html/seminaries/seminary.tpl | 4 +
views/html/users/create.tpl | 2 +-
views/html/users/edit.tpl | 6 +-
views/html/users/user.tpl | 1 +
15 files changed, 247 insertions(+), 27 deletions(-)
create mode 100644 views/html/seminaries/create.tpl
create mode 100644 views/html/seminaries/delete.tpl
create mode 100644 views/html/seminaries/edit.tpl
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 12624ab0..aeafd57e 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -73,7 +73,8 @@
array('css/?(.*)', 'css/$1?layout=stylesheet', false),
array('users/([^/]+)/(edit|delete)', 'users/$2/$1', true),
array('users/(?!(index|login|logout|create|edit|delete))', 'users/user/$1', true),
- array('seminaries/(.+)', 'seminaries/seminary/$1', false)
+ array('seminaries/([^/]+)/(edit|delete)', 'seminaries/$2/$1', true),
+ array('seminaries/(?!(index|create|edit|delete))', 'seminaries/seminary/$1', true)
);
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
index 4a9581bf..7e307087 100644
--- a/controllers/SeminariesController.inc
+++ b/controllers/SeminariesController.inc
@@ -82,6 +82,103 @@
$this->set('seminary', $seminary);
}
+
+ /**
+ * Action: create.
+ *
+ * Create a new seminary.
+ */
+ public function create()
+ {
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
+ {
+ // Create new seminary
+ var_dump($this->Auth->getUserId());
+ $seminaryId = $this->Seminaries->createSeminary(
+ $this->request->getPostParam('title'),
+ $this->Auth->getUserId()
+ );
+
+ // Redirect to seminary
+ $user = $this->Seminaries->getSeminaryById($seminaryId);
+ $this->redirect($this->linker->link(array($seminary['url']), 1));
+ }
+ }
+
+
+ /**
+ * Action: edit.
+ *
+ * Edit a seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function edit($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Save changes
+ if(!empty($this->request->getPostParam('save')))
+ {
+ // Edit seminary
+ $this->Seminaries->editSeminary(
+ $seminary['id'],
+ $this->request->getPostParam('title')
+ );
+ $seminary = $this->Seminaries->getSeminaryById($seminary['id']);
+ }
+
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array($seminary['url']), 1));
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ }
+
+
+ /**
+ * Action: delete.
+ *
+ * Delete a seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function delete($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Check confirmation
+ if(!empty($this->request->getPostParam('delete')))
+ {
+ // Delete seminary
+ $this->Seminaries->deleteSeminary($seminary['id']);
+
+ // Redirect to overview
+ $this->redirect($this->linker->link(null, 1));
+ }
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array('seminary', $seminary['url']), 1));
+ }
+
+
+ // Show confirmation
+ $this->set('seminary', $seminary);
+ }
+
}
?>
diff --git a/controllers/UsersController.inc b/controllers/UsersController.inc
index aea5ffbb..d8b44ccd 100644
--- a/controllers/UsersController.inc
+++ b/controllers/UsersController.inc
@@ -167,10 +167,11 @@
$this->request->getPostParam('email'),
$this->request->getPostParam('password')
);
+ $user = $this->Users->getUserById($user['id']);
}
- // Redirect to user
+ // Redirect to entry
$this->redirect($this->linker->link(array($user['url']), 1));
}
@@ -197,7 +198,7 @@
if($this->request->getRequestMethod() == 'POST')
{
// Check confirmation
- if($this->request->getPostParam('delete') == 'delete')
+ if(!empty($this->request->getPostParam('delete')))
{
// Delete user
$this->Users->deleteUser($user['id']);
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index cb455ec186be0d5ee691003275f56b08f9b65462..621bc112b8c5dacdd562cb787b33290e193e8a09 100644
GIT binary patch
delta 801
zcmYMx&r1|x7{KvoXLc=hwX#+FVK78`3(XM1iy-EuzaeV2eW`(QshOQXgLZ`iDLlj=
zbyyVzp+nF?EV|U8pn?w3HR`ZkqFWSn@L=C(dY4}Ic|ZHU@67YQ&pS)S<=*<&zWj>N
zjuS(~Z(^AEkfWnrc0>-Nj|VWZ-ob
zpZ!eyv5G6w#kdnkv4mqdgPJ%&eg2jm-$6}y&-wuMz>no#NhON$Mg2
zS&y)A8?};$cnG&pD}Iie@Ga^_pHUOGP;cND@{>I}T`$mS0Y&V^LDU0}pguQ>XK(^1
z*7i@?}@0o3|Uev#JN|gjS-5)Jps8TpKMy57wRLoUvN>KCKE9p7s#;NweYc-m~ajUWFMaB=qd9Q4|O7>=DDqVFJ^Ra)^q$k{2
zXJR}x?g(rzyO(mOFC9_+uN(9U+O#YH5nw5hC~pP#$aJ45rY&%32pDvrLl=Homd%7EE0pk
zQj0+hh^>!U_>2bIxvPQ
z9Kbdl!x&Cu1ap|i1&rfLaDEd#`t9I+8Kd<3O{?aRKdqdwn8j1n3m=;|n3tfhqh9nD
z_>Kzp74%-X86bgYgdfCCuHU-G^x_k?;|J=wAM{Msm<+Qic^_(Jqo@Fr95mr9Dqs$i
zxQJT8D)KWM9A>Z(^yjD@xIo=^gW9QD-~)Eizv?>kn@|2I**9v}6O@8zvcI9kdg%XX
zq3NbF6r0c(EV>a|jXo)hY=qYWwHpeixfF=$Ohn%_YL}e}*DvLZ_R`t2OJU#Mhv%K~
jtWCQka5d$wg;I0*9lu=37l#YA>(cs`y^B=ru4jJ%kFGXK
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
index c42c969d..8d264180 100644
--- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
-"POT-Creation-Date: 2014-01-25 20:20+0100\n"
-"PO-Revision-Date: 2014-01-25 20:20+0100\n"
+"POT-Creation-Date: 2014-01-25 20:52+0100\n"
+"PO-Revision-Date: 2014-01-25 20:52+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -25,6 +25,8 @@ msgstr "Benutzer"
#: ../../../views/html/menu/index.tpl:3
#: ../../../views/html/seminaries/seminary.tpl:1
#: ../../../views/html/seminaries/index.tpl:1
+#: ../../../views/html/seminaries/edit.tpl:1
+#: ../../../views/html/seminaries/delete.tpl:1
#: ../../../views/html/seminaries/create.tpl:1
msgid "Seminaries"
msgstr "Kurse"
@@ -52,11 +54,15 @@ msgstr "Benutzername"
msgid "Password"
msgstr "Passwort"
-#: ../../../views/html/users/user.tpl:4 ../../../views/html/users/delete.tpl:2
+#: ../../../views/html/users/user.tpl:4 ../../../views/html/users/edit.tpl:2
+msgid "Edit user"
+msgstr "Benutzer bearbeiten"
+
+#: ../../../views/html/users/user.tpl:5 ../../../views/html/users/delete.tpl:2
msgid "Delete user"
msgstr "Benutzer löschen"
-#: ../../../views/html/users/user.tpl:7 ../../../views/html/users/index.tpl:10
+#: ../../../views/html/users/user.tpl:8 ../../../views/html/users/index.tpl:10
#, php-format
msgid "registered on %s"
msgstr "registriert am %s"
@@ -65,10 +71,6 @@ msgstr "registriert am %s"
msgid "Create new user"
msgstr "Neuen Benutzer erstellen"
-#: ../../../views/html/users/edit.tpl:2
-msgid "Edit user"
-msgstr "Benutzer bearbeiten"
-
#: ../../../views/html/users/edit.tpl:8 ../../../views/html/users/edit.tpl:9
#: ../../../views/html/users/create.tpl:8
#: ../../../views/html/users/create.tpl:9
@@ -76,10 +78,9 @@ msgid "E‑Mail-Address"
msgstr "E‑Mail-Adresse"
#: ../../../views/html/users/edit.tpl:13
-#: ../../../views/html/users/create.tpl:13
-#: ../../../views/html/seminaries/create.tpl:9
-msgid "create"
-msgstr "erstellen"
+#: ../../../views/html/seminaries/edit.tpl:9
+msgid "save"
+msgstr "speichern"
#: ../../../views/html/users/delete.tpl:4
#, php-format
@@ -87,10 +88,12 @@ msgid "Should the user “%s” (%s) really be deleted?"
msgstr "Soll der Benutzer „%s“ (%s) wirklich gelöscht werden?"
#: ../../../views/html/users/delete.tpl:6
+#: ../../../views/html/seminaries/delete.tpl:6
msgid "delete"
msgstr "löschen"
#: ../../../views/html/users/delete.tpl:7
+#: ../../../views/html/seminaries/delete.tpl:7
msgid "cancel"
msgstr "abbrechen"
@@ -98,11 +101,26 @@ msgstr "abbrechen"
msgid "New user"
msgstr "Neuer Benutzer"
+#: ../../../views/html/users/create.tpl:13
+#: ../../../views/html/seminaries/create.tpl:9
+msgid "create"
+msgstr "erstellen"
+
#: ../../../views/html/error/index.tpl:1
msgid "Error"
msgstr "Fehler"
#: ../../../views/html/seminaries/seminary.tpl:4
+#: ../../../views/html/seminaries/edit.tpl:2
+msgid "Edit seminary"
+msgstr "Kurs bearbeiten"
+
+#: ../../../views/html/seminaries/seminary.tpl:5
+#: ../../../views/html/seminaries/delete.tpl:2
+msgid "Delete seminary"
+msgstr "Kurs löschen"
+
+#: ../../../views/html/seminaries/seminary.tpl:8
#: ../../../views/html/seminaries/index.tpl:10
#, php-format
msgid "created by %s on %s"
@@ -112,15 +130,22 @@ msgstr "erstellt von %s am %s"
msgid "Create new seminary"
msgstr "Neuen Kurs erstellen"
-#: ../../../views/html/seminaries/create.tpl:2
-msgid "New seminary"
-msgstr "Neuer Kurs"
-
+#: ../../../views/html/seminaries/edit.tpl:6
+#: ../../../views/html/seminaries/edit.tpl:7
#: ../../../views/html/seminaries/create.tpl:6
#: ../../../views/html/seminaries/create.tpl:7
msgid "Title"
msgstr "Titel"
+#: ../../../views/html/seminaries/delete.tpl:4
+#, php-format
+msgid "Should the seminary “%s” really be deleted?"
+msgstr "Soll der Kurs „%s“ wirklich gelöscht werden?"
+
+#: ../../../views/html/seminaries/create.tpl:2
+msgid "New seminary"
+msgstr "Neuer Kurs"
+
#: ../../../views/html/introduction/index.tpl:1
msgid "Introduction"
msgstr "Einführung"
diff --git a/models/SeminariesModel.inc b/models/SeminariesModel.inc
index c4ae7954..03ccc2f0 100644
--- a/models/SeminariesModel.inc
+++ b/models/SeminariesModel.inc
@@ -99,6 +99,63 @@
return $seminary[0];
}
+
+ /**
+ * Create a new seminary.
+ *
+ * @param string $title Title of seminary to create
+ * @param int $userId ID of creating user
+ * @return int ID of the newly created seminary
+ */
+ public function createSeminary($title, $userId)
+ {
+ $this->db->query(
+ 'INSERT INTO seminaries '.
+ '(created_user_id, title, url) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iss',
+ $userId,
+ $title,
+ \nre\core\Linker::createLinkParam($title)
+ );
+
+
+ return $this->db->getInsertId();
+ }
+
+
+ /**
+ * Edit a seminary.
+ *
+ * @throws DatamodelException
+ * @param int $seminaryId ID of the seminary to delete
+ * @param string $title New title of seminary
+ */
+ public function editSeminary($seminaryId, $title)
+ {
+ $this->db->query(
+ 'UPDATE seminaries '.
+ 'SET title = ?, url = ? '.
+ 'WHERE id = ?',
+ 'ssi',
+ $title,
+ \nre\core\Linker::createLinkParam($title),
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Delete a seminary.
+ *
+ * @param int $seminaryId ID of the seminary to delete
+ */
+ public function deleteSeminary($seminaryId)
+ {
+ $this->db->query('DELETE FROM seminaries WHERE id = ?', 'i', $seminaryId);
+ }
+
}
?>
diff --git a/models/UsersModel.inc b/models/UsersModel.inc
index 576bc1a2..0456a7ec 100644
--- a/models/UsersModel.inc
+++ b/models/UsersModel.inc
@@ -155,6 +155,7 @@
* Edit a user.
*
* @throws DatamodelException
+ * @param int $userId ID of the user to delete
* @param string $username New name of user
* @param string $email Changed e‑mail-address of user
* @param string $password Changed plaintext password of user
@@ -165,10 +166,12 @@
// Update user data
$this->db->query(
'UPDATE users '.
- 'SET username = ?, email = ? '.
+ 'SET username = ?, url = ?, email = ? '.
'WHERE id = ?',
- 'ssi',
- $sername, $email,
+ 'sssi',
+ $username,
+ \nre\core\Linker::createLinkParam($username),
+ $email,
$userId
);
@@ -214,7 +217,7 @@
* @param string $password Plaintext password
* @return string Hashed password
*/
- private function hash($password)
+ public function hash($password)
{
return password_hash($password, PASSWORD_DEFAULT);
}
diff --git a/views/html/seminaries/create.tpl b/views/html/seminaries/create.tpl
new file mode 100644
index 00000000..823eec70
--- /dev/null
+++ b/views/html/seminaries/create.tpl
@@ -0,0 +1,10 @@
+=_('Seminaries')?>
+=_('New seminary')?>
+
+
diff --git a/views/html/seminaries/delete.tpl b/views/html/seminaries/delete.tpl
new file mode 100644
index 00000000..d2253f14
--- /dev/null
+++ b/views/html/seminaries/delete.tpl
@@ -0,0 +1,8 @@
+=_('Seminaries')?>
+=_('Delete seminary')?>
+
+=sprintf(_('Should the seminary “%s” really be deleted?'), $seminary['title'])?>
+
diff --git a/views/html/seminaries/edit.tpl b/views/html/seminaries/edit.tpl
new file mode 100644
index 00000000..007acf15
--- /dev/null
+++ b/views/html/seminaries/edit.tpl
@@ -0,0 +1,10 @@
+=_('Seminaries')?>
+=_('Edit seminary')?>
+
+
diff --git a/views/html/seminaries/index.tpl b/views/html/seminaries/index.tpl
index 6e40934a..8ac8c8b0 100644
--- a/views/html/seminaries/index.tpl
+++ b/views/html/seminaries/index.tpl
@@ -1,4 +1,7 @@
=_('Seminaries')?>
+
+ =_('Create new seminary')?>
+
From 305a086ae64c3ab8fe010a0f22e0c0a94e7d2ad9 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 16 Feb 2014 02:48:29 +0100
Subject: [PATCH 049/213] implement CharactergroupsAgent and include it in
Seminary page
---
agents/intermediate/CharactergroupsAgent.inc | 35 +++++
configs/AppConfig.inc | 2 +
controllers/CharactergroupsController.inc | 131 +++++++++++++++++++
models/CharactergroupsModel.inc | 127 ++++++++++++++++++
views/html/charactergroups/group.tpl | 5 +
views/html/charactergroups/groupsgroup.tpl | 10 ++
views/html/charactergroups/index.tpl | 9 ++
views/html/seminaries/seminary.tpl | 3 +
8 files changed, 322 insertions(+)
create mode 100644 agents/intermediate/CharactergroupsAgent.inc
create mode 100644 controllers/CharactergroupsController.inc
create mode 100644 models/CharactergroupsModel.inc
create mode 100644 views/html/charactergroups/group.tpl
create mode 100644 views/html/charactergroups/groupsgroup.tpl
create mode 100644 views/html/charactergroups/index.tpl
diff --git a/agents/intermediate/CharactergroupsAgent.inc b/agents/intermediate/CharactergroupsAgent.inc
new file mode 100644
index 00000000..77ac5f5a
--- /dev/null
+++ b/agents/intermediate/CharactergroupsAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Character groups.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 3e8d92da..97c0a080 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -82,6 +82,7 @@
array('^([^/]+)/([^/]+)/?$', 'questgropus/questgroup/$1/$2', true),
// z/// ⇒ z/quests/quest///
array('^([^/]+)/([^/]+)/([^/]+)/?$', 'quests/quest/$1/$2/3', true)*/
+ array('charactergroups/(?!(index|groupsgroup|group))', 'charactergroups/index/$1', true),
array('media/(.*)', 'media/$1?layout=binary', false),
array('media/(.*)', 'media/index/$1', true)
);
@@ -98,6 +99,7 @@
array('users/([^/]+)/(.*)', 'users/$2/$1', true),
array('seminaries/seminary/(.*)', 'seminaries/$1', false),
//array('seminaries/seminary/(.*)', '$1', false)
+ array('charactergroup/index/(.*)', 'charactergroup/$1', true),
array('media/index/(.*)', 'media/$1', true)
);
diff --git a/controllers/CharactergroupsController.inc b/controllers/CharactergroupsController.inc
new file mode 100644
index 00000000..1402e140
--- /dev/null
+++ b/controllers/CharactergroupsController.inc
@@ -0,0 +1,131 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the CharactergroupsAgent to display Character groups.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'charactergroups');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show Character groups-groups for a Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ */
+ public function index($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-groups
+ $groupsgroups = $this->Charactergroups->getGroupsroupsForSeminary($seminary['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroups', $groupsgroups);
+ }
+
+
+ /**
+ * Action: groupsgroups.
+ *
+ * Show Character groups for a Character groups-group of a
+ * Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ */
+ public function groupsgroup($seminaryUrl, $groupsgroupUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character groups
+ $groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('groups', $groups);
+ }
+
+
+ /**
+ * Action: group.
+ *
+ * Show a Character group for a Character groups-group of a
+ * Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ * @param string $groupUrl URL-Title of a Character group
+ */
+ public function group($seminaryUrl, $groupsgroupUrl, $groupUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character group
+ $group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('group', $group);
+ }
+
+ }
+
+?>
diff --git a/models/CharactergroupsModel.inc b/models/CharactergroupsModel.inc
new file mode 100644
index 00000000..4fc32b80
--- /dev/null
+++ b/models/CharactergroupsModel.inc
@@ -0,0 +1,127 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the CharactergroupsAgent to interact with
+ * Charactergroups-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new CharactergroupsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Character groups-groups of a Seminary.
+ *
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @return array Character groups-groups data
+ */
+ public function getGroupsroupsForSeminary($seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroupsgroups '.
+ 'WHERE seminary_id = ?',
+ 'i',
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Get a Character groups-group by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @param string $groupsgroupUrl URL-name of the Character groups-group
+ * @return array Character groups-group data
+ */
+ public function getGroupsgroupByUrl($seminaryId, $groupsgroupUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroupsgroups '.
+ 'WHERE seminary_id = ? AND url = ?',
+ 'is',
+ $seminaryId, $groupsgroupUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($groupsgroupUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get Character groups for a Character groups-group.
+ *
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @return array Character groups
+ */
+ public function getGroupsForGroupsgroup($groupsgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroups '.
+ 'WHERE charactergroupsgroup_id = ?',
+ 'i',
+ $groupsgroupId
+ );
+ }
+
+
+ /**
+ * Get a Character group by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @param string $groupUrl URL-name of the Character group
+ * @return array Character group data
+ */
+ public function getGroupByUrl($groupsgroupId, $groupUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroups '.
+ 'WHERE charactergroupsgroup_id = ? AND url = ?',
+ 'is',
+ $groupsgroupId, $groupUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($groupUrl);
+ }
+
+
+ return $data[0];
+ }
+
+ }
+
+?>
diff --git a/views/html/charactergroups/group.tpl b/views/html/charactergroups/group.tpl
new file mode 100644
index 00000000..6b50852c
--- /dev/null
+++ b/views/html/charactergroups/group.tpl
@@ -0,0 +1,5 @@
+=_('Seminaries')?>
+=$seminary['title']?>
+=_('Character Groups')?>
+=$groupsgroup['name']?>
+=$group['name']?>
diff --git a/views/html/charactergroups/groupsgroup.tpl b/views/html/charactergroups/groupsgroup.tpl
new file mode 100644
index 00000000..ebdd8973
--- /dev/null
+++ b/views/html/charactergroups/groupsgroup.tpl
@@ -0,0 +1,10 @@
+=_('Seminaries')?>
+=$seminary['title']?>
+=_('Character Groups')?>
+=$groupsgroup['name']?>
+
+
diff --git a/views/html/charactergroups/index.tpl b/views/html/charactergroups/index.tpl
new file mode 100644
index 00000000..584428fb
--- /dev/null
+++ b/views/html/charactergroups/index.tpl
@@ -0,0 +1,9 @@
+=_('Seminaries')?>
+=$seminary['title']?>
+=_('Character Groups')?>
+
+
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 2f63cdfa..89378d65 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -4,6 +4,9 @@
=_('Edit seminary')?>
=_('Delete seminary')?>
+
+ =_('Character Groups')?>
+
=sprintf(_('created by %s on %s'), $seminary['creator']['username'], $dateFormatter->format(new \DateTime($seminary['created'])))?>
From 3d82dd7297c239ecce8a3c11f5bd311d6b2f2588 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 16 Feb 2014 13:17:59 +0100
Subject: [PATCH 050/213] create method for savely printing text
---
app/Utils.inc | 27 +++++++++++++++++++++++++++
views/html/questgroups/questgroup.tpl | 2 +-
views/html/quests/quest.tpl | 4 ++--
views/html/quests/sidequest.tpl | 4 ++--
views/html/seminaries/seminary.tpl | 2 +-
5 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/app/Utils.inc b/app/Utils.inc
index 1e3527c1..76ccc7fe 100644
--- a/app/Utils.inc
+++ b/app/Utils.inc
@@ -19,6 +19,33 @@
*/
class Utils
{
+
+
+ /**
+ * Mask HTML-chars for save output.
+ *
+ * @static
+ * @param string $string String to be masked
+ * @return string Masked string
+ */
+ static function t($string)
+ {
+ return nl2br(htmlspecialchars($string));
+ }
+
+
+ /**
+ * ‚htmlspecialchars‘ with support for UTF-8.
+ *
+ * @static
+ * @param string $string String to be masked
+ * @return string Masked string
+ */
+ public static function htmlspecialchars_utf8($string)
+ {
+ return htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
+ }
+
}
?>
diff --git a/views/html/questgroups/questgroup.tpl b/views/html/questgroups/questgroup.tpl
index b78d1fe4..5699bfa7 100644
--- a/views/html/questgroups/questgroup.tpl
+++ b/views/html/questgroups/questgroup.tpl
@@ -6,7 +6,7 @@
=$questgroupshierarchy['title_singular']?> =$questgroup['pos']?>: =$questgroup['title']?>
-=$text['text']?>
+=\hhu\z\Utils::t($text['text'])?>
diff --git a/views/html/quests/quest.tpl b/views/html/quests/quest.tpl
index afccd176..9a8b7376 100644
--- a/views/html/quests/quest.tpl
+++ b/views/html/quests/quest.tpl
@@ -10,7 +10,7 @@
=$questtext['type']?>
- =$questtext['text']?>
+ =\hhu\z\Utils::t($questtext['text'])?>
@@ -35,6 +35,6 @@
=_('Task')?>
- =$quest['task']?>
+ =\hhu\z\Utils::t($quest['task'])?>
diff --git a/views/html/quests/sidequest.tpl b/views/html/quests/sidequest.tpl
index 4527b3c8..b1bff276 100644
--- a/views/html/quests/sidequest.tpl
+++ b/views/html/quests/sidequest.tpl
@@ -12,7 +12,7 @@
=$sidequesttext['type']?>
- =$sidequesttext['text']?>
+ =\hhu\z\Utils::t($sidequesttext['text'])?>
@@ -33,6 +33,6 @@
=_('Task')?>
- =$sidequest['task']?>
+ =\hhu\z\Utils::t(($sidequest['task'])?>
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 89378d65..3e93b154 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -11,7 +11,7 @@
=sprintf(_('created by %s on %s'), $seminary['creator']['username'], $dateFormatter->format(new \DateTime($seminary['created'])))?>
Beschreibung
-=$seminary['description']?>
+=\hhu\z\Utils::t($seminary['description'])?>
=$hierarchy['title_plural']?>
From 3517d6d0ed09f3417e35fee34eb76fff9cb35e51 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 16 Feb 2014 13:20:58 +0100
Subject: [PATCH 051/213] implement Quests for Character groups (-groups)
---
.../CharactergroupsquestsAgent.inc | 35 +++++
configs/AppConfig.inc | 40 +++---
controllers/CharactergroupsController.inc | 10 +-
.../CharactergroupsquestsController.inc | 91 ++++++++++++
models/CharactergroupsquestsModel.inc | 136 ++++++++++++++++++
views/html/charactergroups/group.tpl | 19 ++-
views/html/charactergroups/groupsgroup.tpl | 10 +-
views/html/charactergroupsquests/quest.tpl | 46 ++++++
8 files changed, 364 insertions(+), 23 deletions(-)
create mode 100644 agents/intermediate/CharactergroupsquestsAgent.inc
create mode 100644 controllers/CharactergroupsquestsController.inc
create mode 100644 models/CharactergroupsquestsModel.inc
create mode 100644 views/html/charactergroupsquests/quest.tpl
diff --git a/agents/intermediate/CharactergroupsquestsAgent.inc b/agents/intermediate/CharactergroupsquestsAgent.inc
new file mode 100644
index 00000000..bfc87de1
--- /dev/null
+++ b/agents/intermediate/CharactergroupsquestsAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Character groups Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 97c0a080..4dd71853 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -71,20 +71,21 @@
* @var array
*/
public static $routes = array(
- array('css/?(.*)', 'css/$1?layout=stylesheet', true),
- array('users/([^/]+)/(edit|delete)', 'users/$2/$1', true),
- array('users/(?!(index|login|logout|create|edit|delete))', 'users/user/$1', true),
- array('seminaries/([^/]+)/(edit|delete)', 'seminaries/$2/$1', true),
- array('seminaries/(?!(index|create|edit|delete))', 'seminaries/seminary/$1', true),
+ array('css/?(.*)', 'css/$1?layout=stylesheet', true),
+ array('users/([^/]+)/(edit|delete)', 'users/$2/$1', true),
+ array('users/(?!(index|login|logout|create|edit|delete))', 'users/user/$1', true),
+ array('seminaries/([^/]+)/(edit|delete)', 'seminaries/$2/$1', true),
+ array('seminaries/(?!(index|create|edit|delete))', 'seminaries/seminary/$1', true),
/*// z/ ⇒ z/seminaries/seminary/
- array('^([^/]+)/*$', 'seminaries/seminary/$1', true),
- // z// ⇒ z/questgroups/questgroup//
- array('^([^/]+)/([^/]+)/?$', 'questgropus/questgroup/$1/$2', true),
- // z/// ⇒ z/quests/quest///
- array('^([^/]+)/([^/]+)/([^/]+)/?$', 'quests/quest/$1/$2/3', true)*/
- array('charactergroups/(?!(index|groupsgroup|group))', 'charactergroups/index/$1', true),
- array('media/(.*)', 'media/$1?layout=binary', false),
- array('media/(.*)', 'media/index/$1', true)
+ array('^([^/]+)/*$', 'seminaries/seminary/$1', true),
+ // z// ⇒ z/questgroups/questgroup//
+ array('^([^/]+)/([^/]+)/?$', 'questgropus/questgroup/$1/$2', true),
+ // z/// ⇒ z/quests/quest///
+ array('^([^/]+)/([^/]+)/([^/]+)/?$', 'quests/quest/$1/$2/3', true)*/
+ array('charactergroups/(?!(index|groupsgroup|group))', 'charactergroups/index/$1', true),
+ array('charactergroupsquests/(?!(quest))', 'charactergroupsquests/quest/$1', true),
+ array('media/(.*)', 'media/$1?layout=binary', false),
+ array('media/(.*)', 'media/index/$1', true)
);
@@ -95,12 +96,13 @@
* @var array
*/
public static $reverseRoutes = array(
- array('users/user/(.*)', 'users/$1', true),
- array('users/([^/]+)/(.*)', 'users/$2/$1', true),
- array('seminaries/seminary/(.*)', 'seminaries/$1', false),
- //array('seminaries/seminary/(.*)', '$1', false)
- array('charactergroup/index/(.*)', 'charactergroup/$1', true),
- array('media/index/(.*)', 'media/$1', true)
+ array('users/user/(.*)', 'users/$1', true),
+ array('users/([^/]+)/(.*)', 'users/$2/$1', true),
+ array('seminaries/seminary/(.*)', 'seminaries/$1', false),
+ //array('seminaries/seminary/(.*)', '$1', false)
+ array('charactergroup/index/(.*)', 'charactergroup/$1', true),
+ array('charactergroupsquests/quest/(.*)', 'charactergroupsquests/$1', true),
+ array('media/index/(.*)', 'media/$1', true)
);
diff --git a/controllers/CharactergroupsController.inc b/controllers/CharactergroupsController.inc
index 1402e140..e98e3dd1 100644
--- a/controllers/CharactergroupsController.inc
+++ b/controllers/CharactergroupsController.inc
@@ -24,7 +24,7 @@
*
* @var array
*/
- public $models = array('seminaries', 'charactergroups');
+ public $models = array('seminaries', 'charactergroups', 'charactergroupsquests');
/**
* User permissions
*
@@ -89,11 +89,15 @@
// Get Character groups
$groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id']);
+ // Get Character groups-group Quests
+ $quests = $this->Charactergroupsquests->getQuestsForCharactergroupsgroup($groupsgroup['id']);
+
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('groups', $groups);
+ $this->set('quests', $quests);
}
@@ -119,11 +123,15 @@
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
+ // Get Character groups Quests
+ $quests = $this->Charactergroupsquests->getQuestsForGroup($group['id']);
+
// Pass data to view
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
+ $this->set('quests', $quests);
}
}
diff --git a/controllers/CharactergroupsquestsController.inc b/controllers/CharactergroupsquestsController.inc
new file mode 100644
index 00000000..52dc3435
--- /dev/null
+++ b/controllers/CharactergroupsquestsController.inc
@@ -0,0 +1,91 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the CharactergroupsquestsAgent to display Character
+ * groups Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'media');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: quest.
+ *
+ * Show a Character groups Quest for a Character groups-group
+ * of a Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ * @param string $questUrl URL-Title of a Character groups Quest
+ */
+ public function quest($seminaryUrl, $groupsgroupUrl, $questUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character groups-group Quests
+ $quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
+
+ // Get Character groups-groups
+ $groups = $this->Charactergroupsquests->getGroupsForQuest($quest['id']);
+
+ // Media
+ $questmedia = null;
+ if(!is_null($quest['questsmedia_id'])) {
+ $questmedia = $this->Media->getMediaById($quest['questsmedia_id']);
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('quest', $quest);
+ $this->set('groups', $groups);
+ $this->set('media', $questmedia);
+ }
+
+ }
+
+?>
diff --git a/models/CharactergroupsquestsModel.inc b/models/CharactergroupsquestsModel.inc
new file mode 100644
index 00000000..eed514dd
--- /dev/null
+++ b/models/CharactergroupsquestsModel.inc
@@ -0,0 +1,136 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the CharactergroupsquestsAgent to interact with
+ * Charactergroupsquests-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new CharactergroupsquestsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Character groups Quests of a Character groups-groups.
+ *
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @return array Character groups Quest data
+ */
+ public function getQuestsForCharactergroupsgroup($groupsgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, questgroups_id, title, url '.
+ 'FROM charactergroupsquests '.
+ 'WHERE charactergroupsgroup_id = ?',
+ 'i',
+ $groupsgroupId
+ );
+ }
+
+
+ /**
+ * Get a Character groups Quest by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @param string $questUrl URL-title of the Character groups Quest
+ * @return array Character groups Quest data
+ */
+ public function getQuestByUrl($groupsgroupId, $questUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, questgroups_id, title, url, description, xps, rules, won_text, lost_text, questsmedia_id '.
+ 'FROM charactergroupsquests '.
+ 'WHERE charactergroupsgroup_id = ? AND url = ?',
+ 'is',
+ $groupsgroupId,
+ $questUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get the Character groups for a Quest.
+ *
+ * @param int $questId ID of the Character groups Quest
+ * @return array Character groups
+ */
+ public function getGroupsForQuest($questId)
+ {
+ $groups = $this->db->query(
+ 'SELECT charactergroups.id, charactergroups.name, charactergroups.url, charactergroupsquests_groups.created, charactergroupsquests_groups.xps_factor, charactergroupsquests.xps '.
+ 'FROM charactergroupsquests_groups '.
+ 'LEFT JOIN charactergroups ON charactergroups.id = charactergroupsquests_groups.charactergroup_id '.
+ 'LEFT JOIN charactergroupsquests ON charactergroupsquests.id = charactergroupsquests_groups.charactergroupsquest_id '.
+ 'WHERE charactergroupsquests_groups.charactergroupsquest_id = ?',
+ 'i',
+ $questId
+ );
+ foreach($groups as &$group) {
+ $group['xps'] = round($group['xps'] * $group['xps_factor'], 1);
+ }
+
+
+ return $groups;
+ }
+
+
+ /**
+ * Get Character groups Quests for a Character group.
+ *
+ * @param int $groupId ID of the Character group
+ * @return array Character groups Quests
+ */
+ public function getQuestsForGroup($groupId)
+ {
+ $quests = $this->db->query(
+ 'SELECT charactergroupsquests.id, charactergroupsquests_groups.created, charactergroupsquests.title, charactergroupsquests.url, charactergroupsquests.xps, charactergroupsquests_groups.xps_factor '.
+ 'FROM charactergroupsquests_groups '.
+ 'LEFT JOIN charactergroupsquests ON charactergroupsquests.id = charactergroupsquests_groups.charactergroupsquest_id '.
+ 'WHERE charactergroupsquests_groups.charactergroup_id = ?',
+ 'i',
+ $groupId
+ );
+ foreach($quests as &$quest) {
+ $quest['group_xps'] = round($quest['xps'] * $quest['xps_factor'], 1);
+ }
+
+
+ return $quests;
+ }
+
+
+ }
+
+?>
diff --git a/views/html/charactergroups/group.tpl b/views/html/charactergroups/group.tpl
index 6b50852c..dc3932ef 100644
--- a/views/html/charactergroups/group.tpl
+++ b/views/html/charactergroups/group.tpl
@@ -1,5 +1,20 @@
=_('Seminaries')?>
=$seminary['title']?>
-=_('Character Groups')?>
-=$groupsgroup['name']?>
+
+
=$group['name']?>
+
+
+ =_('Quests')?>
+
+
+
+
+ =$dateFormatter->format(new \DateTime($quest['created']))?>
+ =$quest['title']?>
+ =$quest['group_xps']?>/=$quest['xps']?> XPs
+
+
+
+
+
diff --git a/views/html/charactergroups/groupsgroup.tpl b/views/html/charactergroups/groupsgroup.tpl
index ebdd8973..9a24a91b 100644
--- a/views/html/charactergroups/groupsgroup.tpl
+++ b/views/html/charactergroups/groupsgroup.tpl
@@ -1,6 +1,6 @@
=_('Seminaries')?>
=$seminary['title']?>
-=_('Character Groups')?>
+
=$groupsgroup['name']?>
+
+
+=_('Character Groups Quests')?>
+
diff --git a/views/html/charactergroupsquests/quest.tpl b/views/html/charactergroupsquests/quest.tpl
new file mode 100644
index 00000000..cf0e9923
--- /dev/null
+++ b/views/html/charactergroupsquests/quest.tpl
@@ -0,0 +1,46 @@
+=_('Seminaries')?>
+=$seminary['title']?>
+=_('Character Groups Quests')?>
+=$quest['title']?>
+
+
+
+
+
+
+ XPs: =$quest['xps']?>
+ =_('Description')?>
+ =\hhu\z\Utils::t($quest['description'])?>
+
+ =_('Rules')?>
+ =\hhu\z\Utils::t($quest['rules'])?>
+
+
+
+
+
+ =_('Won Quest')?>
+ =\hhu\z\Utils::t($quest['won_text'])?>
+
+
+
+
+ =_('Lost Quest')?>
+ =\hhu\z\Utils::t($quest['lost_text'])?>
+
+
+
+
+ =$groupsgroup['name']?>
+
+
+
+
+ =$dateFormatter->format(new \DateTime($group['created']))?>
+ =$group['name']?>
+ =$group['xps']?>/=$quest['xps']?> XPs
+
+
+
+
+
From 2f65a89ef4bff920104910d51b828b11dd37c3c5 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 16 Feb 2014 15:31:08 +0100
Subject: [PATCH 052/213] 1) implement basic CharactersAgent 2) use view for
Character groups
---
agents/intermediate/CharactersAgent.inc | 43 ++++++++++
app/controllers/ToplevelController.inc | 23 ++++-
configs/AppConfig.inc | 2 +
controllers/CharactergroupsController.inc | 4 +
controllers/CharactersController.inc | 97 ++++++++++++++++++++++
controllers/HtmlController.inc | 2 +
models/CharactergroupsModel.inc | 28 ++++++-
models/CharactersModel.inc | 75 ++++++++++++++++-
views/html/charactergroups/group.tpl | 13 +++
views/html/charactergroups/groupsgroup.tpl | 2 +-
views/html/characters/character.tpl | 19 +++++
views/html/characters/index.tpl | 8 ++
views/html/html.tpl | 3 +
views/html/seminaries/seminary.tpl | 1 +
views/html/users/user.tpl | 2 +-
15 files changed, 311 insertions(+), 11 deletions(-)
create mode 100644 agents/intermediate/CharactersAgent.inc
create mode 100644 controllers/CharactersController.inc
create mode 100644 views/html/characters/character.tpl
create mode 100644 views/html/characters/index.tpl
diff --git a/agents/intermediate/CharactersAgent.inc b/agents/intermediate/CharactersAgent.inc
new file mode 100644
index 00000000..25102198
--- /dev/null
+++ b/agents/intermediate/CharactersAgent.inc
@@ -0,0 +1,43 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered Characters and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactersAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+
+ /**
+ * Action: character.
+ */
+ public function character(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/app/controllers/ToplevelController.inc b/app/controllers/ToplevelController.inc
index 74f63667..544748a9 100644
--- a/app/controllers/ToplevelController.inc
+++ b/app/controllers/ToplevelController.inc
@@ -24,13 +24,23 @@
*
* @var array
*/
- public $models = array('users', 'userroles');
+ public $models = array('users', 'userroles', 'seminaries', 'characters');
/**
* Current user
*
* @var array
*/
public static $user = null;
+ /**
+ *
+ */
+ public static $seminary = null;
+ /**
+ * Character of current user and Seminary
+ *
+ * @var array
+ */
+ public static $character = null;
@@ -67,6 +77,15 @@
// Get userdata
try {
static::$user = $this->Users->getUserById($this->Auth->getUserId());
+
+ // Character
+ $controller = $this->agent->getIntermediateAgent()->controller;
+ if(in_array(\hhu\z\controllers\SeminaryRoleController::class, class_parents($controller)))
+ {
+ $seminaryUrl = $this->request->getParam(3);
+ static::$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+ static::$character = $this->Characters->getCharacterForUserAndSeminary(static::$user['id'], static::$seminary['id']);
+ }
}
catch(\nre\exceptions\IdNotFoundException $e) {
}
@@ -76,6 +95,8 @@
// Set userdata
$this->set('loggedUser', static::$user);
+ $this->set('loggedSeminary', static::$seminary);
+ $this->set('loggedCharacter', static::$character);
}
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 4dd71853..8c388dce 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -82,6 +82,7 @@
array('^([^/]+)/([^/]+)/?$', 'questgropus/questgroup/$1/$2', true),
// z/// ⇒ z/quests/quest///
array('^([^/]+)/([^/]+)/([^/]+)/?$', 'quests/quest/$1/$2/3', true)*/
+ array('characters/(?!(index|character))', 'characters/index/$1', true),
array('charactergroups/(?!(index|groupsgroup|group))', 'charactergroups/index/$1', true),
array('charactergroupsquests/(?!(quest))', 'charactergroupsquests/quest/$1', true),
array('media/(.*)', 'media/$1?layout=binary', false),
@@ -100,6 +101,7 @@
array('users/([^/]+)/(.*)', 'users/$2/$1', true),
array('seminaries/seminary/(.*)', 'seminaries/$1', false),
//array('seminaries/seminary/(.*)', '$1', false)
+ array('characters/index/(.*)', 'characters/$1', true),
array('charactergroup/index/(.*)', 'charactergroup/$1', true),
array('charactergroupsquests/quest/(.*)', 'charactergroupsquests/$1', true),
array('media/index/(.*)', 'media/$1', true)
diff --git a/controllers/CharactergroupsController.inc b/controllers/CharactergroupsController.inc
index e98e3dd1..1028d28c 100644
--- a/controllers/CharactergroupsController.inc
+++ b/controllers/CharactergroupsController.inc
@@ -123,6 +123,9 @@
// Get Character group
$group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
+ // Get Characters
+ $characters = $this->Characters->getCharactersForGroup($group['id']);
+
// Get Character groups Quests
$quests = $this->Charactergroupsquests->getQuestsForGroup($group['id']);
@@ -131,6 +134,7 @@
$this->set('seminary', $seminary);
$this->set('groupsgroup', $groupsgroup);
$this->set('group', $group);
+ $this->set('characters', $characters);
$this->set('quests', $quests);
}
diff --git a/controllers/CharactersController.inc b/controllers/CharactersController.inc
new file mode 100644
index 00000000..27c4edcb
--- /dev/null
+++ b/controllers/CharactersController.inc
@@ -0,0 +1,97 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactersController extends \hhu\z\Controller
+ {
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array('admin', 'moderator'),
+ 'character' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'characters', 'users', 'charactergroups');
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * List registered Characters for a Seminary
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ */
+ public function index($seminaryUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get registered Characters
+ $characters = $this->Characters->getCharactersForSeminary($seminary['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('characters', $characters);
+ }
+
+
+ /**
+ * Action: character.
+ *
+ * Show a Charater and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $characterUrl URL-name of a Charater
+ */
+ public function character($seminaryUrl, $characterUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character
+ $character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
+
+ // Get User
+ $user = $this->Users->getUserById($character['user_id']);
+
+ // Get Character groups
+ $groups = $this->Charactergroups->getGroupsForCharacter($character['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('character', $character);
+ $this->set('user', $user);
+ $this->set('groups', $groups);
+ }
+
+ }
+
+?>
diff --git a/controllers/HtmlController.inc b/controllers/HtmlController.inc
index d7660f5a..20795d5b 100644
--- a/controllers/HtmlController.inc
+++ b/controllers/HtmlController.inc
@@ -50,6 +50,8 @@
// Set userdata
$this->set('loggedUser', static::$user);
+ $this->set('loggedSeminary', static::$seminary);
+ $this->set('loggedCharacter', static::$character);
}
}
diff --git a/models/CharactergroupsModel.inc b/models/CharactergroupsModel.inc
index 4fc32b80..ce6e8b61 100644
--- a/models/CharactergroupsModel.inc
+++ b/models/CharactergroupsModel.inc
@@ -88,8 +88,8 @@
public function getGroupsForGroupsgroup($groupsgroupId)
{
return $this->db->query(
- 'SELECT id, name, url '.
- 'FROM charactergroups '.
+ 'SELECT id, name, url, xps '.
+ 'FROM v_charactergroups '.
'WHERE charactergroupsgroup_id = ?',
'i',
$groupsgroupId
@@ -97,6 +97,26 @@
}
+ /**
+ * Get Character groups for a Character.
+ *
+ * @param int $characterId ID of the Character
+ * @return array Character groups
+ */
+ public function getGroupsForCharacter($characterId)
+ {
+ return $this->db->query(
+ 'SELECT charactergroups.id, charactergroups.charactergroupsgroup_id, charactergroups.name, charactergroups.url, charactergroups.xps, charactergroupsgroups.id AS charactergroupsgroup_id, charactergroupsgroups.name AS charactergroupsgroup_name, charactergroupsgroups.url AS charactergroupsgroup_url '.
+ 'FROM characters_charactergroups '.
+ 'LEFT JOIN v_charactergroups AS charactergroups ON charactergroups.id = characters_charactergroups.charactergroup_id '.
+ 'LEFT JOIN charactergroupsgroups ON charactergroupsgroups.id = charactergroups.charactergroupsgroup_id '.
+ 'WHERE characters_charactergroups.character_id = ?',
+ 'i',
+ $characterId
+ );
+ }
+
+
/**
* Get a Character group by its URL.
*
@@ -108,8 +128,8 @@
public function getGroupByUrl($groupsgroupId, $groupUrl)
{
$data = $this->db->query(
- 'SELECT id, name, url '.
- 'FROM charactergroups '.
+ 'SELECT id, name, url, xps '.
+ 'FROM v_charactergroups '.
'WHERE charactergroupsgroup_id = ? AND url = ?',
'is',
$groupsgroupId, $groupUrl
diff --git a/models/CharactersModel.inc b/models/CharactersModel.inc
index c62f294c..0f637d19 100644
--- a/models/CharactersModel.inc
+++ b/models/CharactersModel.inc
@@ -43,8 +43,8 @@
public function getCharactersForUser($userId)
{
return $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
- 'FROM characters '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
'WHERE user_id = ?',
@@ -54,6 +54,46 @@
}
+ /**
+ * Get Characters for a Seminary.
+ *
+ * @param int $seminaryId ID of the Seminary
+ * @return array Characters
+ */
+ public function getCharactersForSeminary($seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
+ 'WHERE seminaries.id = ?',
+ 'i',
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Get Characters for a Character group.
+ *
+ * @param int $groupId ID of the Character group
+ * @return array Characters
+ */
+ public function getCharactersForGroup($groupId)
+ {
+ return $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN characters_charactergroups ON characters_charactergroups.character_id = characters.id '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'WHERE characters_charactergroups.charactergroup_id = ?',
+ 'i',
+ $groupId
+ );
+ }
+
+
/**
* Get the character of a user for a Seminary.
*
@@ -65,8 +105,8 @@
public function getCharacterForUserAndSeminary($userId, $seminaryId)
{
$data = $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
- 'FROM characters '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'WHERE characters.user_id = ? AND charactertypes.seminary_id = ?',
'ii',
@@ -80,6 +120,33 @@
return $data[0];
}
+
+ /**
+ * Get a Character by its Url.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the Seminary
+ * @param string $characterUrl URL-name of the Character
+ * @return array Character data
+ */
+ public function getCharacterByUrl($seminaryId, $characterUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'WHERE charactertypes.seminary_id = ? AND characters.url = ?',
+ 'is',
+ $seminaryId, $characterUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($characterUrl);
+ }
+
+
+ return $data[0];
+ }
+
}
?>
diff --git a/views/html/charactergroups/group.tpl b/views/html/charactergroups/group.tpl
index dc3932ef..f46b24b4 100644
--- a/views/html/charactergroups/group.tpl
+++ b/views/html/charactergroups/group.tpl
@@ -4,6 +4,19 @@
=$group['name']?>
+
+ XPs: =$group['xps']?>
+
+
+
+
=_('Quests')?>
diff --git a/views/html/charactergroups/groupsgroup.tpl b/views/html/charactergroups/groupsgroup.tpl
index 9a24a91b..3108b483 100644
--- a/views/html/charactergroups/groupsgroup.tpl
+++ b/views/html/charactergroups/groupsgroup.tpl
@@ -5,7 +5,7 @@
diff --git a/views/html/characters/character.tpl b/views/html/characters/character.tpl
new file mode 100644
index 00000000..aa8bdd78
--- /dev/null
+++ b/views/html/characters/character.tpl
@@ -0,0 +1,19 @@
+=$seminary['title']?>
+=_('Characters')?>
+=$character['name']?>
+
+
+
+
+ =_('Character Groups')?>
+
+
diff --git a/views/html/characters/index.tpl b/views/html/characters/index.tpl
new file mode 100644
index 00000000..362d60c1
--- /dev/null
+++ b/views/html/characters/index.tpl
@@ -0,0 +1,8 @@
+=$seminary['title']?>
+=_('Characters')?>
+
+
diff --git a/views/html/html.tpl b/views/html/html.tpl
index 0eadc348..ad8f4648 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -17,6 +17,9 @@
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 3e93b154..3ff9b9c0 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -5,6 +5,7 @@
=_('Delete seminary')?>
+ =_('Characters')?>
=_('Character Groups')?>
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
index 2c081f2d..9be97544 100644
--- a/views/html/users/user.tpl
+++ b/views/html/users/user.tpl
@@ -11,7 +11,7 @@
=_('Characters')?>
From 0ef30ac1ca12d0c9f4c8e819ef7bae430f2ef667 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 16 Feb 2014 15:46:18 +0100
Subject: [PATCH 053/213] correct classname determination for older
PHP-versions
---
app/controllers/ToplevelController.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/ToplevelController.inc b/app/controllers/ToplevelController.inc
index 544748a9..30558c91 100644
--- a/app/controllers/ToplevelController.inc
+++ b/app/controllers/ToplevelController.inc
@@ -80,7 +80,7 @@
// Character
$controller = $this->agent->getIntermediateAgent()->controller;
- if(in_array(\hhu\z\controllers\SeminaryRoleController::class, class_parents($controller)))
+ if(is_subclass_of($controller, '\hhu\z\controllers\SeminaryRoleController'))
{
$seminaryUrl = $this->request->getParam(3);
static::$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
From 16189f5d122d59be7e4ceed66dde8821b9d6669f Mon Sep 17 00:00:00 2001
From: coderkun
Date: Mon, 17 Feb 2014 02:18:01 +0100
Subject: [PATCH 054/213] correct typo in template for Sidequests
---
views/html/quests/sidequest.tpl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/views/html/quests/sidequest.tpl b/views/html/quests/sidequest.tpl
index b1bff276..1cb888ce 100644
--- a/views/html/quests/sidequest.tpl
+++ b/views/html/quests/sidequest.tpl
@@ -33,6 +33,6 @@
=_('Task')?>
- =\hhu\z\Utils::t(($sidequest['task'])?>
+ =\hhu\z\Utils::t($sidequest['task'])?>
From e356b71b175909ff8c79010d501166d516a1dbfb Mon Sep 17 00:00:00 2001
From: coderkun
Date: Mon, 17 Feb 2014 02:19:00 +0100
Subject: [PATCH 055/213] implement different media for Quest- and
Sidequesttexts (Ticket #26)
---
controllers/QuestsController.inc | 11 ++++++++---
models/QuesttextsModel.inc | 4 ++--
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index dda3e718..b5df177c 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -95,12 +95,14 @@
// Media
$questmedia = null;
- if(!is_null($quest['questsmedia_id'])) {
+ if(!is_null($questtext) && !empty($questtext['questsmedia_id'])) {
+ $questmedia = $this->Media->getMediaById($questtext['questsmedia_id']);
+ }
+ elseif(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getMediaById($quest['questsmedia_id']);
}
-
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
@@ -166,7 +168,10 @@
// Media
$sidequestmedia = null;
- if(!is_null($sidequest['questsmedia_id'])) {
+ if(!is_null($sidequesttext) && !empty($sidequesttext['questsmedia_id'])) {
+ $sidequestmedia = $this->Media->getMediaById($sidequesttext['questsmedia_id']);
+ }
+ elseif(!is_null($sidequest['questsmedia_id'])) {
$sidequestmedia = $this->Media->getMediaById($sidequest['questsmedia_id']);
}
diff --git a/models/QuesttextsModel.inc b/models/QuesttextsModel.inc
index 50a9f85a..3a7d8526 100644
--- a/models/QuesttextsModel.inc
+++ b/models/QuesttextsModel.inc
@@ -46,7 +46,7 @@
public function getQuesttextByUrl($questId, $questtexttypeUrl, $pos)
{
$data = $this->db->query(
- 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.out_text, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.out_text, questtexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
'FROM questtexts '.
'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
'WHERE questtexts.quest_id = ? AND questtexttypes.url = ? AND questtexts.pos = ?',
@@ -74,7 +74,7 @@
public function getSidequesttextByUrl($sidequestId, $questtexttypeUrl, $pos)
{
$data = $this->db->query(
- 'SELECT sidequesttexts.id, sidequesttexts.text, sidequesttexts.pos, sidequesttexts.out_text, sidequesttexts.abort_text, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'SELECT sidequesttexts.id, sidequesttexts.text, sidequesttexts.pos, sidequesttexts.out_text, sidequesttexts.abort_text, sidequesttexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
'FROM sidequesttexts '.
'LEFT JOIN questtexttypes ON questtexttypes.id = sidequesttexts.questtexttype_id '.
'WHERE sidequesttexts.sidequest_id = ? AND questtexttypes.url = ? AND sidequesttexts.pos = ?',
From 59d358005fc01f77e69cedc568980a7975b3b0b7 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Mon, 17 Feb 2014 02:30:14 +0100
Subject: [PATCH 056/213] implement group leaders for Character groups (Ticket
#23)
---
models/CharactersModel.inc | 2 +-
views/html/charactergroups/group.tpl | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/models/CharactersModel.inc b/models/CharactersModel.inc
index 0f637d19..2bbe7744 100644
--- a/models/CharactersModel.inc
+++ b/models/CharactersModel.inc
@@ -83,7 +83,7 @@
public function getCharactersForGroup($groupId)
{
return $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters_charactergroups.is_leader, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
'FROM v_characters AS characters '.
'LEFT JOIN characters_charactergroups ON characters_charactergroups.character_id = characters.id '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
diff --git a/views/html/charactergroups/group.tpl b/views/html/charactergroups/group.tpl
index f46b24b4..96146f31 100644
--- a/views/html/charactergroups/group.tpl
+++ b/views/html/charactergroups/group.tpl
@@ -12,7 +12,7 @@
=_('Characters')?>
From 82f75fff4790e4928a03bacf0bef32fd7f0f5ed4 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Mon, 17 Feb 2014 02:30:21 +0100
Subject: [PATCH 057/213] update translations
---
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 2106 -> 2519 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 301 ++++++++++++--------
2 files changed, 176 insertions(+), 125 deletions(-)
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index 8680ecbba6a35368600de60d9e20a7e18e7ec4ce..09213b4bc7d8d63e6ef8815628bcb22d800dd269 100644
GIT binary patch
literal 2519
zcmaKsO>7)B6vtgCU(099S1FXbKp-iabT?GA-6){8*+wlXS&}V{IDou6FFQjV&&u{B
z4HwF_5=ccLKq{0AQhNc!p$F&zsX{$*K|-A1kPBxdB(D75jI+BH71r24Kl}Ol`Ppy&
z*uM2+fwC9%2~@pBh)MA3Eoe|K-73Tb;AQYp@O!WV{sKM-{tn&`{uQ`os}OfX-WIqE
zychBqco%p8ybU}IvfUZ*9&j;`!n_4<$M_kL_j@Dy&_UFR*BFKKf335mhkoQ{#cY-#^?}HqVkAi#&
zsoyl)r0540dY@g5r1I~RC9@KccOTm)<2S706d
z4TLLVJA%Z1?*v)z1rSr>5XgQX3Gy7s`!9lcG9m%-3617)a5cyuf)7K!0J5F$K#s!?
zVg6?j;VkZe&%uTF<(Tj~E_|*%MNfzkkmJj-;lg(^R`kj^?GAm$Q>ag(K88Aq%7xFy
z`N2MNe0HI7yq`g3zu->cCvZdIoRO$|QThEmjmq)hm~9q*hr?w%1dh$Ks2r>3P{q+i
zS=I4m<&4epp8L;$d@U#EhsM#hq&!JOYtqq5YLs0c9?KnBF-@AF)1MD=m~$PQ_I#Qd
z(TGz&&?=-tr(tboMPuXa`I9Qu(cw6@~Y+9o5gvjFf^NWQzOu3xd)st
z9T%?-d&xp!zNwsB%WN#d>E<&{PR!@rE|h0VxtnCUj-^iqCy^UxFO0a2v!6>uLF;wd
zCK(rpjb9$t=WPbMqa$wYW(!)%EsIu?y3$*TPF4g)Y0*l(CUJ_R$&FDfrR2ov%!Jb^
zCpyY>NQ+Kpyh=@Kx_t|!4m67U3W#NUU5;QIgI1KD3rpS9;So?A#+_Ov(X`py)bY{r
zIC`C|!*$hV3!#{$E*WSp$u}y^xmHxX2h2v(couazQLXKdsuNM|fUHi`Ck{SetyQZ~
zjOJ-IWh*z=J5=h;D(9n?RmN%MGh3IHS!KGp>QdAqwK62v5%;&I80~iNSeFOesjn>T0p#rE6Cc%T{m5Ydk}pS=>o@{_MCdPE(x0%1swV
zNN_I(3C<^-$J5oOaFxVDrZwJBX#lzU1?Tkzxt7{xopurl)#B)0u91z&Aip9@?T(6vOY|?9w8j~1BrhDZ<%Hz
delta 867
zcmZ9~Pe_zO7{~F)e0TTVGXHO`R{jA6gUDSKLWvL$fwh4I($!G0Mcr3S1rM?Z4~Cb(
zAtDuwI@z@@N!`M0co6YY1VVZ7q=!!R{q4ScX?SNo^SGwZ^e7icKI@gkmJ9iCwo`sGEFc!~Q?yo|jV$3cu>2CMNAR^V9pd={f-d0Px$
zEThkWwNO_aU|Xn(-k~t}d)Q;DX%Qk7Y$;unl1_qd=9v@&5M^TY4VGXXLGV~fX?+$X=7aGm`6_v3AjIh4_
zq{C&uXtcm7R^lI21b(dez9uw@im(OK*n$1{7`benMjP8ejr)K~{U_9Xd#GRZ4f9v&
z9EA_gF~R*`)W8IdB5Fo`kU|n+wNx#jH0t~Rix$;_I#0@kev9T+)H+r=YhjrwsPrk-
zie3x0Qng?URpmNWDKC`?5)RhPi7`;(<#>*eP7n&
genelmSFvGt7Q5r_`i*YVPrGgZt-Bwubkp&vf1@{3i~s-t
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
index e5954918..086c0741 100644
--- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -1,39 +1,106 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
-"POT-Creation-Date: 2014-02-12 23:09+0100\n"
-"PO-Revision-Date: 2014-02-12 23:10+0100\n"
+"POT-Creation-Date: 2014-02-17 02:28+0100\n"
+"PO-Revision-Date: 2014-02-17 02:29+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.6.3\n"
+"X-Generator: Poedit 1.6.4\n"
"X-Poedit-Basepath: .\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-SearchPath-0: ../../../views\n"
-#: ../../../views/html/menu/index.tpl:2 ../../../views/html/users/login.tpl:1
-#: ../../../views/html/users/user.tpl:1 ../../../views/html/users/index.tpl:1
-#: ../../../views/html/users/edit.tpl:1 ../../../views/html/users/delete.tpl:1
-#: ../../../views/html/users/create.tpl:1
-msgid "Users"
-msgstr "Benutzer"
+#: ../../../views/binary/error/index.tpl:1
+#: ../../../views/html/error/index.tpl:1
+msgid "Error"
+msgstr "Fehler"
+#: ../../../views/html/charactergroups/group.tpl:1
+#: ../../../views/html/charactergroups/groupsgroup.tpl:1
+#: ../../../views/html/charactergroups/index.tpl:1
+#: ../../../views/html/charactergroupsquests/quest.tpl:1
#: ../../../views/html/menu/index.tpl:3
-#: ../../../views/html/seminaries/seminary.tpl:1
-#: ../../../views/html/seminaries/index.tpl:1
-#: ../../../views/html/seminaries/edit.tpl:1
-#: ../../../views/html/seminaries/delete.tpl:1
-#: ../../../views/html/seminaries/create.tpl:1
#: ../../../views/html/questgroups/questgroup.tpl:1
#: ../../../views/html/quests/quest.tpl:1
#: ../../../views/html/quests/sidequest.tpl:1
+#: ../../../views/html/seminaries/create.tpl:1
+#: ../../../views/html/seminaries/delete.tpl:1
+#: ../../../views/html/seminaries/edit.tpl:1
+#: ../../../views/html/seminaries/index.tpl:1
+#: ../../../views/html/seminaries/seminary.tpl:1
msgid "Seminaries"
msgstr "Kurse"
+#: ../../../views/html/charactergroups/group.tpl:3
+#: ../../../views/html/charactergroups/groupsgroup.tpl:3
+#: ../../../views/html/charactergroups/index.tpl:3
+#: ../../../views/html/characters/character.tpl:13
+#: ../../../views/html/seminaries/seminary.tpl:9
+msgid "Character Groups"
+msgstr "Charaktergruppen"
+
+#: ../../../views/html/charactergroups/group.tpl:12
+#: ../../../views/html/characters/character.tpl:2
+#: ../../../views/html/characters/index.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:8
+#: ../../../views/html/users/user.tpl:11
+msgid "Characters"
+msgstr "Charaktere"
+
+#: ../../../views/html/charactergroups/group.tpl:15
+msgid "Group Leader"
+msgstr "Gruppenleiter"
+
+#: ../../../views/html/charactergroups/group.tpl:21
+#: ../../../views/html/questgroups/questgroup.tpl:24
+msgid "Quests"
+msgstr "Quests"
+
+#: ../../../views/html/charactergroups/groupsgroup.tpl:13
+#: ../../../views/html/charactergroupsquests/quest.tpl:3
+msgid "Character Groups Quests"
+msgstr "Charactergruppen-Quests"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:12
+msgid "Description"
+msgstr "Beschreibung"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:15
+msgid "Rules"
+msgstr "Regeln"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:22
+msgid "Won Quest"
+msgstr "Gewonnene Quest"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:28
+msgid "Lost Quest"
+msgstr "Verlorene Quest"
+
+#: ../../../views/html/characters/character.tpl:8
+msgid "User"
+msgstr "Benutzer"
+
+#: ../../../views/html/html.tpl:21
+msgid "as"
+msgstr "als"
+
+#: ../../../views/html/introduction/index.tpl:1
+msgid "Introduction"
+msgstr "Einführung"
+
+#: ../../../views/html/menu/index.tpl:2 ../../../views/html/users/create.tpl:1
+#: ../../../views/html/users/delete.tpl:1 ../../../views/html/users/edit.tpl:1
+#: ../../../views/html/users/index.tpl:1 ../../../views/html/users/login.tpl:1
+#: ../../../views/html/users/user.tpl:1
+msgid "Users"
+msgstr "Benutzer"
+
#: ../../../views/html/menu/index.tpl:5 ../../../views/html/users/login.tpl:2
#: ../../../views/html/users/login.tpl:11
msgid "Login"
@@ -43,140 +110,124 @@ msgstr "Login"
msgid "Logout"
msgstr "Logout"
-#: ../../../views/html/users/login.tpl:6 ../../../views/html/users/login.tpl:7
-#: ../../../views/html/users/edit.tpl:6 ../../../views/html/users/edit.tpl:7
-#: ../../../views/html/users/create.tpl:6
-#: ../../../views/html/users/create.tpl:7
-msgid "Username"
-msgstr "Benutzername"
+#: ../../../views/html/questgroups/questgroup.tpl:30
+msgid "containing optional Quests"
+msgstr "Enthaltene optionale Quests"
-#: ../../../views/html/users/login.tpl:8 ../../../views/html/users/login.tpl:9
-#: ../../../views/html/users/edit.tpl:10 ../../../views/html/users/edit.tpl:11
-#: ../../../views/html/users/create.tpl:10
-#: ../../../views/html/users/create.tpl:11
-msgid "Password"
-msgstr "Passwort"
+#: ../../../views/html/quests/quest.tpl:37
+#: ../../../views/html/quests/sidequest.tpl:35
+msgid "Task"
+msgstr "Aufgabe"
-#: ../../../views/html/users/user.tpl:4 ../../../views/html/users/edit.tpl:2
-msgid "Edit user"
-msgstr "Benutzer bearbeiten"
+#: ../../../views/html/quests/sidequest.tpl:9
+msgid "This Quest is optional"
+msgstr "Diese Quest ist optional"
-#: ../../../views/html/users/user.tpl:5 ../../../views/html/users/delete.tpl:2
-msgid "Delete user"
-msgstr "Benutzer löschen"
+#: ../../../views/html/seminaries/create.tpl:2
+msgid "New seminary"
+msgstr "Neuer Kurs"
-#: ../../../views/html/users/user.tpl:8 ../../../views/html/users/index.tpl:10
-#, php-format
-msgid "registered on %s"
-msgstr "registriert am %s"
+#: ../../../views/html/seminaries/create.tpl:6
+#: ../../../views/html/seminaries/create.tpl:7
+#: ../../../views/html/seminaries/edit.tpl:6
+#: ../../../views/html/seminaries/edit.tpl:7
+msgid "Title"
+msgstr "Titel"
-#: ../../../views/html/users/user.tpl:11
-msgid "Characters"
-msgstr "Charaktere"
-
-#: ../../../views/html/users/user.tpl:18
-msgid "Roles"
-msgstr "Rollen"
-
-#: ../../../views/html/users/index.tpl:3
-msgid "Create new user"
-msgstr "Neuen Benutzer erstellen"
-
-#: ../../../views/html/users/edit.tpl:8 ../../../views/html/users/edit.tpl:9
-#: ../../../views/html/users/create.tpl:8
-#: ../../../views/html/users/create.tpl:9
-msgid "E‑Mail-Address"
-msgstr "E‑Mail-Adresse"
-
-#: ../../../views/html/users/edit.tpl:13
-#: ../../../views/html/seminaries/edit.tpl:9
-msgid "save"
-msgstr "speichern"
-
-#: ../../../views/html/users/delete.tpl:4
-#, php-format
-msgid "Should the user “%s” (%s) really be deleted?"
-msgstr "Soll der Benutzer „%s“ (%s) wirklich gelöscht werden?"
-
-#: ../../../views/html/users/delete.tpl:6
-#: ../../../views/html/seminaries/delete.tpl:6
-msgid "delete"
-msgstr "löschen"
-
-#: ../../../views/html/users/delete.tpl:7
-#: ../../../views/html/seminaries/delete.tpl:7
-msgid "cancel"
-msgstr "abbrechen"
-
-#: ../../../views/html/users/create.tpl:2
-msgid "New user"
-msgstr "Neuer Benutzer"
-
-#: ../../../views/html/users/create.tpl:13
#: ../../../views/html/seminaries/create.tpl:9
+#: ../../../views/html/users/create.tpl:13
msgid "create"
msgstr "erstellen"
-#: ../../../views/html/error/index.tpl:1
-msgid "Error"
-msgstr "Fehler"
-
-#: ../../../views/html/seminaries/seminary.tpl:4
-#: ../../../views/html/seminaries/edit.tpl:2
-msgid "Edit seminary"
-msgstr "Kurs bearbeiten"
-
-#: ../../../views/html/seminaries/seminary.tpl:5
#: ../../../views/html/seminaries/delete.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:5
msgid "Delete seminary"
msgstr "Kurs löschen"
-#: ../../../views/html/seminaries/seminary.tpl:8
-#: ../../../views/html/seminaries/index.tpl:10
-#, php-format
-msgid "created by %s on %s"
-msgstr "erstellt von %s am %s"
-
-#: ../../../views/html/seminaries/index.tpl:3
-msgid "Create new seminary"
-msgstr "Neuen Kurs erstellen"
-
-#: ../../../views/html/seminaries/edit.tpl:6
-#: ../../../views/html/seminaries/edit.tpl:7
-#: ../../../views/html/seminaries/create.tpl:6
-#: ../../../views/html/seminaries/create.tpl:7
-msgid "Title"
-msgstr "Titel"
-
#: ../../../views/html/seminaries/delete.tpl:4
#, php-format
msgid "Should the seminary “%s” really be deleted?"
msgstr "Soll der Kurs „%s“ wirklich gelöscht werden?"
-#: ../../../views/html/seminaries/create.tpl:2
-msgid "New seminary"
-msgstr "Neuer Kurs"
+#: ../../../views/html/seminaries/delete.tpl:6
+#: ../../../views/html/users/delete.tpl:6
+msgid "delete"
+msgstr "löschen"
-#: ../../../views/html/questgroups/questgroup.tpl:23
-msgid "Quests"
-msgstr "Quests"
+#: ../../../views/html/seminaries/delete.tpl:7
+#: ../../../views/html/users/delete.tpl:7
+msgid "cancel"
+msgstr "abbrechen"
-#: ../../../views/html/questgroups/questgroup.tpl:29
-msgid "containing optional Quests"
-msgstr "Enthaltene optionale Quests"
+#: ../../../views/html/seminaries/edit.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:4
+msgid "Edit seminary"
+msgstr "Kurs bearbeiten"
-#: ../../../views/html/introduction/index.tpl:1
-msgid "Introduction"
-msgstr "Einführung"
+#: ../../../views/html/seminaries/edit.tpl:9
+#: ../../../views/html/users/edit.tpl:13
+msgid "save"
+msgstr "speichern"
-#: ../../../views/html/quests/quest.tpl:33
-#: ../../../views/html/quests/sidequest.tpl:20
-msgid "Task"
-msgstr "Aufgabe"
+#: ../../../views/html/seminaries/index.tpl:3
+msgid "Create new seminary"
+msgstr "Neuen Kurs erstellen"
-#: ../../../views/html/quests/sidequest.tpl:8
-msgid "This Quest is optional"
-msgstr "Diese Quest ist optional"
+#: ../../../views/html/seminaries/index.tpl:10
+#: ../../../views/html/seminaries/seminary.tpl:12
+#, php-format
+msgid "created by %s on %s"
+msgstr "erstellt von %s am %s"
+
+#: ../../../views/html/users/create.tpl:2
+msgid "New user"
+msgstr "Neuer Benutzer"
+
+#: ../../../views/html/users/create.tpl:6
+#: ../../../views/html/users/create.tpl:7 ../../../views/html/users/edit.tpl:6
+#: ../../../views/html/users/edit.tpl:7 ../../../views/html/users/login.tpl:6
+#: ../../../views/html/users/login.tpl:7
+msgid "Username"
+msgstr "Benutzername"
+
+#: ../../../views/html/users/create.tpl:8
+#: ../../../views/html/users/create.tpl:9 ../../../views/html/users/edit.tpl:8
+#: ../../../views/html/users/edit.tpl:9
+msgid "E‑Mail-Address"
+msgstr "E‑Mail-Adresse"
+
+#: ../../../views/html/users/create.tpl:10
+#: ../../../views/html/users/create.tpl:11
+#: ../../../views/html/users/edit.tpl:10 ../../../views/html/users/edit.tpl:11
+#: ../../../views/html/users/login.tpl:8 ../../../views/html/users/login.tpl:9
+msgid "Password"
+msgstr "Passwort"
+
+#: ../../../views/html/users/delete.tpl:2 ../../../views/html/users/user.tpl:5
+msgid "Delete user"
+msgstr "Benutzer löschen"
+
+#: ../../../views/html/users/delete.tpl:4
+#, php-format
+msgid "Should the user “%s” (%s) really be deleted?"
+msgstr "Soll der Benutzer „%s“ (%s) wirklich gelöscht werden?"
+
+#: ../../../views/html/users/edit.tpl:2 ../../../views/html/users/user.tpl:4
+msgid "Edit user"
+msgstr "Benutzer bearbeiten"
+
+#: ../../../views/html/users/index.tpl:3
+msgid "Create new user"
+msgstr "Neuen Benutzer erstellen"
+
+#: ../../../views/html/users/index.tpl:10 ../../../views/html/users/user.tpl:8
+#, php-format
+msgid "registered on %s"
+msgstr "registriert am %s"
+
+#: ../../../views/html/users/user.tpl:18
+msgid "Roles"
+msgstr "Rollen"
#~ msgid "created by %s on %s at %s"
#~ msgstr "erstellt von %s am %s um %s Uhr"
From 3af0e9d5706e3b1e43e74fbe772a596da4d5cf24 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Mon, 17 Feb 2014 02:54:49 +0100
Subject: [PATCH 058/213] implement fields for Characters for Seminaries
(Ticket #23)
---
controllers/CharactersController.inc | 6 ++-
models/SeminarycharacterfieldsModel.inc | 58 +++++++++++++++++++++++++
views/html/characters/character.tpl | 3 ++
3 files changed, 66 insertions(+), 1 deletion(-)
create mode 100644 models/SeminarycharacterfieldsModel.inc
diff --git a/controllers/CharactersController.inc b/controllers/CharactersController.inc
index 27c4edcb..4e65ed40 100644
--- a/controllers/CharactersController.inc
+++ b/controllers/CharactersController.inc
@@ -33,7 +33,7 @@
*
* @var array
*/
- public $models = array('seminaries', 'characters', 'users', 'charactergroups');
+ public $models = array('seminaries', 'characters', 'users', 'charactergroups', 'seminarycharacterfields');
@@ -78,6 +78,9 @@
// Get Character
$character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
+ // Get Seminarycharacterfields
+ $characterfields = $this->Seminarycharacterfields->getFieldsForCharacter($character['id']);
+
// Get User
$user = $this->Users->getUserById($character['user_id']);
@@ -88,6 +91,7 @@
// Pass data to view
$this->set('seminary', $seminary);
$this->set('character', $character);
+ $this->set('characterfields', $characterfields);
$this->set('user', $user);
$this->set('groups', $groups);
}
diff --git a/models/SeminarycharacterfieldsModel.inc b/models/SeminarycharacterfieldsModel.inc
new file mode 100644
index 00000000..c881df2c
--- /dev/null
+++ b/models/SeminarycharacterfieldsModel.inc
@@ -0,0 +1,58 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with the Seminarycharacterfields-tables.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminarycharacterfieldsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new SeminarycharacterfieldsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Seminary Character fields of a Character.
+ *
+ * @param int $characterId ID of the Character
+ * @return array Seminary Character fields
+ */
+ public function getFieldsForCharacter($characterId)
+ {
+ return $this->db->query(
+ 'SELECT seminarycharacterfields.title, characters_seminarycharacterfields.value '.
+ 'FROM characters_seminarycharacterfields '.
+ 'LEFT JOIN seminarycharacterfields ON seminarycharacterfields.id = characters_seminarycharacterfields.seminarycharacterfield_id '.
+ 'LEFT JOIN seminarycharacterfieldtypes ON seminarycharacterfieldtypes.id = seminarycharacterfields.seminarycharacterfieldtype_id '.
+ 'WHERE characters_seminarycharacterfields.character_id = ?',
+ 'i',
+ $characterId
+ );
+ }
+
+ }
+
+?>
diff --git a/views/html/characters/character.tpl b/views/html/characters/character.tpl
index aa8bdd78..dcc9cea3 100644
--- a/views/html/characters/character.tpl
+++ b/views/html/characters/character.tpl
@@ -6,6 +6,9 @@
XPs: =$character['xps']?>
=_('User')?>: =$user['username']?>
+
+ =$field['title']?>: =$field['value']?>
+
From f1b5affa799c4bdada42155bf90a14fdeaff24d0 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 23 Feb 2014 14:45:07 +0100
Subject: [PATCH 059/213] implementing abstract classes for QuesttypeAgents
(-Agent, -Controller, -Model and -View)
---
app/QuesttypeAgent.inc | 231 +++++++++++++++++
app/QuesttypeController.inc | 235 ++++++++++++++++++
app/QuesttypeModel.inc | 154 ++++++++++++
app/QuesttypeView.inc | 76 ++++++
.../QuesttypeAgentNotFoundException.inc | 77 ++++++
.../QuesttypeAgentNotValidException.inc | 77 ++++++
.../QuesttypeControllerNotFoundException.inc | 77 ++++++
.../QuesttypeControllerNotValidException.inc | 77 ++++++
.../QuesttypeModelNotFoundException.inc | 77 ++++++
.../QuesttypeModelNotValidException.inc | 77 ++++++
configs/AppConfig.inc | 3 +-
core/Controller.inc | 6 +-
core/View.inc | 4 +-
13 files changed, 1165 insertions(+), 6 deletions(-)
create mode 100644 app/QuesttypeAgent.inc
create mode 100644 app/QuesttypeController.inc
create mode 100644 app/QuesttypeModel.inc
create mode 100644 app/QuesttypeView.inc
create mode 100644 app/exceptions/QuesttypeAgentNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeAgentNotValidException.inc
create mode 100644 app/exceptions/QuesttypeControllerNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeControllerNotValidException.inc
create mode 100644 app/exceptions/QuesttypeModelNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeModelNotValidException.inc
diff --git a/app/QuesttypeAgent.inc b/app/QuesttypeAgent.inc
new file mode 100644
index 00000000..9f104be1
--- /dev/null
+++ b/app/QuesttypeAgent.inc
@@ -0,0 +1,231 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeAgent.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeAgent extends \nre\agents\BottomlevelAgent
+ {
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+
+
+
+
+ /**
+ * Load a QuesttypeAgent.
+ *
+ * @static
+ * @throws QuesttypeAgentNotFoundException
+ * @throws QuesttypeAgentNotValidException
+ * @param string $questtypeName Name of the QuesttypeAgent to load
+ */
+ public static function load($questtypeName)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ try {
+ // Load class
+ static::loadClass($questtypeName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeAgentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeAgentNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeAgent (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ * @param string $questtypeName Name of the QuesttypeAgent to instantiate
+ * @param Request $request Current request
+ * @param Response $respone Current respone
+ * @param Logger $log Log-system
+ */
+ public static function factory($questtypeName, \nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ // Construct and return Questmodule
+ return new $className($request, $response, $log);
+ }
+
+
+ /**
+ * Determine the Agent-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Agent-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'agent');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeAgent.
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeAgent to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeAgent-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeAgent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+
+
+ // Call parent constructor
+ parent::__construct($request, $response, $log);
+ }
+
+
+
+
+ /**
+ * Load the Controller of this Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ */
+ protected function loadController()
+ {
+ // Determine Controller name
+ $controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
+
+ // Determine ToplevelAgent
+ $toplevelAgentName = $this->response->getParam(0);
+ if(is_null($toplevelAgentName)) {
+ $toplevelAgentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($toplevelAgentName);
+ }
+
+ // Determine Action
+ $action = \nre\configs\CoreConfig::$defaults['action'];
+
+
+ // Load Controller
+ \hhu\z\QuesttypeController::load($controllerName);
+
+ // Construct Controller
+ $this->controller = QuesttypeController::factory($controllerName, $toplevelAgentName, $action, $this);
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
new file mode 100644
index 00000000..5c7b9e04
--- /dev/null
+++ b/app/QuesttypeController.inc
@@ -0,0 +1,235 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeController.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Load a QuesttypeController.
+ *
+ * @static
+ * @throws QuesttypeControllerNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @param string $controllerName Name of the QuesttypeController to load
+ */
+ public static function load($controllerName)
+ {
+ // Determine full classname
+ $className = self::getClassName($controllerName);
+
+ try {
+ // Load class
+ static::loadClass($controllerName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeControllerNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeControllerNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeController (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws ViewNotFoundException
+ * @param string $controllerName Name of the QuesttypeController 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 Controller-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Controller-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'controller');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeController
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeController to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeController-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new application Controller.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of the current Layout
+ * @param string $action Current Action
+ * @param Agent $agent Corresponding Agent
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+ }
+
+
+
+
+ /**
+ * Load the Models of this Controller.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ protected function loadModels()
+ {
+ // Load default models
+ parent::loadModels();
+
+ // Load QuesttypeModel
+ $this->loadModel();
+ }
+
+
+ /**
+ * Load the Model of the Questtype.
+ *
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ private function loadModel()
+ {
+ // Determine Model
+ $model = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class($this))));
+
+ // Load class
+ QuesttypeModel::load($model);
+
+ // Construct Model
+ $modelName = ucfirst(strtolower($model));
+ $this->$modelName = QuesttypeModel::factory($model);
+ }
+
+
+ /**
+ * Load the View of this QuesttypeController.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of the current Layout
+ * @param string $action Current Action
+ */
+ protected function loadView($layoutName, $action)
+ {
+ // Check Layout name
+ if(is_null($layoutName)) {
+ return;
+ }
+
+ // Determine controller name
+ $controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
+
+
+ // Load view
+ $this->view = QuesttypeView::loadAndFactory($layoutName, $controllerName, $action);
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeModel.inc b/app/QuesttypeModel.inc
new file mode 100644
index 00000000..d30699fb
--- /dev/null
+++ b/app/QuesttypeModel.inc
@@ -0,0 +1,154 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeModel.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Load a Model.
+ *
+ * @static
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @param string $modelName Name of the QuesttypeModel to load
+ */
+ public static function load($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ try {
+ // Load class
+ static::loadClass($modelName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeModelNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeModelNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeModel (Factory Pattern).
+ *
+ * @static
+ * @param string $questtypeName Name of the QuesttypeModel to instantiate
+ */
+ public static function factory($questtypeName)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ // Construct and return Model
+ return new $className();
+ }
+
+
+ /**
+ * Determine the Model-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Model-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'model');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeModel.
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeModel to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeModel-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeModel.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeView.inc b/app/QuesttypeView.inc
new file mode 100644
index 00000000..8e77ee00
--- /dev/null
+++ b/app/QuesttypeView.inc
@@ -0,0 +1,76 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeView.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeView extends \nre\core\View
+ {
+
+
+
+
+ /**
+ * Load and instantiate the QuesttypeView of a QuesttypeAgent.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ public static function loadAndFactory($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ return new QuesttypeView($layoutName, $agentName, $action, $isToplevel);
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeView.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ protected function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ // Create template filename
+ // LayoutName
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($agentName).DS.strtolower($layoutName).DS;
+
+ // Action
+ $fileName .= strtolower($action);
+
+ // File extension
+ $fileName .= \nre\configs\CoreConfig::getFileExt('views');
+
+
+ // Check template file
+ if(!file_exists($fileName)) {
+ throw new \nre\exceptions\ViewNotFoundException($fileName);
+ }
+
+ // Save filename
+ $this->templateFilename = $fileName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeAgentNotFoundException.inc b/app/exceptions/QuesttypeAgentNotFoundException.inc
new file mode 100644
index 00000000..5f6f4ea9
--- /dev/null
+++ b/app/exceptions/QuesttypeAgentNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeAgent not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeAgentNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 101;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeAgent not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeAgent that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeAgent that was not found.
+ *
+ * @return string Name of the QuesttypeAgent that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeAgentNotValidException.inc b/app/exceptions/QuesttypeAgentNotValidException.inc
new file mode 100644
index 00000000..8fa7237f
--- /dev/null
+++ b/app/exceptions/QuesttypeAgentNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeAgent not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeAgentNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 102;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeAgent not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeAgent
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeAgent.
+ *
+ * @return string Name of the invalid QuesttypeAgent
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeControllerNotFoundException.inc b/app/exceptions/QuesttypeControllerNotFoundException.inc
new file mode 100644
index 00000000..6d3a4a36
--- /dev/null
+++ b/app/exceptions/QuesttypeControllerNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeController not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeControllerNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 103;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeController not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeController that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeController that was not found.
+ *
+ * @return string Name of the QuesttypeController that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeControllerNotValidException.inc b/app/exceptions/QuesttypeControllerNotValidException.inc
new file mode 100644
index 00000000..8c6735b8
--- /dev/null
+++ b/app/exceptions/QuesttypeControllerNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeController not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeControllerNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 104;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeController not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeController
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeController.
+ *
+ * @return string Name of the invalid QuesttypeController
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeModelNotFoundException.inc b/app/exceptions/QuesttypeModelNotFoundException.inc
new file mode 100644
index 00000000..a2aa01c8
--- /dev/null
+++ b/app/exceptions/QuesttypeModelNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeModel not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeModelNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 105;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeModel not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeModel that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeModel that was not found.
+ *
+ * @return string Name of the QuesttypeModel that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeModelNotValidException.inc b/app/exceptions/QuesttypeModelNotValidException.inc
new file mode 100644
index 00000000..4a78beb6
--- /dev/null
+++ b/app/exceptions/QuesttypeModelNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeModel not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeModelNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 106;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeModel not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeModel
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeModel.
+ *
+ * @return string Name of the invalid QuesttypeModel
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
index 8c388dce..5b5a7558 100644
--- a/configs/AppConfig.inc
+++ b/configs/AppConfig.inc
@@ -60,7 +60,8 @@
*/
public static $dirs = array(
'locale' => 'locale',
- 'media' => 'media'
+ 'media' => 'media',
+ 'questtypes' => 'questtypes'
);
diff --git a/core/Controller.inc b/core/Controller.inc
index 55a7675a..c2814e99 100644
--- a/core/Controller.inc
+++ b/core/Controller.inc
@@ -30,7 +30,7 @@
*
* @var View
*/
- private $view = null;
+ protected $view = null;
/**
* Data to pass to the View
*
@@ -348,7 +348,7 @@
* @throws ModelNotValidException
* @throws ModelNotFoundException
*/
- private function loadModels()
+ protected function loadModels()
{
// Determine Models
$explicit = false;
@@ -403,7 +403,7 @@
* @param string $layoutName Name of the current Layout
* @param string $action Current Action
*/
- private function loadView($layoutName, $action)
+ protected function loadView($layoutName, $action)
{
// Check Layout name
if(is_null($layoutName)) {
diff --git a/core/View.inc b/core/View.inc
index 513bd953..546ddb6e 100644
--- a/core/View.inc
+++ b/core/View.inc
@@ -26,7 +26,7 @@
*
* @var string
*/
- private $templateFilename;
+ protected $templateFilename;
@@ -57,7 +57,7 @@
* @param string $action Current Action
* @param bool $isToplevel Agent is a ToplevelAgent
*/
- private function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ protected function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
{
// Create template filename
// LayoutName
From 2923bd8421e9fbeef2c91404e638fdfd28d840ff Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 26 Feb 2014 20:20:38 +0100
Subject: [PATCH 060/213] provide methods to mark Quests as solved and unsolved
for QuesttypeControllers
---
app/QuesttypeController.inc | 73 ++++++++++++++++++++++++++++++++++++-
models/QuesttypesModel.inc | 62 +++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 1 deletion(-)
create mode 100644 models/QuesttypesModel.inc
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
index 5c7b9e04..603626ac 100644
--- a/app/QuesttypeController.inc
+++ b/app/QuesttypeController.inc
@@ -17,8 +17,14 @@
*
* @author Oliver Hanraths
*/
- abstract class QuesttypeController extends \nre\core\Controller
+ abstract class QuesttypeController extends \hhu\z\Controller
{
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroups', 'quests', 'characters');
@@ -230,6 +236,71 @@
$this->view = QuesttypeView::loadAndFactory($layoutName, $controllerName, $action);
}
+
+ /**
+ * Mark the current Quest as solved and redirect to solved page.
+ */
+ protected function setQuestSolved()
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($this->request->getParam(3));
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $this->request->getParam(4));
+
+ // Get Quest
+ $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
+
+ // Sidequest
+ $sidequest = null;
+ if($this->request->getParam(2) == 'sidequest') {
+ $sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $this->request->getParam(6));
+ }
+
+ // Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Set solved
+ $this->Quests->setQuestSolved($quest['id'], $character['id']);
+
+
+ // Redirect
+ $this->redirect($this->linker->link('solved', $sidequest != null ? 6 : 5));
+ }
+
+
+ /**
+ * Mark the current Quest as unsolved and redirect to unsolved
+ * page.
+ */
+ protected function setQuestUnsolved()
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($this->request->getParam(3));
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $this->request->getParam(4));
+
+ // Get Quest
+ $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
+
+ // Sidequest
+ $sidequest = null;
+ if($this->request->getParam(2) == 'sidequest') {
+ $sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $this->request->getParam(6));
+ }
+
+ // Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Set solved
+ $this->Quests->setQuestSolved($quest['id'], $character['id']);
+
+
+ // Redirect
+ $this->redirect($this->linker->link('unsolved', $sidequest != null ? 6 : 5));
+ }
+
}
?>
diff --git a/models/QuesttypesModel.inc b/models/QuesttypesModel.inc
new file mode 100644
index 00000000..3e0ef265
--- /dev/null
+++ b/models/QuesttypesModel.inc
@@ -0,0 +1,62 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Questtypes-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new QuesttypesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get a Questtype by its ID
+ *
+ * @param int $questtypeId ID of Questtype
+ * @return array Questtype data
+ */
+ public function getQuesttypeById($questtypeId)
+ {
+ $data = $this->db->query(
+ 'SELECT title, classname '.
+ 'FROM questtypes '.
+ 'WHERE id = ?',
+ 'i',
+ $questtypeId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questtypeId);
+ }
+
+
+ return $data = $data[0];
+ }
+
+ }
+
+?>
From 1ef9b1d6e64b8e772c12d60cf0085b61975e1ce9 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 26 Feb 2014 20:23:15 +0100
Subject: [PATCH 061/213] integrate loading, running and rendering of
QuesttypeAgent for a Quest
---
controllers/QuestsController.inc | 201 ++++++++++++++++++++++++-------
models/QuestsModel.inc | 34 +++++-
views/html/quests/quest.tpl | 15 ++-
views/html/quests/sidequest.tpl | 15 ++-
4 files changed, 215 insertions(+), 50 deletions(-)
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index b5df177c..1fcd3f56 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -24,7 +24,7 @@
*
* @var array
*/
- public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media');
+ public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes');
/**
* User permissions
*
@@ -51,10 +51,10 @@
* Show a quest and its task.
*
* @throws IdNotFoundException
- * @param string $seminaryUrl URL-Title of a Seminary
- * @param string $questgroupUrl URL-Title of a Questgroup
- * @param string $questUrl URL-Title of a Quest
- * @param string $questtexttypeUrl URL-Title of a Questtexttype
+ * @param string $seminaryUrl URL-Title of Seminary
+ * @param string $questgroupUrl URL-Title of Questgroup
+ * @param string $questUrl URL-Title of Quest
+ * @param string $questtexttypeUrl URL-Title of Questtexttype
* @param int $questtextPos Position of Questtext
*/
public function quest($seminaryUrl, $questgroupUrl, $questUrl, $questtexttypeUrl=null, $questtextPos=1)
@@ -70,15 +70,35 @@
// Get Questtext
$questtext = null;
- $questtexttypes = $this->Questtexts->getQuesttexttypes();
- $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
if(is_null($questtexttypeUrl)) {
$questtexttypeUrl = 'Prolog';
}
- $questtextCount = $this->Questtexts->getQuesttextsCountForQuest($quest['id'], $questtexttypeUrl);
- if($questtextCount > 0)
+ // Quest solved
+ if($questtexttypeUrl == 'solved')
{
- if(in_array($questtexttypeUrl, $questtexttypes))
+ $questtext = array(
+ 'type' => 'solved',
+ 'text' => $quest['right_text']
+ );
+ }
+ // Quest unsolved
+ elseif($questtexttypeUrl == 'unsolved')
+ {
+ $questtext = array(
+ 'type' => 'unsolved',
+ 'text' => $quest['wrong_text']
+ );
+ }
+ // Text
+ else
+ {
+ // Text type
+ $questtexttypes = $this->Questtexts->getQuesttexttypes();
+ $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
+ // Text count
+ $questtextCount = $this->Questtexts->getQuesttextsCountForQuest($quest['id'], $questtexttypeUrl);
+ // Get text
+ if($questtextCount > 0 && in_array($questtexttypeUrl, $questtexttypes))
{
$questtextPos = max(intval($questtextPos), 1);
$questtext = $this->Questtexts->getQuesttextByUrl($quest['id'], $questtexttypeUrl, $questtextPos);
@@ -87,43 +107,49 @@
}
}
- // Show task only for Prologes
- $showTask = false;
- if($questtext['type'] == 'Prolog') {
- $showTask = true;
- }
-
// Media
$questmedia = null;
- if(!is_null($questtext) && !empty($questtext['questsmedia_id'])) {
+ if(!is_null($questtext) && array_key_exists('questmedia_id', $questtext) && !empty($questtext['questsmedia_id'])) {
$questmedia = $this->Media->getMediaById($questtext['questsmedia_id']);
}
elseif(!is_null($quest['questsmedia_id'])) {
$questmedia = $this->Media->getMediaById($quest['questsmedia_id']);
}
-
+
+ // Task
+ $task = null;
+ if($questtext['type'] == 'Prolog')
+ {
+ // Questtype
+ $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
+
+ // Task
+ $task = $this->runAndRenderTask($questtype['classname']);
+ }
+
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('questtext', $questtext);
$this->set('quest', $quest);
- $this->set('showtask', $showTask);
+ $this->set('task', $task);
$this->set('media', $questmedia);
}
+
/**
* Action: sidequest.
*
* Show a sidequest and its task.
*
* @throws IdNotFoundException
- * @param string $seminaryUrl URL-Title of a Seminary
- * @param string $questgroupUrl URL-Title of a Questgroup
- * @param string $questUrl URL-Title of a Quest
- * @param string $sidequestUrl URL-Title of a Sidequest
- * @param string $questtexttypeUrl URL-Title of a Questtexttype
- * @param int $questtextPos Position of Questtext
+ * @param string $seminaryUrl URL-Title of Seminary
+ * @param string $questgroupUrl URL-Title of Questgroup
+ * @param string $questUrl URL-Title of Quest
+ * @param string $sidequestUrl URL-Title of Sidequest
+ * @param string $sidequesttexttypeUrl URL-Title of Sidequesttexttype
+ * @param int $sidequesttextPos Position of Sidequesttext
*/
public function sidequest($seminaryUrl, $questgroupUrl, $questUrl, $sidequestUrl, $sidequesttexttypeUrl=null, $sidequesttextPos=1)
{
@@ -144,26 +170,43 @@
// Get Sidequesttext
$sidequesttext = null;
- $questtexttypes = $this->Questtexts->getQuesttexttypes();
- $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
if(is_null($sidequesttexttypeUrl)) {
$sidequesttexttypeUrl = 'Prolog';
}
- $sidequesttextCount = $this->Questtexts->getQuesttextsCountForSidequest($sidequest['id'], $sidequesttexttypeUrl);
- if($sidequesttextCount > 0)
+ // Quest solved
+ if($sidequesttexttypeUrl == 'solved')
{
- if(in_array($sidequesttexttypeUrl, $questtexttypes))
- {
- $sidequesttextPos = max(intval($sidequesttextPos), 1);
- $sidequesttext = $this->Questtexts->getSidequesttextByUrl($sidequest['id'], $sidequesttexttypeUrl, $sidequesttextPos);
- $sidequesttext['count'] = $sidequesttextCount;
- }
+ $sidequesttext = array(
+ 'type' => 'solved',
+ 'text' => $quest['right_text']
+ );
}
-
- // Show task only for Prologes
- $showTask = false;
- if($sidequesttext['type'] == 'Prolog') {
- $showTask = true;
+ // Quest unsolved
+ elseif($sidequesttexttypeUrl == 'unsolved')
+ {
+ $sidequesttext = array(
+ 'type' => 'unsolved',
+ 'text' => $quest['wrong_text']
+ );
+ }
+ // Text
+ else
+ {
+ // Text type
+ $questtexttypes = $this->Questtexts->getQuesttexttypes();
+ $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
+ // Text count
+ $sidequesttextCount = $this->Questtexts->getQuesttextsCountForSidequest($sidequest['id'], $sidequesttexttypeUrl);
+ // Get text
+ if($sidequesttextCount > 0 && in_array($sidequesttexttypeUrl, $questtexttypes))
+ {
+ if(in_array($sidequesttexttypeUrl, $questtexttypes))
+ {
+ $sidequesttextPos = max(intval($sidequesttextPos), 1);
+ $sidequesttext = $this->Questtexts->getSidequesttextByUrl($sidequest['id'], $sidequesttexttypeUrl, $sidequesttextPos);
+ $sidequesttext['count'] = $sidequesttextCount;
+ }
+ }
}
// Media
@@ -175,18 +218,92 @@
$sidequestmedia = $this->Media->getMediaById($sidequest['questsmedia_id']);
}
+ // Task
+ $task = null;
+ if($sidequesttext['type'] == 'Prolog')
+ {
+ // Questtype
+ $questtype = $this->Questtypes->getQuesttypeById($sidequest['questtype_id']);
+
+ // Task
+ $task = $this->runAndRenderTask($questtype['classname']);
+ }
+
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('sidequesttext', $sidequesttext);
$this->set('quest', $quest);
- $this->set('questtext', $questtext);
$this->set('sidequest', $sidequest);
- $this->set('showtask', $showTask);
+ $this->set('task', $task);
$this->set('media', $sidequestmedia);
}
+
+
+
+ /**
+ * Load, construct, run and render the Agent for the given
+ * classname of a Questtype and return ist output.
+ *
+ * @param string $questtypeClassname Classname of Questtype to run and render
+ * @return string Rendered output of Questtype-Agent
+ */
+ private function runAndRenderTask($questtypeClassname)
+ {
+ $task = null;
+ $questtypeAgent = null;
+ try {
+ // Load Agent
+ \hhu\z\QuesttypeAgent::load($questtypeClassname);
+ // Construct Agent
+ $questtypeAgent = \hhu\z\QuesttypeAgent::factory($questtypeClassname, $this->request, $this->response);
+
+ // Generate response
+ $response = clone $this->response;
+ $response->clearParams(1);
+ $response->addParams(
+ null,
+ \nre\configs\CoreConfig::$defaults['action']
+ );
+ // Run Agent
+ $questtypeAgent->run($this->request, $response);
+
+ // Render output
+ $task = $questtypeAgent->render();
+
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+
+
+ // Return rendered output
+ return $task;
+ }
+
}
?>
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
index 0873c6cd..d8baed5f 100644
--- a/models/QuestsModel.inc
+++ b/models/QuestsModel.inc
@@ -64,7 +64,7 @@
public function getQuestByUrl($seminaryId, $questgroupId, $questUrl)
{
$data = $this->db->query(
- 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.questsmedia_id '.
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id '.
'FROM quests '.
'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
@@ -94,7 +94,7 @@
public function getSidequestByUrl($seminaryId, $questgroupId, $questId, $sidequestUrl)
{
$data = $this->db->query(
- 'SELECT sidequests.id, sidequests.questtype_id, sidequests.title, sidequests.url, sidequests.xps, sidequests.task, sidequests.questsmedia_id '.
+ 'SELECT sidequests.id, sidequests.questtype_id, sidequests.title, sidequests.url, sidequests.xps, sidequests.task, quests.right_text, quests.wrong_text, sidequests.questsmedia_id '.
'FROM sidequests '.
'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
'LEFT JOIN quests ON quests.id = questtexts.quest_id '.
@@ -153,6 +153,36 @@
);
}
+
+ public function setQuestSolved($questId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO quests_characters '.
+ '(quest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $questId,
+ $characterId,
+ 0
+ );
+ }
+
+
+ public function setQuestUnsolved($questId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO quests_characters '.
+ '(quest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $questId,
+ $characterId,
+ -1
+ );
+ }
+
}
?>
diff --git a/views/html/quests/quest.tpl b/views/html/quests/quest.tpl
index 9a8b7376..bfbe8a9d 100644
--- a/views/html/quests/quest.tpl
+++ b/views/html/quests/quest.tpl
@@ -9,10 +9,16 @@
+
+ =_('solved')?>
+
+ =_('unsolved')?>
+
=$questtext['type']?>
+
=\hhu\z\Utils::t($questtext['text'])?>
-
+
-
+
=$questtext['out_text']?>
+
1) : ?><
=$questtext['pos']?>/=$questtext['count']?>
>
+
-
+
=_('Task')?>
=\hhu\z\Utils::t($quest['task'])?>
+ =$task?>
diff --git a/views/html/quests/sidequest.tpl b/views/html/quests/sidequest.tpl
index 1cb888ce..3067b914 100644
--- a/views/html/quests/sidequest.tpl
+++ b/views/html/quests/sidequest.tpl
@@ -11,11 +11,17 @@
+
+ =_('solved')?>
+
+ =_('unsolved')?>
+
=$sidequesttext['type']?>
+
=\hhu\z\Utils::t($sidequesttext['text'])?>
-
-
+
+
-
+
=_('Task')?>
=\hhu\z\Utils::t($sidequest['task'])?>
+ =$task?>
From 256558e048ceb1a4ca7d36abd811188dd8f4f2f6 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 26 Feb 2014 20:32:02 +0100
Subject: [PATCH 062/213] implement dummy-QuesttypeAgent for testing basic
QuesttypeAgent-functionality
---
questtypes/dummy/DummyQuesttypeAgent.inc | 24 ++++++++++
questtypes/dummy/DummyQuesttypeController.inc | 48 +++++++++++++++++++
questtypes/dummy/DummyQuesttypeModel.inc | 25 ++++++++++
questtypes/dummy/html/index.tpl | 4 ++
4 files changed, 101 insertions(+)
create mode 100644 questtypes/dummy/DummyQuesttypeAgent.inc
create mode 100644 questtypes/dummy/DummyQuesttypeController.inc
create mode 100644 questtypes/dummy/DummyQuesttypeModel.inc
create mode 100644 questtypes/dummy/html/index.tpl
diff --git a/questtypes/dummy/DummyQuesttypeAgent.inc b/questtypes/dummy/DummyQuesttypeAgent.inc
new file mode 100644
index 00000000..f0de5cb1
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Dummy-QuesttypeAgent for testing basic QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/dummy/DummyQuesttypeController.inc b/questtypes/dummy/DummyQuesttypeController.inc
new file mode 100644
index 00000000..0f3012fa
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeController.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the Dummy-QuesttypeAgent for testing basic
+ * QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Right answer (dummy)
+ if(!is_null($this->request->getPostParam('submit'))) {
+ $this->setQuestSolved();
+ }
+ // Wrong answer (dummy)
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+ }
+
+ }
+
+?>
diff --git a/questtypes/dummy/DummyQuesttypeModel.inc b/questtypes/dummy/DummyQuesttypeModel.inc
new file mode 100644
index 00000000..c4aadf3e
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeModel.inc
@@ -0,0 +1,25 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the Dummy-QuesttypeAgent for testing basic
+ * QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+ }
+
+?>
diff --git a/questtypes/dummy/html/index.tpl b/questtypes/dummy/html/index.tpl
new file mode 100644
index 00000000..f482a07b
--- /dev/null
+++ b/questtypes/dummy/html/index.tpl
@@ -0,0 +1,4 @@
+
+
+
+
From 34e63718bd3a993999a82a789fd31a1690511b72 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 26 Feb 2014 21:00:22 +0100
Subject: [PATCH 063/213] correct Questtext for Sidequests
---
controllers/QuestsController.inc | 1 +
1 file changed, 1 insertion(+)
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index 1fcd3f56..87d800d4 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -233,6 +233,7 @@
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
+ $this->set('questtext', $questtext);
$this->set('sidequesttext', $sidequesttext);
$this->set('quest', $quest);
$this->set('sidequest', $sidequest);
From 48f796a0c796d208878ad2849c9bb4b58939abd4 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 28 Feb 2014 19:55:09 +0100
Subject: [PATCH 064/213] change solved/unsolved status of a Quest to
GET-parameter
---
app/QuesttypeController.inc | 4 +-
controllers/QuestsController.inc | 115 +++++++++++++++----------------
models/QuestsModel.inc | 33 +++++++++
views/html/quests/quest.tpl | 27 ++++++--
views/html/quests/sidequest.tpl | 16 +++--
5 files changed, 126 insertions(+), 69 deletions(-)
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
index 603626ac..89913fb5 100644
--- a/app/QuesttypeController.inc
+++ b/app/QuesttypeController.inc
@@ -265,7 +265,7 @@
// Redirect
- $this->redirect($this->linker->link('solved', $sidequest != null ? 6 : 5));
+ $this->redirect($this->linker->link('Epilog', $sidequest != null ? 6 : 5, true, array('status'=>'solved')));
}
@@ -298,7 +298,7 @@
// Redirect
- $this->redirect($this->linker->link('unsolved', $sidequest != null ? 6 : 5));
+ $this->redirect($this->linker->link('Prolog', $sidequest != null ? 6 : 5, true, array('status'=>'unsolved')));
}
}
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index 87d800d4..fd64d771 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -73,37 +73,30 @@
if(is_null($questtexttypeUrl)) {
$questtexttypeUrl = 'Prolog';
}
- // Quest solved
- if($questtexttypeUrl == 'solved')
+ $questtexttypes = $this->Questtexts->getQuesttexttypes();
+ $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
+ $questtextCount = $this->Questtexts->getQuesttextsCountForQuest($quest['id'], $questtexttypeUrl);
+ if($questtextCount > 0 && in_array($questtexttypeUrl, $questtexttypes))
{
- $questtext = array(
- 'type' => 'solved',
- 'text' => $quest['right_text']
- );
+ $questtextPos = max(intval($questtextPos), 1);
+ $questtext = $this->Questtexts->getQuesttextByUrl($quest['id'], $questtexttypeUrl, $questtextPos);
+ $questtext['count'] = $questtextCount;
+ $questtext['sidequests'] = $this->Quests->getSidequestsForQuesttext($questtext['id']);
}
- // Quest unsolved
- elseif($questtexttypeUrl == 'unsolved')
+
+ // Quest status
+ $questStatus = $this->request->getGetParam('status');
+ $questStatusText = null;
+ if(!is_null($questStatus))
{
- $questtext = array(
- 'type' => 'unsolved',
- 'text' => $quest['wrong_text']
- );
- }
- // Text
- else
- {
- // Text type
- $questtexttypes = $this->Questtexts->getQuesttexttypes();
- $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
- // Text count
- $questtextCount = $this->Questtexts->getQuesttextsCountForQuest($quest['id'], $questtexttypeUrl);
- // Get text
- if($questtextCount > 0 && in_array($questtexttypeUrl, $questtexttypes))
+ switch($questStatus)
{
- $questtextPos = max(intval($questtextPos), 1);
- $questtext = $this->Questtexts->getQuesttextByUrl($quest['id'], $questtexttypeUrl, $questtextPos);
- $questtext['count'] = $questtextCount;
- $questtext['sidequests'] = $this->Quests->getSidequestsForQuesttext($questtext['id']);
+ case 'solved':
+ $questStatusText = $quest['right_text'];
+ break;
+ case 'unsolved':
+ $questStatusText = $quest['wrong_text'];
+ break;
}
}
@@ -127,12 +120,21 @@
$task = $this->runAndRenderTask($questtype['classname']);
}
+ // Next Quest
+ $nextQuests = null;
+ if($questtexttypeUrl == 'Epilog') {
+ $nextQuests = $this->Quests->getNextQuests($quest['id']);
+ }
+
// Pass data to view
$this->set('seminary', $seminary);
$this->set('questgroup', $questgroup);
$this->set('questtext', $questtext);
$this->set('quest', $quest);
+ $this->set('queststatus', $questStatus);
+ $this->set('queststatustext', $questStatusText);
+ $this->set('nextquests', $nextQuests);
$this->set('task', $task);
$this->set('media', $questmedia);
}
@@ -173,39 +175,32 @@
if(is_null($sidequesttexttypeUrl)) {
$sidequesttexttypeUrl = 'Prolog';
}
- // Quest solved
- if($sidequesttexttypeUrl == 'solved')
+ $questtexttypes = $this->Questtexts->getQuesttexttypes();
+ $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
+ $sidequesttextCount = $this->Questtexts->getQuesttextsCountForSidequest($sidequest['id'], $sidequesttexttypeUrl);
+ if($sidequesttextCount > 0 && in_array($sidequesttexttypeUrl, $questtexttypes))
{
- $sidequesttext = array(
- 'type' => 'solved',
- 'text' => $quest['right_text']
- );
- }
- // Quest unsolved
- elseif($sidequesttexttypeUrl == 'unsolved')
- {
- $sidequesttext = array(
- 'type' => 'unsolved',
- 'text' => $quest['wrong_text']
- );
- }
- // Text
- else
- {
- // Text type
- $questtexttypes = $this->Questtexts->getQuesttexttypes();
- $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
- // Text count
- $sidequesttextCount = $this->Questtexts->getQuesttextsCountForSidequest($sidequest['id'], $sidequesttexttypeUrl);
- // Get text
- if($sidequesttextCount > 0 && in_array($sidequesttexttypeUrl, $questtexttypes))
+ if(in_array($sidequesttexttypeUrl, $questtexttypes))
{
- if(in_array($sidequesttexttypeUrl, $questtexttypes))
- {
- $sidequesttextPos = max(intval($sidequesttextPos), 1);
- $sidequesttext = $this->Questtexts->getSidequesttextByUrl($sidequest['id'], $sidequesttexttypeUrl, $sidequesttextPos);
- $sidequesttext['count'] = $sidequesttextCount;
- }
+ $sidequesttextPos = max(intval($sidequesttextPos), 1);
+ $sidequesttext = $this->Questtexts->getSidequesttextByUrl($sidequest['id'], $sidequesttexttypeUrl, $sidequesttextPos);
+ $sidequesttext['count'] = $sidequesttextCount;
+ }
+ }
+
+ // Sidequest status
+ $sidequestStatus = $this->request->getGetParam('status');
+ $sidequestStatusText = null;
+ if(!is_null($sidequestStatus))
+ {
+ switch($sidequestStatus)
+ {
+ case 'solved':
+ $sidequestStatusText = $sidequest['right_text'];
+ break;
+ case 'unsolved':
+ $sidequestStatusText = $sidequest['wrong_text'];
+ break;
}
}
@@ -220,7 +215,7 @@
// Task
$task = null;
- if($sidequesttext['type'] == 'Prolog')
+ if(!is_null($sidequesttext) && $sidequesttext['type'] == 'Prolog')
{
// Questtype
$questtype = $this->Questtypes->getQuesttypeById($sidequest['questtype_id']);
@@ -237,6 +232,8 @@
$this->set('sidequesttext', $sidequesttext);
$this->set('quest', $quest);
$this->set('sidequest', $sidequest);
+ $this->set('sidequeststatus', $sidequestStatus);
+ $this->set('sidequeststatustext', $sidequestStatusText);
$this->set('task', $task);
$this->set('media', $sidequestmedia);
}
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
index d8baed5f..4ac41986 100644
--- a/models/QuestsModel.inc
+++ b/models/QuestsModel.inc
@@ -154,6 +154,33 @@
}
+ /**
+ * Get Quests that follow-up a Quest.
+ *
+ * @param int $questId ID of Quest to get next Quests of
+ * @return array Quests data
+ */
+ public function getNextQuests($questId)
+ {
+ return $this->db->query(
+ 'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
+ 'FROM quests_previousquests '.
+ 'LEFT JOIN quests ON quests.id = quests_previousquests.quest_id '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE quests_previousquests.previous_quest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Mark a Quest as solved for a Character.
+ *
+ * @param int $questId ID of Quest to mark as solved
+ * @param int $characterId ID of Character that solved the Quest
+ */
public function setQuestSolved($questId, $characterId)
{
$this->db->query(
@@ -169,6 +196,12 @@
}
+ /**
+ * Mark a Quest as unsolved for a Character.
+ *
+ * @param int $questId ID of Quest to mark as unsolved
+ * @param int $characterId ID of Character that unsolved the Quest
+ */
public function setQuestUnsolved($questId, $characterId)
{
$this->db->query(
diff --git a/views/html/quests/quest.tpl b/views/html/quests/quest.tpl
index bfbe8a9d..2c919a3d 100644
--- a/views/html/quests/quest.tpl
+++ b/views/html/quests/quest.tpl
@@ -8,14 +8,21 @@
+
+
-
+
=_('solved')?>
-
+
=_('unsolved')?>
-
- =$questtext['type']?>
+ =\hhu\z\Utils::t($queststatustext)?>
+
+
+
+
+
+ =$questtext['type']?>
=\hhu\z\Utils::t($questtext['text'])?>
@@ -39,6 +46,18 @@
>
+
+
+
+
+ =_('Next Quests')?>
+
+
+
diff --git a/views/html/quests/sidequest.tpl b/views/html/quests/sidequest.tpl
index 3067b914..191648d1 100644
--- a/views/html/quests/sidequest.tpl
+++ b/views/html/quests/sidequest.tpl
@@ -10,14 +10,21 @@
+
+
-
+
=_('solved')?>
-
+
=_('unsolved')?>
-
- =$sidequesttext['type']?>
+ =\hhu\z\Utils::t($sidequeststatustext)?>
+
+
+
+
+
+ =$sidequesttext['type']?>
=\hhu\z\Utils::t($sidequesttext['text'])?>
@@ -37,6 +44,7 @@
>
+
From e7227fe2c9ce5f5c2e9e0e079a1eb67d342d9cd4 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 28 Feb 2014 19:55:24 +0100
Subject: [PATCH 065/213] update translations
---
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 2519 -> 2585 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 20 +++++++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index 09213b4bc7d8d63e6ef8815628bcb22d800dd269..77e8b492bff97ab2c588f07f110cfb874d724ab4 100644
GIT binary patch
delta 823
zcmX}qKS*0q6vy$C#3cSt$s1
zO0JJSvsS$DbK^(_%${HxV|b3a_!o=u79$wV%2o1=iygHeie-LhHaX>f1{Kz1Z&_
z45JE+y7?*8&ZkjLnL`zv$EUd9##^Y4?7DFZ)wvT?!C!9v4{H4zT=Qu6KLRB#hBGbR
zK<#`VOE8V)c!_G|e~e;~Rn)l{>J!wUHV{W`umiPjH|o7!)TbFiO4#AyKjAT<4a_0`
zCtF5NTjf@P8*cm!OBsJhE%Y1JiEH=#7F9URuOPHYZgS86%2$_+2447Tcisfv`6J__
viT4BjHaU_BlE=a4*-gz=O${yaXUY6f)#G3%9$F6+4GtuZzKl{t&du34ol*u;&a_*Q#USI$sDwE;zlI^=
zUFRWc-6`te3+FXz-yL@0BgXI-d997bb>z2BI@&l!qlpPrf}|Typ>95lDoO^GZ~>#3
zb@4i?BHJ!LK~?S?b?!YLP~8VNo-U%IEtil&mr9M$5|3)SB
zb6Z`g0hO=?wJ(PHDTa`oHi23uLJA77EX
zScEd^;!)JPZe+^(P!}I{aT0ZbRM>`%|BYoB;I&1XMqG077Ss-uzEsI27+`jV1aMz4^gl>wnO9H5WYc{Q)tmLk0i<
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
index 086c0741..45c97262 100644
--- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
-"POT-Creation-Date: 2014-02-17 02:28+0100\n"
-"PO-Revision-Date: 2014-02-17 02:29+0100\n"
+"POT-Creation-Date: 2014-02-26 20:45+0100\n"
+"PO-Revision-Date: 2014-02-26 20:45+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -39,7 +39,7 @@ msgstr "Kurse"
#: ../../../views/html/charactergroups/group.tpl:3
#: ../../../views/html/charactergroups/groupsgroup.tpl:3
#: ../../../views/html/charactergroups/index.tpl:3
-#: ../../../views/html/characters/character.tpl:13
+#: ../../../views/html/characters/character.tpl:16
#: ../../../views/html/seminaries/seminary.tpl:9
msgid "Character Groups"
msgstr "Charaktergruppen"
@@ -114,8 +114,18 @@ msgstr "Logout"
msgid "containing optional Quests"
msgstr "Enthaltene optionale Quests"
-#: ../../../views/html/quests/quest.tpl:37
-#: ../../../views/html/quests/sidequest.tpl:35
+#: ../../../views/html/quests/quest.tpl:13
+#: ../../../views/html/quests/sidequest.tpl:15
+msgid "solved"
+msgstr "gelöst"
+
+#: ../../../views/html/quests/quest.tpl:15
+#: ../../../views/html/quests/sidequest.tpl:17
+msgid "unsolved"
+msgstr "ungelöst"
+
+#: ../../../views/html/quests/quest.tpl:45
+#: ../../../views/html/quests/sidequest.tpl:43
msgid "Task"
msgstr "Aufgabe"
From 351db837f87c3dc668d701be3f370d24cc756bad Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 28 Feb 2014 20:53:48 +0100
Subject: [PATCH 066/213] show xplevel for characters
---
models/CharactersModel.inc | 8 ++++----
views/html/characters/character.tpl | 2 +-
views/html/characters/index.tpl | 2 +-
views/html/html.tpl | 2 +-
views/html/users/user.tpl | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/models/CharactersModel.inc b/models/CharactersModel.inc
index 2bbe7744..c2899d8e 100644
--- a/models/CharactersModel.inc
+++ b/models/CharactersModel.inc
@@ -43,7 +43,7 @@
public function getCharactersForUser($userId)
{
return $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
@@ -63,7 +63,7 @@
public function getCharactersForSeminary($seminaryId)
{
return $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
@@ -105,7 +105,7 @@
public function getCharacterForUserAndSeminary($userId, $seminaryId)
{
$data = $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'WHERE characters.user_id = ? AND charactertypes.seminary_id = ?',
@@ -132,7 +132,7 @@
public function getCharacterByUrl($seminaryId, $characterUrl)
{
$data = $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
'WHERE charactertypes.seminary_id = ? AND characters.url = ?',
diff --git a/views/html/characters/character.tpl b/views/html/characters/character.tpl
index dcc9cea3..b2130746 100644
--- a/views/html/characters/character.tpl
+++ b/views/html/characters/character.tpl
@@ -4,7 +4,7 @@
- XPs: =$character['xps']?>
+ XPs: =$character['xps']?> (=$character['xplevel']?>)
=_('User')?>: =$user['username']?>
=$field['title']?>: =$field['value']?>
diff --git a/views/html/characters/index.tpl b/views/html/characters/index.tpl
index 362d60c1..f16261cb 100644
--- a/views/html/characters/index.tpl
+++ b/views/html/characters/index.tpl
@@ -3,6 +3,6 @@
diff --git a/views/html/html.tpl b/views/html/html.tpl
index ad8f4648..ab275bdf 100644
--- a/views/html/html.tpl
+++ b/views/html/html.tpl
@@ -18,7 +18,7 @@
diff --git a/views/html/users/user.tpl b/views/html/users/user.tpl
index 9be97544..506fdf94 100644
--- a/views/html/users/user.tpl
+++ b/views/html/users/user.tpl
@@ -11,7 +11,7 @@
=_('Characters')?>
From b6ea1fafae147b5c4ec0ad541474cd06274f09ff Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 03:03:32 +0100
Subject: [PATCH 067/213] correct typo by marking Quest as unsolved
---
app/QuesttypeController.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
index 89913fb5..132a25e5 100644
--- a/app/QuesttypeController.inc
+++ b/app/QuesttypeController.inc
@@ -294,7 +294,7 @@
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Set solved
- $this->Quests->setQuestSolved($quest['id'], $character['id']);
+ $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
// Redirect
From 42a7e9303c443ca1498341f2ff335ca7465da8fd Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 03:16:02 +0100
Subject: [PATCH 068/213] implement permissions for Questgroups, Quests and
Sidequests
---
controllers/QuestgroupsController.inc | 33 +++++-
controllers/QuestsController.inc | 82 ++++++++++++-
controllers/SeminariesController.inc | 12 +-
models/QuestgroupsModel.inc | 164 ++++++++++++++++++++++++++
models/QuestsModel.inc | 46 +++++++-
views/html/questgroups/questgroup.tpl | 17 ++-
views/html/quests/quest.tpl | 12 +-
views/html/seminaries/seminary.tpl | 8 +-
8 files changed, 355 insertions(+), 19 deletions(-)
diff --git a/controllers/QuestgroupsController.inc b/controllers/QuestgroupsController.inc
index a0639592..1e7c2a29 100644
--- a/controllers/QuestgroupsController.inc
+++ b/controllers/QuestgroupsController.inc
@@ -65,10 +65,28 @@
// Get Questgrouphierarchy
$questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyById($questgroup['questgroupshierarchy_id']);
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Check permission
+ $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
+ if(!is_null($previousQuestgroup)) {
+ if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+
// Get child Questgroupshierarchy
$childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($questgroupshierarchy['id']);
- foreach($childQuestgroupshierarchy as &$hierarchy) {
+ foreach($childQuestgroupshierarchy as &$hierarchy)
+ {
+ // Get Questgroups
$hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id'], $questgroup['id']);
+
+ // Check permission of Questgroups
+ for($i=1; $iQuestgroups->hasCharacterSolvedQuestgroup($hierarchy['questgroups'][$i-1]['id'], $character['id']);
+ }
}
// Get texts
@@ -79,10 +97,15 @@
if(count($childQuestgroupshierarchy) == 0)
{
$quests = $this->Quests->getQuestsForQuestgroup($questgroup['id']);
-
- // Attach sidequests
- foreach($quests as &$quest) {
- $quest['sidequests'] = $this->Quests->getSidequestsForQuest($quest['id']);
+ for($i=0; $i 0) {
+ $quests[$i]['access'] = $this->Quests->hasCharacterSolvedQuest($quests[$i-1]['id'], $character['id']);
+ }
+
+ // Attach sidequests
+ $quests[$i]['sidequests'] = $this->Quests->getSidequestsForQuest($quests[$i]['id']);
}
}
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index fd64d771..e6e7ce54 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -24,7 +24,7 @@
*
* @var array
*/
- public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes');
+ public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes', 'questgroupshierarchy');
/**
* User permissions
*
@@ -68,6 +68,35 @@
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Check permissions
+ $previousQuests = $this->Quests->getPreviousQuests($quest['id']);
+ if(count($previousQuests) == 0)
+ {
+ // Previous Questgroup
+ $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
+ if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+ else
+ {
+ // Previous Quests
+ $solved = false;
+ foreach($previousQuests as &$previousQuest)
+ {
+ if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
+ $solved = true;
+ break;
+ }
+ }
+ if(!$solved) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+
// Get Questtext
$questtext = null;
if(is_null($questtexttypeUrl)) {
@@ -111,7 +140,7 @@
// Task
$task = null;
- if($questtext['type'] == 'Prolog')
+ if($questtexttypeUrl == 'Prolog')
{
// Questtype
$questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
@@ -120,10 +149,20 @@
$task = $this->runAndRenderTask($questtype['classname']);
}
- // Next Quest
+ // Next Quest/Questgroup
$nextQuests = null;
- if($questtexttypeUrl == 'Epilog') {
+ $nextQuestgroup = null;
+ if($questtexttypeUrl == 'Epilog')
+ {
+ // Next Quest
$nextQuests = $this->Quests->getNextQuests($quest['id']);
+
+ // Next Questgroup
+ if(empty($nextQuests))
+ {
+ $nextQuestgroup = $this->Questgroups->getNextQuestgroup($questgroup['id']);
+ $nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($nextQuestgroup['questgroupshierarchy_id']);
+ }
}
@@ -135,6 +174,7 @@
$this->set('queststatus', $questStatus);
$this->set('queststatustext', $questStatusText);
$this->set('nextquests', $nextQuests);
+ $this->set('nextquestgroup', $nextQuestgroup);
$this->set('task', $task);
$this->set('media', $questmedia);
}
@@ -167,6 +207,38 @@
// Get Sidequest
$sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $sidequestUrl);
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Check permission
+ $previousQuests = $this->Quests->getPreviousQuests($quest['id']);
+ if(count($previousQuests) == 0)
+ {
+ // Previous Questgroup
+ $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
+ if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+ else
+ {
+ // Previous Quests
+ if(count($previousQuests) > 0)
+ {
+ $solved = false;
+ foreach($previousQuests as &$previousQuest)
+ {
+ if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
+ $solved = true;
+ break;
+ }
+ }
+ if(!$solved) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+ }
+
// Get Questtext
$questtext = $this->Questtexts->getQuesttextForSidequest($sidequest['id']);
@@ -215,7 +287,7 @@
// Task
$task = null;
- if(!is_null($sidequesttext) && $sidequesttext['type'] == 'Prolog')
+ if($sidequesttexttypeUrl == 'Prolog')
{
// Questtype
$questtype = $this->Questtypes->getQuesttypeById($sidequest['questtype_id']);
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
index 94303d88..bf89b9f2 100644
--- a/controllers/SeminariesController.inc
+++ b/controllers/SeminariesController.inc
@@ -90,10 +90,20 @@
// Created user
$seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
// Questgrouphierarchy and Questgroups
$questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyForSeminary($seminary['id']);
- foreach($questgroupshierarchy as &$hierarchy) {
+ foreach($questgroupshierarchy as &$hierarchy)
+ {
+ // Get Questgroups
$hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id']);
+
+ // Check permission of Questgroups
+ for($i=1; $iQuestgroups->hasCharacterSolvedQuestgroup($hierarchy['questgroups'][$i-1]['id'], $character['id']);
+ }
}
diff --git a/models/QuestgroupsModel.inc b/models/QuestgroupsModel.inc
index ac820bf1..471fef71 100644
--- a/models/QuestgroupsModel.inc
+++ b/models/QuestgroupsModel.inc
@@ -19,6 +19,12 @@
*/
class QuestgroupsModel extends \hhu\z\Model
{
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('questgroupshierarchy', 'quests');
@@ -138,6 +144,164 @@
);
}
+
+ /**
+ * Get the next Questgroup.
+ *
+ * Determine the next Questgroup. If there is no next Questgroup
+ * on the same level as the given Quest then the followed-up
+ * Questgroup from a higher hierarchy level is returned.
+ *
+ * @param int $questgroupId ID of Questgroup to get next Questgroup of
+ * @return array Questgroup data
+ */
+ public function getNextQuestgroup($questgroupId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $nextQuestgroup = $this->_getNextQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ while(is_null($nextQuestgroup) && !is_null($currentQuestgroup['parent_questgroup_id']))
+ {
+ $currentQuestgroup = $this->getQuestgroupById($currentQuestgroup['parent_questgroup_id']);
+ $nextQuestgroup = $this->_getNextQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ }
+
+
+ return $nextQuestgroup;
+ }
+
+
+ /**
+ * Get the previous Questgroup.
+ *
+ * Determine the previous Questgroup. If there is no previous
+ * Questgroup on the same level as the given Quest then the
+ * followed-up Questgroup from a higher hierarchy level is
+ * returned.
+ *
+ * @param int $questgroupId ID of Questgroup to get previous Questgroup of
+ * @return array Questgroup data
+ */
+ public function getPreviousQuestgroup($questgroupId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $previousQuestgroup = $this->_getPreviousQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ while(is_null($previousQuestgroup) && !is_null($currentQuestgroup['parent_questgroup_id']))
+ {
+ $currentQuestgroup = $this->getQuestgroupById($currentQuestgroup['parent_questgroup_id']);
+ $previousQuestgroup = $this->_getPreviousQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ }
+
+
+ return $previousQuestgroup;
+ }
+
+
+ /**
+ * Determine if the given Character has solved the Quests form
+ * this Questgroup.
+ *
+ * @param int $questgroupId ID of Questgroup to check
+ * @param int $characterId ID of Character to check
+ * @result boolean Whether Character has solved the Questgroup or not
+ */
+ public function hasCharacterSolvedQuestgroup($questgroupId, $characterId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($currentQuestgroup['questgroupshierarchy_id']);
+ $lastChildQuestgroupshierarchy = array_pop($childQuestgroupshierarchy);
+ while(!is_null($lastChildQuestgroupshierarchy))
+ {
+ $questgroups = $this->getQuestgroupsForHierarchy($lastChildQuestgroupshierarchy['id'], $currentQuestgroup['id']);
+ $currentQuestgroup = array_pop($questgroups);
+ $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($currentQuestgroup['questgroupshierarchy_id']);
+ $lastChildQuestgroupshierarchy = array_pop($childQuestgroupshierarchy);
+ }
+
+ $quests = $this->Quests->getQuestsForQuestgroup($currentQuestgroup['id']);
+ $lastQuest = array_pop($quests);
+
+
+ return $this->Quests->hasCharacterSolvedQuest($lastQuest['id'], $characterId);
+ }
+
+
+
+
+ /**
+ * Get the next (direct) Questgroup.
+ *
+ * @param int $parentQuestgroupId ID of parent Questgroup to get next Questgroup of
+ * @param int $questgroupPos Position of Questgroup to get next Questgroup of
+ * @return array Data of next Questgroup or NULL
+ */
+ private function _getNextQuestgroup($parentQuestgroupId, $questgroupPos)
+ {
+ if(!is_null($parentQuestgroupId))
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id = ? AND pos = ? + 1',
+ 'ii',
+ $parentQuestgroupId, $questgroupPos
+ );
+ }
+ else
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id IS NULL AND pos = ? + 1',
+ 'i',
+ $questgroupPos
+ );
+ }
+ if(empty($data)) {
+ return null;
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get the previous (direct) Questgroup.
+ *
+ * @param int $parentQuestgroupId ID of parent Questgroup to get previous Questgroup of
+ * @param int $questgroupPos Position of Questgroup to get previous Questgroup of
+ * @return array Data of previous Questgroup or NULL
+ */
+ private function _getPreviousQuestgroup($parentQuestgroupId, $questgroupPos)
+ {
+ if(!is_null($parentQuestgroupId))
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id = ? AND pos = ? - 1',
+ 'ii',
+ $parentQuestgroupId, $questgroupPos
+ );
+ }
+ else
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id IS NULL AND pos = ? - 1',
+ 'i',
+ $questgroupPos
+ );
+ }
+ if(empty($data)) {
+ return null;
+ }
+
+
+ return $data[0];
+ }
+
}
?>
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
index 4ac41986..e531ac26 100644
--- a/models/QuestsModel.inc
+++ b/models/QuestsModel.inc
@@ -109,7 +109,7 @@
$seminaryId
);
if(empty($data)) {
- throw new \nre\exceptions\IdNotFoundException();
+ throw new \nre\exceptions\IdNotFoundException($sidequestUrl);
}
@@ -175,6 +175,27 @@
}
+ /**
+ * Get Quests that the given Quests follows-up to.
+ *
+ * @param int $questId ID of Quest to get previous Quests of
+ * @return array Quests data
+ */
+ public function getPreviousQuests($questId)
+ {
+ return $this->db->query(
+ 'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
+ 'FROM quests_previousquests '.
+ 'LEFT JOIN quests ON quests.id = quests_previousquests.previous_quest_id '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE quests_previousquests.quest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
/**
* Mark a Quest as solved for a Character.
*
@@ -216,6 +237,29 @@
);
}
+
+ /**
+ * Determine if the given Character has solved the given Quest.
+ *
+ * @param int $questId ID of Quest to check
+ * @param int $characterId ID of Character to check
+ * @result boolean Whether Character has solved the Quest or not
+ */
+ public function hasCharacterSolvedQuest($questId, $characterId)
+ {
+ $count = $this->db->query(
+ 'SELECT count(id) AS c '.
+ 'FROM quests_characters '.
+ 'WHERE quest_id = ? AND character_id = ? AND status = 0',
+ 'ii',
+ $questId,
+ $characterId
+ );
+
+
+ return (!empty($count) && intval($count[0]['c']) > 0);
+ }
+
}
?>
diff --git a/views/html/questgroups/questgroup.tpl b/views/html/questgroups/questgroup.tpl
index 5699bfa7..848bf187 100644
--- a/views/html/questgroups/questgroup.tpl
+++ b/views/html/questgroups/questgroup.tpl
@@ -1,5 +1,5 @@
-=_('Seminaries')?>
-=$seminary['title']?>
+=_('Seminaries')?>
+=$seminary['title']?>
=$questgroupshierarchypath?>
=$questgroupspicture?>
@@ -14,7 +14,14 @@
=$hierarchy['title_plural']?>
@@ -25,6 +32,7 @@
+
+ =_('Locked')?>
+
diff --git a/views/html/quests/quest.tpl b/views/html/quests/quest.tpl
index 2c919a3d..6aca7048 100644
--- a/views/html/quests/quest.tpl
+++ b/views/html/quests/quest.tpl
@@ -48,14 +48,20 @@
-
+
diff --git a/views/html/seminaries/seminary.tpl b/views/html/seminaries/seminary.tpl
index 3ff9b9c0..e84f15f4 100644
--- a/views/html/seminaries/seminary.tpl
+++ b/views/html/seminaries/seminary.tpl
@@ -18,7 +18,13 @@
=$hierarchy['title_plural']?>
From 4085457bb1684a9e72968dc61d02587576dc0a1d Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 11:46:09 +0100
Subject: [PATCH 069/213] correct exceptions for Questgroupspictures and
Questtexts
---
controllers/QuestgroupspictureController.inc | 7 ++++++-
models/QuesttextsModel.inc | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/controllers/QuestgroupspictureController.inc b/controllers/QuestgroupspictureController.inc
index 182c2b50..7810869b 100644
--- a/controllers/QuestgroupspictureController.inc
+++ b/controllers/QuestgroupspictureController.inc
@@ -47,7 +47,12 @@
$questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
// Get Picture
- $picture = $this->Media->getMediaById($questgroup['questgroupspicture_id']);
+ $picture = null;
+ try {
+ $picture = $this->Media->getMediaById($questgroup['questgroupspicture_id']);
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ }
// Pass data to view
diff --git a/models/QuesttextsModel.inc b/models/QuesttextsModel.inc
index 3a7d8526..5324157f 100644
--- a/models/QuesttextsModel.inc
+++ b/models/QuesttextsModel.inc
@@ -163,7 +163,7 @@
$sidequestId
);
if(empty($data)) {
- throw new \nre\exceptions\IdNotFoundException();
+ throw new \nre\exceptions\IdNotFoundException($sidequestId);
}
From ef37c1ea15bfb44e1e665d39c824be5b297d9d14 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 12:00:53 +0100
Subject: [PATCH 070/213] update translations
---
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 2585 -> 2719 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 34 ++++++++++++++------
views/html/questgroups/questgroup.tpl | 2 +-
3 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
index 77e8b492bff97ab2c588f07f110cfb874d724ab4..d2a2559161443dd7666423b67ee58c7d64c09e6e 100644
GIT binary patch
delta 1160
zcmXxjPe{{Y9LMoz`PnyfXpT`K^#~?mJ#;uyC
zwqX%l=vcBY+xG7mqJ0H5@o(F&QNq+)t=*`B`}orHL$;oCLBfLd%0Q_OG56d2Ro
z!)|w=TYMfjVga?2*HK4v8}%Z0ks-}P)VPnas*aZw
zG{Ae**?mD4VSb^0@CP-}Khz7fvHUiSBTZ%)^?Vxj{C?|U>v7wE64Ugb!7Sd2u>UO1
zJf}e`d1D{^gc|rOY9&8yeHHa0LEb|5Gln#oIBvlKTR(y^>L*a+Ojrx39hye{?q-zz
z*9*+rhB;*C>!ArWsQwj-p$7F8Y7m7>?j{qYVzfbhH&oQ3bf@~sU8F*HglWtO*`o7T
z^pSdFg^onW5hry{+sU;Uq@W#0k~>M=1H}%qqh4yP%ofcU1?_;2RhL{bOlr~Fl)AwR
z{kL_dYtc(#z<<^B#3{PPtNx60wzlXr2SQhhmo9sGe<_%c?iow%b<^qWzJvauP_M0K
xvZ+)pA6gA`j!$_dchW0VT(9iTcvBUxmrU4j{>txxUq{rT5-2o9hNYQpD~TU@BnUME!M}Xw&EVfz3vs<$M_nia2Vrw3t2a`
z2|9Z@FzHVFggH!bd;zs#-p{|l8pbc(H>i0f)WRR#HPm$**p1(@2eV9~YXjKC{x(QQ
z7moXhJE#rr`SD3q=8sWDnMG~*1P|k!kC#yuS@m%dRk<>1!!LgP8*2TZm=7uUZ#tSd
zpRAU636=S4Y{U{C#7$Hw|6o1FSw)r0q8>pzDuF&!f&-{^hfvpzq8`m%WJ`O9p(akz
z(E>B5ji2Ive2)BVg+I-E<-T=`sD;Ydi=VI`laz}b?J6qq>!^8S$P~McO8h~J`s+Z*
z0VObtyic}({A`iGBe>+_cbH-P0d?J1R3(1+`7PAON$!HK)glG1JSN?kni5f!w2t1t
z%AK}W24*KwC0DuB^xQfsy=v)>dtYBm8_`T0BF+$Mx?6okN?H{=M(7c=6G~J`De-^p
z2EDU{KCKp_lh8|cf>4QcH#@Cqr{gxDs&$G`^-f2b*lJXc-7Iv*gCNQ!#?rZSxr;5i
fp8mcIQ9jZ9->~pL@i&OpYeou}Q(ZxHKYe~1Z{b!e
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
index 45c97262..80b79587 100644
--- a/locale/de_DE/LC_MESSAGES/The Legend of Z.po
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: The Legend of Z\n"
-"POT-Creation-Date: 2014-02-26 20:45+0100\n"
-"PO-Revision-Date: 2014-02-26 20:45+0100\n"
+"POT-Creation-Date: 2014-03-04 11:59+0100\n"
+"PO-Revision-Date: 2014-03-04 12:00+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -57,7 +57,7 @@ msgid "Group Leader"
msgstr "Gruppenleiter"
#: ../../../views/html/charactergroups/group.tpl:21
-#: ../../../views/html/questgroups/questgroup.tpl:24
+#: ../../../views/html/questgroups/questgroup.tpl:31
msgid "Quests"
msgstr "Quests"
@@ -110,22 +110,36 @@ msgstr "Login"
msgid "Logout"
msgstr "Logout"
-#: ../../../views/html/questgroups/questgroup.tpl:30
+#: ../../../views/html/questgroups/questgroup.tpl:22
+#: ../../../views/html/questgroups/questgroup.tpl:47
+#: ../../../views/html/seminaries/seminary.tpl:26
+msgid "locked"
+msgstr "gesperrt"
+
+#: ../../../views/html/questgroups/questgroup.tpl:38
msgid "containing optional Quests"
msgstr "Enthaltene optionale Quests"
-#: ../../../views/html/quests/quest.tpl:13
-#: ../../../views/html/quests/sidequest.tpl:15
+#: ../../../views/html/quests/quest.tpl:15
+#: ../../../views/html/quests/sidequest.tpl:17
msgid "solved"
msgstr "gelöst"
-#: ../../../views/html/quests/quest.tpl:15
-#: ../../../views/html/quests/sidequest.tpl:17
+#: ../../../views/html/quests/quest.tpl:17
+#: ../../../views/html/quests/sidequest.tpl:19
msgid "unsolved"
msgstr "ungelöst"
-#: ../../../views/html/quests/quest.tpl:45
-#: ../../../views/html/quests/sidequest.tpl:43
+#: ../../../views/html/quests/quest.tpl:53
+msgid "Go on"
+msgstr "Hier geht es weiter"
+
+#: ../../../views/html/quests/quest.tpl:57
+msgid "Quest"
+msgstr "Quest"
+
+#: ../../../views/html/quests/quest.tpl:70
+#: ../../../views/html/quests/sidequest.tpl:51
msgid "Task"
msgstr "Aufgabe"
diff --git a/views/html/questgroups/questgroup.tpl b/views/html/questgroups/questgroup.tpl
index 848bf187..2e5596d7 100644
--- a/views/html/questgroups/questgroup.tpl
+++ b/views/html/questgroups/questgroup.tpl
@@ -44,7 +44,7 @@
- =_('Locked')?>
+ =_('locked')?>
From 5706d6fe14b6e01828c2dc5e199dfa81d25324b8 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 12:04:56 +0100
Subject: [PATCH 071/213] correct permissions checking for previous Questgroups
if there is none
---
controllers/QuestsController.inc | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index e6e7ce54..8ce5705c 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -77,7 +77,7 @@
{
// Previous Questgroup
$previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
- if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
throw new \nre\exceptions\AccessDeniedException();
}
}
@@ -216,7 +216,7 @@
{
// Previous Questgroup
$previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
- if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
throw new \nre\exceptions\AccessDeniedException();
}
}
From 5cd7372ad221f9e393c6bf12f340fbffe7a8b48a Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 4 Mar 2014 12:18:00 +0100
Subject: [PATCH 072/213] correctly set status of Sidequests
---
app/QuesttypeController.inc | 15 +++++++++++--
models/QuestsModel.inc | 42 +++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
index 132a25e5..31596073 100644
--- a/app/QuesttypeController.inc
+++ b/app/QuesttypeController.inc
@@ -261,7 +261,12 @@
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Set solved
- $this->Quests->setQuestSolved($quest['id'], $character['id']);
+ if(is_null($sidequest)) {
+ $this->Quests->setQuestSolved($quest['id'], $character['id']);
+ }
+ else {
+ $this->Quests->setSidequestSolved($sidequest['id'], $character['id']);
+ }
// Redirect
@@ -294,7 +299,13 @@
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Set solved
- $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
+ if(is_null($sidequest)) {
+ $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
+ }
+ else {
+ $this->Quests->setSidequestUnsolved($sidequest['id'], $character['id']);
+ }
+
// Redirect
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
index e531ac26..e49947f8 100644
--- a/models/QuestsModel.inc
+++ b/models/QuestsModel.inc
@@ -217,6 +217,27 @@
}
+ /**
+ * Mark a Sidequest as solved for a Character.
+ *
+ * @param int $sidequestId ID of Sidequest to mark as solved
+ * @param int $characterId ID of Character that solved the Sidequest
+ */
+ public function setSidequestSolved($sidequestId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO sidequests_characters '.
+ '(sidequest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $sidequestId,
+ $characterId,
+ 0
+ );
+ }
+
+
/**
* Mark a Quest as unsolved for a Character.
*
@@ -238,6 +259,27 @@
}
+ /**
+ * Mark a Sidequest as unsolved for a Character.
+ *
+ * @param int $sidequestId ID of Sidequest to mark as unsolved
+ * @param int $characterId ID of Character that unsolved the Sidequest
+ */
+ public function setSidequestUnsolved($sidequestId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO sidequests_characters '.
+ '(sidequest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $sidequestId,
+ $characterId,
+ -1
+ );
+ }
+
+
/**
* Determine if the given Character has solved the given Quest.
*
From 7fec7e6afa0f2804e5108a2a05e778dc204faa6c Mon Sep 17 00:00:00 2001
From: coderkun
Date: Fri, 7 Mar 2014 13:37:59 +0100
Subject: [PATCH 073/213] implement avatar pictures
---
controllers/CharactersController.inc | 2 +-
models/CharactersModel.inc | 5 ++++-
views/html/characters/character.tpl | 3 +++
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/controllers/CharactersController.inc b/controllers/CharactersController.inc
index 4e65ed40..581b5b5a 100644
--- a/controllers/CharactersController.inc
+++ b/controllers/CharactersController.inc
@@ -17,7 +17,7 @@
*
* @author Oliver Hanraths
*/
- class CharactersController extends \hhu\z\Controller
+ class CharactersController extends \hhu\z\controllers\SeminaryRoleController
{
/**
* User permissions
diff --git a/models/CharactersModel.inc b/models/CharactersModel.inc
index c2899d8e..59125e32 100644
--- a/models/CharactersModel.inc
+++ b/models/CharactersModel.inc
@@ -132,9 +132,12 @@
public function getCharacterByUrl($seminaryId, $characterUrl)
{
$data = $this->db->query(
- 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, media.url AS avatar_url, media.description AS avatar_description '.
'FROM v_characters AS characters '.
'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'LEFT JOIN avatars ON avatars.id = characters.avatar_id '.
+ 'LEFT JOIN avatarpictures ON avatarpictures.media_id = avatars.avatarpicture_id '.
+ 'LEFT JOIN media ON media.id = avatarpictures.media_id '.
'WHERE charactertypes.seminary_id = ? AND characters.url = ?',
'is',
$seminaryId, $characterUrl
diff --git a/views/html/characters/character.tpl b/views/html/characters/character.tpl
index b2130746..b4bb166d 100644
--- a/views/html/characters/character.tpl
+++ b/views/html/characters/character.tpl
@@ -10,6 +10,9 @@
=$field['title']?>: =$field['value']?>
+
+
+
From 1cc251038aa38ac980f390faab0c2673c3709f47 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 9 Mar 2014 13:25:55 +0100
Subject: [PATCH 074/213] unify Main- and Sidequests
---
agents/intermediate/QuestsAgent.inc | 10 --
app/QuesttypeController.inc | 27 +---
controllers/QuestgroupsController.inc | 2 +-
controllers/QuestsController.inc | 182 ++++++--------------------
models/QuestgroupsModel.inc | 2 +-
models/QuestsModel.inc | 111 ++++++++--------
models/QuesttextsModel.inc | 64 +--------
views/html/questgroups/questgroup.tpl | 2 +-
views/html/quests/quest.tpl | 25 ++--
views/html/quests/sidequest.tpl | 55 --------
10 files changed, 117 insertions(+), 363 deletions(-)
delete mode 100644 views/html/quests/sidequest.tpl
diff --git a/agents/intermediate/QuestsAgent.inc b/agents/intermediate/QuestsAgent.inc
index 8de47e79..c26a2f70 100644
--- a/agents/intermediate/QuestsAgent.inc
+++ b/agents/intermediate/QuestsAgent.inc
@@ -32,16 +32,6 @@
$this->addSubAgent('Questgroupspicture', 'index', $request->getParam(3), $request->getParam(4), true);
}
-
- /**
- * Action: quest.
- */
- public function sidequest(\nre\core\Request $request, \nre\core\Response $response)
- {
- $this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4), true);
- $this->addSubAgent('Questgroupspicture', 'index', $request->getParam(3), $request->getParam(4), true);
- }
-
}
?>
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
index 31596073..743c5d59 100644
--- a/app/QuesttypeController.inc
+++ b/app/QuesttypeController.inc
@@ -251,22 +251,11 @@
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
- // Sidequest
- $sidequest = null;
- if($this->request->getParam(2) == 'sidequest') {
- $sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $this->request->getParam(6));
- }
-
// Character
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Set solved
- if(is_null($sidequest)) {
- $this->Quests->setQuestSolved($quest['id'], $character['id']);
- }
- else {
- $this->Quests->setSidequestSolved($sidequest['id'], $character['id']);
- }
+ $this->Quests->setQuestSolved($quest['id'], $character['id']);
// Redirect
@@ -289,23 +278,11 @@
// Get Quest
$quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
- // Sidequest
- $sidequest = null;
- if($this->request->getParam(2) == 'sidequest') {
- $sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $this->request->getParam(6));
- }
-
// Character
$character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
// Set solved
- if(is_null($sidequest)) {
- $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
- }
- else {
- $this->Quests->setSidequestUnsolved($sidequest['id'], $character['id']);
- }
-
+ $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
// Redirect
diff --git a/controllers/QuestgroupsController.inc b/controllers/QuestgroupsController.inc
index 1e7c2a29..42e19d05 100644
--- a/controllers/QuestgroupsController.inc
+++ b/controllers/QuestgroupsController.inc
@@ -96,7 +96,7 @@
$quests = null;
if(count($childQuestgroupshierarchy) == 0)
{
- $quests = $this->Quests->getQuestsForQuestgroup($questgroup['id']);
+ $quests = $this->Quests->getMainquestsForQuestgroup($questgroup['id']);
for($i=0; $i 0)
{
- if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
- $solved = true;
- break;
+ $solved = false;
+ foreach($previousQuests as &$previousQuest)
+ {
+ if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
+ $solved = true;
+ break;
+ }
+ }
+ if(!$solved) {
+ throw new \nre\exceptions\AccessDeniedException();
}
}
- if(!$solved) {
- throw new \nre\exceptions\AccessDeniedException();
+ }
+
+ // Get (related) Questtext (for Sidequests)
+ $relatedQuesttext = null;
+ if(!$quest['is_mainquest'])
+ {
+ $relatedQuesttext = $this->Questtexts->getQuesttextForSidequest($quest['id']);
+ if(!empty($relatedQuesttext)) {
+ $relatedQuesttext['quest'] = $this->Quests->getQuestById($relatedQuesttext['quest_id']);
}
}
@@ -154,14 +167,23 @@
$nextQuestgroup = null;
if($questtexttypeUrl == 'Epilog')
{
- // Next Quest
- $nextQuests = $this->Quests->getNextQuests($quest['id']);
-
- // Next Questgroup
- if(empty($nextQuests))
+ if($quest['is_mainquest'])
{
- $nextQuestgroup = $this->Questgroups->getNextQuestgroup($questgroup['id']);
- $nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($nextQuestgroup['questgroupshierarchy_id']);
+ // Next Quest
+ $nextQuests = $this->Quests->getNextQuests($quest['id']);
+
+ // Next Questgroup
+ if(empty($nextQuests))
+ {
+ $nextQuestgroup = $this->Questgroups->getNextQuestgroup($questgroup['id']);
+ $nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($nextQuestgroup['questgroupshierarchy_id']);
+ }
+ }
+ else {
+ // Related (Main-) Quest
+ $nextQuest = $relatedQuesttext['quest'];
+ $nextQuest['questgroup_url'] = $questgroup['url'];
+ $nextQuests = array($nextQuest);
}
}
@@ -173,6 +195,7 @@
$this->set('quest', $quest);
$this->set('queststatus', $questStatus);
$this->set('queststatustext', $questStatusText);
+ $this->set('relatedquesttext', $relatedQuesttext);
$this->set('nextquests', $nextQuests);
$this->set('nextquestgroup', $nextQuestgroup);
$this->set('task', $task);
@@ -180,137 +203,6 @@
}
- /**
- * Action: sidequest.
- *
- * Show a sidequest and its task.
- *
- * @throws IdNotFoundException
- * @param string $seminaryUrl URL-Title of Seminary
- * @param string $questgroupUrl URL-Title of Questgroup
- * @param string $questUrl URL-Title of Quest
- * @param string $sidequestUrl URL-Title of Sidequest
- * @param string $sidequesttexttypeUrl URL-Title of Sidequesttexttype
- * @param int $sidequesttextPos Position of Sidequesttext
- */
- public function sidequest($seminaryUrl, $questgroupUrl, $questUrl, $sidequestUrl, $sidequesttexttypeUrl=null, $sidequesttextPos=1)
- {
- // Get seminary
- $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
-
- // Get Questgroup
- $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
-
- // Get Quest
- $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
-
- // Get Sidequest
- $sidequest = $this->Quests->getSidequestByUrl($seminary['id'], $questgroup['id'], $quest['id'], $sidequestUrl);
-
- // Get Character
- $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
-
- // Check permission
- $previousQuests = $this->Quests->getPreviousQuests($quest['id']);
- if(count($previousQuests) == 0)
- {
- // Previous Questgroup
- $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
- if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
- throw new \nre\exceptions\AccessDeniedException();
- }
- }
- else
- {
- // Previous Quests
- if(count($previousQuests) > 0)
- {
- $solved = false;
- foreach($previousQuests as &$previousQuest)
- {
- if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
- $solved = true;
- break;
- }
- }
- if(!$solved) {
- throw new \nre\exceptions\AccessDeniedException();
- }
- }
- }
-
- // Get Questtext
- $questtext = $this->Questtexts->getQuesttextForSidequest($sidequest['id']);
-
- // Get Sidequesttext
- $sidequesttext = null;
- if(is_null($sidequesttexttypeUrl)) {
- $sidequesttexttypeUrl = 'Prolog';
- }
- $questtexttypes = $this->Questtexts->getQuesttexttypes();
- $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
- $sidequesttextCount = $this->Questtexts->getQuesttextsCountForSidequest($sidequest['id'], $sidequesttexttypeUrl);
- if($sidequesttextCount > 0 && in_array($sidequesttexttypeUrl, $questtexttypes))
- {
- if(in_array($sidequesttexttypeUrl, $questtexttypes))
- {
- $sidequesttextPos = max(intval($sidequesttextPos), 1);
- $sidequesttext = $this->Questtexts->getSidequesttextByUrl($sidequest['id'], $sidequesttexttypeUrl, $sidequesttextPos);
- $sidequesttext['count'] = $sidequesttextCount;
- }
- }
-
- // Sidequest status
- $sidequestStatus = $this->request->getGetParam('status');
- $sidequestStatusText = null;
- if(!is_null($sidequestStatus))
- {
- switch($sidequestStatus)
- {
- case 'solved':
- $sidequestStatusText = $sidequest['right_text'];
- break;
- case 'unsolved':
- $sidequestStatusText = $sidequest['wrong_text'];
- break;
- }
- }
-
- // Media
- $sidequestmedia = null;
- if(!is_null($sidequesttext) && !empty($sidequesttext['questsmedia_id'])) {
- $sidequestmedia = $this->Media->getMediaById($sidequesttext['questsmedia_id']);
- }
- elseif(!is_null($sidequest['questsmedia_id'])) {
- $sidequestmedia = $this->Media->getMediaById($sidequest['questsmedia_id']);
- }
-
- // Task
- $task = null;
- if($sidequesttexttypeUrl == 'Prolog')
- {
- // Questtype
- $questtype = $this->Questtypes->getQuesttypeById($sidequest['questtype_id']);
-
- // Task
- $task = $this->runAndRenderTask($questtype['classname']);
- }
-
-
- // Pass data to view
- $this->set('seminary', $seminary);
- $this->set('questgroup', $questgroup);
- $this->set('questtext', $questtext);
- $this->set('sidequesttext', $sidequesttext);
- $this->set('quest', $quest);
- $this->set('sidequest', $sidequest);
- $this->set('sidequeststatus', $sidequestStatus);
- $this->set('sidequeststatustext', $sidequestStatusText);
- $this->set('task', $task);
- $this->set('media', $sidequestmedia);
- }
-
-
/**
diff --git a/models/QuestgroupsModel.inc b/models/QuestgroupsModel.inc
index 471fef71..088d54c0 100644
--- a/models/QuestgroupsModel.inc
+++ b/models/QuestgroupsModel.inc
@@ -217,7 +217,7 @@
$lastChildQuestgroupshierarchy = array_pop($childQuestgroupshierarchy);
}
- $quests = $this->Quests->getQuestsForQuestgroup($currentQuestgroup['id']);
+ $quests = $this->Quests->getMainquestsForQuestgroup($currentQuestgroup['id']);
$lastQuest = array_pop($quests);
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
index e49947f8..09ebc125 100644
--- a/models/QuestsModel.inc
+++ b/models/QuestsModel.inc
@@ -40,11 +40,12 @@
* @param int $questgroupId ID of a Questgroup
* @return array Quests of the given Questgroup
*/
- public function getQuestsForQuestgroup($questgroupId)
+ public function getMainquestsForQuestgroup($questgroupId)
{
return $this->db->query(
'SELECT id, questtype_id, title, url, xps, task '.
'FROM quests '.
+ 'INNER JOIN mainquests ON mainquests.quest_id = quests.id '.
'WHERE questgroup_id = ?',
'i',
$questgroupId
@@ -64,7 +65,8 @@
public function getQuestByUrl($seminaryId, $questgroupId, $questUrl)
{
$data = $this->db->query(
- 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id '.
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id, ('.
+ 'SELECT count(mainquests.quest_id) FROM mainquests WHERE mainquests.quest_id = quests.id) AS is_mainquest '.
'FROM quests '.
'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
@@ -76,6 +78,38 @@
throw new \nre\exceptions\IdNotFoundException($questUrl);
}
+ $data[0]['is_mainquest'] = ($data[0]['is_mainquest'] == 1);
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Quest and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param string $questId ID of a Quest
+ * @return array Quest data
+ */
+ public function getQuestById($questId)
+ {
+ $data = $this->db->query(
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id, ('.
+ 'SELECT count(mainquests.quest_id) FROM mainquests WHERE mainquests.quest_id = quests.id) AS is_mainquest '.
+ 'FROM quests '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE quests.id = ?',
+ 'i',
+ $questId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questId);
+ }
+
+ $data[0]['is_mainquest'] = ($data[0]['is_mainquest'] == 1);
+
return $data[0];
}
@@ -94,14 +128,15 @@
public function getSidequestByUrl($seminaryId, $questgroupId, $questId, $sidequestUrl)
{
$data = $this->db->query(
- 'SELECT sidequests.id, sidequests.questtype_id, sidequests.title, sidequests.url, sidequests.xps, sidequests.task, quests.right_text, quests.wrong_text, sidequests.questsmedia_id '.
- 'FROM sidequests '.
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
- 'LEFT JOIN quests ON quests.id = questtexts.quest_id '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = questtexts.mainquest_id '.
'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
'LEFT JOIN seminaries ON seminaries.id = questgroupshierarchy.seminary_id '.
- 'WHERE sidequests.url = ? AND quests.id = ? AND questgroups.id = ? AND seminaries.id = ?',
+ 'WHERE quests.url = ? AND mainquests.id = ? AND questgroups.id = ? AND seminaries.id = ?',
'siii',
$sidequestUrl,
$questId,
@@ -126,8 +161,9 @@
public function getSidequestsForQuest($questId)
{
return $this->db->query(
- 'SELECT sidequests.id, sidequests.questtext_id, sidequests.title, sidequests.url, sidequests.entry_text '.
- 'FROM sidequests '.
+ 'SELECT quests.id, sidequests.questtext_id, quests.title, quests.url, sidequests.entry_text '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
'WHERE questtexts.quest_id = ?',
'i',
@@ -146,7 +182,8 @@
{
return $this->db->query(
'SELECT id, questtext_id, title, url, entry_text '.
- 'FROM sidequests '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
'WHERE questtext_id = ?',
'i',
$questtextId
@@ -164,11 +201,12 @@
{
return $this->db->query(
'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
- 'FROM quests_previousquests '.
- 'LEFT JOIN quests ON quests.id = quests_previousquests.quest_id '.
+ 'FROM mainquests_previousmainquests '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = mainquests_previousmainquests.mainquest_id '.
+ 'INNER JOIN quests ON quests.id = mainquests.quest_id '.
'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
- 'WHERE quests_previousquests.previous_quest_id = ?',
+ 'WHERE mainquests_previousmainquests.previous_mainquest_id = ?',
'i',
$questId
);
@@ -185,11 +223,12 @@
{
return $this->db->query(
'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
- 'FROM quests_previousquests '.
- 'LEFT JOIN quests ON quests.id = quests_previousquests.previous_quest_id '.
+ 'FROM mainquests_previousmainquests '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = mainquests_previousmainquests.previous_mainquest_id '.
+ 'INNER JOIN quests ON quests.id = mainquests.quest_id '.
'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
- 'WHERE quests_previousquests.quest_id = ?',
+ 'WHERE mainquests_previousmainquests.mainquest_id = ?',
'i',
$questId
);
@@ -217,27 +256,6 @@
}
- /**
- * Mark a Sidequest as solved for a Character.
- *
- * @param int $sidequestId ID of Sidequest to mark as solved
- * @param int $characterId ID of Character that solved the Sidequest
- */
- public function setSidequestSolved($sidequestId, $characterId)
- {
- $this->db->query(
- 'INSERT INTO sidequests_characters '.
- '(sidequest_id, character_id, status) '.
- 'VALUES '.
- '(?, ?, ?)',
- 'iii',
- $sidequestId,
- $characterId,
- 0
- );
- }
-
-
/**
* Mark a Quest as unsolved for a Character.
*
@@ -259,27 +277,6 @@
}
- /**
- * Mark a Sidequest as unsolved for a Character.
- *
- * @param int $sidequestId ID of Sidequest to mark as unsolved
- * @param int $characterId ID of Character that unsolved the Sidequest
- */
- public function setSidequestUnsolved($sidequestId, $characterId)
- {
- $this->db->query(
- 'INSERT INTO sidequests_characters '.
- '(sidequest_id, character_id, status) '.
- 'VALUES '.
- '(?, ?, ?)',
- 'iii',
- $sidequestId,
- $characterId,
- -1
- );
- }
-
-
/**
* Determine if the given Character has solved the given Quest.
*
diff --git a/models/QuesttextsModel.inc b/models/QuesttextsModel.inc
index 5324157f..38a1286d 100644
--- a/models/QuesttextsModel.inc
+++ b/models/QuesttextsModel.inc
@@ -46,7 +46,7 @@
public function getQuesttextByUrl($questId, $questtexttypeUrl, $pos)
{
$data = $this->db->query(
- 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.out_text, questtexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.out_text, questtexts.abort_text, questtexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
'FROM questtexts '.
'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
'WHERE questtexts.quest_id = ? AND questtexttypes.url = ? AND questtexts.pos = ?',
@@ -62,34 +62,6 @@
}
- /**
- * Get a Questtext for a Sidequest by its URL.
- *
- * @throws IdNotFoundException
- * @param int $sidequestId ID of the Sidequest to get text for
- * @param string $questtexttypeUrl URL of the Questtexttype
- * @param int $pos Position of Questtexttype
- * @return array Questtexttype data
- */
- public function getSidequesttextByUrl($sidequestId, $questtexttypeUrl, $pos)
- {
- $data = $this->db->query(
- 'SELECT sidequesttexts.id, sidequesttexts.text, sidequesttexts.pos, sidequesttexts.out_text, sidequesttexts.abort_text, sidequesttexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
- 'FROM sidequesttexts '.
- 'LEFT JOIN questtexttypes ON questtexttypes.id = sidequesttexts.questtexttype_id '.
- 'WHERE sidequesttexts.sidequest_id = ? AND questtexttypes.url = ? AND sidequesttexts.pos = ?',
- 'isi',
- $sidequestId, $questtexttypeUrl, $pos
- );
- if(empty($data)) {
- throw new \nre\exceptions\IdNotFoundException($questtexttypeUrl);
- }
-
-
- return $data = $data[0];
- }
-
-
/**
* Get count of Questtexts for a Quest.
*
@@ -117,33 +89,6 @@
}
- /**
- * Get count of Questtexts for a Sidequest.
- *
- * @param int $sidequestId ID of the Sidequest
- * @param string $questtexttypeUrl URL of the Questtexttype
- * @return int Conut of Questtexts for Sideuest
- */
- public function getQuesttextsCountForSidequest($questId, $questtexttypUrl)
- {
- $count = 0;
- $data = $this->db->query(
- 'SELECT COUNT(sidequesttexts.id) AS c '.
- 'FROM sidequesttexts '.
- 'LEFT JOIN questtexttypes ON questtexttypes.id = sidequesttexts.questtexttype_id '.
- 'WHERE sidequesttexts.sidequest_id = ? AND questtexttypes.url = ?',
- 'is',
- $questId, $questtexttypUrl
- );
- if(!empty($data)) {
- $count = $data[0]['c'];
- }
-
-
- return $count;
- }
-
-
/**
* Get corresponding Questtext for a Sidequest.
*
@@ -154,11 +99,12 @@
public function getQuesttextForSidequest($sidequestId)
{
$data = $this->db->query(
- 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
- 'FROM sidequests '.
+ 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.quest_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
- 'WHERE sidequests.id = ?',
+ 'WHERE quests.id = ?',
'i',
$sidequestId
);
diff --git a/views/html/questgroups/questgroup.tpl b/views/html/questgroups/questgroup.tpl
index 2e5596d7..d8d2ce42 100644
--- a/views/html/questgroups/questgroup.tpl
+++ b/views/html/questgroups/questgroup.tpl
@@ -34,9 +34,9 @@
=$quest['title']?>
+ 0) : ?>
=_('containing optional Quests')?>:
- 0) : ?>
1) : ?><
@@ -54,7 +57,11 @@
0) : ?>
diff --git a/views/html/quests/sidequest.tpl b/views/html/quests/sidequest.tpl
deleted file mode 100644
index 191648d1..00000000
--- a/views/html/quests/sidequest.tpl
+++ /dev/null
@@ -1,55 +0,0 @@
-=_('Seminaries')?>
-=$seminary['title']?>
-
-=$questgroupshierarchypath?>
-=$questgroupspicture?>
-
-
-=$sidequest['title']?>
-=_('This Quest is optional')?>.
-
-
-
-
-
-
-
- =_('solved')?>
-
- =_('unsolved')?>
-
- =\hhu\z\Utils::t($sidequeststatustext)?>
-
-
-
-
-
- =$sidequesttext['type']?>
- =\hhu\z\Utils::t($sidequesttext['text'])?>
-
-
-
-
-
- =$sidequesttext['out_text']?>
-
-
-
-
- 1) : ?><
- =$sidequesttext['pos']?>/=$sidequesttext['count']?>
- >
-
-
-
-
-
-
- =_('Task')?>
- =\hhu\z\Utils::t($sidequest['task'])?>
- =$task?>
-
-
From 7ce4cf5292ace836a1e97db2cc8570a45c25445d Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 9 Mar 2014 14:31:40 +0100
Subject: [PATCH 075/213] pass Quest-ID to QuesttypeController
---
controllers/QuestsController.inc | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
index 9a5041c3..211c8104 100644
--- a/controllers/QuestsController.inc
+++ b/controllers/QuestsController.inc
@@ -159,7 +159,7 @@
$questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
// Task
- $task = $this->runAndRenderTask($questtype['classname']);
+ $task = $this->runAndRenderTask($quest['id'], $questtype['classname']);
}
// Next Quest/Questgroup
@@ -209,10 +209,11 @@
* Load, construct, run and render the Agent for the given
* classname of a Questtype and return ist output.
*
+ * @param int $questId ID of Quest
* @param string $questtypeClassname Classname of Questtype to run and render
* @return string Rendered output of Questtype-Agent
*/
- private function runAndRenderTask($questtypeClassname)
+ private function runAndRenderTask($questId, $questtypeClassname)
{
$task = null;
$questtypeAgent = null;
@@ -222,15 +223,18 @@
// Construct Agent
$questtypeAgent = \hhu\z\QuesttypeAgent::factory($questtypeClassname, $this->request, $this->response);
+ // Generate request
+ $request = clone $this->request;
// Generate response
$response = clone $this->response;
$response->clearParams(1);
$response->addParams(
null,
- \nre\configs\CoreConfig::$defaults['action']
+ \nre\configs\CoreConfig::$defaults['action'],
+ $questId
);
// Run Agent
- $questtypeAgent->run($this->request, $response);
+ $questtypeAgent->run($request, $response);
// Render output
$task = $questtypeAgent->render();
From e8c00354181be9fd326b3dbf13b0cd0d697617c7 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Sun, 9 Mar 2014 14:35:13 +0100
Subject: [PATCH 076/213] implement Questtype ?textinput?
---
.../textinput/TextinputQuesttypeAgent.inc | 24 ++++++
.../TextinputQuesttypeController.inc | 74 +++++++++++++++++++
.../textinput/TextinputQuesttypeModel.inc | 67 +++++++++++++++++
questtypes/textinput/html/index.tpl | 11 +++
4 files changed, 176 insertions(+)
create mode 100644 questtypes/textinput/TextinputQuesttypeAgent.inc
create mode 100644 questtypes/textinput/TextinputQuesttypeController.inc
create mode 100644 questtypes/textinput/TextinputQuesttypeModel.inc
create mode 100644 questtypes/textinput/html/index.tpl
diff --git a/questtypes/textinput/TextinputQuesttypeAgent.inc b/questtypes/textinput/TextinputQuesttypeAgent.inc
new file mode 100644
index 00000000..8144c148
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * QuesttypeAgent for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/textinput/TextinputQuesttypeController.inc b/questtypes/textinput/TextinputQuesttypeController.inc
new file mode 100644
index 00000000..e41facfd
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeController.inc
@@ -0,0 +1,74 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the TextinputQuesttypeAgent for for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Display a text with input fields and evaluate if user input
+ * matches with stored regular expressions.
+ */
+ public function index($questId)
+ {
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
+ {
+ // Get right answers
+ $regexs = $this->Textinput->getTextinputRegexs($questId);
+
+ // Match regexs with user answers
+ $allSolved = true;
+ for($i=0; $irequest->getPostParam('answer-'.strval($i+1));
+ $score = preg_match($regexs[$i]['regex'], $answer);
+ if($score === 0 || $score === false) {
+ $allSolved = false;
+ }
+ }
+
+ // Set status
+ if($allSolved) {
+ $this->setQuestSolved();
+ }
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+
+
+ // Get Task
+ $task = $this->Textinput->getTextinputQuest($questId);
+
+ // Process text
+ $textParts = preg_split('/(\$\$)/', $task['text'], -1, PREG_SPLIT_NO_EMPTY);
+
+
+ // Pass data to view
+ $this->set('text', $textParts);
+ }
+
+ }
+
+?>
diff --git a/questtypes/textinput/TextinputQuesttypeModel.inc b/questtypes/textinput/TextinputQuesttypeModel.inc
new file mode 100644
index 00000000..d242f251
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeModel.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the TextinputQuesttypeAgent for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+
+
+
+
+ /**
+ * Get textinput-text for a Quest.
+ *
+ * @param int $questId ID of Quest
+ * @return array Textinput-text
+ */
+ public function getTextinputQuest($questId)
+ {
+ $data = $this->db->query(
+ 'SELECT text '.
+ 'FROM questtypes_textinput '.
+ 'WHERE quest_id = ?',
+ 'i',
+ $questId
+ );
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get regular expressions for a textinput-text.
+ *
+ * @param int $questId ID of Quest
+ * @return array Regexs
+ */
+ public function getTextinputRegexs($questId)
+ {
+ return $this->db->query(
+ 'SELECT number, regex '.
+ 'FROM questtypes_textinput_regexs '.
+ 'WHERE questtypes_textinput_quest_id = ? '.
+ 'ORDER BY number ASC',
+ 'i',
+ $questId
+ );
+ }
+
+ }
+
+?>
diff --git a/questtypes/textinput/html/index.tpl b/questtypes/textinput/html/index.tpl
new file mode 100644
index 00000000..b3701630
--- /dev/null
+++ b/questtypes/textinput/html/index.tpl
@@ -0,0 +1,11 @@
+
+
+ 0) : ?>
+
+
+ =\hhu\z\Utils::t($text[$i])?>
+
+
+
+
+
From ddd210dfc16683584b759b61767728d9d1b9787e Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 11 Mar 2014 00:06:18 +0100
Subject: [PATCH 077/213] add support for Apache 2.4
---
.htaccess | 46 +++++++++++++++++++++++++++++++++-------------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/.htaccess b/.htaccess
index e5c5c191..cb3fb9ef 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,4 +1,3 @@
-Allow From All
Options -Indexes -MultiViews
ErrorDocument 403 /www/error403.html
@@ -6,20 +5,41 @@ ErrorDocument 404 /www/error404.html
ErrorDocument 500 /www/error500.html
-
- Order Deny,Allow
- Deny From All
-
-
- Order Deny,Allow
- Deny From All
-
+
+ Require all granted
+
+
+ Require all denied
+
-
- Order Deny,Allow
- Deny From All
-
+
+ Require all denied
+
+
+
+ Require all denied
+
+
+
+
+ Allow From All
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
From ad1da597486c28a0c9c8d11f4948a382ca012604 Mon Sep 17 00:00:00 2001
From: coderkun
Date: Tue, 11 Mar 2014 00:49:26 +0100
Subject: [PATCH 078/213] save answers for Questtype ?Textinput?
---
.../textinput/TextinputQuesttypeController.inc | 12 ++++++++++++
questtypes/textinput/html/index.tpl | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/questtypes/textinput/TextinputQuesttypeController.inc b/questtypes/textinput/TextinputQuesttypeController.inc
index e41facfd..ad4073ce 100644
--- a/questtypes/textinput/TextinputQuesttypeController.inc
+++ b/questtypes/textinput/TextinputQuesttypeController.inc
@@ -31,10 +31,17 @@
*/
public function index($questId)
{
+ // Answers
+ if(!array_key_exists('answers', $_SESSION)) {
+ $_SESSION['answers'] = array();
+ }
+ $answers = array_key_exists($questId, $_SESSION['answers']) ? $_SESSION['answers'][$questId] : array();
+
// Check for submission
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
{
// Get right answers
+ $answers = array();
$regexs = $this->Textinput->getTextinputRegexs($questId);
// Match regexs with user answers
@@ -42,12 +49,16 @@
for($i=0; $irequest->getPostParam('answer-'.strval($i+1));
+ $answers[] = $answer;
$score = preg_match($regexs[$i]['regex'], $answer);
if($score === 0 || $score === false) {
$allSolved = false;
}
}
+ // Store answers in session
+ $_SESSION['answers'][$questId] = $answers;
+
// Set status
if($allSolved) {
$this->setQuestSolved();
@@ -67,6 +78,7 @@
// Pass data to view
$this->set('text', $textParts);
+ $this->set('answers', $answers);
}
}
diff --git a/questtypes/textinput/html/index.tpl b/questtypes/textinput/html/index.tpl
index b3701630..714d828d 100644
--- a/questtypes/textinput/html/index.tpl
+++ b/questtypes/textinput/html/index.tpl
@@ -1,7 +1,7 @@
0) : ?>
-
+
=\hhu\z\Utils::t($text[$i])?>
From 6f91287afc3fe79ac3723ac78374ed7650833e8a Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 12 Mar 2014 01:28:26 +0100
Subject: [PATCH 079/213] correct for-loops and answers-array for Questtype
?Textinput?
---
.../TextinputQuesttypeController.inc | 28 ++++++++++++-------
questtypes/textinput/html/index.tpl | 8 +++---
views/html/quests/quest.tpl | 2 +-
3 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/questtypes/textinput/TextinputQuesttypeController.inc b/questtypes/textinput/TextinputQuesttypeController.inc
index ad4073ce..52acdb25 100644
--- a/questtypes/textinput/TextinputQuesttypeController.inc
+++ b/questtypes/textinput/TextinputQuesttypeController.inc
@@ -40,25 +40,33 @@
// Check for submission
if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
{
+ // Get answers
+ $answers = $this->request->getPostParam('answers');
+
+ // Store answers in session
+ $_SESSION['answers'][$questId] = $answers;
+
// Get right answers
- $answers = array();
$regexs = $this->Textinput->getTextinputRegexs($questId);
// Match regexs with user answers
$allSolved = true;
- for($i=0; $i &$regex)
{
- $answer = $this->request->getPostParam('answer-'.strval($i+1));
- $answers[] = $answer;
- $score = preg_match($regexs[$i]['regex'], $answer);
- if($score === 0 || $score === false) {
+ if(!array_key_exists($i, $answers))
+ {
$allSolved = false;
+ break;
+ }
+
+ $score = preg_match($regex['regex'], $answers[$i]);
+ if($score === 0 || $score === false)
+ {
+ $allSolved = false;
+ break;
}
}
- // Store answers in session
- $_SESSION['answers'][$questId] = $answers;
-
// Set status
if($allSolved) {
$this->setQuestSolved();
@@ -77,7 +85,7 @@
// Pass data to view
- $this->set('text', $textParts);
+ $this->set('texts', $textParts);
$this->set('answers', $answers);
}
diff --git a/questtypes/textinput/html/index.tpl b/questtypes/textinput/html/index.tpl
index 714d828d..40f0d213 100644
--- a/questtypes/textinput/html/index.tpl
+++ b/questtypes/textinput/html/index.tpl
@@ -1,10 +1,10 @@
-
+ &$text) : ?>
0) : ?>
-
+
- =\hhu\z\Utils::t($text[$i])?>
-
+ =\hhu\z\Utils::t($text)?>
+
diff --git a/views/html/quests/quest.tpl b/views/html/quests/quest.tpl
index 66110f7b..42d218d1 100644
--- a/views/html/quests/quest.tpl
+++ b/views/html/quests/quest.tpl
@@ -76,6 +76,6 @@
=_('Task')?>
=\hhu\z\Utils::t($quest['task'])?>
- =$task?>
+ =$task?>
From 5461a4d93711d4c0c8b124717970cfda56723a8e Mon Sep 17 00:00:00 2001
From: coderkun
Date: Wed, 12 Mar 2014 01:29:11 +0100
Subject: [PATCH 080/213] implement Questtype ?Multiple choice?
---
.../MultiplechoiceQuesttypeAgent.inc | 24 +++++
.../MultiplechoiceQuesttypeController.inc | 88 +++++++++++++++++++
.../MultiplechoiceQuesttypeModel.inc | 64 ++++++++++++++
questtypes/multiplechoice/html/index.tpl | 11 +++
4 files changed, 187 insertions(+)
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
create mode 100644 questtypes/multiplechoice/html/index.tpl
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
new file mode 100644
index 00000000..2789c5f6
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * QuesttypeAgent for multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
new file mode 100644
index 00000000..44c99e3b
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
@@ -0,0 +1,88 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the MultiplechoiceQuesttypeAgent multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Display a text with input fields and evaluate if user input
+ * matches with stored regular expressions.
+ */
+ public function index($questId)
+ {
+ // Answers
+ if(!array_key_exists('answers', $_SESSION)) {
+ $_SESSION['answers'] = array();
+ }
+ $answers = array_key_exists($questId, $_SESSION['answers']) ? $_SESSION['answers'][$questId] : array();
+
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
+ {
+ // Get answers
+ $answers = $this->request->getPostParam('answers');
+
+ // Store answers in session
+ $_SESSION['answers'][$questId] = $answers;
+
+ // Get right answers
+ $tickQuestions = $this->Multiplechoice->getTickQuestionsOfQuest($questId);
+
+ // Match tick questions with user answers
+ $allSolved = true;
+ foreach($tickQuestions as &$tickQuestion)
+ {
+ $pos = intval($tickQuestion['pos'])-1;
+ if(!array_key_exists($pos, $answers) && $answers[$pos] == 'true')
+ {
+ $allSolved = false;
+ break;
+ }
+ else {
+ unset($answers[$pos]);
+ }
+ }
+
+ // Set status
+ if($allSolved && count($answers) == 0) {
+ $this->setQuestSolved();
+ }
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+
+
+ // Get questions
+ $questions = $this->Multiplechoice->getQuestionsOfQuest($questId);
+
+
+ // Pass data to view
+ $this->set('questions', $questions);
+ $this->set('answers', $answers);
+ }
+
+ }
+
+?>
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
new file mode 100644
index 00000000..cf170390
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
@@ -0,0 +1,64 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the MultiplechoiceQuesttypeAgent for multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+
+
+
+
+ /**
+ * Get all multiple choice questions of a Quest.
+ *
+ * @param int $questId ID of Quest
+ * @return array Multiple choice questions
+ */
+ public function getQuestionsOfQuest($questId)
+ {
+ return $this->db->query(
+ 'SELECT question, tick '.
+ 'FROM questtypes_multiplechoice '.
+ 'WHERE quest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Get all multiple choice questions of a Quest that should be
+ * ticked.
+ *
+ * @param int $questId ID of Quest
+ * @return array Multiple choice questions that should be ticked
+ */
+ public function getTickQuestionsOfQuest($questId)
+ {
+ return $this->db->query(
+ 'SELECT question, tick, pos '.
+ 'FROM questtypes_multiplechoice '.
+ 'WHERE quest_id = ? AND tick = True',
+ 'i',
+ $questId
+ );
+ }
+
+ }
+
+?>
diff --git a/questtypes/multiplechoice/html/index.tpl b/questtypes/multiplechoice/html/index.tpl
new file mode 100644
index 00000000..1e64f3c7
--- /dev/null
+++ b/questtypes/multiplechoice/html/index.tpl
@@ -0,0 +1,11 @@
+
+
+ &$question) : ?>
+
+ />
+ =\hhu\z\Utils::t($question['question'])?>
+
+
+
+
+
From a017c7a79db48430ecf8b30763bf7ed3a0cf2ed2 Mon Sep 17 00:00:00 2001
From: Daniel
Date: Mon, 17 Mar 2014 16:00:48 +0100
Subject: [PATCH 081/213] belanglose vervollst?ndigung / test
---
.hgignore | 2 +
.htaccess | 50 ++
agents/BottomlevelAgent.inc | 25 +
agents/IntermediateAgent.inc | 48 ++
agents/ToplevelAgent.inc | 395 ++++++++++++
agents/bottomlevel/MenuAgent.inc | 35 +
.../QuestgroupshierarchypathAgent.inc | 35 +
.../bottomlevel/QuestgroupspictureAgent.inc | 35 +
agents/bottomlevel/UserrolesAgent.inc | 35 +
agents/intermediate/CharactergroupsAgent.inc | 35 +
.../CharactergroupsquestsAgent.inc | 35 +
agents/intermediate/CharactersAgent.inc | 43 ++
agents/intermediate/ErrorAgent.inc | 35 +
agents/intermediate/IntroductionAgent.inc | 35 +
agents/intermediate/MediaAgent.inc | 35 +
agents/intermediate/QuestgroupsAgent.inc | 37 ++
agents/intermediate/QuestsAgent.inc | 37 ++
agents/intermediate/SeminariesAgent.inc | 35 +
agents/intermediate/UsersAgent.inc | 44 ++
agents/toplevel/BinaryAgent.inc | 41 ++
agents/toplevel/FaultAgent.inc | 35 +
agents/toplevel/HtmlAgent.inc | 67 ++
apis/WebApi.inc | 250 ++++++++
app/Controller.inc | 99 +++
app/Model.inc | 42 ++
app/QuesttypeAgent.inc | 231 +++++++
app/QuesttypeController.inc | 294 +++++++++
app/QuesttypeModel.inc | 154 +++++
app/QuesttypeView.inc | 76 +++
app/ToplevelAgent.inc | 36 ++
app/Utils.inc | 51 ++
app/controllers/SeminaryRoleController.inc | 136 ++++
app/controllers/ToplevelController.inc | 170 +++++
.../QuesttypeAgentNotFoundException.inc | 77 +++
.../QuesttypeAgentNotValidException.inc | 77 +++
.../QuesttypeControllerNotFoundException.inc | 77 +++
.../QuesttypeControllerNotValidException.inc | 77 +++
.../QuesttypeModelNotFoundException.inc | 77 +++
.../QuesttypeModelNotValidException.inc | 77 +++
app/lib/Password.inc | 316 +++++++++
bootstrap.inc | 33 +
configs/AppConfig.inc | 127 ++++
configs/CoreConfig.inc | 167 +++++
controllers/BinaryController.inc | 37 ++
controllers/CharactergroupsController.inc | 143 +++++
.../CharactergroupsquestsController.inc | 91 +++
controllers/CharactersController.inc | 101 +++
controllers/ErrorController.inc | 48 ++
controllers/FaultController.inc | 37 ++
controllers/HtmlController.inc | 59 ++
controllers/IntroductionController.inc | 35 +
controllers/MediaController.inc | 143 +++++
controllers/MenuController.inc | 50 ++
controllers/QuestgroupsController.inc | 124 ++++
.../QuestgroupshierarchypathController.inc | 76 +++
controllers/QuestgroupspictureController.inc | 65 ++
controllers/QuestsController.inc | 275 ++++++++
controllers/SeminariesController.inc | 214 ++++++
controllers/UserrolesController.inc | 47 ++
controllers/UsersController.inc | 231 +++++++
.../components/AchievementComponent.inc | 41 ++
controllers/components/AuthComponent.inc | 79 +++
core/Agent.inc | 607 ++++++++++++++++++
core/Api.inc | 163 +++++
core/Autoloader.inc | 98 +++
core/ClassLoader.inc | 129 ++++
core/Component.inc | 85 +++
core/Config.inc | 49 ++
core/Controller.inc | 424 ++++++++++++
core/Driver.inc | 96 +++
core/Exception.inc | 65 ++
core/Linker.inc | 311 +++++++++
core/Logger.inc | 132 ++++
core/Model.inc | 141 ++++
core/Request.inc | 64 ++
core/Response.inc | 158 +++++
core/View.inc | 124 ++++
core/WebUtils.inc | 75 +++
drivers/DatabaseDriver.inc | 87 +++
drivers/MysqliDriver.inc | 169 +++++
exceptions/AccessDeniedException.inc | 51 ++
exceptions/ActionNotFoundException.inc | 77 +++
exceptions/AgentNotFoundException.inc | 67 ++
exceptions/AgentNotValidException.inc | 67 ++
exceptions/ClassNotFoundException.inc | 77 +++
exceptions/ClassNotValidException.inc | 77 +++
exceptions/ComponentNotFoundException.inc | 67 ++
exceptions/ComponentNotValidException.inc | 67 ++
exceptions/ControllerNotFoundException.inc | 67 ++
exceptions/ControllerNotValidException.inc | 67 ++
exceptions/DatamodelException.inc | 99 +++
exceptions/DriverNotFoundException.inc | 68 ++
exceptions/DriverNotValidException.inc | 68 ++
exceptions/FatalDatamodelException.inc | 96 +++
exceptions/IdNotFoundException.inc | 77 +++
exceptions/LayoutNotFoundException.inc | 68 ++
exceptions/LayoutNotValidException.inc | 67 ++
exceptions/ModelNotFoundException.inc | 67 ++
exceptions/ModelNotValidException.inc | 68 ++
exceptions/ParamsNotValidException.inc | 77 +++
exceptions/ServiceUnavailableException.inc | 77 +++
exceptions/ViewNotFoundException.inc | 77 +++
locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 0 -> 2719 bytes
locale/de_DE/LC_MESSAGES/The Legend of Z.po | 260 ++++++++
logs/empty | 0
media/empty | 0
models/AchievementsModel.inc | 36 ++
models/CharactergroupsModel.inc | 147 +++++
models/CharactergroupsquestsModel.inc | 136 ++++
models/CharactersModel.inc | 155 +++++
models/DatabaseModel.inc | 83 +++
models/MediaModel.inc | 90 +++
models/QuestgroupsModel.inc | 307 +++++++++
models/QuestgroupshierarchyModel.inc | 103 +++
models/QuestsModel.inc | 304 +++++++++
models/QuesttextsModel.inc | 135 ++++
models/QuesttypesModel.inc | 62 ++
models/SeminariesModel.inc | 161 +++++
models/SeminarycharacterfieldsModel.inc | 58 ++
models/UserrolesModel.inc | 77 +++
models/UsersModel.inc | 249 +++++++
models/UserseminaryrolesModel.inc | 78 +++
questtypes/dummy/DummyQuesttypeAgent.inc | 24 +
questtypes/dummy/DummyQuesttypeController.inc | 48 ++
questtypes/dummy/DummyQuesttypeModel.inc | 25 +
questtypes/dummy/html/index.tpl | 4 +
.../MultiplechoiceQuesttypeAgent.inc | 24 +
.../MultiplechoiceQuesttypeController.inc | 88 +++
.../MultiplechoiceQuesttypeModel.inc | 64 ++
questtypes/multiplechoice/html/index.tpl | 11 +
.../textinput/TextinputQuesttypeAgent.inc | 24 +
.../TextinputQuesttypeController.inc | 94 +++
.../textinput/TextinputQuesttypeModel.inc | 67 ++
questtypes/textinput/html/index.tpl | 11 +
requests/WebRequest.inc | 401 ++++++++++++
responses/WebResponse.inc | 250 ++++++++
views/binary/binary.tpl | 1 +
views/binary/error/index.tpl | 1 +
views/binary/media/index.tpl | 1 +
views/error.tpl | 13 +
views/fault/error/index.tpl | 2 +
views/fault/fault.tpl | 16 +
views/html/charactergroups/group.tpl | 33 +
views/html/charactergroups/groupsgroup.tpl | 18 +
views/html/charactergroups/index.tpl | 9 +
views/html/charactergroupsquests/quest.tpl | 46 ++
views/html/characters/character.tpl | 25 +
views/html/characters/index.tpl | 8 +
views/html/error/index.tpl | 2 +
views/html/html.tpl | 31 +
views/html/introduction/index.tpl | 21 +
views/html/menu/index.tpl | 9 +
views/html/questgroups/questgroup.tpl | 52 ++
views/html/questgroupshierarchypath/index.tpl | 8 +
views/html/questgroupspicture/index.tpl | 3 +
views/html/quests/index.tpl | 0
views/html/quests/quest.tpl | 81 +++
views/html/seminaries/create.tpl | 10 +
views/html/seminaries/delete.tpl | 8 +
views/html/seminaries/edit.tpl | 10 +
views/html/seminaries/index.tpl | 14 +
views/html/seminaries/seminary.tpl | 30 +
views/html/userroles/user.tpl | 5 +
views/html/users/create.tpl | 14 +
views/html/users/delete.tpl | 8 +
views/html/users/edit.tpl | 14 +
views/html/users/index.tpl | 14 +
views/html/users/login.tpl | 12 +
views/html/users/logout.tpl | 0
views/html/users/user.tpl | 19 +
views/inlineerror.tpl | 1 +
www/.htaccess | 8 +
www/css/desktop.css | 1 +
www/error403.html | 14 +
www/error404.html | 14 +
www/error500.html | 14 +
www/index.php | 45 ++
177 files changed, 14495 insertions(+)
create mode 100644 .hgignore
create mode 100644 .htaccess
create mode 100644 agents/BottomlevelAgent.inc
create mode 100644 agents/IntermediateAgent.inc
create mode 100644 agents/ToplevelAgent.inc
create mode 100644 agents/bottomlevel/MenuAgent.inc
create mode 100644 agents/bottomlevel/QuestgroupshierarchypathAgent.inc
create mode 100644 agents/bottomlevel/QuestgroupspictureAgent.inc
create mode 100644 agents/bottomlevel/UserrolesAgent.inc
create mode 100644 agents/intermediate/CharactergroupsAgent.inc
create mode 100644 agents/intermediate/CharactergroupsquestsAgent.inc
create mode 100644 agents/intermediate/CharactersAgent.inc
create mode 100644 agents/intermediate/ErrorAgent.inc
create mode 100644 agents/intermediate/IntroductionAgent.inc
create mode 100644 agents/intermediate/MediaAgent.inc
create mode 100644 agents/intermediate/QuestgroupsAgent.inc
create mode 100644 agents/intermediate/QuestsAgent.inc
create mode 100644 agents/intermediate/SeminariesAgent.inc
create mode 100644 agents/intermediate/UsersAgent.inc
create mode 100644 agents/toplevel/BinaryAgent.inc
create mode 100644 agents/toplevel/FaultAgent.inc
create mode 100644 agents/toplevel/HtmlAgent.inc
create mode 100644 apis/WebApi.inc
create mode 100644 app/Controller.inc
create mode 100644 app/Model.inc
create mode 100644 app/QuesttypeAgent.inc
create mode 100644 app/QuesttypeController.inc
create mode 100644 app/QuesttypeModel.inc
create mode 100644 app/QuesttypeView.inc
create mode 100644 app/ToplevelAgent.inc
create mode 100644 app/Utils.inc
create mode 100644 app/controllers/SeminaryRoleController.inc
create mode 100644 app/controllers/ToplevelController.inc
create mode 100644 app/exceptions/QuesttypeAgentNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeAgentNotValidException.inc
create mode 100644 app/exceptions/QuesttypeControllerNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeControllerNotValidException.inc
create mode 100644 app/exceptions/QuesttypeModelNotFoundException.inc
create mode 100644 app/exceptions/QuesttypeModelNotValidException.inc
create mode 100644 app/lib/Password.inc
create mode 100644 bootstrap.inc
create mode 100644 configs/AppConfig.inc
create mode 100644 configs/CoreConfig.inc
create mode 100644 controllers/BinaryController.inc
create mode 100644 controllers/CharactergroupsController.inc
create mode 100644 controllers/CharactergroupsquestsController.inc
create mode 100644 controllers/CharactersController.inc
create mode 100644 controllers/ErrorController.inc
create mode 100644 controllers/FaultController.inc
create mode 100644 controllers/HtmlController.inc
create mode 100644 controllers/IntroductionController.inc
create mode 100644 controllers/MediaController.inc
create mode 100644 controllers/MenuController.inc
create mode 100644 controllers/QuestgroupsController.inc
create mode 100644 controllers/QuestgroupshierarchypathController.inc
create mode 100644 controllers/QuestgroupspictureController.inc
create mode 100644 controllers/QuestsController.inc
create mode 100644 controllers/SeminariesController.inc
create mode 100644 controllers/UserrolesController.inc
create mode 100644 controllers/UsersController.inc
create mode 100644 controllers/components/AchievementComponent.inc
create mode 100644 controllers/components/AuthComponent.inc
create mode 100644 core/Agent.inc
create mode 100644 core/Api.inc
create mode 100644 core/Autoloader.inc
create mode 100644 core/ClassLoader.inc
create mode 100644 core/Component.inc
create mode 100644 core/Config.inc
create mode 100644 core/Controller.inc
create mode 100644 core/Driver.inc
create mode 100644 core/Exception.inc
create mode 100644 core/Linker.inc
create mode 100644 core/Logger.inc
create mode 100644 core/Model.inc
create mode 100644 core/Request.inc
create mode 100644 core/Response.inc
create mode 100644 core/View.inc
create mode 100644 core/WebUtils.inc
create mode 100644 drivers/DatabaseDriver.inc
create mode 100644 drivers/MysqliDriver.inc
create mode 100644 exceptions/AccessDeniedException.inc
create mode 100644 exceptions/ActionNotFoundException.inc
create mode 100644 exceptions/AgentNotFoundException.inc
create mode 100644 exceptions/AgentNotValidException.inc
create mode 100644 exceptions/ClassNotFoundException.inc
create mode 100644 exceptions/ClassNotValidException.inc
create mode 100644 exceptions/ComponentNotFoundException.inc
create mode 100644 exceptions/ComponentNotValidException.inc
create mode 100644 exceptions/ControllerNotFoundException.inc
create mode 100644 exceptions/ControllerNotValidException.inc
create mode 100644 exceptions/DatamodelException.inc
create mode 100644 exceptions/DriverNotFoundException.inc
create mode 100644 exceptions/DriverNotValidException.inc
create mode 100644 exceptions/FatalDatamodelException.inc
create mode 100644 exceptions/IdNotFoundException.inc
create mode 100644 exceptions/LayoutNotFoundException.inc
create mode 100644 exceptions/LayoutNotValidException.inc
create mode 100644 exceptions/ModelNotFoundException.inc
create mode 100644 exceptions/ModelNotValidException.inc
create mode 100644 exceptions/ParamsNotValidException.inc
create mode 100644 exceptions/ServiceUnavailableException.inc
create mode 100644 exceptions/ViewNotFoundException.inc
create mode 100644 locale/de_DE/LC_MESSAGES/The Legend of Z.mo
create mode 100644 locale/de_DE/LC_MESSAGES/The Legend of Z.po
create mode 100644 logs/empty
create mode 100644 media/empty
create mode 100644 models/AchievementsModel.inc
create mode 100644 models/CharactergroupsModel.inc
create mode 100644 models/CharactergroupsquestsModel.inc
create mode 100644 models/CharactersModel.inc
create mode 100644 models/DatabaseModel.inc
create mode 100644 models/MediaModel.inc
create mode 100644 models/QuestgroupsModel.inc
create mode 100644 models/QuestgroupshierarchyModel.inc
create mode 100644 models/QuestsModel.inc
create mode 100644 models/QuesttextsModel.inc
create mode 100644 models/QuesttypesModel.inc
create mode 100644 models/SeminariesModel.inc
create mode 100644 models/SeminarycharacterfieldsModel.inc
create mode 100644 models/UserrolesModel.inc
create mode 100644 models/UsersModel.inc
create mode 100644 models/UserseminaryrolesModel.inc
create mode 100644 questtypes/dummy/DummyQuesttypeAgent.inc
create mode 100644 questtypes/dummy/DummyQuesttypeController.inc
create mode 100644 questtypes/dummy/DummyQuesttypeModel.inc
create mode 100644 questtypes/dummy/html/index.tpl
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
create mode 100644 questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
create mode 100644 questtypes/multiplechoice/html/index.tpl
create mode 100644 questtypes/textinput/TextinputQuesttypeAgent.inc
create mode 100644 questtypes/textinput/TextinputQuesttypeController.inc
create mode 100644 questtypes/textinput/TextinputQuesttypeModel.inc
create mode 100644 questtypes/textinput/html/index.tpl
create mode 100644 requests/WebRequest.inc
create mode 100644 responses/WebResponse.inc
create mode 100644 views/binary/binary.tpl
create mode 100644 views/binary/error/index.tpl
create mode 100644 views/binary/media/index.tpl
create mode 100644 views/error.tpl
create mode 100644 views/fault/error/index.tpl
create mode 100644 views/fault/fault.tpl
create mode 100644 views/html/charactergroups/group.tpl
create mode 100644 views/html/charactergroups/groupsgroup.tpl
create mode 100644 views/html/charactergroups/index.tpl
create mode 100644 views/html/charactergroupsquests/quest.tpl
create mode 100644 views/html/characters/character.tpl
create mode 100644 views/html/characters/index.tpl
create mode 100644 views/html/error/index.tpl
create mode 100644 views/html/html.tpl
create mode 100644 views/html/introduction/index.tpl
create mode 100644 views/html/menu/index.tpl
create mode 100644 views/html/questgroups/questgroup.tpl
create mode 100644 views/html/questgroupshierarchypath/index.tpl
create mode 100644 views/html/questgroupspicture/index.tpl
create mode 100644 views/html/quests/index.tpl
create mode 100644 views/html/quests/quest.tpl
create mode 100644 views/html/seminaries/create.tpl
create mode 100644 views/html/seminaries/delete.tpl
create mode 100644 views/html/seminaries/edit.tpl
create mode 100644 views/html/seminaries/index.tpl
create mode 100644 views/html/seminaries/seminary.tpl
create mode 100644 views/html/userroles/user.tpl
create mode 100644 views/html/users/create.tpl
create mode 100644 views/html/users/delete.tpl
create mode 100644 views/html/users/edit.tpl
create mode 100644 views/html/users/index.tpl
create mode 100644 views/html/users/login.tpl
create mode 100644 views/html/users/logout.tpl
create mode 100644 views/html/users/user.tpl
create mode 100644 views/inlineerror.tpl
create mode 100644 www/.htaccess
create mode 100644 www/css/desktop.css
create mode 100644 www/error403.html
create mode 100644 www/error404.html
create mode 100644 www/error500.html
create mode 100644 www/index.php
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 00000000..5c118c1e
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,2 @@
+syntax: glob
+media/*
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 00000000..cb3fb9ef
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,50 @@
+Options -Indexes -MultiViews
+
+ErrorDocument 403 /www/error403.html
+ErrorDocument 404 /www/error404.html
+ErrorDocument 500 /www/error500.html
+
+
+
+
+ Require all granted
+
+
+ Require all denied
+
+
+
+ Require all denied
+
+
+
+ Require all denied
+
+
+
+
+ Allow From All
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+ Order Deny,Allow
+ Deny From All
+
+
+
+
+
+ RewriteEngine On
+
+ RewriteBase /
+ RewriteRule ^(.*)$ www/$1 [L]
+
diff --git a/agents/BottomlevelAgent.inc b/agents/BottomlevelAgent.inc
new file mode 100644
index 00000000..37816614
--- /dev/null
+++ b/agents/BottomlevelAgent.inc
@@ -0,0 +1,25 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The BottomlevelAgent is the standard Agent and can have indefinite
+ * SubAgents.
+ *
+ * @author coderkun
+ */
+ abstract class BottomlevelAgent extends \nre\core\Agent
+ {
+ }
+
+?>
diff --git a/agents/IntermediateAgent.inc b/agents/IntermediateAgent.inc
new file mode 100644
index 00000000..7139653d
--- /dev/null
+++ b/agents/IntermediateAgent.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The IntermediateAgent assumes the task of a module. There is only one
+ * IntermediateAgent per request.
+ *
+ * @author coderkun
+ */
+ abstract class IntermediateAgent extends \nre\core\Agent
+ {
+
+
+
+
+ /**
+ * Get the layout if it was explicitly defined.
+ *
+ * @return string Layout of the IntermediateAgent
+ */
+ public static function getLayout($agentName)
+ {
+ // Determine classname
+ $className = Autoloader::concatClassNames($agentName, 'Agent');
+
+ // Check property
+ if(isset($className::$layout)) {
+ return $className::$layout;
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
diff --git a/agents/ToplevelAgent.inc b/agents/ToplevelAgent.inc
new file mode 100644
index 00000000..9d6d6f8a
--- /dev/null
+++ b/agents/ToplevelAgent.inc
@@ -0,0 +1,395 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\agents;
+
+
+ /**
+ * The ToplevelAgent assumes the task of a FrontController. There is
+ * only one per request.
+ *
+ * @author coderkun
+ */
+ class ToplevelAgent extends \nre\core\Agent
+ {
+ /**
+ * Stage: Load
+ *
+ * @var string
+ */
+ const STAGE_LOAD = 'load';
+ /**
+ * Stage: Run
+ *
+ * @var string
+ */
+ const STAGE_RUN = 'run';
+
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+ /**
+ * Layout instace
+ *
+ * @var Layout
+ */
+ private $layout = null;
+ /**
+ * IntermediateAgent instance
+ *
+ * @var IntermediateAgent
+ */
+ private $intermediateAgent = null;
+
+
+
+
+ /**
+ * Construct a ToplevelAgent.
+ *
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+
+
+ // Create response
+ $response = clone $response;
+ $response->clearParams(1);
+ $response->addParams(
+ null,
+ \nre\configs\CoreConfig::$defaults['action']
+ );
+
+ // Call parent constructor
+ parent::__construct($request, $response, $log, true);
+
+
+ // Load IntermediateAgent
+ $this->loadIntermediateAgent();
+ }
+
+
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws ServiceUnavailableException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ public function run(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ try {
+ return $this->_run($request, $response);
+ }
+ catch(\nre\exceptions\AccessDeniedException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_FORBIDDEN, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\ParamsNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE, self::STAGE_RUN);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND, self::STAGE_RUN);
+ }
+ }
+
+
+ /**
+ * Generate output of the Controller of this Agent and its
+ * SubAgents.
+ *
+ * @param array $data View data
+ * @return string Generated output
+ */
+ public function render($data=array())
+ {
+ // Render IntermediateAgent
+ $data = array();
+ $data['intermediate'] = $this->intermediateAgent->render();
+
+
+ // Render ToplevelAgent
+ return parent::render($data);
+ }
+
+
+ /**
+ * Return the IntermediateAgent.
+ *
+ * @return IntermediateAgent IntermediateAgent
+ */
+ public function getIntermediateAgent()
+ {
+ return $this->intermediateAgent;
+ }
+
+
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws FatalDatamodelException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function addSubAgent($agentName)
+ {
+ try {
+ call_user_func_array(
+ array(
+ $this,
+ '_addSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ throw new \nre\exceptions\FatalDatamodelException($e->getDatamodelMessage(), $e->getDatamodelErrorNumber());
+ }
+ }
+
+
+
+
+ /**
+ * Load IntermediateAgent defined by the current request.
+ *
+ * @throws ServiceUnavailableException
+ */
+ private function loadIntermediateAgent()
+ {
+ try {
+ $this->_loadIntermediateAgent();
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ }
+
+
+ /**
+ * Load IntermediateAgent defined by the current request.
+ *
+ * @throws ServiceUnavailableException
+ */
+ private function _loadIntermediateAgent()
+ {
+ // Determine IntermediateAgent
+ $agentName = $this->response->getParam(1);
+ if(is_null($agentName)) {
+ $agentName = $this->request->getParam(1, 'intermediate');
+ $this->response->addParam($agentName);
+ }
+
+ // Load IntermediateAgent
+ IntermediateAgent::load($agentName);
+
+
+ // Determine Action
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+ // Construct IntermediateAgent
+ $this->intermediateAgent = \nre\agents\IntermediateAgent::factory(
+ $agentName,
+ $this->request,
+ $this->response,
+ $this->log
+ );
+ }
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws AccessDeniedException
+ * @throws IdNotFoundException
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ private function _run(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ // Run IntermediateAgent
+ $this->runIntermediateAgent();
+
+
+ // TODO Request instead of response?
+ $response = clone $response;
+ $response->clearParams(2);
+ $response->addParam(\nre\configs\CoreConfig::$defaults['action']);
+
+
+ // Run ToplevelAgent
+ return parent::run($request, $response);
+ }
+
+
+ /**
+ * Run IntermediateAgent.
+ *
+ * @throws AccessDeniedException
+ * @throws ParamsNotValidException
+ * @throws IdNotFoundException
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ */
+ private function runIntermediateAgent()
+ {
+ $this->intermediateAgent->run(
+ $this->request,
+ $this->response
+ );
+ }
+
+
+ /**
+ * Handle an error that occurred during
+ * loading/cnostructing/running of the IntermediateAgent.
+ *
+ * @throws ServiceUnavailableException
+ * @param Exception $exception Occurred exception
+ * @param int $httpStatusCode HTTP-statuscode
+ * @param string $stage Stage of execution
+ */
+ private function error($exception, $httpStatusCode, $stage=self::STAGE_LOAD)
+ {
+ // Log error
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+
+ try {
+ // Define ErrorAgent
+ $this->response->clearParams(1);
+ $this->response->addParams(
+ \nre\configs\AppConfig::$defaults['intermediate-error'],
+ \nre\configs\CoreConfig::$defaults['action'],
+ $httpStatusCode
+ );
+
+ // Load ErrorAgent
+ $this->_loadIntermediateAgent();
+
+ // Run ErrorAgent
+ if($stage == self::STAGE_RUN) {
+ $this->_run($this->request, $this->response);
+ }
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ catch(Exception $e) {
+ throw new \nre\exceptions\ServiceUnavailableException($e);
+ }
+ }
+
+
+ }
+
+?>
diff --git a/agents/bottomlevel/MenuAgent.inc b/agents/bottomlevel/MenuAgent.inc
new file mode 100644
index 00000000..77d60d8d
--- /dev/null
+++ b/agents/bottomlevel/MenuAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\bottomlevel;
+
+
+ /**
+ * Agent to display a menu.
+ *
+ * @author Oliver Hanraths
+ */
+ class MenuAgent extends \nre\agents\BottomlevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/bottomlevel/QuestgroupshierarchypathAgent.inc b/agents/bottomlevel/QuestgroupshierarchypathAgent.inc
new file mode 100644
index 00000000..a2cb8086
--- /dev/null
+++ b/agents/bottomlevel/QuestgroupshierarchypathAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\bottomlevel;
+
+
+ /**
+ * Agent to display the Questgroups hierarchy path.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupshierarchypathAgent extends \nre\agents\BottomlevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/bottomlevel/QuestgroupspictureAgent.inc b/agents/bottomlevel/QuestgroupspictureAgent.inc
new file mode 100644
index 00000000..8cdca7cd
--- /dev/null
+++ b/agents/bottomlevel/QuestgroupspictureAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\bottomlevel;
+
+
+ /**
+ * Agent to display the picture of a Questgroup.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupspictureAgent extends \nre\agents\BottomlevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/bottomlevel/UserrolesAgent.inc b/agents/bottomlevel/UserrolesAgent.inc
new file mode 100644
index 00000000..b6d6e65b
--- /dev/null
+++ b/agents/bottomlevel/UserrolesAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\bottomlevel;
+
+
+ /**
+ * Agent to display and manage userroles.
+ *
+ * @author Oliver Hanraths
+ */
+ class UserrolesAgent extends \nre\agents\BottomlevelAgent
+ {
+
+
+
+
+ /**
+ * Action: user.
+ */
+ public function user(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/CharactergroupsAgent.inc b/agents/intermediate/CharactergroupsAgent.inc
new file mode 100644
index 00000000..77ac5f5a
--- /dev/null
+++ b/agents/intermediate/CharactergroupsAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Character groups.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/CharactergroupsquestsAgent.inc b/agents/intermediate/CharactergroupsquestsAgent.inc
new file mode 100644
index 00000000..bfc87de1
--- /dev/null
+++ b/agents/intermediate/CharactergroupsquestsAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Character groups Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/CharactersAgent.inc b/agents/intermediate/CharactersAgent.inc
new file mode 100644
index 00000000..25102198
--- /dev/null
+++ b/agents/intermediate/CharactersAgent.inc
@@ -0,0 +1,43 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered Characters and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactersAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+
+ /**
+ * Action: character.
+ */
+ public function character(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/ErrorAgent.inc b/agents/intermediate/ErrorAgent.inc
new file mode 100644
index 00000000..85bb6f95
--- /dev/null
+++ b/agents/intermediate/ErrorAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to show an error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class ErrorAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/IntroductionAgent.inc b/agents/intermediate/IntroductionAgent.inc
new file mode 100644
index 00000000..3a06fdff
--- /dev/null
+++ b/agents/intermediate/IntroductionAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to show an introduction page.
+ *
+ * @author Oliver Hanraths
+ */
+ class IntroductionAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/MediaAgent.inc b/agents/intermediate/MediaAgent.inc
new file mode 100644
index 00000000..c3fd35ae
--- /dev/null
+++ b/agents/intermediate/MediaAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to process and show media.
+ *
+ * @author Oliver Hanraths
+ */
+ class MediaAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/QuestgroupsAgent.inc b/agents/intermediate/QuestgroupsAgent.inc
new file mode 100644
index 00000000..860fd177
--- /dev/null
+++ b/agents/intermediate/QuestgroupsAgent.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Questgroups.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: questgroup.
+ */
+ public function questgroup(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ $this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4));
+ $this->addSubAgent('Questgroupspicture', 'index', $request->getParam(3), $request->getParam(4), true);
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/QuestsAgent.inc b/agents/intermediate/QuestsAgent.inc
new file mode 100644
index 00000000..c26a2f70
--- /dev/null
+++ b/agents/intermediate/QuestsAgent.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to display Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestsAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: quest.
+ */
+ public function quest(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ $this->addSubAgent('Questgroupshierarchypath', 'index', $request->getParam(3), $request->getParam(4), true);
+ $this->addSubAgent('Questgroupspicture', 'index', $request->getParam(3), $request->getParam(4), true);
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/SeminariesAgent.inc b/agents/intermediate/SeminariesAgent.inc
new file mode 100644
index 00000000..53f08124
--- /dev/null
+++ b/agents/intermediate/SeminariesAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/intermediate/UsersAgent.inc b/agents/intermediate/UsersAgent.inc
new file mode 100644
index 00000000..a9094490
--- /dev/null
+++ b/agents/intermediate/UsersAgent.inc
@@ -0,0 +1,44 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\intermediate;
+
+
+ /**
+ * Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersAgent extends \nre\agents\IntermediateAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+
+ /**
+ * Action: user.
+ */
+ public function user(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ $this->addSubAgent('Userroles', 'user');
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/BinaryAgent.inc b/agents/toplevel/BinaryAgent.inc
new file mode 100644
index 00000000..f2d6d33e
--- /dev/null
+++ b/agents/toplevel/BinaryAgent.inc
@@ -0,0 +1,41 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display binary data (e. g. images).
+ *
+ * @author Oliver Hanraths
+ */
+ class BinaryAgent extends \hhu\z\ToplevelAgent
+ {
+
+
+
+
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ parent::__construct($request, $response, $log);
+ }
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/FaultAgent.inc b/agents/toplevel/FaultAgent.inc
new file mode 100644
index 00000000..1ceb682e
--- /dev/null
+++ b/agents/toplevel/FaultAgent.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display a toplevel error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class FaultAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ }
+
+ }
+
+?>
diff --git a/agents/toplevel/HtmlAgent.inc b/agents/toplevel/HtmlAgent.inc
new file mode 100644
index 00000000..63ed4525
--- /dev/null
+++ b/agents/toplevel/HtmlAgent.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\agents\toplevel;
+
+
+ /**
+ * Agent to display a HTML-page.
+ *
+ * @author Oliver Hanraths
+ */
+ class HtmlAgent extends \hhu\z\ToplevelAgent
+ {
+
+
+
+
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ parent::__construct($request, $response, $log);
+
+
+ $this->setLanguage($request);
+ }
+
+
+ /**
+ * Action: index.
+ */
+ public function index(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ // Add menu
+ $this->addSubAgent('Menu');
+ }
+
+
+
+
+ private function setLanguage(\nre\core\Request $request)
+ {
+ // Set domain
+ $domain = \nre\configs\AppConfig::$app['name'];
+
+ // Get language
+ $locale = $request->getGetParam('lang', 'language');
+ if(is_null($locale)) {
+ return;
+ }
+
+ // Load translation
+ putenv("LC_ALL=$locale");
+ setlocale(LC_ALL, $locale);
+ bindtextdomain($domain, ROOT.DS.\nre\configs\AppConfig::$dirs['locale']);
+ textdomain($domain);
+ }
+
+ }
+
+?>
diff --git a/apis/WebApi.inc b/apis/WebApi.inc
new file mode 100644
index 00000000..6851ee2d
--- /dev/null
+++ b/apis/WebApi.inc
@@ -0,0 +1,250 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\apis;
+
+
+ /**
+ * WebApi-implementation.
+ *
+ * This class runs and renders an web-applictaion.
+ *
+ * @author coderkun
+ */
+ class WebApi extends \nre\core\Api
+ {
+
+
+
+
+ /**
+ * Construct a new WebApi.
+ */
+ public function __construct()
+ {
+ parent::__construct(
+ new \nre\requests\WebRequest(),
+ new \nre\responses\WebResponse()
+ );
+
+ // Add routes
+ $this->addRoutes();
+
+ // Disable screen logging for AJAX requests
+ if($this->request->getParam(0, 'toplevel') == 'ajax') {
+ $this->log->disableAutoLogToScreen();
+ }
+ }
+
+
+
+
+ /**
+ * Run application.
+ *
+ * This method runs the application and handles all errors.
+ */
+ public function run()
+ {
+ try {
+ $exception = parent::run();
+
+ if(!is_null($exception)) {
+ $this->errorService($exception);
+ }
+ }
+ catch(\nre\exceptions\ServiceUnavailableException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\FatalDatamodelException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\AgentNoaatValidException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_SERVICE_UNAVAILABLE);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->error($e, \nre\core\WebUtils::HTTP_NOT_FOUND);
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ $this->errorService($e);
+ }
+ }
+
+
+ /**
+ * Render output.
+ */
+ public function render()
+ {
+ // Generate output
+ parent::render();
+
+
+ // Set HTTP-header
+ $this->response->header();
+
+ // Show output
+ echo $this->response->getOutput();
+ }
+
+
+
+
+ /**
+ * Add routes (normal and reverse) defined in the AppConfig.
+ */
+ private function addRoutes()
+ {
+ // Normal routes
+ if(property_exists('\nre\configs\AppConfig', 'routes')) {
+ foreach(\nre\configs\AppConfig::$routes as &$route) {
+ $this->request->addRoute($route[0], $route[1], $route[2]);
+ }
+ }
+
+ // Reverse routes
+ if(property_exists('\nre\configs\AppConfig', 'reverseRoutes')) {
+ foreach(\nre\configs\AppConfig::$reverseRoutes as &$route) {
+ $this->request->addReverseRoute($route[0], $route[1], $route[2]);
+ }
+ }
+
+ // Revalidate request
+ $this->request->revalidate();
+ }
+
+
+ /**
+ * Handle an error that orrcurred during the
+ * loading/constructing/running of the ToplevelAgent.
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $httpStatusCode HTTP-statuscode
+ */
+ private function error(\nre\core\Exception $exception, $httpStatusCode)
+ {
+ // Log error message
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+ try {
+ // Set agent for handling errors
+ $this->response->clearParams();
+ $this->response->addParams(
+ \nre\configs\AppConfig::$defaults['toplevel-error'],
+ \nre\configs\AppConfig::$defaults['intermediate-error'],
+ \nre\configs\CoreConfig::$defaults['action'],
+ $httpStatusCode
+ );
+
+ // Run this agent
+ parent::run();
+ }
+ catch(\nre\exceptions\ServiceUnavailableException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DatamodelException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DriverNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\DriverNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ModelNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ModelNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ControllerNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\ControllerNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\AgentNotValidException $e) {
+ $this->errorService($e);
+ }
+ catch(\nre\exceptions\AgentNotFoundException $e) {
+ $this->errorService($e);
+ }
+ catch(Exception $e) {
+ $this->errorService($e);
+ }
+ }
+
+
+ /**
+ * Handle a error which cannot be handles by the system (and
+ * HTTP 503).
+ *
+ * $param Exception $exception Occurred exception
+ */
+ private function errorService($exception)
+ {
+ // Log error message
+ $this->log($exception, \nre\core\Logger::LOGMODE_AUTO);
+
+ // Set HTTP-rtatuscode
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader(503));
+
+
+ // Read and print static error file
+ $fileName = ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['errorFile'].\nre\configs\CoreConfig::getFileExt('views');
+ ob_start();
+ include($fileName);
+ $this->response->setOutput(ob_get_clean());
+
+
+ // Prevent further execution
+ $this->response->setExit();
+ }
+
+ }
+
+?>
diff --git a/app/Controller.inc b/app/Controller.inc
new file mode 100644
index 00000000..42881662
--- /dev/null
+++ b/app/Controller.inc
@@ -0,0 +1,99 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Controller.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class Controller extends \nre\core\Controller
+ {
+ /**
+ * Required components
+ *
+ * @var array
+ */
+ public $components = array('auth');
+ /**
+ * Linker instance
+ *
+ * @var Linker
+ */
+ protected $linker = null;
+
+
+
+
+ /**
+ * Construct a new application 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
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+ }
+
+
+
+ /**
+ * Prefilter that is executed before running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Create linker
+ $this->linker = new \nre\core\Linker($this->request);
+
+ // Create date and time formatter
+ $this->set('dateFormatter', new \IntlDateFormatter(
+ \nre\core\Config::getDefault('locale'),
+ \IntlDateFormatter::MEDIUM,
+ \IntlDateFormatter::NONE,
+ NULL
+ ));
+ $this->set('timeFormatter', new \IntlDateFormatter(
+ \nre\core\Config::getDefault('locale'),
+ \IntlDateFormatter::NONE,
+ \IntlDateFormatter::SHORT,
+ NULL
+ ));
+ }
+
+
+ /**
+ * Postfilter that is executed after running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::postFilter($request, $response);
+ }
+
+ }
+
+?>
diff --git a/app/Model.inc b/app/Model.inc
new file mode 100644
index 00000000..32835d04
--- /dev/null
+++ b/app/Model.inc
@@ -0,0 +1,42 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Model.
+ *
+ * @author Oliver Hanraths
+ */
+ class Model extends \nre\models\DatabaseModel
+ {
+
+
+
+
+ /**
+ * Construct a new application Model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ public function __construct()
+ {
+ parent::__construct('mysqli', \nre\configs\AppConfig::$database);
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeAgent.inc b/app/QuesttypeAgent.inc
new file mode 100644
index 00000000..9f104be1
--- /dev/null
+++ b/app/QuesttypeAgent.inc
@@ -0,0 +1,231 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeAgent.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeAgent extends \nre\agents\BottomlevelAgent
+ {
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+
+
+
+
+ /**
+ * Load a QuesttypeAgent.
+ *
+ * @static
+ * @throws QuesttypeAgentNotFoundException
+ * @throws QuesttypeAgentNotValidException
+ * @param string $questtypeName Name of the QuesttypeAgent to load
+ */
+ public static function load($questtypeName)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ try {
+ // Load class
+ static::loadClass($questtypeName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeAgentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeAgentNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeAgent (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ * @param string $questtypeName Name of the QuesttypeAgent to instantiate
+ * @param Request $request Current request
+ * @param Response $respone Current respone
+ * @param Logger $log Log-system
+ */
+ public static function factory($questtypeName, \nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ // Construct and return Questmodule
+ return new $className($request, $response, $log);
+ }
+
+
+ /**
+ * Determine the Agent-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Agent-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'agent');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeAgent.
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeAgent to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeAgent-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeAgent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+
+
+ // Call parent constructor
+ parent::__construct($request, $response, $log);
+ }
+
+
+
+
+ /**
+ * Load the Controller of this Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @throws QuesttypeControllerNotFoundException
+ */
+ protected function loadController()
+ {
+ // Determine Controller name
+ $controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
+
+ // Determine ToplevelAgent
+ $toplevelAgentName = $this->response->getParam(0);
+ if(is_null($toplevelAgentName)) {
+ $toplevelAgentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($toplevelAgentName);
+ }
+
+ // Determine Action
+ $action = \nre\configs\CoreConfig::$defaults['action'];
+
+
+ // Load Controller
+ \hhu\z\QuesttypeController::load($controllerName);
+
+ // Construct Controller
+ $this->controller = QuesttypeController::factory($controllerName, $toplevelAgentName, $action, $this);
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeController.inc b/app/QuesttypeController.inc
new file mode 100644
index 00000000..743c5d59
--- /dev/null
+++ b/app/QuesttypeController.inc
@@ -0,0 +1,294 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeController.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeController extends \hhu\z\Controller
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroups', 'quests', 'characters');
+
+
+
+
+ /**
+ * Load a QuesttypeController.
+ *
+ * @static
+ * @throws QuesttypeControllerNotFoundException
+ * @throws QuesttypeControllerNotValidException
+ * @param string $controllerName Name of the QuesttypeController to load
+ */
+ public static function load($controllerName)
+ {
+ // Determine full classname
+ $className = self::getClassName($controllerName);
+
+ try {
+ // Load class
+ static::loadClass($controllerName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeControllerNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeControllerNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeController (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws ViewNotFoundException
+ * @param string $controllerName Name of the QuesttypeController 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 Controller-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Controller-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'controller');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeController
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeController to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeController-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new application Controller.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of the current Layout
+ * @param string $action Current Action
+ * @param Agent $agent Corresponding Agent
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+ }
+
+
+
+
+ /**
+ * Load the Models of this Controller.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ protected function loadModels()
+ {
+ // Load default models
+ parent::loadModels();
+
+ // Load QuesttypeModel
+ $this->loadModel();
+ }
+
+
+ /**
+ * Load the Model of the Questtype.
+ *
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ private function loadModel()
+ {
+ // Determine Model
+ $model = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class($this))));
+
+ // Load class
+ QuesttypeModel::load($model);
+
+ // Construct Model
+ $modelName = ucfirst(strtolower($model));
+ $this->$modelName = QuesttypeModel::factory($model);
+ }
+
+
+ /**
+ * Load the View of this QuesttypeController.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of the current Layout
+ * @param string $action Current Action
+ */
+ protected function loadView($layoutName, $action)
+ {
+ // Check Layout name
+ if(is_null($layoutName)) {
+ return;
+ }
+
+ // Determine controller name
+ $controllerName = \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::getClassName(get_class($this)));
+
+
+ // Load view
+ $this->view = QuesttypeView::loadAndFactory($layoutName, $controllerName, $action);
+ }
+
+
+ /**
+ * Mark the current Quest as solved and redirect to solved page.
+ */
+ protected function setQuestSolved()
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($this->request->getParam(3));
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $this->request->getParam(4));
+
+ // Get Quest
+ $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
+
+ // Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Set solved
+ $this->Quests->setQuestSolved($quest['id'], $character['id']);
+
+
+ // Redirect
+ $this->redirect($this->linker->link('Epilog', $sidequest != null ? 6 : 5, true, array('status'=>'solved')));
+ }
+
+
+ /**
+ * Mark the current Quest as unsolved and redirect to unsolved
+ * page.
+ */
+ protected function setQuestUnsolved()
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($this->request->getParam(3));
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $this->request->getParam(4));
+
+ // Get Quest
+ $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $this->request->getParam(5));
+
+ // Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Set solved
+ $this->Quests->setQuestUnsolved($quest['id'], $character['id']);
+
+
+ // Redirect
+ $this->redirect($this->linker->link('Prolog', $sidequest != null ? 6 : 5, true, array('status'=>'unsolved')));
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeModel.inc b/app/QuesttypeModel.inc
new file mode 100644
index 00000000..d30699fb
--- /dev/null
+++ b/app/QuesttypeModel.inc
@@ -0,0 +1,154 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeModel.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class QuesttypeModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Load a Model.
+ *
+ * @static
+ * @throws QuesttypeModelNotFoundException
+ * @throws QuesttypeModelNotValidException
+ * @param string $modelName Name of the QuesttypeModel to load
+ */
+ public static function load($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ try {
+ // Load class
+ static::loadClass($modelName, $className);
+
+ // Validate class
+ static::checkClass($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \hhu\z\exceptions\QuesttypeModelNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \hhu\z\exceptions\QuesttypeModelNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a QuesttypeModel (Factory Pattern).
+ *
+ * @static
+ * @param string $questtypeName Name of the QuesttypeModel to instantiate
+ */
+ public static function factory($questtypeName)
+ {
+ // Determine full classname
+ $className = self::getClassName($questtypeName);
+
+ // Construct and return Model
+ return new $className();
+ }
+
+
+ /**
+ * Determine the Model-classname for the given Questtype-name.
+ *
+ * @static
+ * @param string $questtypeName Questtype-name to get Model-classname of
+ * @return string Classname for the Questtype-name
+ */
+ private static function getClassName($questtypeName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($questtypeName, \nre\core\ClassLoader::stripClassType(\nre\core\ClassLoader::stripNamespace(get_class())), 'model');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."questtypes\\$className";
+ }
+
+
+ /**
+ * Load the class of a QuesttypeModel.
+ *
+ * @static
+ * @throws ClassNotFoundException
+ * @param string $questtypeName Name of the QuesttypeModel to load
+ * @param string $fullClassName Name of the class to load
+ */
+ private static function loadClass($questtypeName, $fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_pop($className);
+
+ // Determine filename
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($questtypeName).DS.$className.\nre\configs\CoreConfig::getFileExt('includes');
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of the QuesttypeModel-class.
+ *
+ * @static
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function checkClass($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeModel.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws QuesttypeModelNotValidException
+ * @throws QuesttypeModelNotFoundException
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ }
+
+?>
diff --git a/app/QuesttypeView.inc b/app/QuesttypeView.inc
new file mode 100644
index 00000000..8e77ee00
--- /dev/null
+++ b/app/QuesttypeView.inc
@@ -0,0 +1,76 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing a QuesttypeView.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeView extends \nre\core\View
+ {
+
+
+
+
+ /**
+ * Load and instantiate the QuesttypeView of a QuesttypeAgent.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ public static function loadAndFactory($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ return new QuesttypeView($layoutName, $agentName, $action, $isToplevel);
+ }
+
+
+
+
+ /**
+ * Construct a new QuesttypeView.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ protected function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ // Create template filename
+ // LayoutName
+ $fileName = ROOT.DS.\nre\configs\AppConfig::$dirs['questtypes'].DS.strtolower($agentName).DS.strtolower($layoutName).DS;
+
+ // Action
+ $fileName .= strtolower($action);
+
+ // File extension
+ $fileName .= \nre\configs\CoreConfig::getFileExt('views');
+
+
+ // Check template file
+ if(!file_exists($fileName)) {
+ throw new \nre\exceptions\ViewNotFoundException($fileName);
+ }
+
+ // Save filename
+ $this->templateFilename = $fileName;
+ }
+
+ }
+
+?>
diff --git a/app/ToplevelAgent.inc b/app/ToplevelAgent.inc
new file mode 100644
index 00000000..97aea57b
--- /dev/null
+++ b/app/ToplevelAgent.inc
@@ -0,0 +1,36 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Abstract class for implementing an application Controller.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class ToplevelAgent extends \nre\agents\ToplevelAgent
+ {
+
+
+
+
+ protected function __construct(\nre\core\Request $request, \nre\core\Response $response, \nre\core\Logger $log=null)
+ {
+ parent::__construct($request, $response, $log);
+
+
+ // Set timezone
+ date_default_timezone_set(\nre\configs\AppConfig::$app['timeZone']);
+ }
+ }
+
+?>
diff --git a/app/Utils.inc b/app/Utils.inc
new file mode 100644
index 00000000..76ccc7fe
--- /dev/null
+++ b/app/Utils.inc
@@ -0,0 +1,51 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z;
+
+
+ /**
+ * Class for implementing utility methods.
+ *
+ * @author Oliver Hanraths
+ */
+ class Utils
+ {
+
+
+ /**
+ * Mask HTML-chars for save output.
+ *
+ * @static
+ * @param string $string String to be masked
+ * @return string Masked string
+ */
+ static function t($string)
+ {
+ return nl2br(htmlspecialchars($string));
+ }
+
+
+ /**
+ * ‚htmlspecialchars‘ with support for UTF-8.
+ *
+ * @static
+ * @param string $string String to be masked
+ * @return string Masked string
+ */
+ public static function htmlspecialchars_utf8($string)
+ {
+ return htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
+ }
+
+ }
+
+?>
diff --git a/app/controllers/SeminaryRoleController.inc b/app/controllers/SeminaryRoleController.inc
new file mode 100644
index 00000000..e06a9a03
--- /dev/null
+++ b/app/controllers/SeminaryRoleController.inc
@@ -0,0 +1,136 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Abstract class for implementing a Controller for a Seminary and its
+ * concepts.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class SeminaryRoleController extends \hhu\z\Controller
+ {
+ /**
+ * Required components
+ *
+ * @var array
+ */
+ public $components = array('achievement', 'auth');
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'userseminaryroles', 'characters', 'achievements');
+ /**
+ * Data of currently logged in user if any
+ *
+ * @var array
+ */
+ public static $user = null;
+
+
+
+
+ /**
+ * Construct a new SeminaryRole 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
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+ }
+
+
+
+ /**
+ * Prefilter that is executed before running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Check permissions
+ $this->checkPermission($request, $response);
+ }
+
+
+ /**
+ * Postfilter that is executed after running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::postFilter($request, $response);
+ }
+
+
+
+
+ /**
+ * Check user permissions.
+ *
+ * @throws AccessDeniedException
+ */
+ private function checkPermission(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ // Do not check index page
+ if(is_null($request->getParam(3))) {
+ return;
+ }
+
+ // Determine user and seminary
+ $userId = $this->Auth->getUserId();
+ $seminary = $this->Seminaries->getSeminaryByUrl($request->getParam(3));
+
+ // Determine user seminary roles
+ $userSeminaryRoles = array();
+ $roles = $this->Userseminaryroles->getUserseminaryrolesForUserById($userId, $seminary['id']);
+ foreach($roles as &$role) {
+ $userSeminaryRoles[] = $role['name'];
+ }
+
+
+ // Determine permissions for current action
+ $action = $this->request->getParam(2, 'action');
+ if(!property_exists($this, 'seminaryPermissions')) {
+ return; // Allow if nothing is specified
+ }
+ if(!array_key_exists($action, $this->seminaryPermissions)) {
+ return; // Allow if Action is not specified
+ }
+ $permissions = $this->seminaryPermissions[$action];
+
+
+ // Check permissions
+ if(count(array_intersect($userSeminaryRoles, $permissions)) == 0) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+
+ }
+
+?>
diff --git a/app/controllers/ToplevelController.inc b/app/controllers/ToplevelController.inc
new file mode 100644
index 00000000..30558c91
--- /dev/null
+++ b/app/controllers/ToplevelController.inc
@@ -0,0 +1,170 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Abstract class for implementing a Controller of a ToplevelAgent.
+ *
+ * @author Oliver Hanraths
+ */
+ abstract class ToplevelController extends \hhu\z\Controller
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('users', 'userroles', 'seminaries', 'characters');
+ /**
+ * Current user
+ *
+ * @var array
+ */
+ public static $user = null;
+ /**
+ *
+ */
+ public static $seminary = null;
+ /**
+ * Character of current user and Seminary
+ *
+ * @var array
+ */
+ public static $character = null;
+
+
+
+
+ /**
+ * Construct a new application 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
+ */
+ public function __construct($layoutName, $action, $agent)
+ {
+ parent::__construct($layoutName, $action, $agent);
+ }
+
+
+
+ /**
+ * Prefilter that is executed before running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Get userdata
+ try {
+ static::$user = $this->Users->getUserById($this->Auth->getUserId());
+
+ // Character
+ $controller = $this->agent->getIntermediateAgent()->controller;
+ if(is_subclass_of($controller, '\hhu\z\controllers\SeminaryRoleController'))
+ {
+ $seminaryUrl = $this->request->getParam(3);
+ static::$seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+ static::$character = $this->Characters->getCharacterForUserAndSeminary(static::$user['id'], static::$seminary['id']);
+ }
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ }
+
+ // Check permissions
+ $this->checkPermission($request, $response);
+
+ // Set userdata
+ $this->set('loggedUser', static::$user);
+ $this->set('loggedSeminary', static::$seminary);
+ $this->set('loggedCharacter', static::$character);
+ }
+
+
+ /**
+ * Postfilter that is executed after running the Controller.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function postFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::postFilter($request, $response);
+ }
+
+
+
+
+ /**
+ * Check user permissions.
+ *
+ * @throws AccessDeniedException
+ */
+ private function checkPermission(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ // Determine user
+ $userId = $this->Auth->getUserId();
+
+
+ // Do not check error pages
+ if($response->getParam(0, 'toplevel') == \nre\core\Config::getDefault('toplevel-error')) {
+ return;
+ }
+ if($response->getParam(1, 'intermediate') == \nre\core\Config::getDefault('intermediate-error')) {
+ return;
+ }
+
+
+ // Determine user roles
+ if($userId > 0)
+ {
+ $userRoles = array();
+ $roles = $this->Userroles->getUserrolesForUserById($userId);
+ foreach($roles as &$role) {
+ $userRoles[] = $role['name'];
+ }
+ }
+ else {
+ $userRoles = array('guest');
+ }
+
+ // Determine permissions of Intermediate Controller for current action
+ $controller = $this->agent->getIntermediateAgent()->controller;
+ $action = $this->request->getParam(2, 'action');
+ if(!property_exists($controller, 'permissions')) {
+ return; // Allow if nothing is specified
+ }
+ if(!array_key_exists($action, $controller->permissions)) {
+ return; // Allow if Action is not specified
+ }
+ $permissions = $controller->permissions[$action];
+
+
+ // Check permissions
+ if(count(array_intersect($userRoles, $permissions)) == 0) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeAgentNotFoundException.inc b/app/exceptions/QuesttypeAgentNotFoundException.inc
new file mode 100644
index 00000000..5f6f4ea9
--- /dev/null
+++ b/app/exceptions/QuesttypeAgentNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeAgent not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeAgentNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 101;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeAgent not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeAgent that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeAgent that was not found.
+ *
+ * @return string Name of the QuesttypeAgent that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeAgentNotValidException.inc b/app/exceptions/QuesttypeAgentNotValidException.inc
new file mode 100644
index 00000000..8fa7237f
--- /dev/null
+++ b/app/exceptions/QuesttypeAgentNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeAgent not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeAgentNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 102;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeAgent not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeAgent
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeAgent.
+ *
+ * @return string Name of the invalid QuesttypeAgent
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeControllerNotFoundException.inc b/app/exceptions/QuesttypeControllerNotFoundException.inc
new file mode 100644
index 00000000..6d3a4a36
--- /dev/null
+++ b/app/exceptions/QuesttypeControllerNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeController not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeControllerNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 103;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeController not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeController that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeController that was not found.
+ *
+ * @return string Name of the QuesttypeController that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeControllerNotValidException.inc b/app/exceptions/QuesttypeControllerNotValidException.inc
new file mode 100644
index 00000000..8c6735b8
--- /dev/null
+++ b/app/exceptions/QuesttypeControllerNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeController not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeControllerNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 104;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeController not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeController
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeController.
+ *
+ * @return string Name of the invalid QuesttypeController
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeModelNotFoundException.inc b/app/exceptions/QuesttypeModelNotFoundException.inc
new file mode 100644
index 00000000..a2aa01c8
--- /dev/null
+++ b/app/exceptions/QuesttypeModelNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeModel not found.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeModelNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 105;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeModel not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the QuesttypeModel that was not found
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store values
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the QuesttypeModel that was not found.
+ *
+ * @return string Name of the QuesttypeModel that was not found
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/exceptions/QuesttypeModelNotValidException.inc b/app/exceptions/QuesttypeModelNotValidException.inc
new file mode 100644
index 00000000..4a78beb6
--- /dev/null
+++ b/app/exceptions/QuesttypeModelNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\exceptions;
+
+
+ /**
+ * Exception: QuesttypeModel not valid.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypeModelNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 106;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'QuesttypeModel not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $questtypeName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $questtypeName Name of the invalid QuesttypeModel
+ */
+ function __construct($questtypeName, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $questtypeName
+ );
+
+ // Store value
+ $this->questtypeName = $questtypeName;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid QuesttypeModel.
+ *
+ * @return string Name of the invalid QuesttypeModel
+ */
+ public function getClassName()
+ {
+ return $this->questtypeName;
+ }
+
+ }
+
+?>
diff --git a/app/lib/Password.inc b/app/lib/Password.inc
new file mode 100644
index 00000000..f9acf7d5
--- /dev/null
+++ b/app/lib/Password.inc
@@ -0,0 +1,316 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\lib
+ {
+
+
+ /**
+ * Class to ensure that Compatibility library below is loaded.
+ *
+ * @author Oliver Hanraths
+ */
+ class Password
+ {
+
+ /**
+ * Call this function to ensure this file is loaded.
+ */
+ public static function load()
+ {
+ }
+
+ }
+
+ }
+
+
+
+
+/**
+ * A Compatibility library with PHP 5.5's simplified password hashing API.
+ *
+ * @author Anthony Ferrara
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @copyright 2012 The Authors
+ */
+
+namespace {
+
+if (!defined('PASSWORD_DEFAULT')) {
+
+ define('PASSWORD_BCRYPT', 1);
+ define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
+
+ /**
+ * Hash the password using the specified algorithm
+ *
+ * @param string $password The password to hash
+ * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
+ * @param array $options The options for the algorithm to use
+ *
+ * @return string|false The hashed password, or false on error.
+ */
+ function password_hash($password, $algo, array $options = array()) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
+ return null;
+ }
+ if (!is_string($password)) {
+ trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
+ return null;
+ }
+ if (!is_int($algo)) {
+ trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
+ return null;
+ }
+ $resultLength = 0;
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ // Note that this is a C constant, but not exposed to PHP, so we don't define it here.
+ $cost = 10;
+ if (isset($options['cost'])) {
+ $cost = $options['cost'];
+ if ($cost < 4 || $cost > 31) {
+ trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
+ return null;
+ }
+ }
+ // The length of salt to generate
+ $raw_salt_len = 16;
+ // The length required in the final serialization
+ $required_salt_len = 22;
+ $hash_format = sprintf("$2y$%02d$", $cost);
+ // The expected length of the final crypt() output
+ $resultLength = 60;
+ break;
+ default:
+ trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
+ return null;
+ }
+ $salt_requires_encoding = false;
+ if (isset($options['salt'])) {
+ switch (gettype($options['salt'])) {
+ case 'NULL':
+ case 'boolean':
+ case 'integer':
+ case 'double':
+ case 'string':
+ $salt = (string) $options['salt'];
+ break;
+ case 'object':
+ if (method_exists($options['salt'], '__tostring')) {
+ $salt = (string) $options['salt'];
+ break;
+ }
+ case 'array':
+ case 'resource':
+ default:
+ trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
+ return null;
+ }
+ if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
+ trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
+ return null;
+ } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
+ $salt_requires_encoding = true;
+ }
+ } else {
+ $buffer = '';
+ $buffer_valid = false;
+ if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
+ $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
+ $buffer = openssl_random_pseudo_bytes($raw_salt_len);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && @is_readable('/dev/urandom')) {
+ $f = fopen('/dev/urandom', 'r');
+ $read = PasswordCompat\binary\_strlen($buffer);
+ while ($read < $raw_salt_len) {
+ $buffer .= fread($f, $raw_salt_len - $read);
+ $read = PasswordCompat\binary\_strlen($buffer);
+ }
+ fclose($f);
+ if ($read >= $raw_salt_len) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
+ $bl = PasswordCompat\binary\_strlen($buffer);
+ for ($i = 0; $i < $raw_salt_len; $i++) {
+ if ($i < $bl) {
+ $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
+ } else {
+ $buffer .= chr(mt_rand(0, 255));
+ }
+ }
+ }
+ $salt = $buffer;
+ $salt_requires_encoding = true;
+ }
+ if ($salt_requires_encoding) {
+ // encode string with the Base64 variant used by crypt
+ $base64_digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ $bcrypt64_digits =
+ './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $base64_string = base64_encode($salt);
+ $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
+ }
+ $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
+
+ $hash = $hash_format . $salt;
+
+ $ret = crypt($password, $hash);
+
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
+ return false;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get information about the password hash. Returns an array of the information
+ * that was used to generate the password hash.
+ *
+ * array(
+ * 'algo' => 1,
+ * 'algoName' => 'bcrypt',
+ * 'options' => array(
+ * 'cost' => 10,
+ * ),
+ * )
+ *
+ * @param string $hash The password hash to extract info from
+ *
+ * @return array The array of information about the hash.
+ */
+ function password_get_info($hash) {
+ $return = array(
+ 'algo' => 0,
+ 'algoName' => 'unknown',
+ 'options' => array(),
+ );
+ if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
+ $return['algo'] = PASSWORD_BCRYPT;
+ $return['algoName'] = 'bcrypt';
+ list($cost) = sscanf($hash, "$2y$%d$");
+ $return['options']['cost'] = $cost;
+ }
+ return $return;
+ }
+
+ /**
+ * Determine if the password hash needs to be rehashed according to the options provided
+ *
+ * If the answer is true, after validating the password using password_verify, rehash it.
+ *
+ * @param string $hash The hash to test
+ * @param int $algo The algorithm used for new password hashes
+ * @param array $options The options array passed to password_hash
+ *
+ * @return boolean True if the password needs to be rehashed.
+ */
+ function password_needs_rehash($hash, $algo, array $options = array()) {
+ $info = password_get_info($hash);
+ if ($info['algo'] != $algo) {
+ return true;
+ }
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = isset($options['cost']) ? $options['cost'] : 10;
+ if ($cost != $info['options']['cost']) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Verify a password against a hash using a timing attack resistant approach
+ *
+ * @param string $password The password to verify
+ * @param string $hash The hash to verify against
+ *
+ * @return boolean If the password matches the hash
+ */
+ function password_verify($password, $hash) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
+ return false;
+ }
+ $ret = crypt($password, $hash);
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
+ return false;
+ }
+
+ $status = 0;
+ for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
+ $status |= (ord($ret[$i]) ^ ord($hash[$i]));
+ }
+
+ return $status === 0;
+ }
+}
+
+}
+
+namespace PasswordCompat\binary {
+ /**
+ * Count the number of bytes in a string
+ *
+ * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
+ * In this case, strlen() will count the number of *characters* based on the internal encoding. A
+ * sequence of bytes might be regarded as a single multibyte character.
+ *
+ * @param string $binary_string The input string
+ *
+ * @internal
+ * @return int The number of bytes
+ */
+ function _strlen($binary_string) {
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($binary_string, '8bit');
+ }
+ return strlen($binary_string);
+ }
+
+ /**
+ * Get a substring based on byte limits
+ *
+ * @see _strlen()
+ *
+ * @param string $binary_string The input string
+ * @param int $start
+ * @param int $length
+ *
+ * @internal
+ * @return string The substring
+ */
+ function _substr($binary_string, $start, $length) {
+ if (function_exists('mb_substr')) {
+ return mb_substr($binary_string, $start, $length, '8bit');
+ }
+ return substr($binary_string, $start, $length);
+ }
+
+}
diff --git a/bootstrap.inc b/bootstrap.inc
new file mode 100644
index 00000000..55647ac0
--- /dev/null
+++ b/bootstrap.inc
@@ -0,0 +1,33 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ // Include required classes
+ require_once(ROOT.DS.'configs'.DS.'CoreConfig.inc');
+ require_once(ROOT.DS.\nre\configs\CoreConfig::getClassDir('core').DS.'Autoloader.inc');
+
+
+ // Set PHP-logging
+ ini_set('error_log', ROOT.DS.\nre\configs\CoreConfig::getClassDir('logs').DS.'php'.\nre\configs\CoreConfig::getFileExt('logs'));
+
+ // Register autoloader
+ \nre\core\Autoloader::register();
+
+
+ // Initialize WebApi
+ $webApi = new \nre\apis\WebApi();
+
+ // Run WebApi
+ $webApi->run();
+
+ // Render output
+ $webApi->render();
+
+?>
diff --git a/configs/AppConfig.inc b/configs/AppConfig.inc
new file mode 100644
index 00000000..5b5a7558
--- /dev/null
+++ b/configs/AppConfig.inc
@@ -0,0 +1,127 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace nre\configs;
+
+
+ /**
+ * Application configuration.
+ *
+ * This class contains static variables with configuration values for
+ * the specific application.
+ *
+ * @author Oliver Hanraths
+ */
+ final class AppConfig
+ {
+
+ /**
+ * Application values
+ *
+ * @static
+ * @var array
+ */
+ public static $app = array(
+ 'name' => 'The Legend of Z',
+ 'namespace' => 'hhu\\z\\',
+ 'timeZone' => 'Europe/Berlin'
+ );
+
+
+ /**
+ * Default values
+ *
+ * @static
+ * @var array
+ */
+ public static $defaults = array(
+ 'toplevel' => 'html',
+ 'toplevel-error' => 'fault',
+ 'intermediate' => 'introduction',
+ 'intermediate-error' => 'error',
+ 'language' => 'de_DE.utf8',
+ 'locale' => 'de-DE'
+ );
+
+
+ /**
+ * Directories
+ *
+ * @static
+ * @var array
+ */
+ public static $dirs = array(
+ 'locale' => 'locale',
+ 'media' => 'media',
+ 'questtypes' => 'questtypes'
+ );
+
+
+ /**
+ * Routes
+ *
+ * @static
+ * @var array
+ */
+ public static $routes = array(
+ array('css/?(.*)', 'css/$1?layout=stylesheet', true),
+ array('users/([^/]+)/(edit|delete)', 'users/$2/$1', true),
+ array('users/(?!(index|login|logout|create|edit|delete))', 'users/user/$1', true),
+ array('seminaries/([^/]+)/(edit|delete)', 'seminaries/$2/$1', true),
+ array('seminaries/(?!(index|create|edit|delete))', 'seminaries/seminary/$1', true),
+ /*// z/ ⇒ z/seminaries/seminary/
+ array('^([^/]+)/*$', 'seminaries/seminary/$1', true),
+ // z// ⇒ z/questgroups/questgroup//
+ array('^([^/]+)/([^/]+)/?$', 'questgropus/questgroup/$1/$2', true),
+ // z/// ⇒ z/quests/quest///
+ array('^([^/]+)/([^/]+)/([^/]+)/?$', 'quests/quest/$1/$2/3', true)*/
+ array('characters/(?!(index|character))', 'characters/index/$1', true),
+ array('charactergroups/(?!(index|groupsgroup|group))', 'charactergroups/index/$1', true),
+ array('charactergroupsquests/(?!(quest))', 'charactergroupsquests/quest/$1', true),
+ array('media/(.*)', 'media/$1?layout=binary', false),
+ array('media/(.*)', 'media/index/$1', true)
+ );
+
+
+ /**
+ * Reverse routes
+ *
+ * @static
+ * @var array
+ */
+ public static $reverseRoutes = array(
+ array('users/user/(.*)', 'users/$1', true),
+ array('users/([^/]+)/(.*)', 'users/$2/$1', true),
+ array('seminaries/seminary/(.*)', 'seminaries/$1', false),
+ //array('seminaries/seminary/(.*)', '$1', false)
+ array('characters/index/(.*)', 'characters/$1', true),
+ array('charactergroup/index/(.*)', 'charactergroup/$1', true),
+ array('charactergroupsquests/quest/(.*)', 'charactergroupsquests/$1', true),
+ array('media/index/(.*)', 'media/$1', true)
+ );
+
+
+ /**
+ * Database connection settings
+ *
+ * @static
+ * @var array
+ */
+ public static $database = array(
+ 'user' => 'z',
+ 'host' => 'localhost',
+ 'password' => 'legendofZ',
+ 'db' => 'z'
+ );
+
+ }
+
+?>
diff --git a/configs/CoreConfig.inc b/configs/CoreConfig.inc
new file mode 100644
index 00000000..45bc7e4a
--- /dev/null
+++ b/configs/CoreConfig.inc
@@ -0,0 +1,167 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\configs;
+
+
+ /**
+ * Core configuration.
+ *
+ * This class contains static variables with configuration values.
+ *
+ * @author coderkun
+ */
+ final class CoreConfig
+ {
+
+ /**
+ * Core values
+ *
+ * @static
+ * @var array
+ */
+ public static $core = array(
+ 'namespace' => 'nre\\',
+ );
+
+
+ /**
+ * Directories
+ *
+ * @static
+ * @var array
+ */
+ public static $dirs = array(
+ 'core' => 'core',
+ 'publicDir' => 'www'
+ );
+
+
+ /**
+ * File extensions
+ *
+ * @static
+ * @var array
+ */
+ public static $fileExts = array(
+ 'default' => 'inc',
+ 'views' => 'tpl',
+ 'logs' => 'log',
+ );
+
+
+ /**
+ * Default values
+ *
+ * @static
+ * @var array
+ */
+ public static $defaults = array(
+ 'action' => 'index',
+ 'errorFile' => 'error',
+ 'inlineErrorFile' => 'inlineerror'
+ );
+
+
+ /**
+ * Miscellaneous settings
+ *
+ * @static
+ * @var array
+ */
+ public static $misc = array(
+ 'fileExtDot' => '.'
+ );
+
+
+ /**
+ * Logging settings
+ *
+ * @static
+ * @var array
+ */
+ public static $log = array(
+ 'filename' => 'errors',
+ 'format' => 'Fehler %d: %s in %s, Zeile %d'
+ );
+
+
+ /**
+ * Class-specific settings
+ *
+ * @static
+ * @var array
+ */
+ public static $classes = array(
+ 'linker' => array(
+ 'url' => array(
+ 'length' => 128,
+ 'delimiter' => '-'
+ )
+ )
+ );
+
+
+
+
+ /**
+ * Determine the directory for a specific classtype.
+ *
+ * @param string $classType Classtype to get directory of
+ * @return string Directory of given classtype
+ */
+ public static function getClassDir($classType)
+ {
+ // Default directory (for core classes)
+ $classDir = self::$dirs['core'];
+
+ // Configurable directory
+ if(array_key_exists($classType, self::$dirs)) {
+ $classDir = self::$dirs[$classType];
+ }
+ else
+ {
+ // Default directory for classtype
+ if(is_dir(ROOT.DS.$classType)) {
+ $classDir = $classType;
+ }
+ }
+
+
+ // Return directory
+ return $classDir;
+ }
+
+
+ /**
+ * Determine the file extension for a specific filetype.
+ *
+ * @param string $fileType Filetype to get file extension of
+ * @return string File extension of given filetype
+ */
+ public static function getFileExt($fileType)
+ {
+ // Default file extension
+ $fileExt = self::$fileExts['default'];
+
+ // Configurable file extension
+ if(array_key_exists($fileType, self::$fileExts)) {
+ $fileExt = self::$fileExts[$fileType];
+ }
+
+
+ // Return file extension
+ return self::$misc['fileExtDot'].$fileExt;
+ }
+
+ }
+
+?>
diff --git a/controllers/BinaryController.inc b/controllers/BinaryController.inc
new file mode 100644
index 00000000..09fee065
--- /dev/null
+++ b/controllers/BinaryController.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the BinaryAgent to show binary data.
+ *
+ * @author Oliver Hanraths
+ */
+ class BinaryController extends \hhu\z\controllers\ToplevelController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Create binary data.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/CharactergroupsController.inc b/controllers/CharactergroupsController.inc
new file mode 100644
index 00000000..1028d28c
--- /dev/null
+++ b/controllers/CharactergroupsController.inc
@@ -0,0 +1,143 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the CharactergroupsAgent to display Character groups.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'charactergroups', 'charactergroupsquests');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show Character groups-groups for a Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ */
+ public function index($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-groups
+ $groupsgroups = $this->Charactergroups->getGroupsroupsForSeminary($seminary['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroups', $groupsgroups);
+ }
+
+
+ /**
+ * Action: groupsgroups.
+ *
+ * Show Character groups for a Character groups-group of a
+ * Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ */
+ public function groupsgroup($seminaryUrl, $groupsgroupUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character groups
+ $groups = $this->Charactergroups->getGroupsForGroupsgroup($groupsgroup['id']);
+
+ // Get Character groups-group Quests
+ $quests = $this->Charactergroupsquests->getQuestsForCharactergroupsgroup($groupsgroup['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('groups', $groups);
+ $this->set('quests', $quests);
+ }
+
+
+ /**
+ * Action: group.
+ *
+ * Show a Character group for a Character groups-group of a
+ * Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ * @param string $groupUrl URL-Title of a Character group
+ */
+ public function group($seminaryUrl, $groupsgroupUrl, $groupUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character group
+ $group = $this->Charactergroups->getGroupByUrl($groupsgroup['id'], $groupUrl);
+
+ // Get Characters
+ $characters = $this->Characters->getCharactersForGroup($group['id']);
+
+ // Get Character groups Quests
+ $quests = $this->Charactergroupsquests->getQuestsForGroup($group['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('group', $group);
+ $this->set('characters', $characters);
+ $this->set('quests', $quests);
+ }
+
+ }
+
+?>
diff --git a/controllers/CharactergroupsquestsController.inc b/controllers/CharactergroupsquestsController.inc
new file mode 100644
index 00000000..52dc3435
--- /dev/null
+++ b/controllers/CharactergroupsquestsController.inc
@@ -0,0 +1,91 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the CharactergroupsquestsAgent to display Character
+ * groups Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'charactergroups', 'charactergroupsquests', 'media');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: quest.
+ *
+ * Show a Character groups Quest for a Character groups-group
+ * of a Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $groupsgroupUrl URL-Title of a Character groups-group
+ * @param string $questUrl URL-Title of a Character groups Quest
+ */
+ public function quest($seminaryUrl, $groupsgroupUrl, $questUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character groups-group
+ $groupsgroup = $this->Charactergroups->getGroupsgroupByUrl($seminary['id'], $groupsgroupUrl);
+
+ // Get Character groups-group Quests
+ $quest = $this->Charactergroupsquests->getQuestByUrl($groupsgroup['id'], $questUrl);
+
+ // Get Character groups-groups
+ $groups = $this->Charactergroupsquests->getGroupsForQuest($quest['id']);
+
+ // Media
+ $questmedia = null;
+ if(!is_null($quest['questsmedia_id'])) {
+ $questmedia = $this->Media->getMediaById($quest['questsmedia_id']);
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('groupsgroup', $groupsgroup);
+ $this->set('quest', $quest);
+ $this->set('groups', $groups);
+ $this->set('media', $questmedia);
+ }
+
+ }
+
+?>
diff --git a/controllers/CharactersController.inc b/controllers/CharactersController.inc
new file mode 100644
index 00000000..581b5b5a
--- /dev/null
+++ b/controllers/CharactersController.inc
@@ -0,0 +1,101 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactersController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array('admin', 'moderator'),
+ 'character' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'characters', 'users', 'charactergroups', 'seminarycharacterfields');
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * List registered Characters for a Seminary
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ */
+ public function index($seminaryUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get registered Characters
+ $characters = $this->Characters->getCharactersForSeminary($seminary['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('characters', $characters);
+ }
+
+
+ /**
+ * Action: character.
+ *
+ * Show a Charater and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $characterUrl URL-name of a Charater
+ */
+ public function character($seminaryUrl, $characterUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Character
+ $character = $this->Characters->getCharacterByUrl($seminary['id'], $characterUrl);
+
+ // Get Seminarycharacterfields
+ $characterfields = $this->Seminarycharacterfields->getFieldsForCharacter($character['id']);
+
+ // Get User
+ $user = $this->Users->getUserById($character['user_id']);
+
+ // Get Character groups
+ $groups = $this->Charactergroups->getGroupsForCharacter($character['id']);
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('character', $character);
+ $this->set('characterfields', $characterfields);
+ $this->set('user', $user);
+ $this->set('groups', $groups);
+ }
+
+ }
+
+?>
diff --git a/controllers/ErrorController.inc b/controllers/ErrorController.inc
new file mode 100644
index 00000000..efdae4f4
--- /dev/null
+++ b/controllers/ErrorController.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to show an error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class ErrorController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Set HTTP-header and print an error message.
+ *
+ * @param int $httpStatusCode HTTP-statuscode of the error that occurred
+ */
+ public function index($httpStatusCode)
+ {
+ // Set HTTP-header
+ if(!array_key_exists($httpStatusCode, \nre\core\WebUtils::$httpStrings)) {
+ $httpStatusCode = 200;
+ }
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader($httpStatusCode));
+
+ // Display statuscode and message
+ $this->set('code', $httpStatusCode);
+ $this->set('string', \nre\core\WebUtils::$httpStrings[$httpStatusCode]);
+ }
+
+ }
+
+?>
diff --git a/controllers/FaultController.inc b/controllers/FaultController.inc
new file mode 100644
index 00000000..be01fea7
--- /dev/null
+++ b/controllers/FaultController.inc
@@ -0,0 +1,37 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to display a toplevel error page.
+ *
+ * @author Oliver Hanraths
+ */
+ class FaultController extends \nre\core\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show the error message.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/HtmlController.inc b/controllers/HtmlController.inc
new file mode 100644
index 00000000..20795d5b
--- /dev/null
+++ b/controllers/HtmlController.inc
@@ -0,0 +1,59 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the HtmlAgent to display a HTML-page.
+ *
+ * @author Oliver Hanraths
+ */
+ class HtmlController extends \hhu\z\controllers\ToplevelController
+ {
+
+
+
+
+ /**
+ * Prefilter.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Set content-type
+ $this->response->addHeader("Content-type: text/html; charset=utf-8");
+ }
+
+
+ /**
+ * Action: index.
+ *
+ * Create the HTML-structure.
+ */
+ public function index()
+ {
+ // Set the name of the current IntermediateAgent as page title
+ $this->set('title', $this->request->getParam(1, 'intermediate'));
+
+ // Set userdata
+ $this->set('loggedUser', static::$user);
+ $this->set('loggedSeminary', static::$seminary);
+ $this->set('loggedCharacter', static::$character);
+ }
+
+ }
+
+?>
diff --git a/controllers/IntroductionController.inc b/controllers/IntroductionController.inc
new file mode 100644
index 00000000..5fead9cf
--- /dev/null
+++ b/controllers/IntroductionController.inc
@@ -0,0 +1,35 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to show an introduction page.
+ *
+ * @author Oliver Hanraths
+ */
+ class IntroductionController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/MediaController.inc b/controllers/MediaController.inc
new file mode 100644
index 00000000..aa69e704
--- /dev/null
+++ b/controllers/MediaController.inc
@@ -0,0 +1,143 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the MediaAgent to process and show Media.
+ *
+ * @author Oliver Hanraths
+ */
+ class MediaController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'index' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'media');
+
+
+
+
+ /**
+ * Prefilter.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Set headers for caching control
+ $response->addHeader("Pragma: public");
+ $response->addHeader("Cache-control: public, max-age=".(60*60*24));
+ $response->addHeader("Expires: ".gmdate('r', time()+(60*60*24)));
+ $response->addHeader("Date: ".gmdate(\DateTime::RFC822));
+ }
+
+
+ /**
+ * Action: index.
+ *
+ * Display a medium without processing.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-title of the Seminary
+ * @param string $mediaUrl URL-name of the medium
+ */
+ public function index($seminaryUrl, $mediaUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Media
+ $media = $this->Media->getMediaByUrl($seminary['id'], $mediaUrl);
+
+ // Set content-type
+ $this->response->addHeader("Content-type: ".$media['mimetype']."");
+
+ // Set filename
+ $media['filename'] = ROOT.DS.\nre\configs\AppConfig::$dirs['media'].DS.$media['id'];
+ if(!file_exists($media['filename'])) {
+ throw new \nre\exceptions\IdNotFoundException($mediaUrl);
+ }
+
+ // Cache
+ if($this->setCacheHeaders($media['filename'])) {
+ return;
+ }
+
+
+ // Pass data to view
+ $this->set('media', $media);
+ }
+
+
+
+
+ /**
+ * Determine file information and set the HTTP-header for
+ * caching accordingly.
+ *
+ * @param string $fileName Filename
+ * @return boolean HTTP-status 304 was set (in cache)
+ */
+ private function setCacheHeaders($fileName)
+ {
+ // Determine last change of file
+ $fileLastModified = gmdate('r', filemtime($fileName));
+
+ // Generate E-Tag
+ $fileEtag = hash('sha256', $fileLastModified.$fileName);
+
+
+ // Set header
+ $this->response->addHeader("Last-Modified: ".$fileLastModified);
+ $this->response->addHeader("Etag: ".$fileEtag);
+ // HTTP-status
+ $headerModifiedSince = $this->request->getServerParam('HTTP_IF_MODIFIED_SINCE');
+ $headerNoneMatch = $this->request->getServerParam('HTTP_IF_NONE_MATCH');
+ if(
+ !is_null($headerModifiedSince) && $fileLastModified < strtotime($headerModifiedSince) &&
+ !is_null($headerNoneMatch) && $headerNoneMatch == $fileEtag
+ ) {
+ $this->response->setExit(true);
+ $this->response->addHeader(\nre\core\WebUtils::getHttpHeader(304));
+
+ return true;
+ }
+
+
+ return false;
+ }
+
+ }
+
+?>
diff --git a/controllers/MenuController.inc b/controllers/MenuController.inc
new file mode 100644
index 00000000..3d9d5551
--- /dev/null
+++ b/controllers/MenuController.inc
@@ -0,0 +1,50 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to display a menu.
+ *
+ * @author Oliver Hanraths
+ */
+ class MenuController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Prefilter.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ */
+ public function preFilter(\nre\core\Request $request, \nre\core\Response $response)
+ {
+ parent::preFilter($request, $response);
+
+ // Set userdata
+ $this->set('loggedUser', HtmlController::$user);
+ }
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/QuestgroupsController.inc b/controllers/QuestgroupsController.inc
new file mode 100644
index 00000000..42e19d05
--- /dev/null
+++ b/controllers/QuestgroupsController.inc
@@ -0,0 +1,124 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the QuestgroupsAgent to display Questgroups.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroupshierarchy', 'questgroups', 'quests');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'questgroup' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'questgroup' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: questgroup.
+ *
+ * Display a Questgroup and its data.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $questgroupUrl URL-Title of a Questgroup
+ */
+ public function questgroup($seminaryUrl, $questgroupUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
+
+ // Get Questgrouphierarchy
+ $questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyById($questgroup['questgroupshierarchy_id']);
+
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Check permission
+ $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
+ if(!is_null($previousQuestgroup)) {
+ if(!$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+
+ // Get child Questgroupshierarchy
+ $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($questgroupshierarchy['id']);
+ foreach($childQuestgroupshierarchy as &$hierarchy)
+ {
+ // Get Questgroups
+ $hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id'], $questgroup['id']);
+
+ // Check permission of Questgroups
+ for($i=1; $iQuestgroups->hasCharacterSolvedQuestgroup($hierarchy['questgroups'][$i-1]['id'], $character['id']);
+ }
+ }
+
+ // Get texts
+ $questgroupTexts = $this->Questgroups->getQuestgroupTexts($questgroup['id']);
+
+ // Get Quests
+ $quests = null;
+ if(count($childQuestgroupshierarchy) == 0)
+ {
+ $quests = $this->Quests->getMainquestsForQuestgroup($questgroup['id']);
+ for($i=0; $i 0) {
+ $quests[$i]['access'] = $this->Quests->hasCharacterSolvedQuest($quests[$i-1]['id'], $character['id']);
+ }
+
+ // Attach sidequests
+ $quests[$i]['sidequests'] = $this->Quests->getSidequestsForQuest($quests[$i]['id']);
+ }
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('questgroup', $questgroup);
+ $this->set('questgroupshierarchy', $questgroupshierarchy);
+ $this->set('childquestgroupshierarchy', $childQuestgroupshierarchy);
+ $this->set('texts', $questgroupTexts);
+ $this->set('quests', $quests);
+ }
+
+ }
+
+?>
diff --git a/controllers/QuestgroupshierarchypathController.inc b/controllers/QuestgroupshierarchypathController.inc
new file mode 100644
index 00000000..e746d198
--- /dev/null
+++ b/controllers/QuestgroupshierarchypathController.inc
@@ -0,0 +1,76 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of QuestgroupshierarchypathAgent to display the
+ * Questgroups hierarchy path.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupshierarchypathController extends \hhu\z\Controller
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroups', 'questgroupshierarchy');
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Calculate and show the hierarchy path of a Questgroup.
+ *
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $questgroupUrl URL-Title of a Questgroup
+ * @param boolean $showGroup Show the current group itself
+ */
+ public function index($seminaryUrl, $questgroupUrl, $showGroup=false)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
+
+ // Get parent Questgrouphierarchy
+ $parentQuestgroupshierarchy = array();
+ $currentQuestgroup = $questgroup;
+ if($showGroup) {
+ $currentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($currentQuestgroup['questgroupshierarchy_id']);
+ array_unshift($parentQuestgroupshierarchy, $currentQuestgroup);
+ }
+ while(!is_null($currentQuestgroup['parent_questgroup_id']))
+ {
+ // Get Questgroup
+ $currentQuestgroup = $this->Questgroups->GetQuestgroupById($currentQuestgroup['parent_questgroup_id']);
+
+ // Get Questgroupshierarchy
+ $currentQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($currentQuestgroup['questgroupshierarchy_id']);
+
+ array_unshift($parentQuestgroupshierarchy, $currentQuestgroup);
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('parentquestgroupshierarchy', $parentQuestgroupshierarchy);
+ }
+
+ }
+
+?>
diff --git a/controllers/QuestgroupspictureController.inc b/controllers/QuestgroupspictureController.inc
new file mode 100644
index 00000000..7810869b
--- /dev/null
+++ b/controllers/QuestgroupspictureController.inc
@@ -0,0 +1,65 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of QuestgroupspictureAgent to display the picture of a
+ * Questgroups.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupspictureController extends \hhu\z\Controller
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroups', 'media');
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Show the picture of a Questgroup.
+ *
+ * @param string $seminaryUrl URL-Title of a Seminary
+ * @param string $questgroupUrl URL-Title of a Questgroup
+ */
+ public function index($seminaryUrl, $questgroupUrl)
+ {
+ // Get Seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
+
+ // Get Picture
+ $picture = null;
+ try {
+ $picture = $this->Media->getMediaById($questgroup['questgroupspicture_id']);
+ }
+ catch(\nre\exceptions\IdNotFoundException $e) {
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('picture', $picture);
+ }
+
+ }
+
+?>
diff --git a/controllers/QuestsController.inc b/controllers/QuestsController.inc
new file mode 100644
index 00000000..211c8104
--- /dev/null
+++ b/controllers/QuestsController.inc
@@ -0,0 +1,275 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the QuestsAgent to display Quests.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestsController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'questgroups', 'quests', 'questtexts', 'media', 'questtypes', 'questgroupshierarchy');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'quest' => array('admin', 'moderator', 'user')
+ );
+
+
+
+
+ /**
+ * Action: quest.
+ *
+ * Show a quest and its task.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of Seminary
+ * @param string $questgroupUrl URL-Title of Questgroup
+ * @param string $questUrl URL-Title of Quest
+ * @param string $questtexttypeUrl URL-Title of Questtexttype
+ * @param int $questtextPos Position of Questtext
+ */
+ public function quest($seminaryUrl, $questgroupUrl, $questUrl, $questtexttypeUrl=null, $questtextPos=1)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Get Questgroup
+ $questgroup = $this->Questgroups->getQuestgroupByUrl($seminary['id'], $questgroupUrl);
+
+ // Get Quest
+ $quest = $this->Quests->getQuestByUrl($seminary['id'], $questgroup['id'], $questUrl);
+
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Check permissions
+ $previousQuests = $this->Quests->getPreviousQuests($quest['id']);
+ if(count($previousQuests) == 0)
+ {
+ // Previous Questgroup
+ $previousQuestgroup = $this->Questgroups->getPreviousQuestgroup($questgroup['id']);
+ if(!is_null($previousQuestgroup) && !$this->Questgroups->hasCharacterSolvedQuestgroup($previousQuestgroup['id'], $character['id'])) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+ else
+ {
+ // Previous Quests
+ if(count($previousQuests) > 0)
+ {
+ $solved = false;
+ foreach($previousQuests as &$previousQuest)
+ {
+ if($this->Quests->hasCharacterSolvedQuest($previousQuest['id'], $character['id'])) {
+ $solved = true;
+ break;
+ }
+ }
+ if(!$solved) {
+ throw new \nre\exceptions\AccessDeniedException();
+ }
+ }
+ }
+
+ // Get (related) Questtext (for Sidequests)
+ $relatedQuesttext = null;
+ if(!$quest['is_mainquest'])
+ {
+ $relatedQuesttext = $this->Questtexts->getQuesttextForSidequest($quest['id']);
+ if(!empty($relatedQuesttext)) {
+ $relatedQuesttext['quest'] = $this->Quests->getQuestById($relatedQuesttext['quest_id']);
+ }
+ }
+
+ // Get Questtext
+ $questtext = null;
+ if(is_null($questtexttypeUrl)) {
+ $questtexttypeUrl = 'Prolog';
+ }
+ $questtexttypes = $this->Questtexts->getQuesttexttypes();
+ $questtexttypes = array_map(function($t) { return $t['url']; }, $questtexttypes);
+ $questtextCount = $this->Questtexts->getQuesttextsCountForQuest($quest['id'], $questtexttypeUrl);
+ if($questtextCount > 0 && in_array($questtexttypeUrl, $questtexttypes))
+ {
+ $questtextPos = max(intval($questtextPos), 1);
+ $questtext = $this->Questtexts->getQuesttextByUrl($quest['id'], $questtexttypeUrl, $questtextPos);
+ $questtext['count'] = $questtextCount;
+ $questtext['sidequests'] = $this->Quests->getSidequestsForQuesttext($questtext['id']);
+ }
+
+ // Quest status
+ $questStatus = $this->request->getGetParam('status');
+ $questStatusText = null;
+ if(!is_null($questStatus))
+ {
+ switch($questStatus)
+ {
+ case 'solved':
+ $questStatusText = $quest['right_text'];
+ break;
+ case 'unsolved':
+ $questStatusText = $quest['wrong_text'];
+ break;
+ }
+ }
+
+ // Media
+ $questmedia = null;
+ if(!is_null($questtext) && array_key_exists('questmedia_id', $questtext) && !empty($questtext['questsmedia_id'])) {
+ $questmedia = $this->Media->getMediaById($questtext['questsmedia_id']);
+ }
+ elseif(!is_null($quest['questsmedia_id'])) {
+ $questmedia = $this->Media->getMediaById($quest['questsmedia_id']);
+ }
+
+ // Task
+ $task = null;
+ if($questtexttypeUrl == 'Prolog')
+ {
+ // Questtype
+ $questtype = $this->Questtypes->getQuesttypeById($quest['questtype_id']);
+
+ // Task
+ $task = $this->runAndRenderTask($quest['id'], $questtype['classname']);
+ }
+
+ // Next Quest/Questgroup
+ $nextQuests = null;
+ $nextQuestgroup = null;
+ if($questtexttypeUrl == 'Epilog')
+ {
+ if($quest['is_mainquest'])
+ {
+ // Next Quest
+ $nextQuests = $this->Quests->getNextQuests($quest['id']);
+
+ // Next Questgroup
+ if(empty($nextQuests))
+ {
+ $nextQuestgroup = $this->Questgroups->getNextQuestgroup($questgroup['id']);
+ $nextQuestgroup['hierarchy'] = $this->Questgroupshierarchy->getHierarchyById($nextQuestgroup['questgroupshierarchy_id']);
+ }
+ }
+ else {
+ // Related (Main-) Quest
+ $nextQuest = $relatedQuesttext['quest'];
+ $nextQuest['questgroup_url'] = $questgroup['url'];
+ $nextQuests = array($nextQuest);
+ }
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('questgroup', $questgroup);
+ $this->set('questtext', $questtext);
+ $this->set('quest', $quest);
+ $this->set('queststatus', $questStatus);
+ $this->set('queststatustext', $questStatusText);
+ $this->set('relatedquesttext', $relatedQuesttext);
+ $this->set('nextquests', $nextQuests);
+ $this->set('nextquestgroup', $nextQuestgroup);
+ $this->set('task', $task);
+ $this->set('media', $questmedia);
+ }
+
+
+
+
+ /**
+ * Load, construct, run and render the Agent for the given
+ * classname of a Questtype and return ist output.
+ *
+ * @param int $questId ID of Quest
+ * @param string $questtypeClassname Classname of Questtype to run and render
+ * @return string Rendered output of Questtype-Agent
+ */
+ private function runAndRenderTask($questId, $questtypeClassname)
+ {
+ $task = null;
+ $questtypeAgent = null;
+ try {
+ // Load Agent
+ \hhu\z\QuesttypeAgent::load($questtypeClassname);
+ // Construct Agent
+ $questtypeAgent = \hhu\z\QuesttypeAgent::factory($questtypeClassname, $this->request, $this->response);
+
+ // Generate request
+ $request = clone $this->request;
+ // Generate response
+ $response = clone $this->response;
+ $response->clearParams(1);
+ $response->addParams(
+ null,
+ \nre\configs\CoreConfig::$defaults['action'],
+ $questId
+ );
+ // Run Agent
+ $questtypeAgent->run($request, $response);
+
+ // Render output
+ $task = $questtypeAgent->render();
+
+ }
+ catch(\nre\exceptions\ViewNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\nre\exceptions\ActionNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeModelNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeModelNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeControllerNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeControllerNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeAgentNotValidException $e) {
+ $task = $e->getMessage();
+ }
+ catch(\hhu\z\exceptions\QuesttypeAgentNotFoundException $e) {
+ $task = $e->getMessage();
+ }
+
+
+ // Return rendered output
+ return $task;
+ }
+
+ }
+
+?>
diff --git a/controllers/SeminariesController.inc b/controllers/SeminariesController.inc
new file mode 100644
index 00000000..bf89b9f2
--- /dev/null
+++ b/controllers/SeminariesController.inc
@@ -0,0 +1,214 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesController extends \hhu\z\controllers\SeminaryRoleController
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('seminaries', 'users', 'questgroupshierarchy', 'questgroups');
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array('admin', 'moderator', 'user'),
+ 'seminary' => array('admin', 'moderator', 'user'),
+ 'create' => array('admin', 'moderator'),
+ 'edit' => array('admin', 'moderator', 'user'),
+ 'delete' => array('admin', 'moderator', 'user')
+ );
+ /**
+ * User seminary permissions
+ *
+ * @var array
+ */
+ public $seminaryPermissions = array(
+ 'seminary' => array('admin', 'moderator', 'user', 'guest'),
+ 'edit' => array('admin', 'moderator'),
+ 'delete' => array('admin', 'moderator')
+ );
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * List registered seminaries.
+ */
+ public function index()
+ {
+ // Get seminaries
+ $seminaries = $this->Seminaries->getSeminaries();
+
+ // Get additional data
+ foreach($seminaries as &$seminary)
+ {
+ // Created user
+ $seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
+ }
+
+
+ // Pass data to view
+ $this->set('seminaries', $seminaries);
+ }
+
+
+ /**
+ * Action: seminary.
+ *
+ * Show a seminary and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function seminary($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Created user
+ $seminary['creator'] = $this->Users->getUserById($seminary['created_user_id']);
+
+ // Get Character
+ $character = $this->Characters->getCharacterForUserAndSeminary($this->Auth->getUserId(), $seminary['id']);
+
+ // Questgrouphierarchy and Questgroups
+ $questgroupshierarchy = $this->Questgroupshierarchy->getHierarchyForSeminary($seminary['id']);
+ foreach($questgroupshierarchy as &$hierarchy)
+ {
+ // Get Questgroups
+ $hierarchy['questgroups'] = $this->Questgroups->getQuestgroupsForHierarchy($hierarchy['id']);
+
+ // Check permission of Questgroups
+ for($i=1; $iQuestgroups->hasCharacterSolvedQuestgroup($hierarchy['questgroups'][$i-1]['id'], $character['id']);
+ }
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ $this->set('questgroupshierarchy', $questgroupshierarchy);
+ }
+
+
+ /**
+ * Action: create.
+ *
+ * Create a new seminary.
+ */
+ public function create()
+ {
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
+ {
+ // Create new seminary
+ var_dump($this->Auth->getUserId());
+ $seminaryId = $this->Seminaries->createSeminary(
+ $this->request->getPostParam('title'),
+ $this->Auth->getUserId()
+ );
+
+ // Redirect to seminary
+ $user = $this->Seminaries->getSeminaryById($seminaryId);
+ $this->redirect($this->linker->link(array($seminary['url']), 1));
+ }
+ }
+
+
+ /**
+ * Action: edit.
+ *
+ * Edit a seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function edit($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Save changes
+ if(!is_null($this->request->getPostParam('save')))
+ {
+ // Edit seminary
+ $this->Seminaries->editSeminary(
+ $seminary['id'],
+ $this->request->getPostParam('title')
+ );
+ $seminary = $this->Seminaries->getSeminaryById($seminary['id']);
+ }
+
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array($seminary['url']), 1));
+ }
+
+
+ // Pass data to view
+ $this->set('seminary', $seminary);
+ }
+
+
+ /**
+ * Action: delete.
+ *
+ * Delete a seminary.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ */
+ public function delete($seminaryUrl)
+ {
+ // Get seminary
+ $seminary = $this->Seminaries->getSeminaryByUrl($seminaryUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Check confirmation
+ if(!is_null($this->request->getPostParam('delete')))
+ {
+ // Delete seminary
+ $this->Seminaries->deleteSeminary($seminary['id']);
+
+ // Redirect to overview
+ $this->redirect($this->linker->link(null, 1));
+ }
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array('seminary', $seminary['url']), 1));
+ }
+
+
+ // Show confirmation
+ $this->set('seminary', $seminary);
+ }
+
+ }
+
+?>
diff --git a/controllers/UserrolesController.inc b/controllers/UserrolesController.inc
new file mode 100644
index 00000000..80c00347
--- /dev/null
+++ b/controllers/UserrolesController.inc
@@ -0,0 +1,47 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to display and manage userroles.
+ *
+ * @author Oliver Hanraths
+ */
+ class UserrolesController extends \hhu\z\Controller
+ {
+
+
+
+
+ /**
+ * Action: user.
+ *
+ * Show a user and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function user($userUrl)
+ {
+ // Get userroles
+ $roles = $this->Userroles->getUserrolesForUserByUrl($userUrl);
+
+
+ // Pass data to view
+ $this->set('roles', $roles);
+ }
+
+
+ }
+
+?>
diff --git a/controllers/UsersController.inc b/controllers/UsersController.inc
new file mode 100644
index 00000000..a9eb9f91
--- /dev/null
+++ b/controllers/UsersController.inc
@@ -0,0 +1,231 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers;
+
+
+ /**
+ * Controller of the Agent to list registered users and their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersController extends \hhu\z\Controller
+ {
+ /**
+ * User permissions
+ *
+ * @var array
+ */
+ public $permissions = array(
+ 'index' => array('admin', 'moderator'),
+ 'user' => array('admin', 'moderator', 'user'),
+ 'create' => array('admin', 'moderator'),
+ 'edit' => array('admin', 'moderator'),
+ 'delete' => array('admin')
+ );
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('users', 'characters');
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ // Get registered users
+ $users = $this->Users->getUsers();
+
+
+ // Pass data to view
+ $this->set('users', $users);
+ }
+
+
+ /**
+ * Action: user.
+ *
+ * Show a user and its details.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function user($userUrl)
+ {
+ // Get user
+ $user = $this->Users->getUserByUrl($userUrl);
+
+ // Get Characters
+ $characters = $this->Characters->getCharactersForUser($user['id']);
+
+
+ // Pass data to view
+ $this->set('user', $user);
+ $this->set('characters', $characters);
+ }
+
+
+ /**
+ * Action: login.
+ *
+ * Log in a user.
+ */
+ public function login()
+ {
+ $username = '';
+
+ // Log the user in
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('login')))
+ {
+ $username = $this->request->getPostParam('username');
+ $userId = $this->Users->login(
+ $username,
+ $this->request->getPostParam('password')
+ );
+
+ if(!is_null($userId))
+ {
+ $this->Auth->setUserId($userId);
+ $user = $this->Users->getUserById($userId);
+
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+ }
+
+
+ // Pass data to view
+ $this->set('username', $username);
+ $this->set('failed', ($this->request->getRequestMethod() == 'POST'));
+ }
+
+
+ /**
+ * Action: logout.
+ *
+ * Log out a user.
+ */
+ public function logout()
+ {
+ // Unset the currently logged in user
+ $this->Auth->setUserId(null);
+
+ // Redirect
+ $this->redirect($this->linker->link(array()));
+ }
+
+
+ /**
+ * Action: create.
+ *
+ * Create a new user.
+ */
+ public function create()
+ {
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('create')))
+ {
+ // Create new user
+ $userId = $this->Users->createUser(
+ $this->request->getPostParam('username'),
+ $this->request->getPostParam('email'),
+ $this->request->getPostParam('password')
+ );
+
+ // Redirect to user
+ $user = $this->Users->getUserById($userId);
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+ }
+
+
+ /**
+ * Action: edit.
+ *
+ * Edit a user.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function edit($userUrl)
+ {
+ // User
+ $user = $this->Users->getUserByUrl($userUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Save changes
+ if(!is_null($this->request->getPostParam('save')))
+ {
+ // Edit user
+ $this->Users->editUser(
+ $user['id'],
+ $this->request->getPostParam('username'),
+ $this->request->getPostParam('email'),
+ $this->request->getPostParam('password')
+ );
+ $user = $this->Users->getUserById($user['id']);
+ }
+
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array($user['url']), 1));
+ }
+
+
+ // Pass data to view
+ $this->set('user', $user);
+ }
+
+
+ /**
+ * Action: delete.
+ *
+ * Delete a user.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ */
+ public function delete($userUrl)
+ {
+ // User
+ $user = $this->Users->getUserByUrl($userUrl);
+
+ // Check request method
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Check confirmation
+ if(!is_null($this->request->getPostParam('delete')))
+ {
+ // Delete user
+ $this->Users->deleteUser($user['id']);
+
+ // Redirect to overview
+ $this->redirect($this->linker->link(null, 1));
+ }
+
+ // Redirect to entry
+ $this->redirect($this->linker->link(array('user', $user['url']), 1));
+ }
+
+
+ // Show confirmation
+ $this->set('user', $user);
+ }
+
+
+ }
+
+?>
diff --git a/controllers/components/AchievementComponent.inc b/controllers/components/AchievementComponent.inc
new file mode 100644
index 00000000..70601543
--- /dev/null
+++ b/controllers/components/AchievementComponent.inc
@@ -0,0 +1,41 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers\components;
+
+
+ /**
+ * Component to handle achievements.
+ *
+ * @author Oliver Hanraths
+ */
+ class AchievementComponent extends \nre\core\Component
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('achievements');
+
+
+
+
+ /**
+ * Construct a new Achievements-component.
+ */
+ public function __construct()
+ {
+ }
+
+ }
+
+?>
diff --git a/controllers/components/AuthComponent.inc b/controllers/components/AuthComponent.inc
new file mode 100644
index 00000000..0db6c69d
--- /dev/null
+++ b/controllers/components/AuthComponent.inc
@@ -0,0 +1,79 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\controllers\components;
+
+
+ /**
+ * Component to handle authentication and authorization.
+ *
+ * @author Oliver Hanraths
+ */
+ class AuthComponent extends \nre\core\Component
+ {
+ /**
+ * Key to save a user-ID as
+ *
+ * @var string
+ */
+ const KEY_USER_ID = 'user_id';
+
+
+
+
+ /**
+ * Construct a new Auth-component.
+ */
+ public function __construct()
+ {
+ // Start session
+ if(session_id() === '') {
+ session_start();
+ }
+ }
+
+
+
+
+ /**
+ * Set the ID of the user that is currently logged in.
+ *
+ * @param int $userId ID of the currently logged in user
+ */
+ public function setUserId($userId)
+ {
+ if(is_null($userId)) {
+ unset($_SESSION[self::KEY_USER_ID]);
+ }
+ else {
+ $_SESSION[self::KEY_USER_ID] = $userId;
+ }
+ }
+
+
+ /**
+ * Get the ID of the user that is currently logged in.
+ *
+ * @return int ID of the currently logged in user
+ */
+ public function getUserId()
+ {
+ if(array_key_exists(self::KEY_USER_ID, $_SESSION)) {
+ return $_SESSION[self::KEY_USER_ID];
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
diff --git a/core/Agent.inc b/core/Agent.inc
new file mode 100644
index 00000000..00ec1a90
--- /dev/null
+++ b/core/Agent.inc
@@ -0,0 +1,607 @@
+
+ * @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 the implementation af an Agent.
+ *
+ * @author coderkun
+ */
+ abstract class Agent
+ {
+ /**
+ * Name of BottomlevelAgent for showing inline errors
+ *
+ * @var string
+ */
+ const INLINEERROR_AGENT = 'inlineerror';
+
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+ /**
+ * Current response
+ *
+ * @var Response
+ */
+ private $response;
+ /**
+ * Log-system
+ *
+ * @var Logger
+ */
+ protected $log;
+ /**
+ * SubAgents
+ *
+ * @var array
+ */
+ protected $subAgents = array();
+ /**
+ * Controller of this Agent
+ *
+ * @var Controller
+ */
+ public $controller = null;
+
+
+
+
+ /**
+ * Load the class of an Agent.
+ *
+ * @static
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ */
+ public static function load($agentName)
+ {
+ // Determine full classname
+ $agentType = self::getAgentType();
+ $className = self::getClassName($agentName, $agentType);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ $parentAgentClassName = ClassLoader::concatClassNames($agentType, 'agent');
+ $parentAgentClassName = "\\nre\\agents\\$parentAgentClassName";
+ ClassLoader::check($className, $parentAgentClassName);
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\AgentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\AgentNotFoundException($e->getClassName());
+ }
+ }
+
+
+
+ /**
+ * Instantiate an Agent (Factory Pattern).
+ *
+ * @static
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param string $agentName Name of the Agent to instantiate
+ * @param Request $request Current request
+ * @param Response $respone Current respone
+ * @param Logger $log Log-system
+ */
+ public static function factory($agentName, Request $request, Response $response, Logger $log=null)
+ {
+ // Determine full classname
+ $agentType = self::getAgentType();
+ $className = self::getClassName($agentName, $agentType);
+
+
+ // Construct and return Agent
+ return new $className($request, $response, $log);
+ }
+
+
+ /**
+ * Determine the type of an Agent.
+ *
+ * @static
+ * @return string Agent type
+ */
+ private static function getAgentType()
+ {
+ return strtolower(ClassLoader::getClassName(get_called_class()));
+ }
+
+
+ /**
+ * Determine the classname for the given Agent name.
+ *
+ * @static
+ * @param string $agentName Agent name to get classname of
+ * @param string $agentType Agent type of given Agent name
+ * @return string Classname for the Agent name
+ */
+ private static function getClassName($agentName, $agentType)
+ {
+ $className = ClassLoader::concatClassNames($agentName, 'agent');
+
+
+ return \nre\configs\AppConfig::$app['namespace']."agents\\$agentType\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ * @param Logger $log Log-system
+ */
+ protected function __construct(Request $request, Response $response, Logger $log=null)
+ {
+ // Store values
+ $this->request = $request;
+ $this->response = $response;
+ $this->log = $log;
+
+ // Construct SubAgent
+ $this->actionConstruct();
+
+ // Load corresponding Controller
+ $this->loadController();
+ }
+
+
+
+
+ /**
+ * Run the Controller of this Agent and its SubAgents.
+ *
+ * @throws ParamsNotValidException
+ * @throws IdNotFoundException
+ * @throws DatamodelException
+ * @throws ActionNotFoundException
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @return Exception Last occurred exception of SubAgents
+ */
+ public function run(Request $request, Response $response)
+ {
+ // Check Controller
+ if(!is_null($this->controller))
+ {
+ // Call prefilter
+ $this->controller->preFilter($request, $response);
+
+ // Run controller
+ $this->controller->run($request, $response);
+
+ // Call postfilter
+ $this->controller->postFilter($request, $response);
+ }
+
+
+ // Run SubAgents
+ $exception = null;
+ foreach($this->subAgents as &$subAgent)
+ {
+ try {
+ $subAgent['object']->run(
+ $request,
+ $subAgent['response']
+ );
+ }
+ catch(ParamsNotValidException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(IdNotFoundException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(DatamodelException $e) {
+ $exception = $e;
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ catch(ActionNotFoundException $e) {
+ $subAgent = $this->errorInline($subAgent, $request, $e);
+ }
+ }
+
+
+ // Return last occurred exception
+ return $exception;
+ }
+
+
+ /**
+ * Generate output of the Controller of this Agent and its
+ * SubAgents.
+ *
+ * @param array $data View data
+ * @return string Generated output
+ */
+ public function render($data=array())
+ {
+ // Check Controller
+ if(!is_null($this->controller))
+ {
+ // Render SubAgents
+ foreach($this->subAgents as $subAgent)
+ {
+ $label = array_key_exists('label', $subAgent) ? $subAgent['label'] : $subAgent['name'];
+ $data[$label] = $this->renderSubAgent($subAgent);
+ }
+
+ // Render the Controller of this agent
+ return $this->controller->render($data);
+ }
+ }
+
+
+
+
+ /**
+ * Construct SubAgents (per Action).
+ */
+ protected function actionConstruct()
+ {
+ // Action ermitteln
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+ // Initialisierungsmethode für diese Action ausführen
+ if(method_exists($this, $action))
+ {
+ call_user_func_array(
+ array(
+ $this,
+ $action
+ ),
+ array(
+ $this->request,
+ $this->response
+ )
+ );
+ }
+ }
+
+
+ /**
+ * Load the Controller of this Agent.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ */
+ protected function loadController()
+ {
+ // Determine Controller name
+ $controllerName = ClassLoader::getClassName(get_class($this));
+
+ // Determine ToplevelAgent
+ $toplevelAgentName = $this->response->getParam(0);
+ if(is_null($toplevelAgentName)) {
+ $toplevelAgentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($toplevelAgentName);
+ }
+
+ // Determine Action
+ $action = $this->response->getParam(2);
+ if(is_null($action)) {
+ $action = $this->request->getParam(2, 'action');
+ $this->response->addParam($action);
+ }
+
+
+ // Load Controller
+ Controller::load($controllerName);
+
+ // Construct Controller
+ $this->controller = Controller::factory($controllerName, $toplevelAgentName, $action, $this);
+ }
+
+
+ /**
+ * Log an error.
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $logMode Log mode
+ */
+ protected function log($exception, $logMode)
+ {
+ if(is_null($this->log)) {
+ return;
+ }
+
+ $this->log->log(
+ $exception->getMessage(),
+ $logMode
+ );
+ }
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function addSubAgent($agentName)
+ {
+ try {
+ call_user_func_array(
+ array(
+ $this,
+ '_addSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(DatamodelException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ }
+
+
+ /**
+ * Load a SubAgent and add it.
+ *
+ * @throws ServiceUnavailableException
+ * @throws DatamodelException
+ * @throws AgentNotFoundException
+ * @throws AgentNotValidException
+ * @param string $agentName Name of the Agent to load
+ * @param mixed … Additional parameters for the agent
+ */
+ protected function _addSubAgent($agentName)
+ {
+ try {
+ // Load Agent
+ \nre\agents\BottomlevelAgent::load($agentName);
+
+ // Construct Agent
+ $this->subAgents[] = call_user_func_array(
+ array(
+ $this,
+ 'newSubAgent'
+ ),
+ func_get_args()
+ );
+ }
+ catch(ViewNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(DriverNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(DriverNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ModelNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ModelNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ControllerNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(ControllerNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(AgentNotValidException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ catch(AgentNotFoundException $e) {
+ $this->subAgents[] = $this->newInlineError($agentName, $e);
+ }
+ }
+
+
+
+
+ /**
+ * Create a new SubAgent.
+ *
+ * @throws DatamodelException
+ * @param string $agentName Agent name
+ * @return array SubAgent
+ */
+ private function newSubAgent($agentName)
+ {
+ // Response
+ $response = clone $this->response;
+ $response->clearParams(1);
+ $params = func_get_args();
+ if(count($params) < 2 || empty($params[1])) {
+ $params[1] = \nre\configs\CoreConfig::$defaults['action'];
+ }
+ call_user_func_array(
+ array(
+ $response,
+ 'addParams'
+ ),
+ $params
+ );
+
+ return array(
+ 'name' => strtolower($agentName),
+ 'response' => $response,
+ 'object' => \nre\agents\BottomlevelAgent::factory(
+ $agentName,
+ $this->request,
+ $response,
+ $this->log
+ )
+ );
+ }
+
+
+ /**
+ * Render a SubAgent.
+ *
+ * @param array $subAgent SubAgent to render
+ * @return string Generated output
+ */
+ private function renderSubAgent(&$subAgent)
+ {
+ // Check for InlineError
+ if(array_key_exists('inlineerror', $subAgent) && !empty($subAgent['inlineerror'])) {
+ return file_get_contents($subAgent['inlineerror']);
+ }
+
+
+ // Rendern SubAgent and return its output
+ return $subAgent['object']->render();
+ }
+
+
+ /**
+ * Handle the exception of a SubAgent.
+ *
+ * @param string $label Name of the original Agent
+ * @param Excepiton $exception Occurred exception
+ * @return array InlineError-SubAgent
+ */
+ private function errorInline($subAgent, $request, $exception)
+ {
+ // Create the SubAgent for the exception
+ $subAgent = $this->newInlineError($subAgent['name'], $exception);
+
+
+ // Run the InlineError-SubAgent
+ try {
+ $subAgent['object']->run(
+ $request,
+ $subAgent['response']
+ );
+ }
+ catch(ActionNotFoundException $e) {
+ $this->log($e, Logger::LOGMODE_AUTO);
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+
+
+ // Return the InlineError-SubAgent
+ return $subAgent;
+ }
+
+
+ /**
+ * Create a new InlineError.
+ *
+ * @param string $label Name of the original Agent
+ * @param Exception $exception Occurred exception
+ */
+ private function newInlineError($label, $exception)
+ {
+ // Log error
+ $this->log($exception, Logger::LOGMODE_AUTO);
+
+ // Determine Agent name
+ $agentName = self::INLINEERROR_AGENT;
+
+ // Create SugAgent
+ $subAgent = array();
+
+
+ try {
+ // Load Agenten
+ \nre\agents\BottomlevelAgent::load($agentName);
+
+ // Construct Agent
+ $subAgent = $this->newSubAgent($agentName);
+ $subAgent['label'] = $label;
+ $subAgent['response']->addParam($exception);
+ }
+ catch(ViewNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DatamodelException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DriverNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(DriverNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ModelNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ModelNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ControllerNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(ControllerNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(AgentNotValidException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+ catch(AgentNotFoundException $e) {
+ $subAgent['inlineerror'] = $this->newInlineErrorService();
+ }
+
+
+ // Return SubAgent
+ return $subAgent;
+ }
+
+
+ /**
+ * Handle a hardcore error that could not be handled by the
+ * system.
+ */
+ private function newInlineErrorService()
+ {
+ // Read and return static error file
+ return ROOT.DS.\nre\configs\CoreConfig::getClassDir('views').DS.\nre\configs\CoreConfig::$defaults['inlineErrorFile'].\nre\configs\Config::getFileExt('views');
+ }
+
+ }
+
+?>
diff --git a/core/Api.inc b/core/Api.inc
new file mode 100644
index 00000000..b89b12e7
--- /dev/null
+++ b/core/Api.inc
@@ -0,0 +1,163 @@
+
+ * @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 to implement an API.
+ *
+ * The API is the center of each application and specifies how and what
+ * to run and render.
+ *
+ * @author coderkun
+ */
+ abstract class Api
+ {
+ /**
+ * Die aktuelle Anfrage
+ *
+ * @var Request
+ */
+ protected $request;
+ /**
+ * Der Toplevelagent
+ *
+ * @var ToplevelAgent
+ */
+ private $toplevelAgent = null;
+ /**
+ * Die aktuelle Antwort
+ *
+ * @var Response
+ */
+ protected $response;
+ /**
+ * Log-System
+ *
+ * @var Logger
+ */
+ protected $log;
+
+
+
+
+ /**
+ * Construct a new API.
+ *
+ * @param Request $request Current request
+ * @param Response $respone Current response
+ */
+ public function __construct(Request $request, Response $response)
+ {
+ // Store request
+ $this->request = $request;
+
+ // Store response
+ $this->response = $response;
+
+ // Init logging
+ $this->log = new \nre\core\Logger();
+ }
+
+
+
+
+ /**
+ * Run the application.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotValidException
+ * @throws DriverNotFoundException
+ * @throws ViewNotFoundException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ * @throws ControllerNotValidException
+ * @throws ControllerNotFoundException
+ * @throws AgentNotValidException
+ * @throws AgentNotFoundException
+ * @return Exception Last occurred exception of an subagent
+ */
+ public function run()
+ {
+ // Load ToplevelAgent
+ $this->loadToplevelAgent();
+
+ // Run ToplevelAgent
+ return $this->toplevelAgent->run($this->request, $this->response);
+ }
+
+
+ /**
+ * Render the output.
+ */
+ public function render()
+ {
+ // Check exit-status
+ if($this->response->getExit()) {
+ return;
+ }
+
+ // Render ToplevelAgent
+ $this->response->setOutput($this->toplevelAgent->render());
+ }
+
+
+
+
+ /**
+ * Log an exception
+ *
+ * @param Exception $exception Occurred exception
+ * @param int $logMode Log-mode
+ */
+ protected function log($exception, $logMode)
+ {
+ $this->log->log(
+ $exception->getMessage(),
+ $logMode
+ );
+ }
+
+
+
+
+ /**
+ * Load the ToplevelAgent specified by the request.
+ *
+ * @throws ServiceUnavailableException
+ * @throws AgentNotValidException
+ * @throws AgentNotFoundException
+ */
+ private function loadToplevelAgent()
+ {
+ // Determine agent
+ $agentName = $this->response->getParam(0);
+ if(is_null($agentName)) {
+ $agentName = $this->request->getParam(0, 'toplevel');
+ $this->response->addParam($agentName);
+ }
+
+ // Load agent
+ \nre\agents\ToplevelAgent::load($agentName);
+
+ // Construct agent
+ $this->toplevelAgent = \nre\agents\ToplevelAgent::factory(
+ $agentName,
+ $this->request,
+ $this->response,
+ $this->log
+ );
+ }
+
+ }
+
+?>
diff --git a/core/Autoloader.inc b/core/Autoloader.inc
new file mode 100644
index 00000000..020b61f7
--- /dev/null
+++ b/core/Autoloader.inc
@@ -0,0 +1,98 @@
+
+ * @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;
+
+
+ /**
+ * Autoloader.
+ *
+ * This class tries to load not yet used classes.
+ *
+ * @author coderkun
+ */
+ class Autoloader
+ {
+ /**
+ * Private construct().
+ */
+ private function __construct() {}
+
+ /**
+ * Private clone().
+ */
+ private function __clone() {}
+
+
+
+
+ /**
+ * Register load-method.
+ */
+ public static function register()
+ {
+ spl_autoload_register(
+ array(
+ get_class(),
+ 'load'
+ )
+ );
+ }
+
+
+ /**
+ * Look for the given class and try to load it.
+ *
+ * @param string $fullClassName Die zu ladende Klasse
+ */
+ public static function load($fullClassName)
+ {
+ $fullClassNameA = explode('\\', $fullClassName);
+
+ if(strpos($fullClassName, \nre\configs\CoreConfig::$core['namespace']) !== 0)
+ {
+ // App
+ $className = array_slice($fullClassNameA, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
+ array_unshift($className, \nre\configs\CoreConfig::getClassDir('app'));
+ $filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
+ if(file_exists($filename)) {
+ require_once($filename);
+ }
+ }
+ else
+ {
+ // Core
+ $className = array_slice($fullClassNameA, substr_count(\nre\configs\CoreConfig::$core['namespace'], '\\'));
+ $filename = ROOT.DS.implode(DS, $className).\nre\configs\CoreConfig::getFileExt('includes');
+ if(file_exists($filename)) {
+ require_once($filename);
+ }
+ }
+
+
+ }
+
+
+ /**
+ * Determine classtype of a class.
+ *
+ * @param string $className Name of the class to determine the classtype of
+ * @return string Classtype of the given class
+ */
+ public static function getClassType($className)
+ {
+ // CamelCase
+ return strtolower(preg_replace('/^.*([A-Z][^A-Z]+)$/', '$1', $className));
+ }
+
+ }
+
+?>
diff --git a/core/ClassLoader.inc b/core/ClassLoader.inc
new file mode 100644
index 00000000..81cf537a
--- /dev/null
+++ b/core/ClassLoader.inc
@@ -0,0 +1,129 @@
+
+ * @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;
+
+
+ /**
+ * Class for safely loading classes.
+ *
+ * @author coderkun
+ */
+ class ClassLoader
+ {
+
+
+
+
+ /**
+ * Load a class.
+ *
+ * @throws ClassNotFoundException
+ * @param string $className Name of the class to load
+ */
+ public static function load($fullClassName)
+ {
+ // Determine folder to look in
+ $className = explode('\\', $fullClassName);
+ $className = array_slice($className, substr_count(\nre\configs\AppConfig::$app['namespace'], '\\'));
+
+ // Determine filename
+ $fileName = ROOT.DS.implode(DS, $className). \nre\configs\CoreConfig::getFileExt('includes');
+
+
+ // Check file
+ if(!file_exists($fileName))
+ {
+ throw new \nre\exceptions\ClassNotFoundException(
+ $fullClassName
+ );
+ }
+
+ // Include file
+ include_once($fileName);
+ }
+
+
+ /**
+ * Check inheritance of a class.
+ *
+ * @throws ClassNotValidException
+ * @param string $className Name of the class to check
+ * @param string $parentClassName Name of the parent class
+ */
+ public static function check($className, $parentClassName)
+ {
+ // Check if class is subclass of parent class
+ if(!is_subclass_of($className, $parentClassName)) {
+ throw new \nre\exceptions\ClassNotValidException(
+ $className
+ );
+ }
+ }
+
+
+ /**
+ * Strip the namespace from a class name.
+ *
+ * @param string $class Name of a class including its namespace
+ * @return Name of the given class without its namespace
+ */
+ public static function stripNamespace($class)
+ {
+ return array_slice(explode('\\', $class), -1)[0];
+ }
+
+
+ /**
+ * Strip the class type from a class name.
+ *
+ * @param string $className Name of a class
+ * @return Name of the given class without its class type
+ */
+ public static function stripClassType($className)
+ {
+ return preg_replace('/^(.*)[A-Z][^A-Z]+$/', '$1', $className);
+ }
+
+
+ /**
+ * Strip the namespace and the class type of a full class name
+ * to get only its name.
+ *
+ * @param string $class Full name of a class
+ * @return Only the name of the given class
+ */
+ public static function getClassName($class)
+ {
+ return self::stripClassType(self::stripNamespace($class));
+ }
+
+
+ /**
+ * Concatenate strings to a class name following the CamelCase
+ * pattern.
+ *
+ * @param string $className1 Arbitrary number of strings to concat
+ * @return string Class name as CamelCase
+ */
+ public static function concatClassNames($className1)
+ {
+ return implode('', array_map(
+ function($arg) {
+ return ucfirst(strtolower($arg));
+ },
+ func_get_args()
+ ));
+ }
+
+ }
+
+?>
diff --git a/core/Component.inc b/core/Component.inc
new file mode 100644
index 00000000..a93363dc
--- /dev/null
+++ b/core/Component.inc
@@ -0,0 +1,85 @@
+
+ * @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 to implement a (Controller) Component.
+ *
+ * @author coderkun
+ */
+ abstract class Component
+ {
+
+
+
+
+ /**
+ * Load the class of a Component.
+ *
+ * @throws ComponentNotFoundException
+ * @throws ComponentNotValidException
+ * @param string $componentName Name of the Component to load
+ */
+ public static function load($componentName)
+ {
+ // Determine full classname
+ $className = self::getClassName($componentName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\ComponentNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\ComponentNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Component (Factory Pattern).
+ *
+ * @param string $componentName Name of the Component to instantiate
+ */
+ public static function factory($componentName)
+ {
+ // Determine full classname
+ $className = self::getClassName($componentName);
+
+ // Construct and return Controller
+ return new $className();
+ }
+
+
+ /**
+ * Determine the classname for the given Component name.
+ *
+ * @param string $componentName Component name to get classname of
+ * @return string Classname for the Component name
+ */
+ private static function getClassName($componentName)
+ {
+ $className = \nre\core\ClassLoader::concatClassNames($componentName, \nre\core\ClassLoader::stripNamespace(get_class()));
+
+
+ return \nre\configs\AppConfig::$app['namespace']."controllers\\components\\$className";
+ }
+
+ }
+
+?>
diff --git a/core/Config.inc b/core/Config.inc
new file mode 100644
index 00000000..b51f1e47
--- /dev/null
+++ b/core/Config.inc
@@ -0,0 +1,49 @@
+
+ * @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;
+
+
+ /**
+ * Configuration.
+ *
+ * This class does not hold any configuration value but helps to
+ * determine values that can be hold by AppConfig or CoreConfig.
+ *
+ * @author coderkun
+ */
+ final class Config
+ {
+
+
+
+
+ /**
+ * Get a default value.
+ *
+ * @param string $index Index of value to get
+ */
+ public static function getDefault($index)
+ {
+ if(array_key_exists($index, \nre\configs\AppConfig::$defaults)) {
+ return \nre\configs\AppConfig::$defaults[$index];
+ }
+ if(array_key_exists($index, \nre\configs\CoreConfig::$defaults)) {
+ return \nre\configs\CoreConfig::$defaults[$index];
+ }
+
+
+ return null;
+ }
+
+ }
+
+?>
diff --git a/core/Controller.inc b/core/Controller.inc
new file mode 100644
index 00000000..c2814e99
--- /dev/null
+++ b/core/Controller.inc
@@ -0,0 +1,424 @@
+
+ * @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
+ */
+ abstract class Controller
+ {
+ /**
+ * Corresponding Agent
+ *
+ * @var Agent
+ */
+ protected $agent;
+ /**
+ * View of the Controller
+ *
+ * @var View
+ */
+ protected $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 Components
+ $this->loadComponents();
+
+ // 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 Components of this Controller.
+ *
+ * @throws ComponentNotValidException
+ * @throws ComponentNotFoundException
+ */
+ private function loadComponents()
+ {
+ // Determine components
+ $components = array();
+ if(property_exists($this, 'components')) {
+ $components = $this->components;
+ }
+ if(!is_array($components)) {
+ $components = array($components);
+ }
+
+ // Load components
+ foreach($components as &$component)
+ {
+ // Load class
+ Component::load($component);
+
+ // Construct component
+ $componentName = ucfirst(strtolower($component));
+ $this->$componentName = Component::factory($component);
+ }
+ }
+
+
+ /**
+ * Load the Models of this Controller.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ protected 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
+ */
+ protected 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);
+ }
+
+ }
+
+?>
diff --git a/core/Driver.inc b/core/Driver.inc
new file mode 100644
index 00000000..eec59143
--- /dev/null
+++ b/core/Driver.inc
@@ -0,0 +1,96 @@
+
+ * @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 Driver.
+ *
+ * @author coderkun
+ */
+ abstract class Driver
+ {
+
+
+
+
+ /**
+ * Load the class of a Driver.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $driverName Name of the Driver to load
+ */
+ public static function load($driverName)
+ {
+ // Determine full classname
+ $className = self::getClassName($driverName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\DriverNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\DriverNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Driver (Factory Pattern).
+ *
+ * @param string $driverName Name of the Driver to instantiate
+ */
+ public static function factory($driverName, $config)
+ {
+ // Determine full classname
+ $className = self::getClassName($driverName);
+
+
+ // Construct and return Driver
+ return $className::singleton($config);
+ }
+
+
+ /**
+ * Determine the classname for the given Driver name.
+ *
+ * @param string $driverName Driver name to get classname of
+ * @return string Classname fore the Driver name
+ */
+ private static function getClassName($driverName)
+ {
+ $className = ClassLoader::concatClassNames($driverName, ClassLoader::stripNamespace(get_class()));
+
+
+ return "\\nre\\drivers\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Driver.
+ */
+ protected function __construct()
+ {
+ }
+
+ }
+
+?>
diff --git a/core/Exception.inc b/core/Exception.inc
new file mode 100644
index 00000000..a17a700f
--- /dev/null
+++ b/core/Exception.inc
@@ -0,0 +1,65 @@
+
+ * @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;
+
+
+ /**
+ * Exception class.
+ *
+ * @author coderkun
+ */
+ class Exception extends \Exception
+ {
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $message Error message
+ * @param int $code Error code
+ * @param string $name Name to insert
+ */
+ function __construct($message, $code, $name=null)
+ {
+ parent::__construct(
+ $this->concat(
+ $message,
+ $name
+ ),
+ $code
+ );
+ }
+
+
+
+
+ /**
+ * Insert the name in a message
+ *
+ * @param string $message Error message
+ * @param string $name Name to insert
+ */
+ private function concat($message, $name)
+ {
+ if(is_null($name)) {
+ return $message;
+ }
+
+
+ return "$message: $name";
+ }
+
+ }
+
+?>
diff --git a/core/Linker.inc b/core/Linker.inc
new file mode 100644
index 00000000..00c5846b
--- /dev/null
+++ b/core/Linker.inc
@@ -0,0 +1,311 @@
+
+ * @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;
+
+
+ /**
+ * Class to create web links based on the current request.
+ *
+ * @author coderkun
+ */
+ class Linker
+ {
+ /**
+ * Current request
+ *
+ * @var Request
+ */
+ private $request;
+
+
+
+
+ /**
+ * Construct a new linker.
+ *
+ * @param Request $request Current request
+ */
+ function __construct(\nre\requests\WebRequest $request)
+ {
+ $this->request = $request;
+ }
+
+
+
+
+ /**
+ * Mask parameters to be used in an URL.
+ *
+ * @param string $param1 First parameter
+ * @return string Masked parameters as string
+ */
+ public static function createLinkParam($param1)
+ {
+ return implode(
+ \nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
+ call_user_func_array(
+ '\nre\core\Linker::createLinkParams',
+ func_get_args()
+ )
+ );
+ }
+
+
+ /**
+ * Mask parameters to be used in an URL.
+ *
+ * @param string $param1 First parameter
+ * @return string Masked parameters as array
+ */
+ public static function createLinkParams($param1)
+ {
+ // Parameters
+ $linkParams = array();
+ $params = func_get_args();
+
+ foreach($params as $param)
+ {
+ // Mask special signs seperately
+ $specials = array('/', '?', '&');
+ foreach($specials as &$special) {
+ $param = str_replace($special, rawurlencode(rawurlencode($special)), $param);
+ }
+
+ // Process parameter
+ $param = str_replace(
+ ' ',
+ \nre\configs\CoreConfig::$classes['linker']['url']['delimiter'],
+ substr(
+ $param,
+ 0,
+ \nre\configs\CoreConfig::$classes['linker']['url']['length']
+ )
+ );
+
+ // Encode parameter
+ $linkParams[] = rawurlencode($param);
+ }
+
+
+ // Return link parameters
+ return $linkParams;
+ }
+
+
+
+
+ /**
+ * Create a web link.
+ *
+ * @param array $params Parameters to use
+ * @param int $offset Ignore first parameters
+ * @param bool $exclusiveParams Use only the given parameters
+ * @param array $getParams GET-parameter to use
+ * @param bool $exclusiveGetParams Use only the given GET-parameters
+ * @param string $anchor Target anchor
+ * @param bool $absolute Include hostname etc. for an absolute URL
+ * @return string Created link
+ */
+ public function link($params=null, $offset=0, $exclusiveParams=true, $getParams=null, $exclusiveGetParams=true, $anchor=null, $absolute=false)
+ {
+ // Make current request to response
+ $response = new \nre\responses\WebResponse();
+
+
+ // Check parameters
+ if(is_null($params)) {
+ $params = array();
+ }
+ elseif(!is_array($params)) {
+ $params = array($params);
+ }
+
+ // Set parameters from request
+ $reqParams = array_slice($this->request->getParams(), 1, $offset);
+ if(count($reqParams) < $offset && $offset > 0) {
+ $reqParams[] = $this->request->getParam(1, 'intermediate');
+ }
+ if(count($reqParams) < $offset && $offset > 1) {
+ $reqParams[] = $this->request->getParam(2, 'action');
+ }
+ $params = array_map('rawurlencode', $params);
+ $params = array_merge($reqParams, $params);
+
+ // Use Layout
+ $layout = \nre\configs\AppConfig::$defaults['toplevel'];
+ if(!empty($getParams) && array_key_exists('layout', $getParams)) {
+ $layout = $getParams['layout'];
+ }
+ array_unshift($params, $layout);
+
+ // Use parameters from request only
+ if(!$exclusiveParams)
+ {
+ $params = array_merge(
+ $params,
+ array_slice(
+ $this->request->getParams(),
+ count($params)
+ )
+ );
+ }
+
+ // Set parameters
+ call_user_func_array(
+ array(
+ $response,
+ 'addParams'
+ ),
+ $params
+ );
+
+
+ // Check GET-parameters
+ if(is_null($getParams)) {
+ $getParams = array();
+ }
+ elseif(!is_array($params)) {
+ $params = array($params);
+ }
+ if(!$exclusiveGetParams)
+ {
+ $getParams = array_merge(
+ $this->request->getGetParams(),
+ $getParams
+ );
+ }
+
+ // Set GET-parameters
+ $response->addGetParams($getParams);
+
+
+ // Create and return link
+ return self::createLink($this->request, $response, $anchor, $absolute);
+ }
+
+
+ /**
+ * Create a link from an URL.
+ *
+ * @param string $url URL to create link from
+ * @param bool $absolute Create absolute URL
+ * @return string Created link
+ */
+ public function hardlink($url, $absolute=false)
+ {
+ return $this->createUrl($url, $this->request, $absolute);
+ }
+
+
+
+
+ /**
+ * Create a link.
+ *
+ * @param Request $request Current request
+ * @param Response $response Current response
+ * @param bool $absolute Create absolute link
+ * @param string $anchor Anchor on target
+ * @return string Created link
+ */
+ private static function createLink(Request $request, Response $response, $anchor=null, $absolute=false)
+ {
+ // Check response
+ if(is_null($response)) {
+ return null;
+ }
+
+
+ // Get parameters
+ $params = $response->getParams(1);
+
+ // Check Action
+ if(count($params) == 2 && $params[1] == \nre\configs\CoreConfig::$defaults['action']) {
+ array_pop($params);
+ }
+
+ // Set parameters
+ $link = implode('/', $params);
+
+ // Apply reverse-routes
+ $link = $request->applyReverseRoutes($link);
+
+
+ // Get GET-parameters
+ $getParams = $response->getGetParams();
+
+ // Layout überprüfen
+ if(array_key_exists('layout', $getParams) && $getParams['layout'] == \nre\configs\AppConfig::$defaults['toplevel']) {
+ unset($getParams['layout']);
+ }
+
+ // Set GET-parameters
+ if(array_key_exists('url', $getParams)) {
+ unset($getParams['url']);
+ }
+ if(count($getParams) > 0) {
+ $link .= '?'.http_build_query($getParams);
+ }
+
+ // Add anchor
+ if(!is_null($anchor)) {
+ $link .= "#$anchor";
+ }
+
+
+ // Create URL
+ $url = self::createUrl($link, $request, $absolute);
+
+
+ return $url;
+ }
+
+
+ /**
+ * Adapt a link to the environment.
+ *
+ * @param string $url URL
+ * @param Request $request Current request
+ * @param bool $absolute Create absolute URL
+ * @return string Adapted URL
+ */
+ private static function createUrl($url, Request $request, $absolute=false)
+ {
+ // Variables
+ $server = $_SERVER['SERVER_NAME'];
+ $uri = $_SERVER['REQUEST_URI'];
+ $prefix = '';
+
+
+ // Determine prefix
+ $ppos = array(strlen($uri));
+ if(($p = strpos($uri, '/'.$request->getParam(1, 'intermediate'))) !== false) {
+ $ppos[] = $p;
+ }
+ $prefix = substr($uri, 0, min($ppos));
+
+ // Create absolute URL
+ if($absolute) {
+ $prefix = "http://$server/".trim($prefix, '/');
+ }
+
+ // Put URL together
+ $url = rtrim($prefix, '/').'/'.ltrim($url, '/');
+
+
+ // Return URL
+ return $url;
+ }
+
+ }
+
+?>
diff --git a/core/Logger.inc b/core/Logger.inc
new file mode 100644
index 00000000..b5ac7dc9
--- /dev/null
+++ b/core/Logger.inc
@@ -0,0 +1,132 @@
+
+ * @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;
+
+
+ /**
+ * Class to log messages to different targets.
+ *
+ * @author coderkun
+ */
+ class Logger
+ {
+ /**
+ * Log mode: Detect automatic
+ *
+ * @var int
+ */
+ const LOGMODE_AUTO = 0;
+ /**
+ * Log mode: Print to screen
+ *
+ * @var int
+ */
+ const LOGMODE_SCREEN = 1;
+ /**
+ * Log mode: Use PHP-logging mechanism
+ *
+ * @var int
+ */
+ const LOGMODE_PHP = 2;
+
+ /**
+ * Do not auto-log to screen
+ *
+ * @var boolean
+ */
+ private $autoLogToScreenDisabled = false;
+
+
+
+
+ /**
+ * Construct a new logger.
+ */
+ public function __construct()
+ {
+ }
+
+
+
+
+ /**
+ * Log a message.
+ *
+ * @param string $message Message to log
+ * @param int $logMode Log mode to use
+ */
+ public function log($message, $logMode=self::LOGMODE_SCREEN)
+ {
+ // Choose log mode automatically
+ if($logMode == self::LOGMODE_AUTO) {
+ $logMode = $this->getAutoLogMode();
+ }
+
+ // Print message to screen
+ if($logMode & self::LOGMODE_SCREEN) {
+ $this->logToScreen($message);
+ }
+
+ // Use PHP-logging mechanism
+ if($logMode & self::LOGMODE_PHP) {
+ $this->logToPhp($message);
+ }
+ }
+
+
+ /**
+ * Disable logging to screen when the log mode is automatically
+ * detected.
+ */
+ public function disableAutoLogToScreen()
+ {
+ $this->autoLogToScreenDisabled = true;
+ }
+
+
+
+ /**
+ * Print a message to screen.
+ *
+ * @param string $message Message to print
+ */
+ private function logToScreen($message)
+ {
+ echo "$message \n";
+ }
+
+
+ /**
+ * Log a message by using PHP-logging mechanism.
+ *
+ * @param string $message Message to log
+ */
+ private function logToPhp($message)
+ {
+ error_log($message, 0);
+ }
+
+
+ /**
+ * Detect log mode automatically by distinguishing between
+ * production and test environment.
+ *
+ * @return int Automatically detected log mode
+ */
+ private function getAutoLogMode()
+ {
+ return ($_SERVER['SERVER_ADDR'] == '127.0.0.1' && !$this->autoLogToScreenDisabled) ? self::LOGMODE_SCREEN : self::LOGMODE_PHP;
+ }
+
+ }
+
+?>
diff --git a/core/Model.inc b/core/Model.inc
new file mode 100644
index 00000000..c0475b4a
--- /dev/null
+++ b/core/Model.inc
@@ -0,0 +1,141 @@
+
+ * @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 Model.
+ *
+ * @author coderkun
+ */
+ abstract class Model
+ {
+
+
+
+
+ /**
+ * Load the class of a Model.
+ *
+ * @throws ModelNotFoundException
+ * @throws ModelNotValidException
+ * @param string $modelName Name of the Model to load
+ */
+ public static function load($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ try {
+ // Load class
+ ClassLoader::load($className);
+
+ // Validate class
+ ClassLoader::check($className, get_class());
+ }
+ catch(\nre\exceptions\ClassNotValidException $e) {
+ throw new \nre\exceptions\ModelNotValidException($e->getClassName());
+ }
+ catch(\nre\exceptions\ClassNotFoundException $e) {
+ throw new \nre\exceptions\ModelNotFoundException($e->getClassName());
+ }
+ }
+
+
+ /**
+ * Instantiate a Model (Factory Pattern).
+ *
+ * @param string $modelName Name of the Model to instantiate
+ */
+ public static function factory($modelName)
+ {
+ // Determine full classname
+ $className = self::getClassName($modelName);
+
+ // Construct and return Model
+ return new $className();
+ }
+
+
+ /**
+ * Determine the classname for the given Model name.
+ *
+ * @param string $modelName Model name to get classname of
+ * @return string Classname fore the Model name
+ */
+ private static function getClassName($modelName)
+ {
+ $className = ClassLoader::concatClassNames($modelName, ClassLoader::stripNamespace(get_class()));
+
+
+ return \nre\configs\AppConfig::$app['namespace']."models\\$className";
+ }
+
+
+
+
+ /**
+ * Construct a new Model.
+ *
+ * TODO Catch exception
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ protected function __construct()
+ {
+ // Load Models
+ $this->loadModels();
+ }
+
+
+
+
+ /**
+ * Load the Models of this Model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @throws ModelNotValidException
+ * @throws ModelNotFoundException
+ */
+ private function loadModels()
+ {
+ // Determine Models
+ $models = array();
+ if(property_exists($this, 'models')) {
+ $models = $this->models;
+ }
+ if(!is_array($models)) {
+ $models = array($models);
+ }
+
+
+ // Load Models
+ foreach($models as $model)
+ {
+ // Load class
+ Model::load($model);
+
+ // Construct Model
+ $modelName = ucfirst(strtolower($model));
+ $this->$modelName = Model::factory($model);
+ }
+ }
+
+ }
+
+?>
diff --git a/core/Request.inc b/core/Request.inc
new file mode 100644
index 00000000..5fda187e
--- /dev/null
+++ b/core/Request.inc
@@ -0,0 +1,64 @@
+
+ * @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;
+
+
+ /**
+ * Base class to represent a request.
+ *
+ * @author coderkun
+ */
+ class Request
+ {
+ /**
+ * Passed parameters
+ *
+ * @var array
+ */
+ protected $params = array();
+
+
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ // Return parameter
+ if(count($this->params) > $index) {
+ return $this->params[$index];
+ }
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ return array_slice($this->params, $offset);
+ }
+
+ }
+
+?>
diff --git a/core/Response.inc b/core/Response.inc
new file mode 100644
index 00000000..4781b2ab
--- /dev/null
+++ b/core/Response.inc
@@ -0,0 +1,158 @@
+
+ * @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;
+
+
+ /**
+ * Base class to represent a response.
+ *
+ * @author coderkun
+ */
+ class Response
+ {
+ /**
+ * Applied parameters
+ *
+ * @var array
+ */
+ protected $params = array();
+ /**
+ * Generated output
+ *
+ * @var string
+ */
+ private $output = '';
+ /**
+ * Abort futher execution
+ *
+ * @var bool
+ */
+ private $exit = false;
+
+
+
+
+ /**
+ * Add a parameter.
+ *
+ * @param mixed $value Value of parameter
+ */
+ public function addParam($value)
+ {
+ $this->params[] = $value;
+ }
+
+
+ /**
+ * Add multiple parameters.
+ *
+ * @param mixed $value1 Value of first parameter
+ * @param mixed … Values of further parameters
+ */
+ public function addParams($value1)
+ {
+ $this->params = array_merge(
+ $this->params,
+ func_get_args()
+ );
+ }
+
+
+ /**
+ * Delete all stored parameters (from offset on).
+ *
+ * @param int $offset Offset-index
+ */
+ public function clearParams($offset=0)
+ {
+ $this->params = array_slice($this->params, 0, $offset);
+ }
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ // Return parameter
+ if(count($this->params) > $index) {
+ return $this->params[$index];
+ }
+
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ return array_slice($this->params, $offset);
+ }
+
+
+ /**
+ * Set output.
+ *
+ * @param string $output Generated output
+ */
+ public function setOutput($output)
+ {
+ $this->output = $output;
+ }
+
+
+ /**
+ * Get generated output.
+ *
+ * @return string Generated output
+ */
+ public function getOutput()
+ {
+ return $this->output;
+ }
+
+
+ /**
+ * Set exit-state.
+ *
+ * @param bool $exit Abort further execution
+ */
+ public function setExit($exit=true)
+ {
+ $this->exit = $exit;
+ }
+
+
+ /**
+ * Get exit-state.
+ *
+ * @return bool Abort further execution
+ */
+ public function getExit()
+ {
+ return $this->exit;
+ }
+
+ }
+
+?>
diff --git a/core/View.inc b/core/View.inc
new file mode 100644
index 00000000..546ddb6e
--- /dev/null
+++ b/core/View.inc
@@ -0,0 +1,124 @@
+
+ * @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;
+
+
+ /**
+ * View.
+ *
+ * Class to encapsulate a template file and to provide rendering methods.
+ *
+ * @author coderkun
+ */
+ class View
+ {
+ /**
+ * Template filename
+ *
+ * @var string
+ */
+ protected $templateFilename;
+
+
+
+
+ /**
+ * Load and instantiate the View of an Agent.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ public static function loadAndFactory($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ return new View($layoutName, $agentName, $action, $isToplevel);
+ }
+
+
+
+
+ /**
+ * Construct a new View.
+ *
+ * @throws ViewNotFoundException
+ * @param string $layoutName Name of Layout in use
+ * @param string $agentName Name of the Agent
+ * @param string $action Current Action
+ * @param bool $isToplevel Agent is a ToplevelAgent
+ */
+ protected function __construct($layoutName, $agentName=null, $action=null, $isToplevel=false)
+ {
+ // Create template filename
+ // LayoutName
+ $fileName = ROOT.DS. \nre\configs\CoreConfig::getClassDir('views').DS. strtolower($layoutName).DS;
+ // AgentName and Action
+ if(strtolower($agentName) != $layoutName || !$isToplevel) {
+ $fileName .= strtolower($agentName).DS.strtolower($action);
+ }
+ else {
+ $fileName .= strtolower($layoutName);
+ }
+ // File extension
+ $fileName .= \nre\configs\CoreConfig::getFileExt('views');
+
+
+ // Check template file
+ if(!file_exists($fileName)) {
+ throw new \nre\exceptions\ViewNotFoundException($fileName);
+ }
+
+ // Save filename
+ $this->templateFilename = $fileName;
+ }
+
+
+
+
+ /**
+ * Generate output
+ *
+ * @param array $data Data to have available in the template file
+ */
+ public function render($data)
+ {
+ // Extract data
+ if(!is_null($data)) {
+ extract($data, EXTR_SKIP);
+ }
+
+ // Buffer output
+ ob_start();
+
+ // Include template
+ include($this->templateFilename);
+
+
+ // Return buffered output
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Get template filename.
+ *
+ * @return string Template filename
+ */
+ public function getTemplateFilename()
+ {
+ return $this->templateFilename;
+ }
+
+ }
+
+?>
diff --git a/core/WebUtils.inc b/core/WebUtils.inc
new file mode 100644
index 00000000..5a4bb6f0
--- /dev/null
+++ b/core/WebUtils.inc
@@ -0,0 +1,75 @@
+
+ * @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;
+
+
+ /**
+ * Class that holds several web-specific methods and properties.
+ *
+ * @author coderkun
+ */
+ class WebUtils
+ {
+ /**
+ * HTTP-statuscode 403: Forbidden
+ *
+ * @var int
+ */
+ const HTTP_FORBIDDEN = 403;
+ /**
+ * HTTP-statuscode 404: Not Found
+ *
+ * @var int
+ */
+ const HTTP_NOT_FOUND = 404;
+ /**
+ * HTTP-statuscode 503: Service Unavailable
+ *
+ * @var int
+ */
+ const HTTP_SERVICE_UNAVAILABLE = 503;
+
+ /**
+ * HTTP-header strings
+ *
+ * @var array
+ */
+ public static $httpStrings = array(
+ 200 => 'OK',
+ 304 => 'Not Modified',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 503 => 'Service Unavailable'
+ );
+
+
+
+
+ /**
+ * Get the HTTP-header of a HTTP-statuscode
+ *
+ * @param int $httpStatusCode HTTP-statuscode
+ * @return string HTTP-header of HTTP-statuscode
+ */
+ public static function getHttpHeader($httpStatusCode)
+ {
+ if(!array_key_exists($httpStatusCode, self::$httpStrings)) {
+ $httpStatusCode = 200;
+ }
+
+
+ return sprintf("HTTP/1.1 %d %s\n", $httpStatusCode, self::$httpStrings[$httpStatusCode]);
+ }
+
+ }
+
+?>
diff --git a/drivers/DatabaseDriver.inc b/drivers/DatabaseDriver.inc
new file mode 100644
index 00000000..dfd5c0fd
--- /dev/null
+++ b/drivers/DatabaseDriver.inc
@@ -0,0 +1,87 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\drivers;
+
+
+ /**
+ * Abstract class for implementing a database driver.
+ *
+ * @author coderkun
+ */
+ abstract class DatabaseDriver extends \nre\core\Driver
+ {
+ /**
+ * Driver class instance
+ *
+ * @static
+ * @var DatabaseDriver
+ */
+ protected static $driver = null;
+ /**
+ * Connection resource
+ *
+ * @var resource
+ */
+ protected $connection = null;
+
+
+
+
+ /**
+ * Singleton-pattern.
+ *
+ * @param array $config Database driver configuration
+ * @return DatabaseDriver Singleton-instance of database driver class
+ */
+ public static function singleton($config)
+ {
+ // Singleton
+ if(self::$driver !== null) {
+ return self::$driver;
+ }
+
+ // Construct
+ $className = get_called_class();
+ self::$driver = new $className($config);
+
+
+ return self::$driver;
+ }
+
+
+ /**
+ * Construct a new database driver.
+ *
+ * @param array $config Connection and login settings
+ */
+ protected function __construct($config)
+ {
+ parent::__construct();
+
+ // Establish connection
+ $this->connect($config);
+ }
+
+
+
+
+ /**
+ * Establish a connect to a MqSQL-database.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ protected abstract function connect($config);
+
+ }
+
+?>
diff --git a/drivers/MysqliDriver.inc b/drivers/MysqliDriver.inc
new file mode 100644
index 00000000..fe4fa81a
--- /dev/null
+++ b/drivers/MysqliDriver.inc
@@ -0,0 +1,169 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\drivers;
+
+
+ /**
+ * Implementation of a database driver for MySQL-databases.
+ *
+ * @author coderkun
+ */
+ class MysqliDriver extends \nre\drivers\DatabaseDriver
+ {
+
+
+
+
+ /**
+ * Construct a MySQL-driver.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ function __construct($config)
+ {
+ parent::__construct($config);
+ }
+
+
+
+
+ /**
+ * Execute a SQL-query.
+ *
+ * @throws DatamodelException
+ * @param string $query Query to run
+ * @param mixed … Params
+ * @return array Result
+ */
+ public function query($query)
+ {
+ // Prepare statement
+ if(!($stmt = $this->connection->prepare($query))) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+
+ try {
+ // Prepare data
+ $data = array();
+
+ // Bind parameters
+ $p = array_slice(func_get_args(), 1);
+ $params = array();
+ foreach($p as $key => $value) {
+ $params[$key] = &$p[$key];
+ }
+ if(count($params) > 0)
+ {
+ if(!(call_user_func_array(array($stmt, 'bind_param'), $params))) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+ }
+
+ // Execute query
+ if(!$stmt->execute()) {
+ throw new \nre\exceptions\DatamodelException($this->connection->error, $this->connection->errno);
+ }
+
+ // Fetch result
+ if($result = $stmt->get_result()) {
+ while($row = $result->fetch_assoc()) {
+ $data[] = $row;
+ }
+ }
+
+
+ $stmt->close();
+ return $data;
+ }
+ catch(Exception $e) {
+ $stmt->close();
+ throw $e;
+ }
+ }
+
+
+ /**
+ * Return the last insert id (of the last insert-query).
+ *
+ * @return int Last insert id
+ */
+ public function getInsertId()
+ {
+ return $this->connection->insert_id;
+ }
+
+
+ /**
+ * Enable/disable autocommit feature.
+ *
+ * @param boolean $autocommit Enable/disable autocommit
+ */
+ public function setAutocommit($autocommit)
+ {
+ $this->connection->autocommit($autocommit);
+ }
+
+
+ /**
+ * Rollback the current transaction.
+ */
+ public function rollback()
+ {
+ $this->connection->rollback();
+ }
+
+
+ /**
+ * Commit the current transaction.
+ */
+ public function commit()
+ {
+ $this->connection->commit();
+ }
+
+
+
+
+ /**
+ * Establish a connect to a MqSQL-database.
+ *
+ * @throws DatamodelException
+ * @param array $config Connection and login settings
+ */
+ protected function connect($config)
+ {
+ // Connect
+ $con = @new \mysqli(
+ $config['host'],
+ $config['user'],
+ $config['password'],
+ $config['db']
+ );
+
+ // Check connection
+ if($con->connect_error) {
+ throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
+ }
+
+ // Set character encoding
+ if(!$con->set_charset('utf8')) {
+ throw new \nre\exceptions\DatamodelException($con->connect_error, $con->connect_errno);
+ }
+
+ // Save connection
+ $this->connection = $con;
+ }
+
+ }
+
+?>
diff --git a/exceptions/AccessDeniedException.inc b/exceptions/AccessDeniedException.inc
new file mode 100644
index 00000000..31bba929
--- /dev/null
+++ b/exceptions/AccessDeniedException.inc
@@ -0,0 +1,51 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Access denied.
+ *
+ * @author coderkun
+ */
+ class AccessDeniedException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'access denied';
+
+
+
+
+ /**
+ * Consturct a new exception.
+ */
+ function __construct()
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+ }
+
+?>
diff --git a/exceptions/ActionNotFoundException.inc b/exceptions/ActionNotFoundException.inc
new file mode 100644
index 00000000..418dd49c
--- /dev/null
+++ b/exceptions/ActionNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ActionNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 70;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'action not found';
+
+ /**
+ * Name of the action that was not found
+ *
+ * @var string
+ */
+ private $action;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $action Name of the action that was not found
+ */
+ function __construct($action)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $action
+ );
+
+ // Store values
+ $this->action = $action;
+ }
+
+
+
+
+ /**
+ * Get the name of the action that was not found.
+ *
+ * @return string Name of the action that was not found
+ */
+ public function getAction()
+ {
+ return $this->action;
+ }
+
+ }
+
+?>
diff --git a/exceptions/AgentNotFoundException.inc b/exceptions/AgentNotFoundException.inc
new file mode 100644
index 00000000..f0b3a2a7
--- /dev/null
+++ b/exceptions/AgentNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Agent not found.
+ *
+ * @author coderkun
+ */
+ class AgentNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 66;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'agent not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $agentName Name of the Agent that was not found
+ */
+ function __construct($agentName)
+ {
+ parent::__construct(
+ $agentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Agent that was not found.
+ *
+ * @return string Name of the Agent that was not found
+ */
+ public function getAgentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/AgentNotValidException.inc b/exceptions/AgentNotValidException.inc
new file mode 100644
index 00000000..1c752051
--- /dev/null
+++ b/exceptions/AgentNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Agent not valid.
+ *
+ * @author coderkun
+ */
+ class AgentNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 76;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'agent not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $agentName Name of the invalid Agent
+ */
+ function __construct($agentName)
+ {
+ parent::__construct(
+ $agentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Agent.
+ *
+ * @return string Name of the invalid Agent
+ */
+ public function getAgentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ClassNotFoundException.inc b/exceptions/ClassNotFoundException.inc
new file mode 100644
index 00000000..070f383f
--- /dev/null
+++ b/exceptions/ClassNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Class not found.
+ *
+ * @author coderkun
+ */
+ class ClassNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 64;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'class not found';
+
+ /**
+ * Name of the class that was not found
+ *
+ * @var string
+ */
+ private $className;
+
+
+
+
+ /**
+ * Construct a new exception
+ *
+ * @param string $className Name of the class that was not found
+ */
+ function __construct($className, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $className
+ );
+
+ // Store values
+ $this->className = $className;
+ }
+
+
+
+
+ /**
+ * Get the name of the class that was not found.
+ *
+ * @return string Name of the class that was not found
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ClassNotValidException.inc b/exceptions/ClassNotValidException.inc
new file mode 100644
index 00000000..bdd36d5e
--- /dev/null
+++ b/exceptions/ClassNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Class not valid.
+ *
+ * @author coderkun
+ */
+ class ClassNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 74;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'class not valid';
+
+ /**
+ * Name of the invalid class
+ *
+ * @var string
+ */
+ private $className;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $className Name of the invalid class
+ */
+ function __construct($className, $message=self::MESSAGE, $code=self::CODE)
+ {
+ parent::__construct(
+ $message,
+ $code,
+ $className
+ );
+
+ // Store value
+ $this->className = $className;
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid class.
+ *
+ * @return string Name of the invalid class
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ComponentNotFoundException.inc b/exceptions/ComponentNotFoundException.inc
new file mode 100644
index 00000000..5e75de44
--- /dev/null
+++ b/exceptions/ComponentNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Component not found.
+ *
+ * @author coderkun
+ */
+ class ComponentNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 67;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'component not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $componentName Name of the Component that was not found
+ */
+ function __construct($componentName)
+ {
+ parent::__construct(
+ $componentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Component that was not found.
+ *
+ * @return string Name of the Component that was not found
+ */
+ public function getComponentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ComponentNotValidException.inc b/exceptions/ComponentNotValidException.inc
new file mode 100644
index 00000000..a03b0c0d
--- /dev/null
+++ b/exceptions/ComponentNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Component not valid.
+ *
+ * @author coderkun
+ */
+ class ComponentNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 77;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'component not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $componentName Name of the invalid Component
+ */
+ function __construct($componentName)
+ {
+ parent::__construct(
+ $componentName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Component.
+ *
+ * @return string Name of the invalid Component
+ */
+ public function getComponentName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ControllerNotFoundException.inc b/exceptions/ControllerNotFoundException.inc
new file mode 100644
index 00000000..90859c49
--- /dev/null
+++ b/exceptions/ControllerNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Controller not found.
+ *
+ * @author coderkun
+ */
+ class ControllerNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 67;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'controller not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $controllerName Name of the Controller that was not found
+ */
+ function __construct($controllerName)
+ {
+ parent::__construct(
+ $controllerName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Controller that was not found.
+ *
+ * @return string Name of the Controller that was not found
+ */
+ public function getControllerName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ControllerNotValidException.inc b/exceptions/ControllerNotValidException.inc
new file mode 100644
index 00000000..0c945bcb
--- /dev/null
+++ b/exceptions/ControllerNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Controller not valid.
+ *
+ * @author coderkun
+ */
+ class ControllerNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 77;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'controller not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $controllerName Name of the invalid Controller
+ */
+ function __construct($controllerName)
+ {
+ parent::__construct(
+ $controllerName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Controller.
+ *
+ * @return string Name of the invalid Controller
+ */
+ public function getControllerName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/DatamodelException.inc b/exceptions/DatamodelException.inc
new file mode 100644
index 00000000..7785cd21
--- /dev/null
+++ b/exceptions/DatamodelException.inc
@@ -0,0 +1,99 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Datamodel.
+ *
+ * This exception is thrown when an error occurred during the execution
+ * of a datamodel.
+ *
+ * @author coderkun
+ */
+ class DatamodelException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 84;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'datamodel error';
+
+ /**
+ * Error message of datamodel
+ *
+ * @var string
+ */
+ private $datamodelMessage;
+ /**
+ * Error code of datamodel
+ *
+ * @var int
+ */
+ private $datamodelErrorNumber;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param string $datamodelMessage Error message of datamodel
+ * @param int $datamodelErrorNumber Error code of datamodel
+ */
+ function __construct($datamodelMessage, $datamodelErrorNumber)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $datamodelMessage." ($datamodelErrorNumber)"
+ );
+
+ // Store values
+ $this->datamodelMessage = $datamodelMessage;
+ $this->datamodelErrorNumber = $datamodelErrorNumber;
+ }
+
+
+
+
+ /**
+ * Get the error message of datamodel.
+ *
+ * @return string Error message of datamodel
+ */
+ public function getDatamodelMessage()
+ {
+ return $this->datamodelMessage;
+ }
+
+
+ /**
+ * Get the error code of datamodel.
+ *
+ * @return string Error code of datamodel
+ */
+ public function getDatamodelErrorNumber()
+ {
+ return $this->datamodelErrorNumber;
+ }
+
+ }
+
+?>
diff --git a/exceptions/DriverNotFoundException.inc b/exceptions/DriverNotFoundException.inc
new file mode 100644
index 00000000..9b218f29
--- /dev/null
+++ b/exceptions/DriverNotFoundException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Driver not found.
+ *
+ * @author coderkun
+ */
+ class DriverNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 71;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'driver not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $driverName Name of the driver that was not found
+ */
+ function __construct($driverName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $driverName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the driver that was not found.
+ *
+ * @return string Name of the driver that was not found
+ */
+ public function getDriverName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/DriverNotValidException.inc b/exceptions/DriverNotValidException.inc
new file mode 100644
index 00000000..fa9022e8
--- /dev/null
+++ b/exceptions/DriverNotValidException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Driver not valid.
+ *
+ * @author coderkun
+ */
+ class DriverNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 81;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'driver not valid';
+
+
+
+
+ /**
+ * Konstruktor.
+ *
+ * @param string $driverName Name of the invalid driver
+ */
+ function __construct($driverName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $driverName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid driver.
+ *
+ * @return string Name of the invalid driver
+ */
+ public function getDriverName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/FatalDatamodelException.inc b/exceptions/FatalDatamodelException.inc
new file mode 100644
index 00000000..afd80b86
--- /dev/null
+++ b/exceptions/FatalDatamodelException.inc
@@ -0,0 +1,96 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Datamodel exception that is fatal for the application.
+ *
+ * @author coderkun
+ */
+ class FatalDatamodelException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'fatal datamodel error';
+
+ /**
+ * Error message of datamodel
+ *
+ * @var string
+ */
+ private $datamodelMessage;
+ /**
+ * Error code of datamodel
+ *
+ * @var int
+ */
+ private $datamodelErrorNumber;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param string $datamodelMessage Error message of datamodel
+ * @param int $datamodelErrorNumber Error code of datamodel
+ */
+ function __construct($datamodelMessage, $datamodelErrorNumber)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $datamodelMessage." ($datamodelErrorNumber)"
+ );
+
+ // Store values
+ $this->datamodelMessage = $datamodelMessage;
+ $this->datamodelErrorNumber = $datamodelErrorNumber;
+ }
+
+
+
+
+ /**
+ * Get the error message of datamodel.
+ *
+ * @return string Error message of datamodel
+ */
+ public function getDatamodelMessage()
+ {
+ return $this->datamodelMessage;
+ }
+
+
+ /**
+ * Get the error code of datamodel.
+ *
+ * @return string Error code of datamodel
+ */
+ public function getDatamodelErrorNumber()
+ {
+ return $this->datamodelErrorNumber;
+ }
+
+ }
+
+?>
diff --git a/exceptions/IdNotFoundException.inc b/exceptions/IdNotFoundException.inc
new file mode 100644
index 00000000..fc3315c3
--- /dev/null
+++ b/exceptions/IdNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: ID not found.
+ *
+ * @author coderkun
+ */
+ class IdNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 85;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'id not found';
+
+ /**
+ * ID that was not found
+ *
+ * @var mixed
+ */
+ private $id;
+
+
+
+
+ /**
+ * Consturct a new exception.
+ *
+ * @param mixed $id ID that was not found
+ */
+ function __construct($id)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $id
+ );
+
+ // Store values
+ $this->id = $id;
+ }
+
+
+
+
+ /**
+ * Get the ID that was not found.
+ *
+ * @return mixed ID that was not found
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ }
+
+?>
diff --git a/exceptions/LayoutNotFoundException.inc b/exceptions/LayoutNotFoundException.inc
new file mode 100644
index 00000000..0eb8c89c
--- /dev/null
+++ b/exceptions/LayoutNotFoundException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Layout not found.
+ *
+ * @author coderkun
+ */
+ class LayoutNotFoundException extends \nre\exceptions\AgentNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 65;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'layout not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $layoutName Name of the Layout that was not found
+ */
+ function __construct($layoutName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $layoutName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Layout that was not found.
+ *
+ * @return string Name of the Layout that was not found
+ */
+ public function getLayoutName()
+ {
+ return $this->getAgentName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/LayoutNotValidException.inc b/exceptions/LayoutNotValidException.inc
new file mode 100644
index 00000000..b3af184f
--- /dev/null
+++ b/exceptions/LayoutNotValidException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Layout not valid.
+ *
+ * @author coderkun
+ */
+ class LayoutNotValidException extends \nre\exceptions\AgentNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 75;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'layout not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $layoutName Name of the invalid Layout
+ */
+ function __construct($layoutName)
+ {
+ parent::__construct(
+ $layoutName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Layout.
+ *
+ * @return string Name of the invalid Layout
+ */
+ public function getLayoutName()
+ {
+ return $this->getAgentName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ModelNotFoundException.inc b/exceptions/ModelNotFoundException.inc
new file mode 100644
index 00000000..48e8c0df
--- /dev/null
+++ b/exceptions/ModelNotFoundException.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ModelNotFoundException extends \nre\exceptions\ClassNotFoundException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 68;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'model not found';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $modelName Name of the Model that was not found
+ */
+ function __construct($modelName)
+ {
+ parent::__construct(
+ $modelName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the Model that was not found
+ *
+ * @return string Name of the Model that was not found
+ */
+ public function getModelName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ModelNotValidException.inc b/exceptions/ModelNotValidException.inc
new file mode 100644
index 00000000..267e460e
--- /dev/null
+++ b/exceptions/ModelNotValidException.inc
@@ -0,0 +1,68 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Action not found.
+ *
+ * @author coderkun
+ */
+ class ModelNotValidException extends \nre\exceptions\ClassNotValidException
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 78;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'model not valid';
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $modelName Name of the invalid Model
+ */
+ function __construct($modelName)
+ {
+ // Elternkonstruktor aufrufen
+ parent::__construct(
+ $modelName,
+ self::MESSAGE,
+ self::CODE
+ );
+ }
+
+
+
+
+ /**
+ * Get the name of the invalid Model
+ *
+ * @return string Name of the invalid Model
+ */
+ public function getModelName()
+ {
+ return $this->getClassName();
+ }
+
+ }
+
+?>
diff --git a/exceptions/ParamsNotValidException.inc b/exceptions/ParamsNotValidException.inc
new file mode 100644
index 00000000..be650ce2
--- /dev/null
+++ b/exceptions/ParamsNotValidException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception Parameters not valid.
+ *
+ * @author coderkun
+ */
+ class ParamsNotValidException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 86;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'parameters not valid';
+
+ /**
+ * Invalid parameters.
+ *
+ * @var array
+ */
+ private $params;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param mixed $param1 Invalid parameters as argument list
+ */
+ function __construct($param1)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ implode(', ', func_get_args())
+ );
+
+ // Store values
+ $this->params = func_get_args();
+ }
+
+
+
+
+ /**
+ * Get invalid parameters.
+ *
+ * @return array Invalid parameters
+ */
+ public function getParams()
+ {
+ return $this->params;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ServiceUnavailableException.inc b/exceptions/ServiceUnavailableException.inc
new file mode 100644
index 00000000..bafc297f
--- /dev/null
+++ b/exceptions/ServiceUnavailableException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: Service is unavailable.
+ *
+ * @author coderkun
+ */
+ class ServiceUnavailableException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 84;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'service unavailable';
+
+ /**
+ * Throws exception
+ *
+ * @var Exception
+ */
+ private $exception;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param Exception $exception Exception that has occurred
+ */
+ function __construct($exception)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $exception->getMessage()
+ );
+
+ // Store values
+ $this->exception = $exception;
+ }
+
+
+
+
+ /**
+ * Get the exception that hat occurred
+ *
+ * @return Exception Exception that has occurred
+ */
+ public function getException()
+ {
+ return $this->exception;
+ }
+
+ }
+
+?>
diff --git a/exceptions/ViewNotFoundException.inc b/exceptions/ViewNotFoundException.inc
new file mode 100644
index 00000000..30366201
--- /dev/null
+++ b/exceptions/ViewNotFoundException.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\exceptions;
+
+
+ /**
+ * Exception: View not found.
+ *
+ * @author coderkun
+ */
+ class ViewNotFoundException extends \nre\core\Exception
+ {
+ /**
+ * Error code
+ *
+ * @var int
+ */
+ const CODE = 69;
+ /**
+ * Error message
+ *
+ * @var string
+ */
+ const MESSAGE = 'view not found';
+
+ /**
+ * Filename of the view that was not found
+ *
+ * @var string
+ */
+ private $fileName;
+
+
+
+
+ /**
+ * Construct a new exception.
+ *
+ * @param string $fileName Filename of the view that was not found
+ */
+ function __construct($fileName)
+ {
+ parent::__construct(
+ self::MESSAGE,
+ self::CODE,
+ $fileName
+ );
+
+ // Save values
+ $this->fileName = $fileName;
+ }
+
+
+
+
+ /**
+ * Get the filename of the view that was not found.
+ *
+ * @return string Filename of the view that was not found
+ */
+ public function getFileName()
+ {
+ return $this->fileName;
+ }
+
+ }
+
+?>
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo
new file mode 100644
index 0000000000000000000000000000000000000000..d2a2559161443dd7666423b67ee58c7d64c09e6e
GIT binary patch
literal 2719
zcmaKsO^6&t6vs5b^)IYd+Lq(bd0tRj*#v
zd#|d#-Mr?4Kp8>32lbWfgct|c-+&*=wlzX*0tdi5!98FJJObVh&VaXq%JU3(3*_fL
z&x0EvzXq-Y-vZZy?}BXi122CDu7~`E=QqCpXYfY!Uj=#H-~2cmxf${XfTa-HspY
z4|;i@=P1bY4}k3JI9LWP2$SMXa4YyWh);a%`#%ABozH#$mmvG`HF!PvJ;>|*1l|Q+
z_3}D&a(p&{Jig0wFUWq6g1qjy?>`3eI>*5`kb{#T>-}+45%+Z%y#7Ww
zzY!b&(ItjJ)~|r9|ETBVo;5!{4OTEd2UfusLAWM90@;sGLALW9$aa4O*^ghm{3po!
zSc^^Y(cA)}OALT_gFC%^2;2gB3S>K{JzF5h=M2d6UI2Oh^IpCHBJ6o#`)rf%1DC-9
zxqobfi$onp-G|C$Z-LwgZn95&o_3(_M&-ii1Ivg#sO%e;?Wnw8E}SRM#Q-Yj=zi2r
z*@XuCKZ5!oDxU!^51?+&TZLb~DFQUuf6ghNGcH4@?DM^-e0I6;o#uRY%6(|;WMRCe
zj0znYIcd_YZU56DpUTL(zJ4?fDMwP%inO#8Yh_mZ`!Y*LOi)75>5hBZkJ-?~Z5O9n
z)S}q+v~nresTq?RQM+>P{=*vppoa!Ba)3(If!L6{-W5qNYZeTB4MZ*Tbv7u
z{IFHaBy5^2V=&XcF>BIiDRjY96g*AFBBNDVM}(%SNg6X32EQ*
zQcx$g)F)Swj?)vh(#+IMt+&C-aJe*&5RrzN)i(Cy=s7piP7t$$GQ^FrezhTp503ct1u8F*u?uwUujC<#1^>$&5;Z
zqp4Z4RjJ##Xvanm%Az?oq~(q=S=oKCH-A3OOh|lDv8}2s_SLmMPs)U?S=bNCSYddi
z_?BZ@v8CcRFCvXileOEVd)M1{1pU{W6$y7GBQ2lEjFm{Kqa?w+qVovp%$>zy?hWL6
z$>sNL*n(PDp|1xchT=x1n<7_kV8;!L5&oWfU*Az`B{=4NSD$Y_iDNO=ZBolgvT}vz
z8$1NLS4kn&V!d$r!;ZlHha|W^lPL@k4M?uEb_BiNh9lT7u;Azi?sj%
literal 0
HcmV?d00001
diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.po b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
new file mode 100644
index 00000000..80b79587
--- /dev/null
+++ b/locale/de_DE/LC_MESSAGES/The Legend of Z.po
@@ -0,0 +1,260 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: The Legend of Z\n"
+"POT-Creation-Date: 2014-03-04 11:59+0100\n"
+"PO-Revision-Date: 2014-03-04 12:00+0100\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.6.4\n"
+"X-Poedit-Basepath: .\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-SearchPath-0: ../../../views\n"
+
+#: ../../../views/binary/error/index.tpl:1
+#: ../../../views/html/error/index.tpl:1
+msgid "Error"
+msgstr "Fehler"
+
+#: ../../../views/html/charactergroups/group.tpl:1
+#: ../../../views/html/charactergroups/groupsgroup.tpl:1
+#: ../../../views/html/charactergroups/index.tpl:1
+#: ../../../views/html/charactergroupsquests/quest.tpl:1
+#: ../../../views/html/menu/index.tpl:3
+#: ../../../views/html/questgroups/questgroup.tpl:1
+#: ../../../views/html/quests/quest.tpl:1
+#: ../../../views/html/quests/sidequest.tpl:1
+#: ../../../views/html/seminaries/create.tpl:1
+#: ../../../views/html/seminaries/delete.tpl:1
+#: ../../../views/html/seminaries/edit.tpl:1
+#: ../../../views/html/seminaries/index.tpl:1
+#: ../../../views/html/seminaries/seminary.tpl:1
+msgid "Seminaries"
+msgstr "Kurse"
+
+#: ../../../views/html/charactergroups/group.tpl:3
+#: ../../../views/html/charactergroups/groupsgroup.tpl:3
+#: ../../../views/html/charactergroups/index.tpl:3
+#: ../../../views/html/characters/character.tpl:16
+#: ../../../views/html/seminaries/seminary.tpl:9
+msgid "Character Groups"
+msgstr "Charaktergruppen"
+
+#: ../../../views/html/charactergroups/group.tpl:12
+#: ../../../views/html/characters/character.tpl:2
+#: ../../../views/html/characters/index.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:8
+#: ../../../views/html/users/user.tpl:11
+msgid "Characters"
+msgstr "Charaktere"
+
+#: ../../../views/html/charactergroups/group.tpl:15
+msgid "Group Leader"
+msgstr "Gruppenleiter"
+
+#: ../../../views/html/charactergroups/group.tpl:21
+#: ../../../views/html/questgroups/questgroup.tpl:31
+msgid "Quests"
+msgstr "Quests"
+
+#: ../../../views/html/charactergroups/groupsgroup.tpl:13
+#: ../../../views/html/charactergroupsquests/quest.tpl:3
+msgid "Character Groups Quests"
+msgstr "Charactergruppen-Quests"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:12
+msgid "Description"
+msgstr "Beschreibung"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:15
+msgid "Rules"
+msgstr "Regeln"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:22
+msgid "Won Quest"
+msgstr "Gewonnene Quest"
+
+#: ../../../views/html/charactergroupsquests/quest.tpl:28
+msgid "Lost Quest"
+msgstr "Verlorene Quest"
+
+#: ../../../views/html/characters/character.tpl:8
+msgid "User"
+msgstr "Benutzer"
+
+#: ../../../views/html/html.tpl:21
+msgid "as"
+msgstr "als"
+
+#: ../../../views/html/introduction/index.tpl:1
+msgid "Introduction"
+msgstr "Einführung"
+
+#: ../../../views/html/menu/index.tpl:2 ../../../views/html/users/create.tpl:1
+#: ../../../views/html/users/delete.tpl:1 ../../../views/html/users/edit.tpl:1
+#: ../../../views/html/users/index.tpl:1 ../../../views/html/users/login.tpl:1
+#: ../../../views/html/users/user.tpl:1
+msgid "Users"
+msgstr "Benutzer"
+
+#: ../../../views/html/menu/index.tpl:5 ../../../views/html/users/login.tpl:2
+#: ../../../views/html/users/login.tpl:11
+msgid "Login"
+msgstr "Login"
+
+#: ../../../views/html/menu/index.tpl:7
+msgid "Logout"
+msgstr "Logout"
+
+#: ../../../views/html/questgroups/questgroup.tpl:22
+#: ../../../views/html/questgroups/questgroup.tpl:47
+#: ../../../views/html/seminaries/seminary.tpl:26
+msgid "locked"
+msgstr "gesperrt"
+
+#: ../../../views/html/questgroups/questgroup.tpl:38
+msgid "containing optional Quests"
+msgstr "Enthaltene optionale Quests"
+
+#: ../../../views/html/quests/quest.tpl:15
+#: ../../../views/html/quests/sidequest.tpl:17
+msgid "solved"
+msgstr "gelöst"
+
+#: ../../../views/html/quests/quest.tpl:17
+#: ../../../views/html/quests/sidequest.tpl:19
+msgid "unsolved"
+msgstr "ungelöst"
+
+#: ../../../views/html/quests/quest.tpl:53
+msgid "Go on"
+msgstr "Hier geht es weiter"
+
+#: ../../../views/html/quests/quest.tpl:57
+msgid "Quest"
+msgstr "Quest"
+
+#: ../../../views/html/quests/quest.tpl:70
+#: ../../../views/html/quests/sidequest.tpl:51
+msgid "Task"
+msgstr "Aufgabe"
+
+#: ../../../views/html/quests/sidequest.tpl:9
+msgid "This Quest is optional"
+msgstr "Diese Quest ist optional"
+
+#: ../../../views/html/seminaries/create.tpl:2
+msgid "New seminary"
+msgstr "Neuer Kurs"
+
+#: ../../../views/html/seminaries/create.tpl:6
+#: ../../../views/html/seminaries/create.tpl:7
+#: ../../../views/html/seminaries/edit.tpl:6
+#: ../../../views/html/seminaries/edit.tpl:7
+msgid "Title"
+msgstr "Titel"
+
+#: ../../../views/html/seminaries/create.tpl:9
+#: ../../../views/html/users/create.tpl:13
+msgid "create"
+msgstr "erstellen"
+
+#: ../../../views/html/seminaries/delete.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:5
+msgid "Delete seminary"
+msgstr "Kurs löschen"
+
+#: ../../../views/html/seminaries/delete.tpl:4
+#, php-format
+msgid "Should the seminary “%s” really be deleted?"
+msgstr "Soll der Kurs „%s“ wirklich gelöscht werden?"
+
+#: ../../../views/html/seminaries/delete.tpl:6
+#: ../../../views/html/users/delete.tpl:6
+msgid "delete"
+msgstr "löschen"
+
+#: ../../../views/html/seminaries/delete.tpl:7
+#: ../../../views/html/users/delete.tpl:7
+msgid "cancel"
+msgstr "abbrechen"
+
+#: ../../../views/html/seminaries/edit.tpl:2
+#: ../../../views/html/seminaries/seminary.tpl:4
+msgid "Edit seminary"
+msgstr "Kurs bearbeiten"
+
+#: ../../../views/html/seminaries/edit.tpl:9
+#: ../../../views/html/users/edit.tpl:13
+msgid "save"
+msgstr "speichern"
+
+#: ../../../views/html/seminaries/index.tpl:3
+msgid "Create new seminary"
+msgstr "Neuen Kurs erstellen"
+
+#: ../../../views/html/seminaries/index.tpl:10
+#: ../../../views/html/seminaries/seminary.tpl:12
+#, php-format
+msgid "created by %s on %s"
+msgstr "erstellt von %s am %s"
+
+#: ../../../views/html/users/create.tpl:2
+msgid "New user"
+msgstr "Neuer Benutzer"
+
+#: ../../../views/html/users/create.tpl:6
+#: ../../../views/html/users/create.tpl:7 ../../../views/html/users/edit.tpl:6
+#: ../../../views/html/users/edit.tpl:7 ../../../views/html/users/login.tpl:6
+#: ../../../views/html/users/login.tpl:7
+msgid "Username"
+msgstr "Benutzername"
+
+#: ../../../views/html/users/create.tpl:8
+#: ../../../views/html/users/create.tpl:9 ../../../views/html/users/edit.tpl:8
+#: ../../../views/html/users/edit.tpl:9
+msgid "E‑Mail-Address"
+msgstr "E‑Mail-Adresse"
+
+#: ../../../views/html/users/create.tpl:10
+#: ../../../views/html/users/create.tpl:11
+#: ../../../views/html/users/edit.tpl:10 ../../../views/html/users/edit.tpl:11
+#: ../../../views/html/users/login.tpl:8 ../../../views/html/users/login.tpl:9
+msgid "Password"
+msgstr "Passwort"
+
+#: ../../../views/html/users/delete.tpl:2 ../../../views/html/users/user.tpl:5
+msgid "Delete user"
+msgstr "Benutzer löschen"
+
+#: ../../../views/html/users/delete.tpl:4
+#, php-format
+msgid "Should the user “%s” (%s) really be deleted?"
+msgstr "Soll der Benutzer „%s“ (%s) wirklich gelöscht werden?"
+
+#: ../../../views/html/users/edit.tpl:2 ../../../views/html/users/user.tpl:4
+msgid "Edit user"
+msgstr "Benutzer bearbeiten"
+
+#: ../../../views/html/users/index.tpl:3
+msgid "Create new user"
+msgstr "Neuen Benutzer erstellen"
+
+#: ../../../views/html/users/index.tpl:10 ../../../views/html/users/user.tpl:8
+#, php-format
+msgid "registered on %s"
+msgstr "registriert am %s"
+
+#: ../../../views/html/users/user.tpl:18
+msgid "Roles"
+msgstr "Rollen"
+
+#~ msgid "created by %s on %s at %s"
+#~ msgstr "erstellt von %s am %s um %s Uhr"
+
+#~ msgid "registered on"
+#~ msgstr "registriert seit"
diff --git a/logs/empty b/logs/empty
new file mode 100644
index 00000000..e69de29b
diff --git a/media/empty b/media/empty
new file mode 100644
index 00000000..e69de29b
diff --git a/models/AchievementsModel.inc b/models/AchievementsModel.inc
new file mode 100644
index 00000000..760c9f06
--- /dev/null
+++ b/models/AchievementsModel.inc
@@ -0,0 +1,36 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Achievements-tables.
+ *
+ * @author Oliver Hanraths
+ */
+ class AchievementsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new AchievementsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+ }
+
+?>
diff --git a/models/CharactergroupsModel.inc b/models/CharactergroupsModel.inc
new file mode 100644
index 00000000..ce6e8b61
--- /dev/null
+++ b/models/CharactergroupsModel.inc
@@ -0,0 +1,147 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the CharactergroupsAgent to interact with
+ * Charactergroups-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new CharactergroupsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Character groups-groups of a Seminary.
+ *
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @return array Character groups-groups data
+ */
+ public function getGroupsroupsForSeminary($seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroupsgroups '.
+ 'WHERE seminary_id = ?',
+ 'i',
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Get a Character groups-group by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @param string $groupsgroupUrl URL-name of the Character groups-group
+ * @return array Character groups-group data
+ */
+ public function getGroupsgroupByUrl($seminaryId, $groupsgroupUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url '.
+ 'FROM charactergroupsgroups '.
+ 'WHERE seminary_id = ? AND url = ?',
+ 'is',
+ $seminaryId, $groupsgroupUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($groupsgroupUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get Character groups for a Character groups-group.
+ *
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @return array Character groups
+ */
+ public function getGroupsForGroupsgroup($groupsgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, name, url, xps '.
+ 'FROM v_charactergroups '.
+ 'WHERE charactergroupsgroup_id = ?',
+ 'i',
+ $groupsgroupId
+ );
+ }
+
+
+ /**
+ * Get Character groups for a Character.
+ *
+ * @param int $characterId ID of the Character
+ * @return array Character groups
+ */
+ public function getGroupsForCharacter($characterId)
+ {
+ return $this->db->query(
+ 'SELECT charactergroups.id, charactergroups.charactergroupsgroup_id, charactergroups.name, charactergroups.url, charactergroups.xps, charactergroupsgroups.id AS charactergroupsgroup_id, charactergroupsgroups.name AS charactergroupsgroup_name, charactergroupsgroups.url AS charactergroupsgroup_url '.
+ 'FROM characters_charactergroups '.
+ 'LEFT JOIN v_charactergroups AS charactergroups ON charactergroups.id = characters_charactergroups.charactergroup_id '.
+ 'LEFT JOIN charactergroupsgroups ON charactergroupsgroups.id = charactergroups.charactergroupsgroup_id '.
+ 'WHERE characters_charactergroups.character_id = ?',
+ 'i',
+ $characterId
+ );
+ }
+
+
+ /**
+ * Get a Character group by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @param string $groupUrl URL-name of the Character group
+ * @return array Character group data
+ */
+ public function getGroupByUrl($groupsgroupId, $groupUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url, xps '.
+ 'FROM v_charactergroups '.
+ 'WHERE charactergroupsgroup_id = ? AND url = ?',
+ 'is',
+ $groupsgroupId, $groupUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($groupUrl);
+ }
+
+
+ return $data[0];
+ }
+
+ }
+
+?>
diff --git a/models/CharactergroupsquestsModel.inc b/models/CharactergroupsquestsModel.inc
new file mode 100644
index 00000000..eed514dd
--- /dev/null
+++ b/models/CharactergroupsquestsModel.inc
@@ -0,0 +1,136 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the CharactergroupsquestsAgent to interact with
+ * Charactergroupsquests-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactergroupsquestsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new CharactergroupsquestsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Character groups Quests of a Character groups-groups.
+ *
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @return array Character groups Quest data
+ */
+ public function getQuestsForCharactergroupsgroup($groupsgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, questgroups_id, title, url '.
+ 'FROM charactergroupsquests '.
+ 'WHERE charactergroupsgroup_id = ?',
+ 'i',
+ $groupsgroupId
+ );
+ }
+
+
+ /**
+ * Get a Character groups Quest by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $groupsgroupId ID of the Character groups-group
+ * @param string $questUrl URL-title of the Character groups Quest
+ * @return array Character groups Quest data
+ */
+ public function getQuestByUrl($groupsgroupId, $questUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, questgroups_id, title, url, description, xps, rules, won_text, lost_text, questsmedia_id '.
+ 'FROM charactergroupsquests '.
+ 'WHERE charactergroupsgroup_id = ? AND url = ?',
+ 'is',
+ $groupsgroupId,
+ $questUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get the Character groups for a Quest.
+ *
+ * @param int $questId ID of the Character groups Quest
+ * @return array Character groups
+ */
+ public function getGroupsForQuest($questId)
+ {
+ $groups = $this->db->query(
+ 'SELECT charactergroups.id, charactergroups.name, charactergroups.url, charactergroupsquests_groups.created, charactergroupsquests_groups.xps_factor, charactergroupsquests.xps '.
+ 'FROM charactergroupsquests_groups '.
+ 'LEFT JOIN charactergroups ON charactergroups.id = charactergroupsquests_groups.charactergroup_id '.
+ 'LEFT JOIN charactergroupsquests ON charactergroupsquests.id = charactergroupsquests_groups.charactergroupsquest_id '.
+ 'WHERE charactergroupsquests_groups.charactergroupsquest_id = ?',
+ 'i',
+ $questId
+ );
+ foreach($groups as &$group) {
+ $group['xps'] = round($group['xps'] * $group['xps_factor'], 1);
+ }
+
+
+ return $groups;
+ }
+
+
+ /**
+ * Get Character groups Quests for a Character group.
+ *
+ * @param int $groupId ID of the Character group
+ * @return array Character groups Quests
+ */
+ public function getQuestsForGroup($groupId)
+ {
+ $quests = $this->db->query(
+ 'SELECT charactergroupsquests.id, charactergroupsquests_groups.created, charactergroupsquests.title, charactergroupsquests.url, charactergroupsquests.xps, charactergroupsquests_groups.xps_factor '.
+ 'FROM charactergroupsquests_groups '.
+ 'LEFT JOIN charactergroupsquests ON charactergroupsquests.id = charactergroupsquests_groups.charactergroupsquest_id '.
+ 'WHERE charactergroupsquests_groups.charactergroup_id = ?',
+ 'i',
+ $groupId
+ );
+ foreach($quests as &$quest) {
+ $quest['group_xps'] = round($quest['xps'] * $quest['xps_factor'], 1);
+ }
+
+
+ return $quests;
+ }
+
+
+ }
+
+?>
diff --git a/models/CharactersModel.inc b/models/CharactersModel.inc
new file mode 100644
index 00000000..59125e32
--- /dev/null
+++ b/models/CharactersModel.inc
@@ -0,0 +1,155 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Characters-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class CharactersModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new CharactersModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get all characters for an user.
+ *
+ * @param int $userId ID of the user
+ * @return array Characters
+ */
+ public function getCharactersForUser($userId)
+ {
+ return $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
+ 'WHERE user_id = ?',
+ 'i',
+ $userId
+ );
+ }
+
+
+ /**
+ * Get Characters for a Seminary.
+ *
+ * @param int $seminaryId ID of the Seminary
+ * @return array Characters
+ */
+ public function getCharactersForSeminary($seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, seminaries.id AS seminary_url, seminaries.title AS seminary_title, seminaries.url AS seminary_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'LEFT JOIN seminaries ON seminaries.id = charactertypes.seminary_id '.
+ 'WHERE seminaries.id = ?',
+ 'i',
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Get Characters for a Character group.
+ *
+ * @param int $groupId ID of the Character group
+ * @return array Characters
+ */
+ public function getCharactersForGroup($groupId)
+ {
+ return $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters_charactergroups.is_leader, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN characters_charactergroups ON characters_charactergroups.character_id = characters.id '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'WHERE characters_charactergroups.charactergroup_id = ?',
+ 'i',
+ $groupId
+ );
+ }
+
+
+ /**
+ * Get the character of a user for a Seminary.
+ *
+ * @throws IdNotFoundException
+ * @param int $userId ID of the user
+ * @param int $seminaryId ID of the Seminary
+ * @return array Character data
+ */
+ public function getCharacterForUserAndSeminary($userId, $seminaryId)
+ {
+ $data = $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'WHERE characters.user_id = ? AND charactertypes.seminary_id = ?',
+ 'ii',
+ $userId, $seminaryId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($userId);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Character by its Url.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the Seminary
+ * @param string $characterUrl URL-name of the Character
+ * @return array Character data
+ */
+ public function getCharacterByUrl($seminaryId, $characterUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT characters.id, characters.created, characters.charactertype_id, characters.name, characters.url, characters.user_id, characters.xps, characters.xplevel, charactertypes.name AS charactertype_name, charactertypes.url AS charactertypes_url, media.url AS avatar_url, media.description AS avatar_description '.
+ 'FROM v_characters AS characters '.
+ 'LEFT JOIN charactertypes ON charactertypes.id = characters.charactertype_id '.
+ 'LEFT JOIN avatars ON avatars.id = characters.avatar_id '.
+ 'LEFT JOIN avatarpictures ON avatarpictures.media_id = avatars.avatarpicture_id '.
+ 'LEFT JOIN media ON media.id = avatarpictures.media_id '.
+ 'WHERE charactertypes.seminary_id = ? AND characters.url = ?',
+ 'is',
+ $seminaryId, $characterUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($characterUrl);
+ }
+
+
+ return $data[0];
+ }
+
+ }
+
+?>
diff --git a/models/DatabaseModel.inc b/models/DatabaseModel.inc
new file mode 100644
index 00000000..51259f4f
--- /dev/null
+++ b/models/DatabaseModel.inc
@@ -0,0 +1,83 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\models;
+
+
+ /**
+ * Default implementation of a database model.
+ *
+ * @author coderkun
+ */
+ class DatabaseModel extends \nre\core\Model
+ {
+ /**
+ * Database connection
+ *
+ * @static
+ * @var DatabaseDriver
+ */
+ protected $db = NULL;
+
+
+
+
+ /**
+ * Construct a new datamase model.
+ *
+ * @throws DatamodelException
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $type Database type
+ * @param array $config Connection settings
+ */
+ function __construct($type, $config)
+ {
+ parent::__construct();
+
+ // Load database driver
+ $this->loadDriver($type);
+
+ // Establish database connection
+ $this->connect($type, $config);
+ }
+
+
+
+
+ /**
+ * Load the database driver.
+ *
+ * @throws DriverNotFoundException
+ * @throws DriverNotValidException
+ * @param string $driverName Name of the database driver
+ */
+ private function loadDriver($driverName)
+ {
+ \nre\core\Driver::load($driverName);
+ }
+
+
+ /**
+ * Establish a connection to the database.
+ *
+ * @throws DatamodelException
+ * @param string $driverName Name of the database driver
+ * @param array $config Connection settings
+ */
+ private function connect($driverName, $config)
+ {
+ $this->db = \nre\core\Driver::factory($driverName, $config);
+ }
+
+ }
+
+?>
diff --git a/models/MediaModel.inc b/models/MediaModel.inc
new file mode 100644
index 00000000..6165f7df
--- /dev/null
+++ b/models/MediaModel.inc
@@ -0,0 +1,90 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with the Media-tables.
+ *
+ * @author Oliver Hanraths
+ */
+ class MediaModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new MediaModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get a Medium by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the seminary
+ * @param string $mediaURL URL-name of the Medium
+ * @return array Medium data
+ */
+ public function getMediaByUrl($seminaryId, $mediaUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url, description, mimetype '.
+ 'FROM media '.
+ 'WHERE media.url = ?',
+ 's',
+ $mediaUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($mediaUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Medium by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the seminary
+ * @param int $mediaId ID of the Medium
+ * @return array Medium data
+ */
+ public function getMediaById($mediaId)
+ {
+ $data = $this->db->query(
+ 'SELECT id, name, url, description, mimetype '.
+ 'FROM media '.
+ 'WHERE media.id = ?',
+ 'i',
+ $mediaId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($mediaId);
+ }
+
+
+ return $data[0];
+ }
+
+ }
+
+?>
diff --git a/models/QuestgroupsModel.inc b/models/QuestgroupsModel.inc
new file mode 100644
index 00000000..088d54c0
--- /dev/null
+++ b/models/QuestgroupsModel.inc
@@ -0,0 +1,307 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Questgroups-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupsModel extends \hhu\z\Model
+ {
+ /**
+ * Required models
+ *
+ * @var array
+ */
+ public $models = array('questgroupshierarchy', 'quests');
+
+
+
+
+ /**
+ * Construct a new QuestgroupsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get all Questgroups for a Questgroup hierarchy.
+ *
+ * @param int $hierarchyId ID of the Questgroup hierarchy to get Questgroups for
+ * @param int $parentQuestgroupId ID of the parent Questgroup hierarchy
+ * @return array Questgroups for the given hierarchy
+ */
+ public function getQuestgroupsForHierarchy($hierarchyId, $parentQuestgroupId=null)
+ {
+ if(is_null($parentQuestgroupId))
+ {
+ return $this->db->query(
+ 'SELECT id, questgroupshierarchy_id, pos, title, url '.
+ 'FROM questgroups '.
+ 'WHERE questgroups.questgroupshierarchy_id = ? AND parent_questgroup_id IS NULL '.
+ 'ORDER BY questgroups.pos ASC',
+ 'i',
+ $hierarchyId
+ );
+ }
+ else
+ {
+ return $this->db->query(
+ 'SELECT id, questgroupshierarchy_id, pos, title, url '.
+ 'FROM questgroups '.
+ 'WHERE questgroups.questgroupshierarchy_id = ? AND parent_questgroup_id = ? '.
+ 'ORDER BY questgroups.pos ASC',
+ 'ii',
+ $hierarchyId, $parentQuestgroupId
+ );
+ }
+ }
+
+
+ /**
+ * Get a Questgroup by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param int $questgroupId ID of a Questgroup
+ * @return array Questgroup data
+ */
+ public function getQuestgroupById($questgroupId)
+ {
+ $data = $this->db->query(
+ 'SELECT id, questgroupshierarchy_id, parent_questgroup_id, pos, title, url, questgroupspicture_id '.
+ 'FROM questgroups '.
+ 'WHERE questgroups.id = ?',
+ 'i',
+ $questgroupId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questgroupId);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Questgroup by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the corresponding seminary
+ * @param string $questgroupURL URL-title of a Questgroup
+ * @return array Questgroup data
+ */
+ public function getQuestgroupByUrl($seminaryId, $questgroupUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT questgroups.id, questgroups.questgroupshierarchy_id, questgroups.parent_questgroup_id, questgroups.pos, questgroups.title, questgroups.url, questgroups.questgroupspicture_id '.
+ 'FROM questgroups '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE questgroupshierarchy.seminary_id = ? AND questgroups.url = ?',
+ 'is',
+ $seminaryId, $questgroupUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questgroupUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get texts of a Questgroup.
+ *
+ * @param int $questgroupId ID of a Questgroup
+ * @return array Texts of this Questgroup
+ */
+ public function getQuestgroupTexts($questgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, pos, text '.
+ 'FROM questgrouptexts '.
+ 'WHERE questgroup_id = ? '.
+ 'ORDER BY pos ASC',
+ 'i',
+ $questgroupId
+ );
+ }
+
+
+ /**
+ * Get the next Questgroup.
+ *
+ * Determine the next Questgroup. If there is no next Questgroup
+ * on the same level as the given Quest then the followed-up
+ * Questgroup from a higher hierarchy level is returned.
+ *
+ * @param int $questgroupId ID of Questgroup to get next Questgroup of
+ * @return array Questgroup data
+ */
+ public function getNextQuestgroup($questgroupId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $nextQuestgroup = $this->_getNextQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ while(is_null($nextQuestgroup) && !is_null($currentQuestgroup['parent_questgroup_id']))
+ {
+ $currentQuestgroup = $this->getQuestgroupById($currentQuestgroup['parent_questgroup_id']);
+ $nextQuestgroup = $this->_getNextQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ }
+
+
+ return $nextQuestgroup;
+ }
+
+
+ /**
+ * Get the previous Questgroup.
+ *
+ * Determine the previous Questgroup. If there is no previous
+ * Questgroup on the same level as the given Quest then the
+ * followed-up Questgroup from a higher hierarchy level is
+ * returned.
+ *
+ * @param int $questgroupId ID of Questgroup to get previous Questgroup of
+ * @return array Questgroup data
+ */
+ public function getPreviousQuestgroup($questgroupId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $previousQuestgroup = $this->_getPreviousQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ while(is_null($previousQuestgroup) && !is_null($currentQuestgroup['parent_questgroup_id']))
+ {
+ $currentQuestgroup = $this->getQuestgroupById($currentQuestgroup['parent_questgroup_id']);
+ $previousQuestgroup = $this->_getPreviousQuestgroup($currentQuestgroup['parent_questgroup_id'], $currentQuestgroup['pos']);
+ }
+
+
+ return $previousQuestgroup;
+ }
+
+
+ /**
+ * Determine if the given Character has solved the Quests form
+ * this Questgroup.
+ *
+ * @param int $questgroupId ID of Questgroup to check
+ * @param int $characterId ID of Character to check
+ * @result boolean Whether Character has solved the Questgroup or not
+ */
+ public function hasCharacterSolvedQuestgroup($questgroupId, $characterId)
+ {
+ $currentQuestgroup = $this->getQuestgroupById($questgroupId);
+ $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($currentQuestgroup['questgroupshierarchy_id']);
+ $lastChildQuestgroupshierarchy = array_pop($childQuestgroupshierarchy);
+ while(!is_null($lastChildQuestgroupshierarchy))
+ {
+ $questgroups = $this->getQuestgroupsForHierarchy($lastChildQuestgroupshierarchy['id'], $currentQuestgroup['id']);
+ $currentQuestgroup = array_pop($questgroups);
+ $childQuestgroupshierarchy = $this->Questgroupshierarchy->getChildQuestgroupshierarchy($currentQuestgroup['questgroupshierarchy_id']);
+ $lastChildQuestgroupshierarchy = array_pop($childQuestgroupshierarchy);
+ }
+
+ $quests = $this->Quests->getMainquestsForQuestgroup($currentQuestgroup['id']);
+ $lastQuest = array_pop($quests);
+
+
+ return $this->Quests->hasCharacterSolvedQuest($lastQuest['id'], $characterId);
+ }
+
+
+
+
+ /**
+ * Get the next (direct) Questgroup.
+ *
+ * @param int $parentQuestgroupId ID of parent Questgroup to get next Questgroup of
+ * @param int $questgroupPos Position of Questgroup to get next Questgroup of
+ * @return array Data of next Questgroup or NULL
+ */
+ private function _getNextQuestgroup($parentQuestgroupId, $questgroupPos)
+ {
+ if(!is_null($parentQuestgroupId))
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id = ? AND pos = ? + 1',
+ 'ii',
+ $parentQuestgroupId, $questgroupPos
+ );
+ }
+ else
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id IS NULL AND pos = ? + 1',
+ 'i',
+ $questgroupPos
+ );
+ }
+ if(empty($data)) {
+ return null;
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get the previous (direct) Questgroup.
+ *
+ * @param int $parentQuestgroupId ID of parent Questgroup to get previous Questgroup of
+ * @param int $questgroupPos Position of Questgroup to get previous Questgroup of
+ * @return array Data of previous Questgroup or NULL
+ */
+ private function _getPreviousQuestgroup($parentQuestgroupId, $questgroupPos)
+ {
+ if(!is_null($parentQuestgroupId))
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id = ? AND pos = ? - 1',
+ 'ii',
+ $parentQuestgroupId, $questgroupPos
+ );
+ }
+ else
+ {
+ $data = $this->db->query(
+ 'SELECT * '.
+ 'FROM questgroups '.
+ 'WHERE parent_questgroup_id IS NULL AND pos = ? - 1',
+ 'i',
+ $questgroupPos
+ );
+ }
+ if(empty($data)) {
+ return null;
+ }
+
+
+ return $data[0];
+ }
+
+ }
+
+?>
diff --git a/models/QuestgroupshierarchyModel.inc b/models/QuestgroupshierarchyModel.inc
new file mode 100644
index 00000000..df676ea4
--- /dev/null
+++ b/models/QuestgroupshierarchyModel.inc
@@ -0,0 +1,103 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Questgroupshierarchy-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestgroupshierarchyModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new QuestgroupshierarchyModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get a Questgroup hierarchy by its ID.
+ *
+ * throws IdNotFoundException
+ * @param int $questgroupshierarchyId ID of a Questgroup hierarchy
+ * @return array Questgroup hierarchy
+ */
+ public function getHierarchyById($questgroupshierarchyId)
+ {
+ $data = $this->db->query(
+ 'SELECT id, seminary_id, parent_questgroupshierarchy_id, pos, title_singular, title_plural, url '.
+ 'FROM questgroupshierarchy '.
+ 'WHERE questgroupshierarchy.id = ?',
+ 'i',
+ $questgroupshierarchyId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questgroupshierarchyId);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get the toplevel hierarchy entries of a Seminary.
+ *
+ * @param int $seminaryId ID of the seminary to get hierarchy for
+ * @return array Toplevel hierarchy
+ */
+ public function getHierarchyForSeminary($seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT id, seminary_id, parent_questgroupshierarchy_id, pos, title_singular, title_plural, url '.
+ 'FROM questgroupshierarchy '.
+ 'WHERE '.
+ 'questgroupshierarchy.seminary_id = ? AND '.
+ 'questgroupshierarchy.parent_questgroupshierarchy_id IS NULL '.
+ 'ORDER BY questgroupshierarchy.pos ASC',
+ 'i',
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Get the child hierarchy entries of a Questgroup hierarchy.
+ *
+ * @param int $questgroupshierarchyId ID of a Questgroup hierarchy
+ * @return array Child Questgroup hierarchy entries
+ */
+ public function getChildQuestgroupshierarchy($questgroupshierarchyId)
+ {
+ return $this->db->query(
+ 'SELECT id, seminary_id, parent_questgroupshierarchy_id, pos, title_singular, title_plural, url '.
+ 'FROM questgroupshierarchy '.
+ 'WHERE questgroupshierarchy.parent_questgroupshierarchy_id = ? '.
+ 'ORDER BY questgroupshierarchy.pos ASC',
+ 'i',
+ $questgroupshierarchyId
+ );
+ }
+
+ }
+
+?>
diff --git a/models/QuestsModel.inc b/models/QuestsModel.inc
new file mode 100644
index 00000000..09ebc125
--- /dev/null
+++ b/models/QuestsModel.inc
@@ -0,0 +1,304 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Quests-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuestsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new QuestsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get all Quests for the given Questgroup.
+ *
+ * @param int $questgroupId ID of a Questgroup
+ * @return array Quests of the given Questgroup
+ */
+ public function getMainquestsForQuestgroup($questgroupId)
+ {
+ return $this->db->query(
+ 'SELECT id, questtype_id, title, url, xps, task '.
+ 'FROM quests '.
+ 'INNER JOIN mainquests ON mainquests.quest_id = quests.id '.
+ 'WHERE questgroup_id = ?',
+ 'i',
+ $questgroupId
+ );
+ }
+
+
+ /**
+ * Get a Quest and its data by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @param int $questgroupId ID of the corresponding Questgroup
+ * @param string $questURL URL-title of a Quest
+ * @return array Quest data
+ */
+ public function getQuestByUrl($seminaryId, $questgroupId, $questUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id, ('.
+ 'SELECT count(mainquests.quest_id) FROM mainquests WHERE mainquests.quest_id = quests.id) AS is_mainquest '.
+ 'FROM quests '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE questgroupshierarchy.seminary_id = ? AND questgroups.id = ? AND quests.url = ?',
+ 'iis',
+ $seminaryId, $questgroupId, $questUrl
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questUrl);
+ }
+
+ $data[0]['is_mainquest'] = ($data[0]['is_mainquest'] == 1);
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Quest and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param string $questId ID of a Quest
+ * @return array Quest data
+ */
+ public function getQuestById($questId)
+ {
+ $data = $this->db->query(
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id, ('.
+ 'SELECT count(mainquests.quest_id) FROM mainquests WHERE mainquests.quest_id = quests.id) AS is_mainquest '.
+ 'FROM quests '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE quests.id = ?',
+ 'i',
+ $questId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questId);
+ }
+
+ $data[0]['is_mainquest'] = ($data[0]['is_mainquest'] == 1);
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get a Sidequest and its data by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $seminaryId ID of the corresponding Seminary
+ * @param int $questgroupId ID of the corresponding Questgroup
+ * @param int $questId ID of the Quest
+ * @param string $sidequestUrl URL-title of a Sidequest
+ * @return array Sidequest data
+ */
+ public function getSidequestByUrl($seminaryId, $questgroupId, $questId, $sidequestUrl)
+ {
+ $data = $this->db->query(
+ 'SELECT quests.id, quests.questtype_id, quests.title, quests.url, quests.xps, quests.task, quests.right_text, quests.wrong_text, quests.questsmedia_id '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
+ 'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = questtexts.mainquest_id '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'LEFT JOIN seminaries ON seminaries.id = questgroupshierarchy.seminary_id '.
+ 'WHERE quests.url = ? AND mainquests.id = ? AND questgroups.id = ? AND seminaries.id = ?',
+ 'siii',
+ $sidequestUrl,
+ $questId,
+ $questgroupId,
+ $seminaryId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($sidequestUrl);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get all sidequests for a Quest.
+ *
+ * @param int $questId ID of the quest
+ * @return array Sidequests for the quest
+ */
+ public function getSidequestsForQuest($questId)
+ {
+ return $this->db->query(
+ 'SELECT quests.id, sidequests.questtext_id, quests.title, quests.url, sidequests.entry_text '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
+ 'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
+ 'WHERE questtexts.quest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Get all sidequests for a Questtext.
+ *
+ * @param int $questtextId ID of the questtext
+ * @return array Sidequests for the questtext
+ */
+ public function getSidequestsForQuesttext($questtextId)
+ {
+ return $this->db->query(
+ 'SELECT id, questtext_id, title, url, entry_text '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
+ 'WHERE questtext_id = ?',
+ 'i',
+ $questtextId
+ );
+ }
+
+
+ /**
+ * Get Quests that follow-up a Quest.
+ *
+ * @param int $questId ID of Quest to get next Quests of
+ * @return array Quests data
+ */
+ public function getNextQuests($questId)
+ {
+ return $this->db->query(
+ 'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
+ 'FROM mainquests_previousmainquests '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = mainquests_previousmainquests.mainquest_id '.
+ 'INNER JOIN quests ON quests.id = mainquests.quest_id '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE mainquests_previousmainquests.previous_mainquest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Get Quests that the given Quests follows-up to.
+ *
+ * @param int $questId ID of Quest to get previous Quests of
+ * @return array Quests data
+ */
+ public function getPreviousQuests($questId)
+ {
+ return $this->db->query(
+ 'SELECT quests.id, quests.title, quests.url, questgroups.title AS questgroup_title, questgroups.url AS questgroup_url '.
+ 'FROM mainquests_previousmainquests '.
+ 'LEFT JOIN mainquests ON mainquests.quest_id = mainquests_previousmainquests.previous_mainquest_id '.
+ 'INNER JOIN quests ON quests.id = mainquests.quest_id '.
+ 'LEFT JOIN questgroups ON questgroups.id = quests.questgroup_id '.
+ 'LEFT JOIN questgroupshierarchy ON questgroupshierarchy.id = questgroups.questgroupshierarchy_id '.
+ 'WHERE mainquests_previousmainquests.mainquest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Mark a Quest as solved for a Character.
+ *
+ * @param int $questId ID of Quest to mark as solved
+ * @param int $characterId ID of Character that solved the Quest
+ */
+ public function setQuestSolved($questId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO quests_characters '.
+ '(quest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $questId,
+ $characterId,
+ 0
+ );
+ }
+
+
+ /**
+ * Mark a Quest as unsolved for a Character.
+ *
+ * @param int $questId ID of Quest to mark as unsolved
+ * @param int $characterId ID of Character that unsolved the Quest
+ */
+ public function setQuestUnsolved($questId, $characterId)
+ {
+ $this->db->query(
+ 'INSERT INTO quests_characters '.
+ '(quest_id, character_id, status) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iii',
+ $questId,
+ $characterId,
+ -1
+ );
+ }
+
+
+ /**
+ * Determine if the given Character has solved the given Quest.
+ *
+ * @param int $questId ID of Quest to check
+ * @param int $characterId ID of Character to check
+ * @result boolean Whether Character has solved the Quest or not
+ */
+ public function hasCharacterSolvedQuest($questId, $characterId)
+ {
+ $count = $this->db->query(
+ 'SELECT count(id) AS c '.
+ 'FROM quests_characters '.
+ 'WHERE quest_id = ? AND character_id = ? AND status = 0',
+ 'ii',
+ $questId,
+ $characterId
+ );
+
+
+ return (!empty($count) && intval($count[0]['c']) > 0);
+ }
+
+ }
+
+?>
diff --git a/models/QuesttextsModel.inc b/models/QuesttextsModel.inc
new file mode 100644
index 00000000..38a1286d
--- /dev/null
+++ b/models/QuesttextsModel.inc
@@ -0,0 +1,135 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Questtexts-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttextsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new QuesttextsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get a Questtext for a Quest by its URL.
+ *
+ * @throws IdNotFoundException
+ * @param int $questId ID of the Quest to get text for
+ * @param string $questtexttypeUrl URL of the Questtexttype
+ * @param int $pos Position of Questtexttype
+ * @return array Questtexttype data
+ */
+ public function getQuesttextByUrl($questId, $questtexttypeUrl, $pos)
+ {
+ $data = $this->db->query(
+ 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.out_text, questtexts.abort_text, questtexts.questsmedia_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'FROM questtexts '.
+ 'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
+ 'WHERE questtexts.quest_id = ? AND questtexttypes.url = ? AND questtexts.pos = ?',
+ 'isi',
+ $questId, $questtexttypeUrl, $pos
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questtexttypeUrl);
+ }
+
+
+ return $data = $data[0];
+ }
+
+
+ /**
+ * Get count of Questtexts for a Quest.
+ *
+ * @param int $questId ID of the Quest
+ * @param string $questtexttypeUrl URL of the Questtexttype
+ * @return int Conut of Questtexts for Quest
+ */
+ public function getQuesttextsCountForQuest($questId, $questtexttypUrl)
+ {
+ $count = 0;
+ $data = $this->db->query(
+ 'SELECT COUNT(questtexts.id) AS c '.
+ 'FROM questtexts '.
+ 'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
+ 'WHERE questtexts.quest_id = ? AND questtexttypes.url = ?',
+ 'is',
+ $questId, $questtexttypUrl
+ );
+ if(!empty($data)) {
+ $count = $data[0]['c'];
+ }
+
+
+ return $count;
+ }
+
+
+ /**
+ * Get corresponding Questtext for a Sidequest.
+ *
+ * @throws IdNotFoundException
+ * @param int $sidequestId ID of the Sidequest to get the Questtext for
+ * @param array Questtext data
+ */
+ public function getQuesttextForSidequest($sidequestId)
+ {
+ $data = $this->db->query(
+ 'SELECT questtexts.id, questtexts.text, questtexts.pos, questtexts.quest_id, questtexttypes.id AS type_id, questtexttypes.type, questtexttypes.url AS type_url '.
+ 'FROM quests '.
+ 'INNER JOIN sidequests ON sidequests.quest_id = quests.id '.
+ 'LEFT JOIN questtexts ON questtexts.id = sidequests.questtext_id '.
+ 'LEFT JOIN questtexttypes ON questtexttypes.id = questtexts.questtexttype_id '.
+ 'WHERE quests.id = ?',
+ 'i',
+ $sidequestId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($sidequestId);
+ }
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get all registered Questtexttypes.
+ *
+ * @return array Registered Questtexttypes
+ */
+ public function getQuesttexttypes()
+ {
+ return $this->db->query(
+ 'SELECT id, type, url '.
+ 'FROM questtexttypes'
+ );
+ }
+
+ }
+
+?>
diff --git a/models/QuesttypesModel.inc b/models/QuesttypesModel.inc
new file mode 100644
index 00000000..3e0ef265
--- /dev/null
+++ b/models/QuesttypesModel.inc
@@ -0,0 +1,62 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with Questtypes-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class QuesttypesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new QuesttypesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get a Questtype by its ID
+ *
+ * @param int $questtypeId ID of Questtype
+ * @return array Questtype data
+ */
+ public function getQuesttypeById($questtypeId)
+ {
+ $data = $this->db->query(
+ 'SELECT title, classname '.
+ 'FROM questtypes '.
+ 'WHERE id = ?',
+ 'i',
+ $questtypeId
+ );
+ if(empty($data)) {
+ throw new \nre\exceptions\IdNotFoundException($questtypeId);
+ }
+
+
+ return $data = $data[0];
+ }
+
+ }
+
+?>
diff --git a/models/SeminariesModel.inc b/models/SeminariesModel.inc
new file mode 100644
index 00000000..15963271
--- /dev/null
+++ b/models/SeminariesModel.inc
@@ -0,0 +1,161 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the SeminariesAgent to list registered seminaries.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminariesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new SeminariesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get registered seminaries.
+ *
+ * @return array Seminaries
+ */
+ public function getSeminaries()
+ {
+ // Get seminaries
+ return $this->db->query(
+ 'SELECT id, created, created_user_id, title, url, description '.
+ 'FROM seminaries '.
+ 'ORDER BY created DESC'
+ );
+ }
+
+
+ /**
+ * Get a seminary and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryId ID of a seminary
+ * @return array Seminary
+ */
+ public function getSeminaryById($seminaryId)
+ {
+ $seminary = $this->db->query(
+ 'SELECT id, created, created_user_id, title, url, description '.
+ 'FROM seminaries '.
+ 'WHERE id = ?',
+ 'i',
+ $seminaryId
+ );
+ if(empty($seminary)) {
+ throw new \nre\exceptions\IdNotFoundException($seminaryId);
+ }
+
+
+ return $seminary[0];
+ }
+
+
+ /**
+ * Get a seminary and its data by its URL-title.
+ *
+ * @throws IdNotFoundException
+ * @param string $seminaryUrl URL-Title of a seminary
+ * @return array Seminary
+ */
+ public function getSeminaryByUrl($seminaryUrl)
+ {
+ $seminary = $this->db->query(
+ 'SELECT id, created, created_user_id, title, url, description '.
+ 'FROM seminaries '.
+ 'WHERE url = ?',
+ 's',
+ $seminaryUrl
+ );
+ if(empty($seminary)) {
+ throw new \nre\exceptions\IdNotFoundException($seminaryUrl);
+ }
+
+
+ return $seminary[0];
+ }
+
+
+ /**
+ * Create a new seminary.
+ *
+ * @param string $title Title of seminary to create
+ * @param int $userId ID of creating user
+ * @return int ID of the newly created seminary
+ */
+ public function createSeminary($title, $userId)
+ {
+ $this->db->query(
+ 'INSERT INTO seminaries '.
+ '(created_user_id, title, url) '.
+ 'VALUES '.
+ '(?, ?, ?)',
+ 'iss',
+ $userId,
+ $title,
+ \nre\core\Linker::createLinkParam($title)
+ );
+
+
+ return $this->db->getInsertId();
+ }
+
+
+ /**
+ * Edit a seminary.
+ *
+ * @throws DatamodelException
+ * @param int $seminaryId ID of the seminary to delete
+ * @param string $title New title of seminary
+ */
+ public function editSeminary($seminaryId, $title)
+ {
+ $this->db->query(
+ 'UPDATE seminaries '.
+ 'SET title = ?, url = ? '.
+ 'WHERE id = ?',
+ 'ssi',
+ $title,
+ \nre\core\Linker::createLinkParam($title),
+ $seminaryId
+ );
+ }
+
+
+ /**
+ * Delete a seminary.
+ *
+ * @param int $seminaryId ID of the seminary to delete
+ */
+ public function deleteSeminary($seminaryId)
+ {
+ $this->db->query('DELETE FROM seminaries WHERE id = ?', 'i', $seminaryId);
+ }
+
+ }
+
+?>
diff --git a/models/SeminarycharacterfieldsModel.inc b/models/SeminarycharacterfieldsModel.inc
new file mode 100644
index 00000000..c881df2c
--- /dev/null
+++ b/models/SeminarycharacterfieldsModel.inc
@@ -0,0 +1,58 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with the Seminarycharacterfields-tables.
+ *
+ * @author Oliver Hanraths
+ */
+ class SeminarycharacterfieldsModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new SeminarycharacterfieldsModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get Seminary Character fields of a Character.
+ *
+ * @param int $characterId ID of the Character
+ * @return array Seminary Character fields
+ */
+ public function getFieldsForCharacter($characterId)
+ {
+ return $this->db->query(
+ 'SELECT seminarycharacterfields.title, characters_seminarycharacterfields.value '.
+ 'FROM characters_seminarycharacterfields '.
+ 'LEFT JOIN seminarycharacterfields ON seminarycharacterfields.id = characters_seminarycharacterfields.seminarycharacterfield_id '.
+ 'LEFT JOIN seminarycharacterfieldtypes ON seminarycharacterfieldtypes.id = seminarycharacterfields.seminarycharacterfieldtype_id '.
+ 'WHERE characters_seminarycharacterfields.character_id = ?',
+ 'i',
+ $characterId
+ );
+ }
+
+ }
+
+?>
diff --git a/models/UserrolesModel.inc b/models/UserrolesModel.inc
new file mode 100644
index 00000000..33121a21
--- /dev/null
+++ b/models/UserrolesModel.inc
@@ -0,0 +1,77 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with userroles-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class UserrolesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new UserrolesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get all userroles for an user referenced by its ID.
+ *
+ * @param int $userId ID of an user
+ * @return array Userroles for an user
+ */
+ public function getUserrolesForUserById($userId)
+ {
+ return $this->db->query(
+ 'SELECT userroles.id, userroles.created, userroles.name '.
+ 'FROM users_userroles '.
+ 'LEFT JOIN userroles ON userroles.id = users_userroles.userrole_id '.
+ 'WHERE users_userroles.user_id = ?',
+ 'i',
+ $userId
+ );
+ }
+
+
+ /**
+ * Get all userroles for an user referenced by its URL-username.
+ *
+ * @param string $userUrl URL-Username of an user
+ * @return array Userroles for an user
+ */
+ public function getUserrolesForUserByUrl($userUrl)
+ {
+ return $this->db->query(
+ 'SELECT userroles.id, userroles.created, userroles.name '.
+ 'FROM users '.
+ 'LEFT JOIN users_userroles ON users_userroles.user_id = users.id '.
+ 'LEFT JOIN userroles ON userroles.id = users_userroles.userrole_id '.
+ 'WHERE users.url = ?',
+ 's',
+ $userUrl
+ );
+ }
+
+ }
+
+?>
diff --git a/models/UsersModel.inc b/models/UsersModel.inc
new file mode 100644
index 00000000..d42db7c7
--- /dev/null
+++ b/models/UsersModel.inc
@@ -0,0 +1,249 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model of the UsersAgent to list users and get their data.
+ *
+ * @author Oliver Hanraths
+ */
+ class UsersModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new UsersModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get registered users.
+ *
+ * @return array Users
+ */
+ public function getUsers()
+ {
+ return $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'ORDER BY username ASC'
+ );
+ }
+
+
+ /**
+ * Get a user and its data by its ID.
+ *
+ * @throws IdNotFoundException
+ * @param int $userId ID of an user
+ * @return array Userdata
+ */
+ public function getUserById($userId)
+ {
+ // Get user
+ $user = $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'WHERE id = ?',
+ 'i',
+ $userId
+ );
+ if(empty($user)) {
+ throw new \nre\exceptions\IdNotFoundException($userId);
+ }
+
+
+ return $user[0];
+ }
+
+
+ /**
+ * Get a user and its data by its URL-username.
+ *
+ * @throws IdNotFoundException
+ * @param string $userUrl URL-Username of an user
+ * @return array Userdata
+ */
+ public function getUserByUrl($userUrl)
+ {
+ // Get user
+ $user = $this->db->query(
+ 'SELECT id, created, username, url, surname, prename, email '.
+ 'FROM users '.
+ 'WHERE url = ?',
+ 's',
+ $userUrl
+ );
+ if(empty($user)) {
+ throw new \nre\exceptions\IdNotFoundException($userUrl);
+ }
+
+
+ return $user[0];
+ }
+
+
+ /**
+ * Log a user in if its credentials are valid.
+ *
+ * @throws DatamodelException
+ * @param string $username The name of the user to log in
+ * @param string $password Plaintext password of the user to log in
+ */
+ public function login($username, $password)
+ {
+ $data = $this->db->query('SELECT id, password FROM users WHERE username = ?', 's', $username);
+ if(!empty($data))
+ {
+ $data = $data[0];
+ if($this->verify($password, $data['password'])) {
+ return $data['id'];
+ }
+ }
+
+
+ return null;
+ }
+
+
+ /**
+ * Create a new user.
+ *
+ * @param string $username Username of the user to create
+ * @param string $email E‑Mail-Address of the user to create
+ * @param string $password Password of the user to create
+ * @return int ID of the newly created user
+ */
+ public function createUser($username, $email, $password)
+ {
+ $this->db->query(
+ 'INSERT INTO users '.
+ '(username, url, email, password) '.
+ 'VALUES '.
+ '(?, ?, ?, ?)',
+ 'ssss',
+ $username,
+ \nre\core\Linker::createLinkParam($username),
+ $email,
+ $this->hash($password)
+ );
+
+
+ return $this->db->getInsertId();
+ }
+
+
+ /**
+ * Edit a user.
+ *
+ * @throws DatamodelException
+ * @param int $userId ID of the user to delete
+ * @param string $username New name of user
+ * @param string $email Changed e‑mail-address of user
+ * @param string $password Changed plaintext password of user
+ */
+ public function editUser($userId, $username, $email, $password)
+ {
+ try {
+ // Update user data
+ $this->db->query(
+ 'UPDATE users '.
+ 'SET username = ?, url = ?, email = ? '.
+ 'WHERE id = ?',
+ 'sssi',
+ $username,
+ \nre\core\Linker::createLinkParam($username),
+ $email,
+ $userId
+ );
+
+ // Set new password
+ if(!empty($password))
+ {
+ $this->db->query(
+ 'UPDATE users '.
+ 'SET password = ? '.
+ 'WHERE id = ?',
+ 'si',
+ $this->hash($password),
+ $userId
+ );
+ }
+ }
+ catch(Exception $e) {
+ $this->db->rollback();
+ $this->db->setAutocommit(true);
+ throw $e;
+ }
+ $this->db->setAutocommit(true);
+ }
+
+
+ /**
+ * Delete a user.
+ *
+ * @param int $userId ID of the user to delete
+ */
+ public function deleteUser($userId)
+ {
+ $this->db->query('DELETE FROM users WHERE id = ?', 'i', $userId);
+ }
+
+
+
+
+ /**
+ * Hash a password.
+ *
+ * @param string $password Plaintext password
+ * @return string Hashed password
+ */
+ public function hash($password)
+ {
+ if(!function_exists('password_hash')) {
+ \hhu\z\lib\Password::load();
+ }
+
+
+ return password_hash($password, PASSWORD_DEFAULT);
+ }
+
+
+ /**
+ * Verify a password.
+ *
+ * @param string $password Plaintext password to verify
+ * @param string $hash Hashed password to match with
+ * @return boolean Verified
+ */
+ private function verify($password, $hash)
+ {
+ if(!function_exists('password_verify')) {
+ \hhu\z\lib\Password::load();
+ }
+
+
+ return password_verify($password, $hash);
+ }
+
+ }
+
+?>
diff --git a/models/UserseminaryrolesModel.inc b/models/UserseminaryrolesModel.inc
new file mode 100644
index 00000000..c07d4c7a
--- /dev/null
+++ b/models/UserseminaryrolesModel.inc
@@ -0,0 +1,78 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\models;
+
+
+ /**
+ * Model to interact with userseminaryroles-table.
+ *
+ * @author Oliver Hanraths
+ */
+ class UserseminaryrolesModel extends \hhu\z\Model
+ {
+
+
+
+
+ /**
+ * Construct a new UserseminaryrolesModel.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ }
+
+
+
+
+ /**
+ * Get all userseminaryroles for an user referenced by its ID.
+ *
+ * @param int $userId ID of an user
+ * @return array Userseminaryroles for an user
+ */
+ public function getUserseminaryrolesForUserById($userId, $seminaryId)
+ {
+ return $this->db->query(
+ 'SELECT userseminaryroles.id, userseminaryroles.created, userseminaryroles.name '.
+ 'FROM users_userseminaryroles '.
+ 'LEFT JOIN userseminaryroles ON userseminaryroles.id = users_userseminaryroles.userseminaryrole_id '.
+ 'WHERE users_userseminaryroles.user_id = ? AND users_userseminaryroles.seminary_id = ?',
+ 'ii',
+ $userId, $seminaryId
+ );
+ }
+
+
+ /**
+ * Get all userseminaryroles for an user referenced by its
+ * URL-username.
+ *
+ * @param string $userUrl URL-Username of an user
+ * @return array Userseminaryroles for an user
+ */
+ public function getUserrolesForUserByUrl($userUrl)
+ {
+ return $this->db->query(
+ 'SELECT userroles.id, userroles.created, userroles.name '.
+ 'FROM users '.
+ 'LEFT JOIN users_userseminaryroles ON users_userseminaryroles.user_id = users.id '.
+ 'LEFT JOIN userseminaryroles ON userseminaryroles.id = users_userseminaryroles.userseminaryrole_id '.
+ 'WHERE users.url = ?',
+ 's',
+ $userUrl
+ );
+ }
+
+ }
+
+?>
diff --git a/questtypes/dummy/DummyQuesttypeAgent.inc b/questtypes/dummy/DummyQuesttypeAgent.inc
new file mode 100644
index 00000000..f0de5cb1
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Dummy-QuesttypeAgent for testing basic QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/dummy/DummyQuesttypeController.inc b/questtypes/dummy/DummyQuesttypeController.inc
new file mode 100644
index 00000000..0f3012fa
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeController.inc
@@ -0,0 +1,48 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the Dummy-QuesttypeAgent for testing basic
+ * QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ */
+ public function index()
+ {
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST')
+ {
+ // Right answer (dummy)
+ if(!is_null($this->request->getPostParam('submit'))) {
+ $this->setQuestSolved();
+ }
+ // Wrong answer (dummy)
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+ }
+
+ }
+
+?>
diff --git a/questtypes/dummy/DummyQuesttypeModel.inc b/questtypes/dummy/DummyQuesttypeModel.inc
new file mode 100644
index 00000000..c4aadf3e
--- /dev/null
+++ b/questtypes/dummy/DummyQuesttypeModel.inc
@@ -0,0 +1,25 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the Dummy-QuesttypeAgent for testing basic
+ * QuesttypeAgent-functionality.
+ *
+ * @author Oliver Hanraths
+ */
+ class DummyQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+ }
+
+?>
diff --git a/questtypes/dummy/html/index.tpl b/questtypes/dummy/html/index.tpl
new file mode 100644
index 00000000..f482a07b
--- /dev/null
+++ b/questtypes/dummy/html/index.tpl
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
new file mode 100644
index 00000000..2789c5f6
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * QuesttypeAgent for multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
new file mode 100644
index 00000000..44c99e3b
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeController.inc
@@ -0,0 +1,88 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the MultiplechoiceQuesttypeAgent multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Display a text with input fields and evaluate if user input
+ * matches with stored regular expressions.
+ */
+ public function index($questId)
+ {
+ // Answers
+ if(!array_key_exists('answers', $_SESSION)) {
+ $_SESSION['answers'] = array();
+ }
+ $answers = array_key_exists($questId, $_SESSION['answers']) ? $_SESSION['answers'][$questId] : array();
+
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
+ {
+ // Get answers
+ $answers = $this->request->getPostParam('answers');
+
+ // Store answers in session
+ $_SESSION['answers'][$questId] = $answers;
+
+ // Get right answers
+ $tickQuestions = $this->Multiplechoice->getTickQuestionsOfQuest($questId);
+
+ // Match tick questions with user answers
+ $allSolved = true;
+ foreach($tickQuestions as &$tickQuestion)
+ {
+ $pos = intval($tickQuestion['pos'])-1;
+ if(!array_key_exists($pos, $answers) && $answers[$pos] == 'true')
+ {
+ $allSolved = false;
+ break;
+ }
+ else {
+ unset($answers[$pos]);
+ }
+ }
+
+ // Set status
+ if($allSolved && count($answers) == 0) {
+ $this->setQuestSolved();
+ }
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+
+
+ // Get questions
+ $questions = $this->Multiplechoice->getQuestionsOfQuest($questId);
+
+
+ // Pass data to view
+ $this->set('questions', $questions);
+ $this->set('answers', $answers);
+ }
+
+ }
+
+?>
diff --git a/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
new file mode 100644
index 00000000..cf170390
--- /dev/null
+++ b/questtypes/multiplechoice/MultiplechoiceQuesttypeModel.inc
@@ -0,0 +1,64 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the MultiplechoiceQuesttypeAgent for multiple choice.
+ *
+ * @author Oliver Hanraths
+ */
+ class MultiplechoiceQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+
+
+
+
+ /**
+ * Get all multiple choice questions of a Quest.
+ *
+ * @param int $questId ID of Quest
+ * @return array Multiple choice questions
+ */
+ public function getQuestionsOfQuest($questId)
+ {
+ return $this->db->query(
+ 'SELECT question, tick '.
+ 'FROM questtypes_multiplechoice '.
+ 'WHERE quest_id = ?',
+ 'i',
+ $questId
+ );
+ }
+
+
+ /**
+ * Get all multiple choice questions of a Quest that should be
+ * ticked.
+ *
+ * @param int $questId ID of Quest
+ * @return array Multiple choice questions that should be ticked
+ */
+ public function getTickQuestionsOfQuest($questId)
+ {
+ return $this->db->query(
+ 'SELECT question, tick, pos '.
+ 'FROM questtypes_multiplechoice '.
+ 'WHERE quest_id = ? AND tick = True',
+ 'i',
+ $questId
+ );
+ }
+
+ }
+
+?>
diff --git a/questtypes/multiplechoice/html/index.tpl b/questtypes/multiplechoice/html/index.tpl
new file mode 100644
index 00000000..1e64f3c7
--- /dev/null
+++ b/questtypes/multiplechoice/html/index.tpl
@@ -0,0 +1,11 @@
+
+
+ &$question) : ?>
+
+ />
+ =\hhu\z\Utils::t($question['question'])?>
+
+
+
+
+
diff --git a/questtypes/textinput/TextinputQuesttypeAgent.inc b/questtypes/textinput/TextinputQuesttypeAgent.inc
new file mode 100644
index 00000000..8144c148
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeAgent.inc
@@ -0,0 +1,24 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * QuesttypeAgent for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeAgent extends \hhu\z\QuesttypeAgent
+ {
+ }
+
+?>
diff --git a/questtypes/textinput/TextinputQuesttypeController.inc b/questtypes/textinput/TextinputQuesttypeController.inc
new file mode 100644
index 00000000..52acdb25
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeController.inc
@@ -0,0 +1,94 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Controller of the TextinputQuesttypeAgent for for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeController extends \hhu\z\QuesttypeController
+ {
+
+
+
+
+ /**
+ * Action: index.
+ *
+ * Display a text with input fields and evaluate if user input
+ * matches with stored regular expressions.
+ */
+ public function index($questId)
+ {
+ // Answers
+ if(!array_key_exists('answers', $_SESSION)) {
+ $_SESSION['answers'] = array();
+ }
+ $answers = array_key_exists($questId, $_SESSION['answers']) ? $_SESSION['answers'][$questId] : array();
+
+ // Check for submission
+ if($this->request->getRequestMethod() == 'POST' && !is_null($this->request->getPostParam('submit')))
+ {
+ // Get answers
+ $answers = $this->request->getPostParam('answers');
+
+ // Store answers in session
+ $_SESSION['answers'][$questId] = $answers;
+
+ // Get right answers
+ $regexs = $this->Textinput->getTextinputRegexs($questId);
+
+ // Match regexs with user answers
+ $allSolved = true;
+ foreach($regexs as $i => &$regex)
+ {
+ if(!array_key_exists($i, $answers))
+ {
+ $allSolved = false;
+ break;
+ }
+
+ $score = preg_match($regex['regex'], $answers[$i]);
+ if($score === 0 || $score === false)
+ {
+ $allSolved = false;
+ break;
+ }
+ }
+
+ // Set status
+ if($allSolved) {
+ $this->setQuestSolved();
+ }
+ else {
+ $this->setQuestUnsolved();
+ }
+ }
+
+
+ // Get Task
+ $task = $this->Textinput->getTextinputQuest($questId);
+
+ // Process text
+ $textParts = preg_split('/(\$\$)/', $task['text'], -1, PREG_SPLIT_NO_EMPTY);
+
+
+ // Pass data to view
+ $this->set('texts', $textParts);
+ $this->set('answers', $answers);
+ }
+
+ }
+
+?>
diff --git a/questtypes/textinput/TextinputQuesttypeModel.inc b/questtypes/textinput/TextinputQuesttypeModel.inc
new file mode 100644
index 00000000..d242f251
--- /dev/null
+++ b/questtypes/textinput/TextinputQuesttypeModel.inc
@@ -0,0 +1,67 @@
+
+ * @copyright 2014 Heinrich-Heine-Universität Düsseldorf
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link https://bitbucket.org/coderkun/the-legend-of-z
+ */
+
+ namespace hhu\z\questtypes;
+
+
+ /**
+ * Model of the TextinputQuesttypeAgent for inserting text.
+ *
+ * @author Oliver Hanraths
+ */
+ class TextinputQuesttypeModel extends \hhu\z\QuesttypeModel
+ {
+
+
+
+
+ /**
+ * Get textinput-text for a Quest.
+ *
+ * @param int $questId ID of Quest
+ * @return array Textinput-text
+ */
+ public function getTextinputQuest($questId)
+ {
+ $data = $this->db->query(
+ 'SELECT text '.
+ 'FROM questtypes_textinput '.
+ 'WHERE quest_id = ?',
+ 'i',
+ $questId
+ );
+
+
+ return $data[0];
+ }
+
+
+ /**
+ * Get regular expressions for a textinput-text.
+ *
+ * @param int $questId ID of Quest
+ * @return array Regexs
+ */
+ public function getTextinputRegexs($questId)
+ {
+ return $this->db->query(
+ 'SELECT number, regex '.
+ 'FROM questtypes_textinput_regexs '.
+ 'WHERE questtypes_textinput_quest_id = ? '.
+ 'ORDER BY number ASC',
+ 'i',
+ $questId
+ );
+ }
+
+ }
+
+?>
diff --git a/questtypes/textinput/html/index.tpl b/questtypes/textinput/html/index.tpl
new file mode 100644
index 00000000..40f0d213
--- /dev/null
+++ b/questtypes/textinput/html/index.tpl
@@ -0,0 +1,11 @@
+
+ &$text) : ?>
+ 0) : ?>
+
+
+ =\hhu\z\Utils::t($text)?>
+
+
+
+
+
diff --git a/requests/WebRequest.inc b/requests/WebRequest.inc
new file mode 100644
index 00000000..2e0f19b9
--- /dev/null
+++ b/requests/WebRequest.inc
@@ -0,0 +1,401 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\requests;
+
+
+ /**
+ * Representation of a web-request.
+ *
+ * @author coderkun
+ */
+ class WebRequest extends \nre\core\Request
+ {
+ /**
+ * Passed GET-parameters
+ *
+ * @var array
+ */
+ private $getParams = array();
+ /**
+ * Passed POST-parameters
+ *
+ * @var array
+ */
+ private $postParams = array();
+ /**
+ * Stored routes
+ *
+ * @var array
+ */
+ private $routes = array();
+ /**
+ * Stored reverse-routes
+ *
+ * @var array
+ */
+ private $reverseRoutes = array();
+
+
+
+
+ /**
+ * Construct a new web-request.
+ */
+ public function __construct()
+ {
+ // Detect current request
+ $this->detectRequest();
+
+ // Load GET-parameters
+ $this->loadGetParams();
+
+ // Load POST-parameters
+ $this->loadPostParams();
+
+ // Detect AJAX
+ $this->detectAJAX();
+ }
+
+
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ if($index == 0) {
+ return $this->getGetParam('layout', $defaultIndex);
+ }
+ else {
+ return parent::getParam($index-1, $defaultIndex);
+ }
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameters
+ */
+ public function getParams($offset=0)
+ {
+ if($offset == 0)
+ {
+ return array_merge(
+ array(
+ $this->getGetParam('layout', 'toplevel')
+ ),
+ parent::getParams()
+ );
+ }
+
+
+ return array_slice($this->params, $offset-1);
+ }
+
+
+ /**
+ * Get a GET-parameter.
+ *
+ * @param string $key Key of GET-parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of GET-parameter
+ */
+ public function getGetParam($key, $defaultIndex=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->getParams))
+ {
+ // Return value
+ return $this->getParams[$key];
+ }
+
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all GET-parameters.
+ *
+ * @return array GET-Parameters
+ */
+ public function getGetParams()
+ {
+ return $this->getParams;
+ }
+
+
+ /**
+ * Get a POST-parameter.
+ *
+ * @param string $key Key of POST-parameter
+ * @param string $defaultValue Default value for this parameter
+ * @return string Value of POST-parameter
+ */
+ public function getPostParam($key, $defaultValue=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->postParams))
+ {
+ // Return value
+ return $this->postParams[$key];
+ }
+
+
+ // Return default value
+ return $defaultValue;
+ }
+
+
+ /**
+ * Get all POST-parameters.
+ *
+ * @return array POST-parameters
+ */
+ public function getPostParams()
+ {
+ return $this->postParams;
+ }
+
+
+ /**
+ * Get the method of the current request.
+ *
+ * @return string Current request method
+ */
+ public function getRequestMethod()
+ {
+ return $_SERVER['REQUEST_METHOD'];
+ }
+
+
+ /**
+ * Add a URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ */
+ public function addRoute($pattern, $replacement, $isLast=false)
+ {
+ // Store route
+ $this->routes[] = $this->newRoute($pattern, $replacement, $isLast);
+ }
+
+
+ /**
+ * Add a reverse URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the reverse routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ */
+ public function addReverseRoute($pattern, $replacement, $isLast=false)
+ {
+ // Store reverse route
+ $this->reverseRoutes[] = $this->newRoute($pattern, $replacement, $isLast);
+ }
+
+
+ /**
+ * Apply stored reverse-routes to an URL
+ *
+ * @param string $url URL to apply reverse-routes to
+ * @return string Reverse-routed URL
+ */
+ public function applyReverseRoutes($url)
+ {
+ return $this->applyRoutes($url, $this->reverseRoutes);
+ }
+
+
+ /**
+ * Revalidate the current request
+ */
+ public function revalidate()
+ {
+ $this->detectRequest();
+ }
+
+
+ /**
+ * Get a SERVER-parameter.
+ *
+ * @param string $key Key of SERVER-parameter
+ * @return string Value of SERVER-parameter
+ */
+ public function getServerParam($key)
+ {
+ if(array_key_exists($key, $_SERVER)) {
+ return $_SERVER[$key];
+ }
+
+
+ return null;
+ }
+
+
+
+
+ /**
+ * Detect the current HTTP-request.
+ */
+ private function detectRequest()
+ {
+ // URL ermitteln
+ $url = isset($_GET) && array_key_exists('url', $_GET) ? $_GET['url'] : '';
+ $url = trim($url, '/');
+
+ // Routes anwenden
+ $url = $this->applyRoutes($url, $this->routes);
+
+ // URL splitten
+ $params = explode('/', $url);
+ if(empty($params[0])) {
+ $params = array();
+ }
+
+
+ // Parameter speichern
+ $this->params = $params;
+ }
+
+
+ /**
+ * Determine parameters passed by GET.
+ */
+ private function loadGetParams()
+ {
+ if(isset($_GET)) {
+ $this->getParams = $_GET;
+ }
+ }
+
+
+ /**
+ * Determine parameters passed by POST.
+ */
+ private function loadPostParams()
+ {
+ if(isset($_POST)) {
+ $this->postParams = $_POST;
+ }
+ }
+
+
+ /**
+ * Detect an AJAX-request by checking the X-Requested-With
+ * header and set the layout to 'ajax' in this case.
+ */
+ private function detectAjax()
+ {
+ // Get request headers
+ $headers = apache_request_headers();
+
+ // Check X-Requested-With header and set layout
+ if(array_key_exists('X-Requested-With', $headers) && $headers['X-Requested-With'] == 'XMLHttpRequest') {
+ if(!array_key_exists('layout', $this->getParams)) {
+ $this->getParams['layout'] = 'ajax';
+ }
+ }
+ }
+
+
+ /**
+ * Create a new URL-route.
+ *
+ * @param string $pattern Regex-Pattern that defines the reverse routing
+ * @param string $replacement Regex-Pattern for replacement
+ * @param bool $isLast Stop after that rule
+ * @return array New URL-route
+ */
+ private function newRoute($pattern, $replacement, $isLast=false)
+ {
+ return array(
+ 'pattern' => $pattern,
+ 'replacement' => $replacement,
+ 'isLast' => $isLast
+ );
+ }
+
+
+ /**
+ * Apply given routes to an URL
+ *
+ * @param string $url URL to apply routes to
+ * @param array $routes Routes to apply
+ * @return string Routed URL
+ */
+ private function applyRoutes($url, $routes)
+ {
+ // Traverse given routes
+ foreach($routes as &$route)
+ {
+ // Create and apply Regex
+ $urlR = preg_replace(
+ '>'.$route['pattern'].'>i',
+ $route['replacement'],
+ $url
+ );
+
+ // Split URL
+ $get = '';
+ if(($gpos = strrpos($urlR, '?')) !== false) {
+ $get = substr($urlR, $gpos+1);
+ $urlR = substr($urlR, 0, $gpos);
+ }
+
+ // Has current route changed anything?
+ if($urlR != $url || !empty($get))
+ {
+ // Extract GET-parameters
+ if(strlen($get) > 0)
+ {
+ $gets = explode('&', $get);
+ foreach($gets as $get)
+ {
+ $get = explode('=', $get);
+ if(!array_key_exists($get[0], $this->getParams)) {
+ $this->getParams[$get[0]] = $get[1];
+ }
+ }
+ }
+
+
+ // Stop when route “isLast”
+ if($route['isLast']) {
+ $url = $urlR;
+ break;
+ }
+ }
+
+
+ // Set new URL
+ $url = $urlR;
+ }
+
+
+ // Return routed URL
+ return $url;
+ }
+
+ }
+
+?>
diff --git a/responses/WebResponse.inc b/responses/WebResponse.inc
new file mode 100644
index 00000000..2ca25079
--- /dev/null
+++ b/responses/WebResponse.inc
@@ -0,0 +1,250 @@
+
+ * @copyright 2013 coderkun (http://www.coderkun.de)
+ * @license http://www.gnu.org/licenses/gpl.html
+ * @link http://www.coderkun.de/projects/nre
+ */
+
+ namespace nre\responses;
+
+
+ /**
+ * Representation of a web-response.
+ *
+ * @author coderkun
+ */
+ class WebResponse extends \nre\core\Response
+ {
+ /**
+ * Applied GET-parameters
+ *
+ * @var array
+ */
+ private $getParams = array();
+ /**
+ * Changed header lines
+ *
+ * @var array
+ */
+ private $headers = array();
+
+
+
+
+ /**
+ * Add a parameter.
+ *
+ * @param mixed $value Value of parameter
+ */
+ public function addParam($value)
+ {
+ if(array_key_exists('layout', $this->getParams)) {
+ parent::addParam($value);
+ }
+ else {
+ $this->addGetParam('layout', $value);
+ }
+ }
+
+
+ /**
+ * Add multiple parameters.
+ *
+ * @param mixed $value1 Value of first parameter
+ * @param mixed … Values of further parameters
+ */
+ public function addParams($value1)
+ {
+ $this->addParam($value1);
+
+ $this->params = array_merge(
+ $this->params,
+ array_slice(
+ func_get_args(),
+ 1
+ )
+ );
+ }
+
+
+ /**
+ * Delete all stored parameters (from offset on).
+ *
+ * @param int $offset Offset-index
+ */
+ public function clearParams($offset=0)
+ {
+ if($offset == 0) {
+ unset($this->getParams['layout']);
+ }
+
+ parent::clearParams(max(0, $offset-1));
+ }
+
+
+ /**
+ * Get a parameter.
+ *
+ * @param int $index Index of parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of parameter
+ */
+ public function getParam($index, $defaultIndex=null)
+ {
+ if($index == 0) {
+ return $this->getGetParam('layout', $defaultIndex);
+ }
+ else {
+ return parent::getParam($index-1, $defaultIndex);
+ }
+ }
+
+
+ /**
+ * Get all parameters from index on.
+ *
+ * @param int $offset Offset-index
+ * @return array Parameter values
+ */
+ public function getParams($offset=0)
+ {
+ if($offset == 0)
+ {
+ if(!array_key_exists('layout', $this->getParams)) {
+ return array();
+ }
+
+ return array_merge(
+ array(
+ $this->getParams['layout']
+ ),
+ $this->params
+ );
+ }
+
+
+ return array_slice($this->params, $offset-1);
+ }
+
+
+ /**
+ * Add a GET-parameter.
+ *
+ * @param string $key Key of GET-parameter
+ * @param mixed $value Value of GET-parameter
+ */
+ public function addGetParam($key, $value)
+ {
+ $this->getParams[$key] = $value;
+ }
+
+
+ /**
+ * Add multiple GET-parameters.
+ *
+ * @param array $params Associative arary with key-value GET-parameters
+ */
+ public function addGetParams($params)
+ {
+ $this->getParams = array_merge(
+ $this->getParams,
+ $params
+ );
+ }
+
+
+ /**
+ * Get a GET-parameter.
+ *
+ * @param int $index Index of GET-parameter
+ * @param string $defaultIndex Index of default configuration value for this parameter
+ * @return string Value of GET-parameter
+ */
+ public function getGetParam($key, $defaultIndex=null)
+ {
+ // Check key
+ if(array_key_exists($key, $this->getParams))
+ {
+ // Return value
+ return $this->getParams[$key];
+ }
+
+ // Return default value
+ return \nre\core\Config::getDefault($defaultIndex);
+ }
+
+
+ /**
+ * Get all GET-parameters.
+ *
+ * @return array All GET-parameters
+ */
+ public function getGetParams()
+ {
+ return $this->getParams;
+ }
+
+
+ /**
+ * Add a line to the response header.
+ *
+ * @param string $headerLine Header line
+ * @param bool $replace Replace existing header line
+ * @param int $http_response_code HTTP-response code
+ */
+ public function addHeader($headerLine, $replace=true, $http_response_code=null)
+ {
+ $this->headers[] = $this->newHeader($headerLine, $replace, $http_response_code);
+ }
+
+
+ /**
+ * Clear all stored headers.
+ */
+ public function clearHeaders()
+ {
+ $this->headers = array();
+ }
+
+
+ /**
+ * Send stored headers.
+ */
+ public function header()
+ {
+ foreach($this->headers as $header)
+ {
+ header(
+ $header['string'],
+ $header['replace'],
+ $header['responseCode']
+ );
+ }
+ }
+
+
+
+
+ /**
+ * Create a new header line.
+ *
+ * @param string $headerLine Header line
+ * @param bool $replace Replace existing header line
+ * @param int $http_response_code HTTP-response code
+ */
+ private function newHeader($headerLine, $replace=true, $http_response_code=null)
+ {
+ return array(
+ 'string' => $headerLine,
+ 'replace' => $replace,
+ 'responseCode' => $http_response_code
+ );
+ }
+
+ }
+
+?>
diff --git a/views/binary/binary.tpl b/views/binary/binary.tpl
new file mode 100644
index 00000000..43a06a51
--- /dev/null
+++ b/views/binary/binary.tpl
@@ -0,0 +1 @@
+=$intermediate?>
diff --git a/views/binary/error/index.tpl b/views/binary/error/index.tpl
new file mode 100644
index 00000000..2d8440b4
--- /dev/null
+++ b/views/binary/error/index.tpl
@@ -0,0 +1 @@
+=_('Error')?>: =$code?>: =$string?>
diff --git a/views/binary/media/index.tpl b/views/binary/media/index.tpl
new file mode 100644
index 00000000..d0f3e0cd
--- /dev/null
+++ b/views/binary/media/index.tpl
@@ -0,0 +1 @@
+=file_get_contents($media['filename'])?>
diff --git a/views/error.tpl b/views/error.tpl
new file mode 100644
index 00000000..f45b01a0
--- /dev/null
+++ b/views/error.tpl
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Service Unavailable
+
+
+
+ Die Anwendung steht zur Zeit leider nicht zur Verfügung.
+
+
+
diff --git a/views/fault/error/index.tpl b/views/fault/error/index.tpl
new file mode 100644
index 00000000..f7e42500
--- /dev/null
+++ b/views/fault/error/index.tpl
@@ -0,0 +1,2 @@
+Fehler
+=$code?>: =$string?>
diff --git a/views/fault/fault.tpl b/views/fault/fault.tpl
new file mode 100644
index 00000000..307b772d
--- /dev/null
+++ b/views/fault/fault.tpl
@@ -0,0 +1,16 @@
+
+
+
+
+
+ The Legend of Z
+
+
+
+ The Legend of Z
+
+ =$intermediate?>
+
+
+
+
diff --git a/views/html/charactergroups/group.tpl b/views/html/charactergroups/group.tpl
new file mode 100644
index 00000000..96146f31
--- /dev/null
+++ b/views/html/charactergroups/group.tpl
@@ -0,0 +1,33 @@
+=_('Seminaries')?>
+=$seminary['title']?>
+
+
+=$group['name']?>
+
+
+ XPs: =$group['xps']?>
+
+
+
+
+