Routing, Controllers, and Views
This tutorial shows how to link URLs to your content.
Defining a route
In Gyro, every possible URL must be defined, using so-called routes. Routes map URLs invoked by the user to functions in your PHP code. These functions are called “actions”.
Routes are defined on Controller-classes. Controllers are created directly in the directory
controllers right beneath your application directory.
The file name is of form
[name].controller.php and contains a class named
[Name]Controller. This class is called a controller class.
Note the lower- and uppercase variants of [name], this is important. The controller class must inherit from class
Each route is constructed with
- an URL to map
- a controller instance responsible for handling the call
- the name of the action to invoke
- an optional array of parameters to specialize things like caching, or access control checking for this special route
Note you don’t pass the name of a function to be called as third parameter, but the name of an action. The function itself must be called
action_[name of action].
Unless some other popular PHP frameworks, the mapping of URLs to PHP code to call is not done automatically. This is: Just dropping functions on a controller will do nothing. You always must declare a route.
Let’s jump right into the code to get things clear. As example we create a
PlaygroundController which should show a little message when URL
/playground/ is invoked.
Frist, create a file
/app/controller/playground.controller.php and type in the following code :
Second, create a file
/app/view/templates/default/playground/index.tpl.php containing the following code:
Let’s step through the code, to see what’s going on there.
First, the class
ExactMatchRoute defines a route that requires the URL invoked to be exactly like the one defined as the
first parameter -
playground/ in this case. Some more complex routes will be discussed later. Second, the route
will delegate to the action named
playground_index on the controller
PlaygroundController, since we passed
$this as instance.
Due to the Gyro naming conventions, the action maps to the function passed as first parameter.
PageData is used to allow
easy communication between different layers of an application, without coupling them too tight. The action
in our example doesn’t do much except of creating a view and delegating rendering too it.
PageData as a response object. Indeed nowadays I would have called it
Views and templates
Views are created using the
ViewFactory. Since we are dealing with the content of a page here, we tell the factory to
create a content view by passing
IViewFactory::CONTENT as type. The second parameter defines the template and
the third are parameters , which depend on the view type. A content view requires a
PageData instance to be passed.
The template name passed is mapped to a template file on the file system. Template files are located in
view/templates/[language]/ and must end with
.tpl.php. Gyro will look up templates in the following order:
- Application’s template directory of current locale:
- Application’s default template directory:
- Module’s template directory of current locale:
- Module’s default template directory:
- Core’s template directory of current locale:
- Core’s default template directory:
The modules are reverse iterated in the order they were loaded, so the module loaded last is checked first, and the module loaded first is checked last. This allows overloading templates of one module by another. For each module localized templates and default templates are checked before stepping to the next.
Within a content view template, the
PageData instance is available as
$page_data, and it can be used to set the
title for the document we create, along with the meta description. As you can see in the example, we can set the breadcrumb, too.
View templates can be seen as HTML files containing PHP code. That’s in the example above we can simply write some HTML
<p>. If you need to execute php code, you must wrap in
The = ?> short tags
Gyro also allows you to use the short form
<?= ?> to just output something using HTML escaping. This was introduced for convenience and to make templates easier to overlook.
It was inspired by the idea, that most people avoid typing to much, which makes them use
Additionally, template people may not be so much into PHP they even know how to correctly use
htmlentities() at all.
Using Gyro they now have an even shorter but safe way of saying “print”:
Note that if you explicitly want to output HTML code, you need to use
<?php print ...; ?>, since
<?= ?> translates
brackets to their HTML entities, so
< will become
> will become
By the way: Rather than using
htmlentities(), you should use the Gyrp helper function
String::escape(). It is always available and acts charset aware.
Parameterized Routes: Flexible and typesafe
It was mentioned above that there are more advanced routes than
ExactMatchRoute. The one probably used the most is
ParameterizedRoute, which can be configured to contain arbitrary, yet type checked parameters.
Let’s have a look into the code right away, to see how
ParameterizedRoute is used.
Parameters on a
ParameterizedRoute are declared using curly brackets like this:
The following types are supported:
ui: unsigned integer
ui>: integer greater than 0
s: string (default). You can specify a length like so:
s:2- String of two ANSI characters
e: enum. Usage is
In the above example a route was defined that takes a name, and an age, where the age must be a positive integer.
ParameterizedRoute type checks the URL, and would return a
404 Not Found if type check fails.
The follwoing URLs would be successfull:
The following URLs would cause errors:
ParameterizedRoute does the type checking, you can rely on the data passed.
$age of the function
action_playground_enter() is ensured to be an unsigned integer greater than zero.
Passing parameters to views
As you may have noticed in above example, we can pass variables to the view using the method assign().
The variables are accessible in the view using the name you passed as first parameter. To demonstrate this, we will
complete our example with the according view for
playground_enter. Place the following code at
$age are used on the view.
Secured sites using https
You may declare a route to use
https by prefixing it with
https:// like so:
This of course works with every route, not only for ExactMatchRoute.
Gyro will force the route to use a secured connection. If a user navigates to the URL using the
she will be redirected to
You can disable secure routes completely by setting the constant
APP_ENABLE_HTTPS to false. All routes declared with
https:// then will be treated as normal, non-secure routes.
Referencing existing routes: action mapping
Mapping a URL to an action is one thing. Gyro also allows you to map an action to an URL. This can be done using the
ActionMapper class has two important static function:
get_url() always returns an absolute URL.
get_path() on the other returns a relative URL in the form
of an absolute path (like
/playground), unless the route has another scheme (e.g. https), in which case it will return an absolute URL, too.
Mapping actions to URL allows to change application’s URLs later on without having to change code - except the route, of course.
Both function take two parameters:
action: The name of an action.
params: Additional paramters
The simplest case is to retrieve the URL for an ExactMatchRoute. We only pass the action name:
For parameterized routes we can pass an associative array with parameter names as keys:
Instead of an array, you may also pass an object, in this case
ActionMapper reads the object’s properties.
If you pass an
IDataObject, you may also use a short form for the action. Gyro will try to prefix the action with the model name:
On top of the
WidgetActionLink. It will return a HTML anchor tag for an action’s URL.
WidgetActionLink always uses the get_path function on
We already saw an example for that:
The first parameter is the text for the anchor, the second the action, and the optional third the parameters for the route. The above code will return
If you pass an instance implementing
ISelfDescribing as first parameter, the widget will use
get_title() to retrieve the anchor’s text, escape, and output it. This makes it possible to invoke the widget like this:
The above is equivalent to