How to pass SensioLabs Insight route check when using SonataAdminBundle
One of the rules SensioLabs Insight checks for is:
A route should always have a valid HTTP method
This will always fail when you use the SonataAdminBundle, because there is no way to set the methods in all routes generated by the admin classes. You can show them with the following command:
$ php app/console router:debug
Which will output those routes:
...
Name Method Scheme Host Path
admin_company_backend_user_list ANY ANY ANY /admin/company/backend/user/list
admin_company_backend_user_create ANY ANY ANY /admin/company/backend/user/create
admin_company_backend_user_batch ANY ANY ANY /admin/company/backend/user/batch
admin_company_backend_user_edit ANY ANY ANY /admin/company/backend/user/{id}/edit
admin_company_backend_user_delete ANY ANY ANY /admin/company/backend/user/{id}/delete
admin_company_backend_user_show ANY ANY ANY /admin/company/backend/user/{id}/show
admin_company_backend_user_custom_action ANY ANY ANY /admin/company/backend/user/{id}/custom-action
...
When you dive into the code of the bundle you're going to see why. The method where they build the routes only offers 4 of the 8 available parameters of the Route
class:
$this->elements[$this->getCode($name)] = function() use ($pattern, $defaults, $requirements, $options) {
return new Route($pattern, $defaults, $requirements, $options);
};
They don't implement $host
, $schemes
, $methods
and $condition
of the Route
constructor:
public function __construct(
$path,
array $defaults = array(),
array $requirements = array(),
array $options = array(),
$host = '',
$schemes = array(),
$methods = array(),
$condition = '')
{
So there is no way to add it to any kind of configuration, because they didn't even consider it within the system.
But I still found a way to implement it. I build my own Admin
class which extends from Sonata\AdminBundle\Admin\Admin
. All my admin classes now extend of it instead of the Sonata Admin class. As part of this class I build a little helper function which adds the methods ["GET", "PUT", "POST", "DELETE"]
to all default routes and whichever you like to your custom ones.
<?php
namespace Company\Bundle\AdminBundle\Admin;
use Sonata\AdminBundle\Admin\Admin as SonataAdmin;
use Sonata\AdminBundle\Route\RouteCollection;
use Symfony\Component\Routing\Route;
/**
* Class Admin
*
* @package Company\Bundle\AdminBundle\Admin
*/
class Admin extends SonataAdmin
{
/**
* Configure routes
*
* @param RouteCollection $collection Route collection
* @param array $customMethods Custom methods
* [
* 'code' => ['GET', 'POST', ..],
* ..
* ]
*/
protected function configureRouteMethods(RouteCollection $collection, array $customMethods = [])
{
/** @var Route $route */
foreach($collection->getElements() as $code => $route) {
if(in_array($code, array_keys($customMethods))) {
$route->setMethods($customMethods[$code]);
} else {
$route->setMethods(["GET", "PUT", "POST", "DELETE"]);
}
}
}
}
Then in my admin classes I overwrite configureRoutes
and call configureRouteMethods
(after I added my own custom methods).
/**
* Configure routes
*
* @param RouteCollection $collection Route collection
*/
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('custom_action', $this->getRouterIdParameter().'/custom-action');
$customMethods = [
$collection->getCode('custom_action') => ['GET', 'DELETE']
];
$this->configureRouteMethods($collection, $customMethods);
}
After the integration it will look like this:
...
Name Method Scheme Host Path
admin_company_backend_user_list GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/list
admin_company_backend_user_create GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/create
admin_company_backend_user_batch GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/batch
admin_company_backend_user_edit GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/{id}/edit
admin_company_backend_user_delete GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/{id}/delete
admin_company_backend_user_show GET|PUT|POST|DELETE ANY ANY /admin/company/backend/user/{id}/show
admin_company_backend_user_custom_action GET|DELETE ANY ANY /admin/company/backend/user/{id}/custom-action
...
And that way you will pass the check.