Chapter 18. Frameworks

An application framework is a set of functions, classes, and conventions that make it easier to accomplish common tasks. Lots of programming languages have popular frameworks, and PHP is no exception. This chapter provides an overview of three popular PHP frameworks. These frameworks speed your journey from nothing to a functioning web application.

Frameworks aimed at web development generally provide standard ways to accomplish at least the following tasks:

Routing
Translating user-requested URLs to specific methods or functions that are responsible for generating a response
Object-relational mapping
Letting you treat rows in your database as objects in your code and providing methods on those objects that modify the database
User management
Standard mechanisms for maintaining information about your app’s users and deciding which users have permission to do which operations

By using a framework, you save time compared to implementing all of the framework’s functionality yourself. You may also be able to jump-start new developers coming to work with you if they are familiar with the framework. The trade-off is that you must invest time in learning the framework and adapting to its conventions of how to accomplish things.

The three frameworks explored in this chapter are Laravel, Symfony, and Zend Framework. Each provides a very different kind of solution to the “framework” question. They differ in how they are installed, what their documentation explains, how they balance simplicity and capability, and what you do to find more information when you’re stumped.

There are many other PHP frameworks out there. The three in this chapter are included because they are some of the most popular and most capable, but the exclusion of other frameworks should not be taken as an injunction against trying something else. The Internet abounds with guides that attempt to answer the question “What PHP framework should I use?” For up-to-date information, check out the PHP Frameworks topic on Quora or search for php framework on Hacker News or SitePoint.

Laravel

Laravel’s creator describes it as a framework for people who value “elegance, simplicity, and readability.” It has well-thought-out documentation, a vibrant ecosystem of users, and available hosting providers and tutorials.

To install Laravel, run the command php composer.phar global require laravel/installer=~1.1". Then, to create a new web project that uses Laravel, run laravel new project-name,1 substituting your project name for project-name. For example, running laravel new menu creates a directory called menu and populates it with the necessary code and configuration scaffolding for Laravel to work properly.

To see the scaffolding in action, fire up the built-in PHP web server by pointing it at server.php in your project directory. For example, php -S localhost:8000 -t menu2/public menu/server.php lets you access the new Laravel project in the menu subdirectory at http://localhost:8000.

Laravel’s routing is controlled by the code in app/Http/routes.php. Each call to a static method in the Route class tells Laravel what to do when an HTTP request comes in with a certain method and URL path. The code in Example 18-1 tells Laravel to respond to a GET request for /show.

Example 18-1. Adding a Laravel route
Route::get('/show', function() {
    $now = new DateTime();
    $items = [ "Fried Potatoes", "Boiled Potatoes", "Baked Potatoes" ];
    return view('show-menu', [ 'when' => $now,
                               'what' => $items ]);
});

In Example 18-1, the call to Route::get() tells Laravel that it should be responding to HTTP GET (not POST) requests, and the first argument of /show tells Laravel that this Route::get() call provides information on what to do when the URL /show is visited. The second argument to Route::get() is the function that Laravel runs to compute the response to GET /show. This function sets up two variables, $now and $items, and then passes them to the show-menu view as keys when and what.

A view is a template that contains presentation logic—what your application should display. The view() function in Laravel looks for a file in a predefined location and then runs the PHP code in that file to generate a response. The call to view('show-menu') tells Laravel to look for a file named show-menu.php in the resources/views directory. Example 18-2 contains the code for this view.

Example 18-2. A Laravel view
<p> At <?php echo $when->format('g:i a') ?>, here is what's available: </p>
<ul>
<?php foreach ($what as $item) { ?>
<li><?php echo $item ?></li>
<?php } ?>
</ul>

The view is just plain PHP. Any data coming from an external source such as a user or database should be properly escaped to prevent cross-site scripting problems, as discussed in “HTML and JavaScript”. Laravel includes support for the Blade templating engine, which makes many things easier, including escaping output by default.

Symfony

Symfony describes itself as both a set of reusable components and a framework for web projects. This means that even if you don’t use its framework for request routing or other web-related tasks, you can still use its individual components for tasks such as templating, managing configuration files, or debugging.

Like Laravel, Symfony has a command-line program used to create and manage projects. Install the symfony program and rename the downloaded installer file to symfony. Move it into a directory in your system path. On Linux or OS X, make the symfony program executable by typing chmod a+x /path/to/symfony (where /path/to/symfony is the full path of the place you’ve put the symfony program).

Then, to create a new web project that uses Symfony, run symfony new project-name, substituting your project name for project-name. For example, running the command symfony new menu creates a directory called menu and populates it with the code and configuration scaffolding necessary for Symfony to work properly.

Symfony includes some glue that makes it easy to run your project in PHP’s built-in web server. Just change your current directory to your project directory (e.g., cd menu) and then run php app/console server:run. Then visit http://localhost:8000/ in your web browser, and you’ll see a “Welcome to Symfony” page complete with lots of interesting diagnostic information at the bottom.

