Keeper routes are accessible via global Spiral\Router\RouterInterface. You can register them directly in the router
or via the keeper bootloader and annotations. The last options allow you to isolate all the routes in the given namespace.
GuardInterceptor is added to the KeeperCore by default, use @GuardNamespace and @Guarded to create a permission.
If @Guarded annotation is missed, KeeperCore will protect a method using namespace.controller.method permission
as a fallback.
New route should be declared after the parent::boot() call. Controllers must be declared before the route declaration:
use Spiral\Boot\BootloadManager;
use Spiral\Keeper\Bootloader;
use Spiral\Router\RouterInterface;
class AdminBootloader extends Bootloader\KeeperBootloader
{
protected const NAMESPACE = 'admin';
protected const PREFIX = '/admin';
public function boot(BootloadManager $bootloadManager, RouterInterface $appRouter): void
{
parent::boot($bootloadManager, $appRouter);
// Controllers are used via aliases
$this->addController('user', 'App\Admin\Controller\User');
$this->addRoute('/users/new', 'user', 'new', ['GET'], 'createUser');
}
}
The next routes will be created (see php app.php route:list output):
+-------------------+--------+------------------+---------------------------------- +
| Name: | Verbs: | Pattern: | Target: |
+-------------------+--------+------------------+---------------------------------- +
| admin[createUser] | POST | /admin/users/new | App\Admin\Controller\User->create |
| admin[user.new] | GET | /admin/users/new | user->new |
+-------------------+--------+------------------+---------------------------------- +
Note
Routes will be duplicated by a generated name likecontroller.method.
Attributes are a more convenient way because annotated routes allows you to use sitemaps - another powerful submodule for building menu navigation and breadcrumbs.
\Spiral\Keeper\Annotation\Action and \Spiral\Keeper\Annotation\Controller attributes are available. They should be
used together.
Controller defines:
namespace (optional, keeper by default)name/alias (required)prefix (optional), used for all actions within the controllerdefaultAction (optional)Action works pretty much the same as a basic Route annotation from the framework annotated routes. It defines:
route pattern (required)name (optional, controller.action will be used as a fallback)methods (optional)defaults (optional)group (not used for now)middleware (optional)Example:
use Spiral\Keeper\Annotation\Action;
use Spiral\Keeper\Annotation\Controller;
use Spiral\Views\ViewsInterface;
#[Controller(namespace: "admin", name: "user", prefix: "/users")]
class User
{
#[Action(route: "/create", name: "createUser", methods: "GET")]
public function create(ViewsInterface $views): string
{
return $views->render('admin:users/create');
}
}
The next routes will be created (see php app.php route:list output):
+--------------------+--------+---------------------+--------------+
| Name: | Verbs: | Pattern: | Target: |
+--------------------+--------+---------------------+--------------+
| admin[createUser] | GET | /admin/users/create | user->create |
| admin[user.create] | GET | /admin/users/create | user->create |
+--------------------+--------+---------------------+--------------+
Note
Routes will be duplicated by a generated name likecontroller.method.
You can either call a route by its name directly or using a RouteBuilder
/**
* @var \Spiral\Router\RouterInterface $router
* @var \Spiral\Keeper\Helper\RouteBuilder $routeBuilder
*/
$router->uri('admin[user.create]');
$routeBuilder->uri('admin', 'user.create');
The output will be the same: /admin/users/new
Note
RouteBuildertakes care about namespace isolation pattern.
To enable default controller routing, it should be added explicitly to the config.
Either via KeeperBootloader::DEFAULT_CONTROLLER value or via config file:
return [
'routeDefaults' => ['controller' => 'App\Admin\Controller'],
];
Default controller action can be also defined either in the config:
return [
'routeDefaults' => ['controller' => 'App\Admin\Controller', 'action' => 'list'],
];
or via defaultAction property in @Controller annotation.
Note
For default controllerindexmethod will be used as a fallback if nodefaultActionprovided in the default controller annotation.