* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Chill\MainBundle\CRUD\Routing; use Symfony\Component\Config\Loader\Loader; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\HttpFoundation\Request; use Chill\MainBundle\CRUD\Controller\ApiController; use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class CRUDRoutesLoader * Load the route for CRUD * * @package Chill\MainBundle\CRUD\Routing */ class CRUDRoutesLoader extends Loader { protected array $crudConfig = []; protected array $apiCrudConfig = []; /** * @var bool */ private $isLoaded = false; private const ALL_SINGLE_METHODS = [ Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_DELETE ]; private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ]; /** * CRUDRoutesLoader constructor. * * @param $crudConfig the config from cruds * @param $apicrudConfig the config from api_crud */ public function __construct(array $crudConfig, array $apiConfig) { $this->crudConfig = $crudConfig; $this->apiConfig = $apiConfig; } /** * @param mixed $resource * @param null $type * @return bool */ public function supports($resource, $type = null) { return 'CRUD' === $type; } /** * Load routes for CRUD and CRUD Api */ 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->apiConfig as $crudConfig) { $collection->addCollection($this->loadApiSingle($crudConfig)); //$collection->addCollection($this->loadApiMulti($crudConfig)); } return $collection; } /** * Load routes for CRUD (without api) * * @param $crudConfig * @return RouteCollection */ protected function loadCrudConfig($crudConfig): RouteCollection { $collection = new RouteCollection(); $controller = $crudConfig['controller'] === CrudController::class ? 'cscrud_'.$crudConfig['name'].'_controller' : $crudConfig['controller']; foreach ($crudConfig['actions'] as $name => $action) { // defaults (controller name) $defaults = [ '_controller' => $controller.':'.($action['controller_action'] ?? $name) ]; if ($name === 'index') { $path = "{_locale}".$crudConfig['base_path']; $route = new Route($path, $defaults); } elseif ($name === 'new') { $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; } /** * Load routes for api single * * @param $crudConfig * @return RouteCollection */ protected function loadApiSingle(array $crudConfig): RouteCollection { $collection = new RouteCollection(); $controller = $crudConfig['controller'] === ApiController::class ? 'cscrud_'.$crudConfig['name'].'_controller' : $crudConfig['controller']; foreach ($crudConfig['actions'] as $name => $action) { // filter only on single actions $singleCollection = $action['single-collection'] ?? $name === '_entity' ? 'single' : NULL; if ('collection' === $singleCollection) { continue; } $defaults = [ '_controller' => $controller.':'.($action['controller_action'] ?? '_entity' === $name ? 'entityApi' : $name.'Api') ]; // path are rewritten // if name === 'default', we rewrite it to nothing :-) $localName = '_entity' === $name ? '' : $name; $localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}'; $path = $crudConfig['base_path'].$localPath; $requirements = $action['requirements'] ?? [ '{id}' => '\d+' ]; $methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; }, ARRAY_FILTER_USE_BOTH)); $route = new Route($path, $defaults, $requirements); $route->setMethods($methods); $collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route); } return $collection; } /** * Load routes for api multi * * @param $crudConfig * @return RouteCollection */ protected function loadApiMultiConfig(array $crudConfig): RouteCollection { $collection = new RouteCollection(); foreach ($crudConfig['actions_multi'] as $name => $action) { // we compute the data from configuration to a local form $defaults = [ '_controller' => 'cscrud_'.$crudConfig['name'].'_controller'.':'.($action['controller_action'] ?? $name.'Api') ]; // path are rewritten // if name === 'index', we rewrite it to nothing :-) $localName = 'index' === $name ? '' : $name; $localPath = $action['path'] ?? '.{_format}'; $path = $crudConfig['base_path'].$localPath.$name; $requirements = $action['requirements'] ?? [ '{id}' => '\d+' ]; $methods = $name === 'default' ? self::ALL_MULTI_METHODS: []; $route = new Route($path, $defaults, $requirements); $collection->add('chill_api_multi'.$crudConfig['name'].'_'.$name, $route); } return $collection; } }