%PDF- %PDF-
| Direktori : /proc/self/root/backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Mvc/ |
| Current File : //proc/self/root/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;
}
}