Controllers: Programming Application Logic - Part 2 [con't]
Redirecting
In dynamic web applications, redirects are often used to control the flow of the application and move the user from one page to another. Without redirects, web applications would be scattered pages without any real flow. In usual PHP-based web applications, the PHP function header()
is very commonly used to redirect the user from one page to another. Whereas, CakePHP offers a built-in controller method redirect()
that is used to direct the user from one action to another. Now, without further ado, let's see how to redirect in CakePHP!
Time for Action: Redirecting from One Action to Another
- Modify the UsersController(
/app/controllers/users_controller.php
). - Create a view file named
welcome.ctp
inside the directory/app/views/users/
with the following code: - Now enter the following URL in your browser:
https://localhost/applogic/users/
What Just Happened?
In the index()
action of the UsersController, we changed the code inside the if{}
block. Instead of printing out the name submitted from the form, we redirected the user to another action using the following line of code:
The redirect()
method is pretty easy to use. The first parameter is an associative array. We specified the controller and action name (where we want to redirect) there through controller and action keys. Also, additional request parameters can be supplied by appending new elements in this array. When the form is submitted, we redirected the user to the UsersController's welcome()
action. We also appended the user's name in the URL as a request parameter. We got the name from the $data
controller attribute and used the PHP function urlencode()
to make that input URL-friendly.
redirect()
by default exits just after the execution. So, codes after the redirect()
call do not execute, we can though set the third parameter to true while calling the redirect()
method to avoid the force exit.
Now, let's have a look at the welcome()
action. This action takes an optional parameter $name
. Inside this action, we first checked if any request parameter is supplied. If no parameter is specified, we set a flash message and then sent back the user to the index()
action of the UsersController using the redirect()
method.
See, this time while calling the redirect()
method, we only set the action key in the parameter. When the controller key is not set, the redirect()
method redirects to the current controller's action.
If the request parameter $name is provided, it will ignore the if{}
block and pass the URL-decoded name to the view as $name variable.
In the view file, we simply welcomed the user by displaying a 'Welcome,' text before the user's name.
Now, if we visit the URL https://localhost/applogic/users/
and enter a name there, it should redirect us to the welcome action and show us a greeting message.
AppController: The Parent Controller
From Object Oriented perspective, every CakePHP controller is a subclass of the AppController
class. Recall how we start the class definition of a controller—look at the following line of code as an example:
Our controllers extend the AppController
class—this means we set the AppController
class as the parent class of all of our controllers. As of now, it seems alright. But the next question that quickly pops up in our mind is: where is that AppController
class located? Well, it can be found inside the app_controller.php
file under the /cake/libs/controller/
directory. This app_controller.php
is actually a placeholder file and can be overridden by our own one.
The main benefit of having our own AppController
class is we can put in common application-wide methods inside this class and all of our controllers will just inherit them. We can use attributes and methods defined inside the AppController
from any of our controller class. We will now see how to create our own AppController
class and how we can make use of the methods written inside the AppController
from a controller class.
Time for Action: Adding Common Functionalities to all Controllers
- Create a new file named
app_controller.php
just inside the/app/
folder with the following code, - Modify the
BooksController
's (/app/controllers/books_controller.php
) code, replace theif{}
block with the controller methodstrip_and_clean()
, - Now visit the following links and see what shows up in the browser:
https://localhost/applogic/books/index/0
https://localhost/applogic/books/index/1
https://localhost/applogic/books/index/xyz
What Just Happened?
We first wrote a class named AppController
and saved it as app_controller.php
inside the /app/
folder.
Inside this class, we wrote a method named strip_and_clean()
. This method takes two parameters -$id
and $array
.
The strip_and_clean()
method simply returns $id
, if $id
is a non-negative integer and $id
is less than the length of $array
. Otherwise it returns a 0
.
Previously, we did this checking inside the BooksController
. And now we have moved this particular code to the AppController
method strip_and_clean()
. As all of our controllers inherit the AppController
class, we can now use this particular routine from any of them.
In BooksController
, we replaced the if{}
block with the strip_and_clean()
method.
$id
and $books
variables are passed to this method as parameters. And the returned result of the method is then stored back to $id
. Now, if the request parameter $id
is invalid, it will make it to 0. And the /books/index/
action will show us the information about the first book defined in $array.
The new approach is better only when we have some common application wide methods. In those cases, we can just write them inside the AppController
class and call them from any of our controllers. But we also have to remember that writing methods inside the AppController
is not always the best way. There may be other controllers that do not require those methods (like we have UsersController
, which does not need the strip_and_clean()
method) but still will inherit them.
The better approach is to load codes on demand, load the methods only where it is required. Moreover, writing methods inside the AppController
does not increase reusability outside the application—it just increases application-specific and application-wide reusability. We just cannot reuse the methods written inside the AppController
for one application in any other application directly. If we want to write reusable codes and follow the DRY (Don't Repeat Yourself) principle, it is always better to write our methods in separate classes and load them only from the controllers that require those methods.
CakePHP also provides a way for writing and using reusable classes. In CakePHP, they are called components. In the next section, we will work with CakePHP components and see how it can increase reusability.
Working with Components
Components are reusable classes that can be used from any controller in CakePHP applications. By definition, components are only limited to be used from and inside controllers and its other components. They are used to help controllers with a goal of reusability—we can just port the component classes to any of our Cake applications and use them in those applications. CakePHP ships with some useful components, like AuthComponent, SessionCompoenent, etc. We will learn about them in Chapter 10. Now, let's see how to create our own custom component and use them from a controller.
Time for action: Creating and Using Reusable Components
- Create a component class
UtilComponent
using the following code and save it in a file namedutil.php
under/app/controllers/components/
directory. - Remove the
strip_and_clean()
method from theAppController
(/app/app_controller.php
) class. - Modify the
BooksController
class (/app/controllers/books_controller.php
), - Now visit the following links and see what shows up in the browser
https://localhost/applogic/books/index/0
https://localhost/applogic/books/index/1
https://localhost/applogic/books/index/xyz
What Just Happened?
At first, we created a component class named UtilComponent
and saved it in a file named util.php
under the /app/controllers/components/
folder. We then moved (cut-pasted) the strip_and_clean()
method from the AppController
to the UtilComponent
.
The class name of a component should always have a Component
postfix. Every component class file should be placed under the /app/controllers/components/
directory. The filenames should be named after the lowercased class name of the component (without the Component
postfix).
Now, to use this UtilComponent
from our BooksController
, we have to add this component to the controller. It can be done through the controller attribute $components
. $components
holds an array of all the component names that we want to make available inside the controller. In our case, as we want to load only the Util
component, we defined the $components
array like the following:
Notice, the component name used in the $components
array is Util
(without the Component
postfix) not UtilComponent
.
Once loaded, the UtilComponent
class can be referred and used from the controller. Now instead of using the strip_and_clean()
method of the AppController
, we called the UtilComponent
's method strip_and_clean()
.
Everything else in the controller remains unchanged. And it will work, as it was working before. The only difference is, now we have a more reusable code that can be used from any controller or any other application when needed.
Summary
A controller is used to manage the application logic. It controls the application flow and works as a bridge between the model and the view. CakePHP applications use a common format for the URL. From the URL, Cake finds out the appropriate controller action to invoke to handle a particular browser request. Request parameters can be appended to the URL and can be accessed from the actions. Controller can load a model class to interact with the database. By default, CakePHP finds out the related model class from the controller name. We can though override the default and tell the controller to load other model classes using the $uses
attribute. Every controller action usually renders a view file to send formatted response to the browser. CakePHP has some conventions for saving and naming view files so that they can be loaded and rendered automatically. We can though skip the view rendering by setting controller attribute $autorender to false. Controller method set()
is very commonly used to pass data to the relevant view file. Redirection is an established method to forward a user from one action to another and in CakePHP it is done using the method redirect()
. In Cake, all controllers are subclasses of the AppController
class. Methods defined inside the AppController
class that can be called from different controllers. In CakePHP applications, common controller functionalities are written inside components to increase reusability.
Well, that's the end of the controller story. Now, get prepared for the next chapter which is about CakePHP models. We will learn lots of cool stuffs there!
This chapter is an excerpt from the book, CakePHP Application Development by Ahsanul Bari, Anupom Syam, published by Packt Publishing Ltd, July 2008, ISBN 1847193897, Copyright 2008 Packt Publishing Ltd
Original: October 6, 2008