%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Mvc/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php |
<?php /* * Copyright (C) 2024 Deciso B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ namespace OPNsense\Mvc; use Exception; use ReflectionClass; use ReflectionMethod; use ReflectionException; use OPNsense\Mvc\Exceptions\ClassNotFoundException; use OPNsense\Mvc\Exceptions\MethodNotFoundException; use OPNsense\Mvc\Exceptions\ParameterMismatchException; class Dispatcher { private string $namespace; private string $controller; private string $action; private array $parameters; private ReflectionClass $controllerClass; private array|string|null $returnedValue; /** * @param string $namespace full namespace to use (including vendor) * @param string $controller classname which implements this controller * @param string $action action handler to call * @param array $parameters list of supplied parameters */ public function __construct(string $namespace, string $controller, string $action, array $parameters) { $this->namespace = $namespace; $this->controller = $controller; $this->action = $action; $this->parameters = $parameters; } /** * XXX: rename to getMethodName when phalcon is removed and return plain $this->action, * next cleanup ApiControllerBase. * @return string action name */ public function getActionName() { return substr($this->action, 0, strlen($this->action) - 6); } /** * Resolve controller class and inspect method to call, except when the target controller offers a __call * hook in which case we expect the target to offer proper error handling * @throws ClassNotFoundException when controller class can not be found * @throws MethodNotFoundException when controller method can not be found * @throws ParameterMismatchException when expected required parameters do not match offered ones */ protected function resolve(): void { if (isset($this->controllerClass)) { // already resolved return; } $clsname = $this->namespace . "\\" . $this->controller; try { $this->controllerClass = new ReflectionClass($clsname); } catch (ReflectionException) { throw new ClassNotFoundException(sprintf("%s not found", $clsname)); } if (!$this->controllerClass->isInstantiable()) { throw new ClassNotFoundException(sprintf("%s not found", $clsname)); } if (!$this->controllerClass->hasMethod($this->action) && $this->controllerClass->hasMethod('__call')) { // dynamic class, we can't probe the method and its expected parameters. return; } if (!$this->controllerClass->hasMethod($this->action)) { throw new MethodNotFoundException(sprintf("%s -> %s not found", $clsname, $this->action)); } try { $actionMethod = $this->controllerClass->getMethod($this->action); } catch (ReflectionException) { throw new MethodNotFoundException(sprintf("%s -> %s not found", $clsname, $this->action)); } $pcount = 0; foreach ($actionMethod->getParameters() as $param) { if ($param->isOptional()) { break; } $pcount++; } if ($pcount > count($this->parameters)) { unset($this->controllerClass); throw new ParameterMismatchException(sprintf( "%s -> %s parameter mismatch (expected %d, got %d)", $clsname, $this->action, $pcount, count($this->parameters) )); } } /** * test if controller action method is callable with the parameters provided * @return bool */ public function canExecute(): bool { try { $this->resolve(); return true; } catch (Exception) { return false; } } /** * Dispatch (execute) controller action method * @param Request $request http request object * @param Response $response http response object * @param Session $session session object * @return bool * @throws ClassNotFoundException when controller class can not be found * @throws MethodNotFoundException when controller method can not be found * @throws ParameterMismatchException when expected required parameters do not match offered ones * @throws ReflectionException when invoke fails */ public function dispatch(Request $request, Response $response, Session $session): bool { $this->resolve(); $controller = $this->controllerClass->newInstance(); $controller->session = $session; $controller->request = $request; $controller->response = $response; $controller->security = new Security($session, $request); if ($controller->beforeExecuteRoute($this) === false) { return false; } /* call initialize() after authentication */ $controller->initialize(); $this->returnedValue = $controller->{$this->action}(...$this->parameters); $session->close(); $controller->afterExecuteRoute($this); return true; } /** * @return array|string|null response */ public function getReturnedValue(): array|string|null { return $this->returnedValue; } /** * XXX: remove call from ControllerBase, seems like a workaround for a specific phalcon issue back in 2015 * @return bool */ public function wasForwarded(): bool { return false; } }