Chapter 3. Scratching the Surface of Zend Framework 2

In this chapter, we will focus on the basic elements of Zend Framework 2. You will get an in-depth look at the components involved on a simple request/response operation and this knowledge will be used and expanded on throughout the book. After that we will review how the welcome page is loaded.

By the end of this chapter, you will know the lifecycle of a request and how to interact with the different components of the framework to produce some output.

Bootstrap your app

There are two ways to bootstrap your ZF2 app. The default is less flexible but handles the entire configuration, and the manual is really flexible but you have to take care of everything.

The goal of the bootstrap is to provide to the application, ZendMvcApplication, with all the components and dependencies needed to successfully handle a request. A Zend Framework 2 application relies on the following six components:

  • Configuration array
  • ServiceManager instance
  • EventManager instance
  • ModuleManager instance
  • Request object
  • Response object

As these are the pillars of a ZF2 application, we will take a look at how these components are configured to bootstrap the app.

To begin with, we will see how the components interact from a high perspective and then we will jump into details of how each one works. When a new request arrives to our application, ZF2 needs to set up the environment to be able to fulfill it. This process implies reading configuration files and creating the required objects and services; attach them to the events that are going to be used and finally create the request object based on the request data.

Once we have the request object, ZF2 will tell the router to do his job and will inspect the request object to determine who is responsible for processing the data.

Once a controller and action has been identified as the one in charge of the request, ZF2 dispatches it and gives the controller/action the control of the program in order to execute the code that will interpret the request and will do something with it. This can be from accepting an uploaded image to showing a sign-up form and also changing data on an external database.

When the controller processes the data, sometimes a view object is generated to encapsulate the data that we should send to the client who made the request, and a response object is created.

After we have a response object, ZF2 sends it to the browser and the request ends.

Now that we have seen a very simple overview of the lifecycle of a request we will jump into the details of how each object works, the options available and some examples of each one.

Configuration array

Let's dissect the first component of the list by taking a look at the index.php file:

chdir(dirname(__DIR__));

// Setup autoloading
require 'init_autoloader.php';

// Run the application!
ZendMvcApplication::init(require 'config/application.config.php')->run();

As you can see we only do three things. The first thing is we change the current folder for the convenience of making everything relative to the root folder. Then we require the autoloader file; we will examine this file later. Finally, we initialize a ZendMvcApplication object by passing a configuration file and only then does the run method get called.

The configuration file looks like the following code snippet:

return array(
    'modules' => array(
        'Application',
    ),
    'module_listener_options' => array(
        'config_glob_paths'    => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
        'module_paths' => array(
            './module',
            './vendor',
        ),
    ),
);

This file will return an array containing the configuration options for the application. Two options are used: modules and module_listener_options. As ZF2 uses a module organization approach, we should add the modules that we want to use on the application here. The second option we are using is passed as configuration to the ModuleManager object. The config_glob_path array is used when scanning the folders in search of config files and the module_paths array is used to tell ModuleManager a set of paths where the module resides.

Note

ZF2 uses a module approach to organize files. A module can contain almost anything, simple PHP files, view scripts, images, CSS, JavaScript, and so on. This approach will allow us to build reusable blocks of functionality and we will adhere to this while developing our project.

PSR-0 and autoloaders

Before continuing with the key components, let's take a closer look at the init_autoloader.php file used in the index.php file. As is stated on the first block comment, this file is more complicated than it's supposed to be. This is because ZF2 will try to set up different loading mechanisms and configurations.

if (file_exists('vendor/autoload.php')) {
    $loader = include 'vendor/autoload.php';
}

The first thing is to check if there is an autoload.php file inside the vendor folder; if it's found, we will load it. This is because the user might be using composer, in which case composer will provide a PSR-0 class loader. Also, this will register the namespaces defined by composer on the loader.

Note

