Pachno routes are defined in controller classes inside modules. Controller classes extends \pachno\core\framework\Action
and are placed in the controllers
namespace inside modules.
You can have as many controller classes as you like, and Pachno will read routes defined in any controller classes present in your modules - whether it's in \pachno\core\modules\module_name\controllers
or \pachno\modules\module_name\controllers
.
Creating a new route
Pachno makes extensive use of annotations throughout the application. For an overview of available annotations and how to use them, see Annotations.
You define new routes by annotating your controller method(s) with @Route
annotations. All routing method names have to start with run
, for example runIndex()
. If you're not returning output (for example file downloads or json responses) directly from the controller method, you should create a matching html template file in the templates/
directory. The template file should have the same name as the route method without the run
prefix, and must be all lowercased.
You can read more about templates and how they work in Templates
<?php
// Example: controller class with a @Route annotated method
namespace \pachno\modules\hello_world\controllers;
class Main extends \pachno\core\framework\Action
{
/**
* @Route(name="index", url="/index")
*/
public function runIndex(\pachno\core\framework\Request $request)
{
}
}
// The method above should have the following template file
// modules/
// hello_world/
// templates/
// index.html.php
The @Route
annotation has the following properties:
Property | Example | Description |
url | url="/index" |
The url pattern for the route. |
name (optional) | name="index" |
If provided, a name for the route. If omitted, the method name without run |
methods (optional) | methods="POST|DELETE" |
If omitted, all request methods will match this route. If provided, a pipe | separated list of allowed methods. If the request method doesn't match a method in this list, the route doesn't match. |
Route url definitions
Pachno urls are relative to the web root and are automatically generated and matched by Pachno. Urls follow a simple pattern and allows for capturing named url parameters via :name
d url parts.
<?php
// Example @Route url definitions
// Basic url
// @Route(url="/boards")
// Capture board_id from the url
// @Route(url="/boards/:board_id")
// In the controller:
$board_id = $request->getParameter('board_id');
// or
$board_id = $request['board_id'];
// Capture board_id and milestone_id from the url
// @Route(url="/boards/:board_id/milestone/:milestone_id")
// In the controller:
$board_id = $request->getParameter('board_id');
$milestone_id = $request->getParameter('milestone_id');
// or
$board_id = $request['board_id'];
$milestone_id = $request['milestone_id'];
Route url or name prefixes
You can prefix all routes within a module or controller by annotating the class with a @Routes
annotation. This lets you specify a url prefix and/or name prefix that applies to all annotated routes in that controller.
<?php
namespace pachno\core\hello_world\publish\controllers;
/**
* @Routes(name_prefix="hello_", url_prefix="/hello")
*/
class Main extends framework\Action
{
/**
* @Route(name="index", url="/index")
*/
public function runIndex(\pachno\core\framework\Request $request)
{
}
}
In the example above, all routes in this controller will have their url prefixed by /hello
, so in this case the full url to the index
page will be /hello/index
- very useful in cases where all routes share a common url namespace.
In addition, the name_prefix
applies to all route names, so the refer to the index
route in this controller, you would refer to hello_index
- useful when you want to prefix all url route names to keep it consistent or related, or when the module name prefix is undesirable.
Using routes
When you have created a route, you don't use the url directly (as this may change), but refer to the route via the name defined in the @Route
annotation (or via @Route
+ @Routes
)
<?php
// Example @Route url definitions and usage
// Basic url
// @Route(url="/boards", name="boards")
// In the controller:
$url = $this->getRouting()->generate('boards');
// or in templates via the template make_url() helper
$url = make_url('boards');
$url = $pachno_routing->generate('boards');
// Urls with named parameters
// @Route(url="/boards/:board_id", name="board")
// In the controller:
$url = $this->getRouting()->generate('board', ['board_id' => $board->getId()]);
// or in templates: via the template make_url() helper or the $pachno_routing template variable
$url = make_url('board', ['board_id' => $board->getId()]);
$url = $pachno_routing->generate('board', ['board_id' => $board->getId()]);
CSRF Protection
Routes can be CSRF protected by adding a @CsrfProtected
annotation to a @Route
annotated method. If the route is @CsrfProtected
Pachno will handle it automatically as long as a :csrf_token
url parameter is present in the url pattern. If not present in the url (for example when posting forms), the csrf token can be retrieved via \pachno\core\framework\Context::getCsrfToken()
and must be passed via a POST
parameter named csrf_token
// Example @Route method with CSRF protection, allowing POST, PUT and DELETE
/**
* @Route(name="post_user", url="/users/:user_id/:csrf_token", methods="POST|PUT|DELETE")
* @CsrfProtected
*/
public function runUpdateUser(\pachno\core\framework\Request $request)
{
}
Specifying additional request parameters
Sometimes you may have a need to specify additional request parameters (such as when using a preExecute()
method for all routes) per route. You can do this by using the @Parameters
annotation on the route.
<?php
// Example route with two specified parameters
/**
* @Route(url="/configure/project/:project_id/mailing", name="configure_settings")
* @Parameters(config_module="core", section=15)
*/
public function runConfigureProjectSettings(\pachno\core\framework\Request $request)
{
echo $request->getParameter('config_module'); // outputs 'core'
}
The parameters listed in the @Parameters
annotation are available on the $request
object in both the following controller methods and the preExecute()
method.
Common handlers and pre execute methods
For route methods that handle more than one entry point - or for routes that share a common request parameter that you may want to retrieve from a database or verify - you can add a preExecute()
method that will run before your route method is executed. Any properties set on the controller will be available to subsequent route methods.
<?php
// Example preExecute() method
public function preExecute(\pachno\core\framework\Request $request)
{
// simplified project lookup
$this->project = Projects::getTable()->selectById($request['project_id']);
if (!$this->project instanceof Project) {
return $this->return404('This project does not exist');
}
}
/**
* @Route(url="/projects/:project_id/mailing", name="configure_mail_settings")
*/
public function runConfigureProjectSettings(\pachno\core\framework\Request $request)
{
echo $this->project->getId(); // echoes the id from the project object set in the preExecute() method
}
Handing off from one route to another
If you want to hand off a request from one route to another, use the internal redirect()
method to move execution to that route instead. This does not send any response to the user, but simply redirects internally and continues execution in the redirected route as if it entered that route originally.
Note: when using this method, the route set in the routing object will still be the original matching route.
<?php
// Example redirecting to another method
/**
* @Route(url="/projects/:project_id/mailing", name="configure_mail_settings")
*/
public function runConfigureProjectMailSettings(\pachno\core\framework\Request $request)
{
return $this->redirect('configureprojectsettings'); // must match the method name redirected to, without the 'run' prefix
}
/**
* @Route(url="/projects/:project_id/settings", name="configure_settings")
*/
public function runConfigureProjectSettings(\pachno\core\framework\Request $request)
{
// this will be executed in both routes
}