With Symfony, routes are not specified in one central place. Instead, individual classes in the src/AppBundle/Controller directory define the methods that are triggered by the routes that the app handles. A special annotation in a comment next to a method indicates what route the method handles. Example 18-3 defines a handler for a GET /show request. Put it in MenuController.php in src/AppBundle/Controllers.

Example 18-3. Specifying a route with Symfony
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;

class MenuController extends Controller
{
    /**
     * @Route("/show")
     * @Method("GET")
     */
    public function showAction()
    {
        $now = new \DateTime();
        $items = [ "Fried Potatoes", "Boiled Potatoes", "Baked Potatoes" ];

        return $this->render("show-menu.html.twig",
                             [ 'when' => $now,
                               'what' => $items ]);
    }
}

In Example 18-3, the items in the comment before the showAction() method indicate the route that showAction() handles: URL path /show with method GET. The render() method returns a Symfony data structure that holds the contents of the response. Its first argument is the name of a view template file to use, and the second argument is data to pass to the template. It is possible to use plain PHP as a template language with Symfony, but its default setup is to use the Twig templating engine, so that’s what’s specified here.

Symfony’s view directory is app/Resources/views. This means that passing show-menu.html.twig to render() tells Symfony to look for app/Resources/views/show-menu.html.twig in your project directory. Save the contents of Example 18-4 in that place.

Example 18-4. Defining a Symfony view
{% extends 'base.html.twig' %}

{% block body %}
<p> At {{ when|date("g:i a") }}, here is what's available: </p>
<ul>
{% for item in what %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endblock %}

In Twig, {% %} indicates a templating language command and {{ }} indicates a variable whose value (with proper HTML escaping) should be included in the output. Its syntax may take some getting used to, but Twig is a powerful and speedy templating language.

Zend Framework

More so than the other two frameworks reviewed in this chapter, Zend Framework takes a “collection of components” approach. While this makes it easy to drop a component or two into an existing project without conforming to a particular file structure or request routing convention, it also means starting from scratch is a little more complicated.

To install a Zend Framework “skeleton” app into the menu directory that contains the basics necessary to get up and running, run the following Composer command all on one line:

composer create-project --no-interaction --stability="dev" 
zendframework/skeleton-application menu

Then, to make the built-in PHP web server serve up your new Zend Framework application, change into the project directory and run php -S localhost:8000 -t public/ public/index.php. Visit http://localhost:8000 to see the default front page of your new application.

Zend Framework organizes related application code into modules. In a big application, you can create separate modules for separate high-level parts of your program. For this small sample application, we’ll add code to the base Application module that’s already there. This module contains some default routing logic that maps paths under /Application to code in controller classes in a specific place in the filesystem. Example 18-5 shows a new MenuController.php. Save it in the module/Application/src/Application/Controller directory of your Zend Framework project.

Example 18-5. A Zend Framework controller
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class MenuController extends AbstractActionController
{
    public function showAction()
    {
        $now = new \DateTime();
        $items = [ "Fried Potatoes", "Boiled Potatoes", "Baked Potatoes" ];

        return new ViewModel(array('when' => $now, 'what' => $items));
    }
}

Then, to tell the framework about your new class, find the section of module/Application/config/module.config.php that looks like this:

'controllers' => array(
        'invokables' => array(
            'Application\Controller\Index' => 
            'Application\Controller\IndexController'
        ),
    ),

And add this line as a second element in the invokables array:

'Application\Controller\Menu' => 'Application\Controller\MenuController'

Don’t forget to add a comma after 'Application\Controller\IndexController' so that the array elements have the proper syntax. When you’re done, this section of the config file should look like this:

'controllers' => array(
        'invokables' => array(
            'Application\Controller\Index' => 
            'Application\Controller\IndexController',
            'Application\Controller\Menu' => 
            'Application\Controller\MenuController'
        ),
    ),

Now you’ve got a new controller and the framework knows how to use it. The last step is to add a view so the time and items information can be rendered. With Zend Framework, the default template language is just plain PHP. Save the code in Example 18-6 in module/Application/view/application/menu/show.phtml under your project directory.

Example 18-6. A Zend Framework view
<p> At <?php echo $when->format("g:i a") ?>, here is what's available: </p>
<ul>
<?php foreach ($what as $item) { ?>
<li><?php echo $this->escapeHtml($item) ?></li>
<?php } ?>
</ul>

The keys in the array passed to new ViewModel() in the controller are local variable names in the view. This makes accessing these values very straightforward. However, because the template language is plain PHP, HTML entities and other special characters are not escaped by default. Example 18-6 uses the escapeHtml() helper method to escape special characters in each item name.

Chapter Summary

This chapter covered:

  • Understanding what an application framework is and why you might want to use one
  • Installing Laravel
  • Creating a new Laravel project
  • Adding a route with Laravel
  • Adding a view for a route with Laravel
  • Installing Symfony
  • Creating a new Symfony project
  • Adding a route with Symfony
  • Adding a view for a route with Symfony
  • Installing Zend Framework
  • Creating a new Zend Framework project
  • Adding a route with Zend Framework
  • Adding a view for a route with Zend Framework

1 This requires that the global composer binary directory be in your system’s $PATH. See “Running a PHP REPL” for more information.