Controllers: Programming Application Logic - Part 2 / Page 2 | WebReference

Controllers: Programming Application Logic - Part 2 / Page 2


[prev]

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

  1. Modify the UsersController(/app/controllers/users_controller.php).
  2. Create a view file named welcome.ctp inside the directory /app/views/users/ with the following code:
  3. Now enter the following URL in your browser:
    • http://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 http://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

  1. Create a new file named app_controller.php just inside the /app/ folder with the following code,
  2. Modify the BooksController's ( /app/controllers/books_controller.php) code, replace the if{} block with the controller method strip_and_clean(),
  3. Now visit the following links and see what shows up in the browser:
    • http://localhost/applogic/books/index/0
    • http://localhost/applogic/books/index/1
    • http://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

  1. Create a component class UtilComponent using the following code and save it in a file named util.php under /app/controllers/components/ directory.
  2. Remove the strip_and_clean() method from the AppController (/app/app_controller.php) class.
  3. Modify the BooksController class (/app/controllers/books_controller.php),
  4. Now visit the following links and see what shows up in the browser
    • http://localhost/applogic/books/index/0
    • http://localhost/applogic/books/index/1
    • http://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!

Cover: WordPress for Business Bloggers

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


[prev]