Revise loading of routes to support @domains tag that only loads these routes for specific domains. To enable multisite behaviour.

This commit is contained in:
Greyscale 2020-07-31 23:10:39 +02:00
parent 036d067757
commit e9519be717
3 changed files with 318 additions and 296 deletions

View file

@ -147,7 +147,11 @@ class App
}
$container = $container->build();
$container->set(Slim\Views\Twig::class, function (EnvironmentService $environmentService, SessionService $sessionService, Translation\Translator $translator) {
$container->set(Slim\Views\Twig::class, function (
EnvironmentService $environmentService,
SessionService $sessionService,
Translation\Translator $translator
) {
foreach ($this->viewPaths as $i => $viewLocation) {
if (!file_exists($viewLocation) || !is_dir($viewLocation)) {
unset($this->viewPaths[$i]);
@ -321,10 +325,9 @@ class App
);
});
/** @var Services\EnvironmentService $environmentService */
$environmentService = $container->get(Services\EnvironmentService::class);
if ($environmentService->has('TIMEZONE')) {
date_default_timezone_set($environmentService->get('TIMEZONE'));
$this->environmentService = $container->get(Services\EnvironmentService::class);
if ($this->environmentService->has('TIMEZONE')) {
date_default_timezone_set($this->environmentService->get('TIMEZONE'));
} elseif (file_exists('/etc/timezone')) {
date_default_timezone_set(trim(file_get_contents('/etc/timezone')));
} else {
@ -516,7 +519,10 @@ class App
}
$this->interrogateControllersComplete = true;
if ($this->router->loadCache()) {
if ($this->environmentService->has('USE_ROUTE_CACHE')
&& 'yes' == strtolower($this->environmentService->get('USE_ROUTE_CACHE'))
&& $this->router->loadCache()
) {
return;
}
@ -531,7 +537,7 @@ class App
$appClass = new \ReflectionClass(get_called_class());
$expectedClasses = [
$appClass->getNamespaceName().'\\Controllers\\'.str_replace('.php', '', $controllerFile->getFilename()),
'\\Controllers\\'.str_replace('.php', '', $controllerFile->getFilename()),
'Benzine\\Controllers\\'.str_replace('.php', '', $controllerFile->getFilename()),
];
foreach ($expectedClasses as $expectedClass) {
if (class_exists($expectedClass)) {
@ -541,51 +547,59 @@ class App
/** @var \ReflectionMethod $method */
if (true || ResponseInterface::class == ($method->getReturnType() instanceof \ReflectionType ? $method->getReturnType()->getName() : null)) {
$docBlock = $method->getDocComment();
$newRoute = new Route($this->logger);
foreach (explode("\n", $docBlock) as $docBlockRow) {
if (false === stripos($docBlockRow, '@route')) {
continue;
}
if (false !== stripos($docBlockRow, '@route')) {
$route = trim(substr(
$docBlockRow,
(stripos($docBlockRow, '@route') + strlen('@route'))
));
$route = trim(substr(
$docBlockRow,
(stripos($docBlockRow, '@route') + strlen('@route'))
));
@list($httpMethods, $path, $extra) = explode(' ', $route, 3);
$httpMethods = explode(',', strtoupper($httpMethods));
@list($httpMethods, $path, $extra) = explode(' ', $route, 3);
$httpMethods = explode(',', strtoupper($httpMethods));
$options = [];
$defaultOptions = [
'access' => Route::ACCESS_PUBLIC,
'weight' => 100,
];
if (isset($extra)) {
foreach (explode(' ', $extra) as $item) {
@list($extraK, $extraV) = explode('=', $item, 2);
if (!isset($extraV)) {
$extraV = true;
}
$options[$extraK] = $extraV;
}
}
$options = array_merge($defaultOptions, $options);
foreach ($httpMethods as $httpMethod) {
$newRoute = Route::Factory()
->setHttpMethod($httpMethod)
->setRouterPattern('/'.ltrim($path, '/'))
->setCallback($method->class.':'.$method->name)
;
foreach ($options as $key => $value) {
$keyMethod = 'set'.ucfirst($key);
if (method_exists($newRoute, $keyMethod)) {
$newRoute->{$keyMethod}($value);
} else {
$newRoute->setArgument($key, $value);
$options = [];
$defaultOptions = [
'access' => Route::ACCESS_PUBLIC,
'weight' => 100,
];
if (isset($extra)) {
foreach (explode(' ', $extra) as $item) {
@list($extraK, $extraV) = explode('=', $item, 2);
if (!isset($extraV)) {
$extraV = true;
}
$options[$extraK] = $extraV;
}
}
$options = array_merge($defaultOptions, $options);
foreach ($httpMethods as $httpMethod) {
$newRoute
->setHttpMethod($httpMethod)
->setRouterPattern('/'.ltrim($path, '/'))
->setCallback($method->class.':'.$method->name)
;
$this->router->addRoute($newRoute);
foreach ($options as $key => $value) {
$keyMethod = 'set'.ucfirst($key);
if (method_exists($newRoute, $keyMethod)) {
$newRoute->{$keyMethod}($value);
} else {
$newRoute->setArgument($key, $value);
}
}
$this->router->addRoute($newRoute);
}
} elseif (false !== stripos($docBlockRow, '@domains')) {
$domains = explode(' ', trim(substr(
$docBlockRow,
(stripos($docBlockRow, '@domains') + strlen('@domains'))
)));
foreach ($domains as $domain) {
$newRoute->addValidDomain($domain);
}
$newRoute->setWeight($newRoute->getWeight() - 10);
}
}
}

View file

@ -2,6 +2,7 @@
namespace Benzine\Router;
use Monolog\Logger;
use Slim\App;
class Route
@ -27,14 +28,17 @@ class Route
protected $propertyOptions;
protected $exampleEntity;
protected $exampleEntityFinderFunction;
protected $callbackProperties = [];
protected $arguments = [
protected array $callbackProperties = [];
protected array $arguments = [
self::ARGUMENT_ACCESS => self::ACCESS_PUBLIC,
];
protected array $validDomains = [];
public static function Factory(): Route
private Logger $logger;
public function __construct(Logger $logger)
{
return new Route();
$this->logger = $logger;
}
public function getCallbackProperties(): array
@ -84,18 +88,6 @@ class Route
return $this;
}
public function getSDKTemplate(): string
{
return $this->SDKTemplate;
}
public function setSDKTemplate(string $SDKTemplate): Route
{
$this->SDKTemplate = $SDKTemplate;
return $this;
}
public function getUniqueIdentifier()
{
return implode(
@ -104,194 +96,11 @@ class Route
$this->getRouterPattern(),
$this->getHttpMethod(),
"Weight={$this->getWeight()}",
$this->callback,
]
);
}
/**
* @return mixed
*/
public function getHttpMethod()
{
return $this->httpMethod;
}
/**
* @param mixed $httpMethod
*/
public function setHttpMethod($httpMethod): Route
{
$this->httpMethod = $httpMethod;
return $this;
}
public function getWeight(): int
{
return $this->weight;
}
public function setWeight(int $weight): Route
{
$this->weight = $weight;
return $this;
}
/**
* @return mixed
*/
public function getRouterPattern()
{
return $this->routerPattern;
}
/**
* @param mixed $routerPattern
*/
public function setRouterPattern($routerPattern): Route
{
$this->routerPattern = $routerPattern;
return $this;
}
public function setExampleEntityFindFunction(callable $finderFunction): Route
{
$this->exampleEntityFinderFunction = $finderFunction;
return $this;
}
/**
* @return mixed
*/
public function getExampleEntity()
{
if (!$this->exampleEntity && $this->exampleEntityFinderFunction) {
$function = $this->exampleEntityFinderFunction;
$this->exampleEntity = $function();
}
return $this->exampleEntity;
}
/**
* @param mixed $exampleEntity
*/
public function setExampleEntity($exampleEntity): Route
{
$this->exampleEntity = $exampleEntity;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param mixed $name
*/
public function setName($name): Route
{
$this->name = $name;
return $this;
}
/**
* @return mixed
*/
public function getSDKClass()
{
return $this->SDKClass;
}
/**
* @param mixed $SDKClass
*/
public function setSDKClass($SDKClass): Route
{
$this->SDKClass = $SDKClass;
return $this;
}
/**
* @return mixed
*/
public function getSDKFunction()
{
return $this->SDKFunction;
}
/**
* @param mixed $function
*/
public function setSDKFunction($function): Route
{
$this->SDKFunction = $function;
return $this;
}
/**
* @return mixed
*/
public function getSingular()
{
return $this->singular;
}
/**
* @param mixed $singular
*/
public function setSingular($singular): Route
{
$this->singular = $singular;
return $this;
}
/**
* @return mixed
*/
public function getPlural()
{
return $this->plural;
}
/**
* @param mixed $plural
*/
public function setPlural($plural): Route
{
$this->plural = $plural;
return $this;
}
public function getPropertyData()
{
return $this->propertyData;
}
/**
* @return mixed
*/
public function getProperties()
{
return $this->properties;
}
/**
* @param mixed $properties
*/
public function setProperties($properties): Route
{
$this->properties = [];
@ -307,14 +116,6 @@ class Route
return $this;
}
/**
* @return mixed
*/
public function getPropertyOptions()
{
return $this->propertyOptions;
}
/**
* @param mixed $propertyOptions
*
@ -333,7 +134,16 @@ class Route
public function populateRoute(App $app): App
{
//echo "Populating: {$this->getHttpMethod()} {$this->getRouterPattern()}\n";
$this->logger->debug(sprintf(
'Router Populating: %s %s',
$this->getHttpMethod(),
$this->getRouterPattern()
));
if ($this->hasValidDomains() && !$this->isInContainedInValidDomains()) {
return $app;
}
$mapping = $app->map(
[$this->getHttpMethod()],
$this->getRouterPattern(),
@ -349,42 +159,6 @@ class Route
return $app;
}
/**
* @return mixed
*/
public function getCallback()
{
return $this->callback;
}
/**
* @param mixed $callback
*/
public function setCallback($callback): Route
{
$this->callback = $callback;
return $this;
}
/**
* @return mixed
*/
public function getHttpEndpoint()
{
return $this->httpEndpoint;
}
/**
* @param mixed $httpEndpoint
*/
public function setHttpEndpoint($httpEndpoint): Route
{
$this->httpEndpoint = $httpEndpoint;
return $this;
}
/**
* @return string
*/
@ -416,6 +190,241 @@ class Route
return $this;
}
public function getName(): string
{
return $this->name ?? 'Unnamed Route';
}
public function setName(string $name): Route
{
$this->name = $name;
return $this;
}
public function getCallback(): string
{
return $this->callback;
}
public function setCallback(string $callback): Route
{
$this->callback = $callback;
return $this;
}
public function getSDKClass(): string
{
return $this->SDKClass;
}
public function setSDKClass(string $SDKClass): Route
{
$this->SDKClass = $SDKClass;
return $this;
}
public function getSDKFunction(): string
{
return $this->SDKFunction;
}
public function setSDKFunction(string $SDKFunction): Route
{
$this->SDKFunction = $SDKFunction;
return $this;
}
public function getSDKTemplate(): string
{
return $this->SDKTemplate;
}
public function setSDKTemplate(string $SDKTemplate): Route
{
$this->SDKTemplate = $SDKTemplate;
return $this;
}
public function getRouterPattern(): string
{
return $this->routerPattern;
}
public function setRouterPattern(string $routerPattern): Route
{
$this->routerPattern = $routerPattern;
return $this;
}
public function getHttpEndpoint(): string
{
return $this->httpEndpoint;
}
public function setHttpEndpoint(string $httpEndpoint): Route
{
$this->httpEndpoint = $httpEndpoint;
return $this;
}
public function getHttpMethod(): string
{
return $this->httpMethod;
}
public function setHttpMethod(string $httpMethod): Route
{
$this->httpMethod = $httpMethod;
return $this;
}
public function getWeight(): int
{
return $this->weight;
}
public function setWeight(int $weight): Route
{
$this->weight = $weight;
return $this;
}
public function getSingular(): string
{
return $this->singular;
}
public function setSingular(string $singular): Route
{
$this->singular = $singular;
return $this;
}
public function getPlural(): string
{
return $this->plural;
}
public function setPlural(string $plural): Route
{
$this->plural = $plural;
return $this;
}
public function getPropertyData(): array
{
return $this->propertyData;
}
public function setPropertyData(array $propertyData): Route
{
$this->propertyData = $propertyData;
return $this;
}
public function getExampleEntity()
{
return $this->exampleEntity;
}
/**
* @param mixed $exampleEntity
*
* @return Route
*/
public function setExampleEntity($exampleEntity)
{
$this->exampleEntity = $exampleEntity;
return $this;
}
public function getExampleEntityFinderFunction()
{
return $this->exampleEntityFinderFunction;
}
/**
* @param mixed $exampleEntityFinderFunction
*
* @return Route
*/
public function setExampleEntityFinderFunction($exampleEntityFinderFunction)
{
$this->exampleEntityFinderFunction = $exampleEntityFinderFunction;
return $this;
}
/**
* @return array|string[]
*/
public function getArguments()
{
return $this->arguments;
}
/**
* @param array|string[] $arguments
*
* @return Route
*/
public function setArguments($arguments)
{
$this->arguments = $arguments;
return $this;
}
public function addValidDomain(string $validDomain): Route
{
$this->validDomains[] = $validDomain;
return $this;
}
public function getValidDomains(): array
{
$this->validDomains = array_unique($this->validDomains);
return $this->validDomains;
}
public function hasValidDomains(): bool
{
return count($this->validDomains) > 0;
}
public function isInContainedInValidDomains(): bool
{
foreach ($this->validDomains as $validDomain) {
if (fnmatch($validDomain, $_SERVER['HTTP_HOST'])) {
return true;
}
}
return false;
}
public function setValidDomains(array $validDomains): Route
{
$this->validDomains = $validDomains;
return $this;
}
private function prefixArgumentKey(string $key)
{
if (0 !== strpos($key, '_')) {

View file

@ -9,7 +9,7 @@ use Slim\App;
class Router
{
/** @var Route[] */
private $routes = [];
private array $routes = [];
private Logger $logger;
private CachePoolChain $cachePoolChain;
private int $cacheTTL = 60;
@ -29,7 +29,8 @@ class Router
});
foreach ($this->routes as $index => $route) {
if (!isset($allocatedRoutes[$route->getHttpMethod().$route->getRouterPattern()])) {
if (($route->isInContainedInValidDomains() || !$route->hasValidDomains())
&& !isset($allocatedRoutes[$route->getHttpMethod().$route->getRouterPattern()])) {
$allocatedRoutes[$route->getHttpMethod().$route->getRouterPattern()] = true;
} else {
unset($this->routes[$index]);
@ -44,7 +45,7 @@ class Router
{
$this->weighRoutes();
if (count($this->routes) > 0) {
foreach ($this->routes as $route) {
foreach ($this->getRoutes() as $route) {
$app = $route->populateRoute($app);
}
}
@ -64,8 +65,6 @@ class Router
*/
public function getRoutes()
{
ksort($this->routes);
return $this->routes;
}