mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
233 lines
7.1 KiB
PHP
233 lines
7.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\CRUD\Routing;
|
|
|
|
use RuntimeException;
|
|
use Symfony\Component\Config\Loader\Loader;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\Routing\Route;
|
|
use Symfony\Component\Routing\RouteCollection;
|
|
|
|
use function array_filter;
|
|
use function array_keys;
|
|
use function array_search;
|
|
use function count;
|
|
use function in_array;
|
|
|
|
use const ARRAY_FILTER_USE_BOTH;
|
|
|
|
class CRUDRoutesLoader extends Loader
|
|
{
|
|
private const ALL_INDEX_METHODS = [Request::METHOD_GET, Request::METHOD_HEAD];
|
|
|
|
private const ALL_SINGLE_METHODS = [
|
|
Request::METHOD_GET,
|
|
Request::METHOD_POST,
|
|
Request::METHOD_PUT,
|
|
Request::METHOD_DELETE,
|
|
];
|
|
|
|
protected array $apiCrudConfig = [];
|
|
|
|
protected array $crudConfig = [];
|
|
|
|
private bool $isLoaded = false;
|
|
|
|
public function __construct(array $crudConfig, array $apiCrudConfig)
|
|
{
|
|
$this->crudConfig = $crudConfig;
|
|
$this->apiCrudConfig = $apiCrudConfig;
|
|
|
|
parent::__construct();
|
|
}
|
|
|
|
/**
|
|
* Load routes for CRUD and CRUD Api.
|
|
*
|
|
* @param mixed $resource
|
|
* @param mixed|null $type
|
|
*/
|
|
public function load($resource, $type = null): RouteCollection
|
|
{
|
|
if (true === $this->isLoaded) {
|
|
throw new RuntimeException('Do not add the "CRUD" loader twice');
|
|
}
|
|
|
|
$collection = new RouteCollection();
|
|
|
|
foreach ($this->crudConfig as $crudConfig) {
|
|
$collection->addCollection($this->loadCrudConfig($crudConfig));
|
|
}
|
|
|
|
foreach ($this->apiCrudConfig as $crudConfig) {
|
|
$collection->addCollection($this->loadApi($crudConfig));
|
|
}
|
|
|
|
return $collection;
|
|
}
|
|
|
|
/**
|
|
* @param mixed $resource
|
|
* @param null $type
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function supports($resource, $type = null)
|
|
{
|
|
return 'CRUD' === $type;
|
|
}
|
|
|
|
/**
|
|
* Load routes for api single.
|
|
*
|
|
* @param $crudConfig
|
|
*/
|
|
protected function loadApi(array $crudConfig): RouteCollection
|
|
{
|
|
$collection = new RouteCollection();
|
|
$controller = 'csapi_' . $crudConfig['name'] . '_controller';
|
|
|
|
foreach ($crudConfig['actions'] as $name => $action) {
|
|
// filter only on single actions
|
|
$singleCollection = $action['single_collection'] ?? '_entity' === $name ? 'single' : null;
|
|
|
|
if ('collection' === $singleCollection) {
|
|
// continue;
|
|
}
|
|
|
|
// compute default action
|
|
switch ($name) {
|
|
case '_entity':
|
|
$controllerAction = 'entityApi';
|
|
|
|
break;
|
|
|
|
case '_index':
|
|
$controllerAction = 'indexApi';
|
|
|
|
break;
|
|
|
|
default:
|
|
$controllerAction = $name . 'Api';
|
|
|
|
break;
|
|
}
|
|
|
|
$defaults = [
|
|
'_controller' => $controller . ':' . ($action['controller_action'] ?? $controllerAction),
|
|
];
|
|
|
|
// path are rewritten
|
|
// if name === 'default', we rewrite it to nothing :-)
|
|
$localName = in_array($name, ['_entity', '_index'], true) ? '' : '/' . $name;
|
|
|
|
if ('collection' === $action['single_collection'] || '_index' === $name) {
|
|
$localPath = $action['path'] ?? $localName . '.{_format}';
|
|
} else {
|
|
$localPath = $action['path'] ?? '/{id}' . $localName . '.{_format}';
|
|
}
|
|
$path = $crudConfig['base_path'] . $localPath;
|
|
|
|
$requirements = $action['requirements'] ?? ['{id}' => '\d+'];
|
|
|
|
$methods = array_keys(array_filter(
|
|
$action['methods'],
|
|
static fn ($value, $key) => $value,
|
|
ARRAY_FILTER_USE_BOTH
|
|
));
|
|
|
|
if (count($methods) === 0) {
|
|
throw new RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", " .
|
|
'does not have any allowed methods. You should remove this action from the config ' .
|
|
'or allow, at least, one method');
|
|
}
|
|
|
|
if ('_entity' === $name && in_array(Request::METHOD_POST, $methods, true)) {
|
|
unset($methods[array_search(Request::METHOD_POST, $methods, true)]);
|
|
$entityPostRoute = $this->createEntityPostRoute(
|
|
$name,
|
|
$crudConfig,
|
|
$action,
|
|
$controller
|
|
);
|
|
$collection->add(
|
|
"chill_api_single_{$crudConfig['name']}_{$name}_create",
|
|
$entityPostRoute
|
|
);
|
|
}
|
|
|
|
if (count($methods) === 0) {
|
|
// the only method was POST,
|
|
// continue to next
|
|
continue;
|
|
}
|
|
|
|
$route = new Route($path, $defaults, $requirements);
|
|
$route->setMethods($methods);
|
|
|
|
$collection->add('chill_api_single_' . $crudConfig['name'] . '_' . $name, $route);
|
|
}
|
|
|
|
return $collection;
|
|
}
|
|
|
|
/**
|
|
* Load routes for CRUD (without api).
|
|
*
|
|
* @param $crudConfig
|
|
*/
|
|
protected function loadCrudConfig($crudConfig): RouteCollection
|
|
{
|
|
$collection = new RouteCollection();
|
|
$controller = 'cscrud_' . $crudConfig['name'] . '_controller';
|
|
|
|
foreach ($crudConfig['actions'] as $name => $action) {
|
|
// defaults (controller name)
|
|
$defaults = [
|
|
'_controller' => $controller . ':' . ($action['controller_action'] ?? $name),
|
|
];
|
|
|
|
if ('index' === $name) {
|
|
$path = '{_locale}' . $crudConfig['base_path'];
|
|
$route = new Route($path, $defaults);
|
|
} elseif ('new' === $name) {
|
|
$path = '{_locale}' . $crudConfig['base_path'] . '/' . $name;
|
|
$route = new Route($path, $defaults);
|
|
} else {
|
|
$path = '{_locale}' . $crudConfig['base_path'] . ($action['path'] ?? '/{id}/' . $name);
|
|
$requirements = $action['requirements'] ?? [
|
|
'{id}' => '\d+',
|
|
];
|
|
$route = new Route($path, $defaults, $requirements);
|
|
}
|
|
|
|
$collection->add('chill_crud_' . $crudConfig['name'] . '_' . $name, $route);
|
|
}
|
|
|
|
return $collection;
|
|
}
|
|
|
|
private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route
|
|
{
|
|
$localPath = $action['path'] . '.{_format}';
|
|
$defaults = [
|
|
'_controller' => $controller . ':' . ($action['controller_action'] ?? 'entityPost'),
|
|
];
|
|
$path = $crudConfig['base_path'] . $localPath;
|
|
$requirements = $action['requirements'] ?? [];
|
|
$route = new Route($path, $defaults, $requirements);
|
|
$route->setMethods([Request::METHOD_POST]);
|
|
|
|
return $route;
|
|
}
|
|
}
|