PSR-0 is an autoloading standard proposed by the PHP Framework Interop Group (http://www.php-fig.org/) that describes the mandatory requirements for autoloader interoperability between frameworks. Zend Framework 2 is one of the projects that adheres to it.

if (getenv('ZF2_PATH')) {
    $zf2Path = getenv('ZF2_PATH'),
} elseif (get_cfg_var('zf2_path')) {
    $zf2Path = get_cfg_var('zf2_path'),
} elseif (is_dir('vendor/ZF2/library')) {
    $zf2Path = 'vendor/ZF2/library';
}

In the next section we will try to get the path of the ZF2 files from different sources. We will first try to get it from the environment, if not, we'll try from a directive value in the php.ini file. Finally, if the previous methods fail the code, we will try to check whether a specific folder exists inside the vendor folder.

if ($zf2Path) {
    if (isset($loader)) {
        $loader->add('Zend', $zf2Path);
    } else {
        include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
        ZendLoaderAutoloaderFactory::factory(array(
            'ZendLoaderStandardAutoloader' => array(
                'autoregister_zf' => true
            )
        ));
    }
}

Finally, if the framework is found by any of these methods, based on the existence of the composer autoloader, the code will just add the Zend namespace or will instantiate an internal autoloader, ZendLoaderAutoloader, and use it as a default.

As you can see, there are multiple ways to set up the autoloading mechanism on ZF2 and at the end what matters is which one you prefer, as all of them in essence will behave the same.

ServiceManager

After all this execution of code, we arrive at the last section of the index.php file where we actually instantiate the ZendMvcApplication object.

As we said, there are two methods of creating an instance of ZendMvcApplication. In the default approach, we call the static method init of the class by passing an optional configuration as the first parameter. This method will take care of instantiating a new ServiceManager object, storing the configuration inside, loading the modules specified in the configuration, and getting a configured ZendMvcApplication.

ServiceManager is a service/object locator that implements the Service Locator design pattern; its responsibility is to retrieve other objects.

$serviceManager = new ServiceManager(
    new ServiceServiceManagerConfig($smConfig)
);
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->get('ModuleManager')->loadModules();

return $serviceManager->get('Application')->bootstrap();

As you can see, the init method calls the bootstrap() method of the ZendMvcApplication instance.

Note

Service Locator is a design pattern used in software development to encapsulate the process of obtaining other objects. The concept is based on a central repository that stores the objects and also knows how to create them if required.

EventManager

This component is designed to provide multiple functionalities. It can be used to implement simple observer patterns, and also can be used to do aspect-oriented design or even create event-driven architectures.

The basic operations you can do over these components is attaching and detaching listeners to named events, trigger events, and interrupting the execution of listeners when an event is fired.

Let's see a couple of examples on how to attach to an event and how to fire them:

//Registering an event listener
$events = new EventManager();
$events->attach(array('EVENT_NAME'), $callback);
//Triggering an event
$events->trigger('EVENT_NAME', $this, $params);

Inside the bootstrap method of ZendMvcApplication, we are registering the events of RouteListener, DispatchListener, and ViewManager. After that, the code is instantiating a new custom event called MvcEvent that will be used as the target when firing events. Finally, this piece of code will fire the bootstrap event.

ModuleManager

Zend Framework 2 introduces a completely redesigned ModuleManager. This new module has been built with simplicity, flexibility, and reuse in mind. These modules can hold everything from PHP to images, CSS, library code, views, and so on.

The responsibility of this component in the bootstrap process of an app is loading the available modules specified by the config file. This is accomplished by the following code line located in the init method of ZendMvcApplication:

$serviceManager->get('ModuleManager')->loadModules();

This line, when executed, will retrieve the list of modules located at the config file and will load each module.

Each module has to contain a file called Module.php with the initialization of the components of the module if needed. This will allow the module manager to retrieve the configuration of the module. Let's see the usual content of this file:

namespace MyModule;

class Module
{
    public function getAutoloaderConfig()
    {
        return array(
            'ZendLoaderClassMapAutoloader' => array(
                __DIR__ . '/autoload_classmap.php',
            ),
            'ZendLoaderStandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }

    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }
}

As you can see we are defining a method called getAutoloaderConfig() that provides the configuration for the autoloader to ModuleManager. The last method getConfig() is used to provide the configuration of the module to ModuleManager; for example, this will contain the routes handled by the module.

Request object

This object encapsulates all data related to a request and allows the developer to interact with the different parts of a request. This object is used in the constructor of ZendMvcApplication and also is set inside MvcEvent to be able to retrieve when some events are fired.

Response object

This object encapsulates all the parts of an HTTP response and provides the developer with a fluent interface to set all the response data. This object is used in the same way as the request object. Basically it is instantiated on the constructor and added to MvcEvent to be able to interact with it across all the events and classes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.120.109