public static function loadClass(ReflectionClass $refl, Reader $reader, Router $router) { $annotation = $reader->getClassAnnotation($refl, 'Destiny\\Common\\Annotation\\Controller'); if (empty($annotation)) { return; } $methods = $refl->getMethods(ReflectionMethod::IS_PUBLIC); foreach ($methods as $method) { /** @var Route[] $routes */ $routes = array(); $annotations = $reader->getMethodAnnotations($method); for ($i = 0; $i < count($annotations); ++$i) { /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ if ($annotations[$i] instanceof \Destiny\Common\Annotation\Route) { $routes[] = $annotations[$i]; } } if (count($routes) <= 0) { continue; } /** @var \Destiny\Common\Annotation\HttpMethod $feature */ $httpMethod = $reader->getMethodAnnotation($method, 'Destiny\\Common\\Annotation\\HttpMethod'); /** @var \Destiny\Common\Annotation\Secure $feature */ $secure = $reader->getMethodAnnotation($method, 'Destiny\\Common\\Annotation\\Secure'); for ($i = 0; $i < count($routes); ++$i) { $router->addRoute(new Route(array('path' => $routes[$i]->path, 'classMethod' => $method->name, 'class' => $refl->name, 'httpMethod' => $httpMethod ? $httpMethod->allow : null, 'secure' => $secure ? $secure->roles : null))); } } }
/** * Executes the action if a route is found */ public function executeRequest(Request $request) { $route = $this->router->findRoute($request); $model = new ViewModel(); $response = null; // No route found if (!$route) { $model->title = Http::$HEADER_STATUSES[Http::STATUS_NOT_FOUND]; $response = new Response(Http::STATUS_NOT_FOUND); $response->setBody($this->template('errors/' . Http::STATUS_NOT_FOUND . '.php', $model)); $this->handleResponse($response); } // Security checks if (!$this->hasRouteSecurity($route, Session::getCredentials())) { $model->title = Http::$HEADER_STATUSES[Http::STATUS_UNAUTHORIZED]; $response = new Response(Http::STATUS_UNAUTHORIZED); $response->setBody($this->template('errors/' . Http::STATUS_UNAUTHORIZED . '.php', $model)); $this->handleResponse($response); } try { // Parameters $params = array_merge($_GET, $_POST, $route->getPathParams($request->path())); // Get and init action class $className = $route->getClass(); $classMethod = $route->getClassMethod(); // Init the action class instance $classInstance = new $className(); // Check for @Transactional annotation $annotationReader = $this->getAnnotationReader(); $transactional = $annotationReader->getMethodAnnotation(new \ReflectionMethod($classInstance, $classMethod), 'Destiny\\Common\\Annotation\\Transactional'); $transactional = empty($transactional) ? false : true; // If transactional begin a DB transaction before the action begins if ($transactional) { $conn = $this->getConnection(); $conn->beginTransaction(); } // Execute the class method $response = $classInstance->{$classMethod}($params, $model, $request); // Log any errors on the model // @TODO neaten this implementation up - better than logging everywhere else ///if (! empty ( $model->error ) && is_a ( $model->error, 'Exception' )) { /// $this->logger->error ( $model->error->getMessage () ); //} // Check if the response is valid if (empty($response)) { throw new Exception('Invalid action response'); } // Redirect response if (is_string($response) && substr($response, 0, 10) === 'redirect: ') { $redirect = substr($response, 10); $response = new Response(Http::STATUS_OK); $response->setLocation($redirect); } // Template response if (is_string($response)) { $tpl = $response . '.php'; $response = new Response(Http::STATUS_OK); $response->setBody($this->template($tpl, $model)); } // Check the response type if (!$response instanceof Response) { throw new Exception('Invalid response'); } // Commit the DB transaction if ($transactional) { $conn->commit(); } } catch (Exception $e) { // Destiny\Exceptions are caught and displayed $this->logger->error($e->getMessage()); if ($transactional) { $conn->rollback(); } $response = new Response(Http::STATUS_ERROR); $model->error = new Exception($e->getMessage()); $model->code = Http::STATUS_ERROR; $model->title = 'Error'; $response->setBody($this->template('errors/' . Http::STATUS_ERROR . '.php', $model)); } catch (\Exception $e) { // \Exceptions are caught and generic message is shown $this->logger->critical($e->getMessage()); if ($transactional) { $conn->rollback(); } $response = new Response(Http::STATUS_ERROR); $model->error = new Exception('Maximum over-rustle has been achieved'); $model->code = Http::STATUS_ERROR; $model->title = 'Error'; $response->setBody($this->template('errors/' . Http::STATUS_ERROR . '.php', $model)); } // Handle the request response $this->handleResponse($response); }
/** * @param Request $request */ public function executeRequest(Request $request) { $route = $this->router->findRoute($request); $conn = $this->getConnection(); $model = new ViewModel(); if ($route == null) { $model->title = Http::$HEADER_STATUSES[Http::STATUS_NOT_FOUND]; $response = new Response(Http::STATUS_NOT_FOUND); $response->setBody($this->template('errors/' . Http::STATUS_NOT_FOUND . '.php', $model)); $this->handleResponse($response); } if ($route->isSecure()) { $creds = Session::getCredentials(); if ($creds->isValid() && strcasecmp($creds->getUserStatus(), 'Active') !== 0) { $response = new Response(Http::STATUS_ERROR); $model->error = new Exception(sprintf('User status not active. Status: %s', $creds->getUserStatus())); $model->code = Http::STATUS_ERROR; $model->title = 'Inactive user'; $response->setBody($this->template('errors/' . Http::STATUS_ERROR . '.php', $model)); $this->handleResponse($response); } if (!$this->hasRouteSecurity($route, $creds)) { $response = new Response(Http::STATUS_UNAUTHORIZED); $model->title = Http::$HEADER_STATUSES[Http::STATUS_UNAUTHORIZED]; $response->setBody($this->template('errors/' . Http::STATUS_UNAUTHORIZED . '.php', $model)); $this->handleResponse($response); } } try { $className = $route->getClass(); $classMethod = $route->getClassMethod(); $classReflection = new \ReflectionClass($className); $classInstance = $classReflection->newInstance(); // Order the controller arguments and invoke the controller $args = array(); $methodReflection = $classReflection->getMethod($classMethod); $methodParams = $methodReflection->getParameters(); foreach ($methodParams as $methodParam) { $paramType = $methodParam->getClass(); if ($methodParam->isArray()) { // the $params passed into the Controller classes. A merge of the _GET, _POST and variables generated from the route path (e.g. /dog/{id}/cat) $args[] = array_merge($request->get(), $request->post(), $this->router->getRoutePathParams($route, $request->path())); } else { if ($paramType->isInstance($model)) { $args[] =& $model; } else { if ($paramType->isInstance($request)) { $args[] =& $request; } } } } // Execute the controller $response = $methodReflection->invokeArgs($classInstance, $args); if (empty($response)) { throw new Exception('Invalid action response'); } // Redirect response if (is_string($response) && substr($response, 0, 10) === 'redirect: ') { $redirect = substr($response, 10); $response = new Response(Http::STATUS_OK); $response->setLocation($redirect); } // Template response if (is_string($response)) { $tpl = $response . '.php'; $response = new Response(Http::STATUS_OK); $response->setBody($this->template($tpl, $model)); } if (!$response instanceof Response) { throw new Exception('Invalid response'); } } catch (Exception $e) { $this->logger->error($e->getMessage() . PHP_EOL . $e->getTraceAsString()); if ($conn->isTransactionActive()) { $conn->rollback(); } $response = new Response(Http::STATUS_ERROR); $model->error = new Exception($e->getMessage()); $model->code = Http::STATUS_ERROR; $model->title = 'Error'; $response->setBody($this->template('errors/' . Http::STATUS_ERROR . '.php', $model)); } catch (\Exception $e) { $this->logger->critical($e->getMessage() . PHP_EOL . $e->getTraceAsString()); if ($conn->isTransactionActive()) { $conn->rollback(); } $response = new Response(Http::STATUS_ERROR); $model->error = new Exception('Maximum over-rustle has been achieved'); $model->code = Http::STATUS_ERROR; $model->title = 'Error'; $response->setBody($this->template('errors/' . Http::STATUS_ERROR . '.php', $model)); } $this->handleResponse($response); }