Frontend

Nice! If you have arrived here that means that we have a shiny API to retrieve info of the user wall. Now that we have the data on a JSON object, we have to create a beautiful HTML client to show the information on a browser.

To build this section of the social network we need to create additional modules that will contain all the code related to the user wall, the user data, and the API access. At this point, as we have an API, we need some sort of a client in order to get the data. The Api module does this job but the contents of it are still complex for us and we will see how the concepts work later on. For now just trust me and use the code. When we reach Chapter 7, Dealing with URLs – Posting Links, we will see how to make requests to external URLs and then you can review the contents of the Api module and you'll understand it.

Frontend

This is what the Users module and the Wall module looks like. Create them and let's move on and see what to do with them.

The Wall module is the one responsible for getting the data and showing it to the user. This module uses the entity located in the Users module to store the data coming from the API and at the same time utilizes the Api module to get the data from the backend. Let's have a quick look at what the User entity is and then we will see the Wall module itself.

Adding the Users module

Right now this module is really simple and just contains the User entity that will store the data passed from the API. Of course this module will be extended later on to add more functionality.

Contents of the Module.php file

namespace Users;

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

These are the contents of the file. As you can see it's pretty simple and we are just adding the module to the autoloader.

Creating the User.php file

namespace UsersEntity;

class User
{
    const GENDER_MALE = 1;
    
    protected $id;
    protected $username;
    protected $name;
    protected $surname;
    protected $avatar;
    protected $bio;
    protected $location;
    protected $gender;
    protected $createdAt = null;
    protected $updatedAt = null;

[...]

This is the beginning of the file. Here, we are defining the namespace where this class lives, the constant that represents the value of the male gender in the database, and then a bunch of protected properties, one for each column in the database. After this the file just contains getters and setters for the properties we just saw.

Requesting the wall content

Now it's time to see how to use the Api module to get the contents of the wall and show them to the user.

Modifying the Module.php file

As we did before with the module on the API side of the project, we should create a new Module.php file for this module. The contents of the file are pretty standard and now you should be able to identify what each method does.

namespace Wall;

use ZendMvcModuleRouteListener;
use ZendMvcMvcEvent;

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

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

Module configuration

Let's see the contents of the configuration file. In this case we only have three sections. Two of them will be familiar and the third one is a completely new one.

'router' => array(
    'routes' => array(
        'wall' => array(
            'type' => 'ZendMvcRouterHttpSegment',
            'options' => array(
                'route'    => '/:username',
                'constraints' => array(
                    'username' => 'w+'
                ),
                'defaults' => array(
                    'controller' => 'WallControllerIndex',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
),

The first one is the route definition. As you can see, we will have a parameter on the URL that will be the username of the user we want to see. The route is also a ZendMvcRouterHttpSegment type as we saw in the API section. We also define the constraints of the parameter, but we have a subtle difference with the route defined in the API. If you take a closer look at the defaults section, we not only define the controller but also the action that should be called. This is because the controller in the frontend doesn't extend the controller, AbstractRestfulController. Instead, we extend AbstractActionController.

Then, we define the controllers available; this section is really simple as we only have one controller.

'controllers' => array(
    'invokables' => array(
        'WallControllerIndex' =>    
        'WallControllerIndexController'
    ),
),

Now we arrive at the new section called view_manager and take care of the configuration of the view object. As this is the client, we will have a proper view outputting HTML code to the browser.

'view_manager' => array(
    'display_not_found_reason' => true,
    'display_exceptions'       => true,
    'doctype'                  => 'HTML5',
    'not_found_template'       => 'error/404',
    'exception_template'       => 'error/index',
    'template_path_stack' => array(
        __DIR__ . '/../view',
    ),
),

We are defining some variables here that control the information we show when an action is not found or an exception is thrown. We also define doctype of the HTML code. You can do it here or you can hardcode doctype in the layout. Finally, we define two templates for specific situations and the path where the templates reside. As we are not defining a layout file on this module, the view will fall back to the one located in the Application module provided by ZF2 by default.

Changes in the IndexController.php file

Let's see how we connect the client to the API. This is accomplished on the IndexController.php file.

namespace WallController;

use ZendMvcControllerAbstractActionController;
use ZendStdlibHydratorClassMethods;
use WallEntityUser;
use ApiClientApiClient as ApiClient;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $viewData = array();
        
        $username = $this->params()->fromRoute('username'),
        $this->layout()->username = $username;
        $response = ApiClient::getWall($username);
        
        if ($response !== false) {
            $hydrator = new ClassMethods();
            
            $user = $hydrator->hydrate($response, new User());
        } else {
            $this->getResponse()->setStatusCode(404);
            return;
        }
        
        $viewData['profileData'] = $user;
        
        return $viewData;
    }
}

The first chunk of code declares the namespace the controller is living on and then we specify the components we are going to use. As you can see, the controller, IndexController extends AbstractActionController. The only method we have is the indexAction() method and it's the one in charge of the wall requests. If you take a closer look, you can see that we retrieve the username from the URL. After that we pass it to the layout, and then we use ApiClient to get the data of the wall by calling getWall().

After that, we examine the response to see if it's successful or not; this can be improved but for now it's enough.

If the response is correct, we decode it; remember that the communication between the frontend and the API is done with the JSON objects. Once the data is decoded, we use a Hydrator to store the data inside a custom entity.

The Hydrator is a component from the Stdlib section of ZF2. This type of object is used to populate objects with data. In this case we are using a hydrator based on class methods; this means that when the hydrator will try to populate, an object will try to use setter functions inside the object.

After the entity has been populated, we return an array containing the user object to the view.

Outputting the user wall

Let's now talk about the view itself. The views on ZF2 are based on layout and the content. The content is a view by itself and can contain PHP code, use helpers, partials, and so on. Usually we have a default layout for the application and we merge that with the HTML generated by a view. The views are tied to controllers and actions following a convention. Inside the view folder, the framework will search for a folder named as the controller. Inside that folder each action will have a view and will be named before the action name. If you review the picture of the folder structure again, you'll see that convention in place.

If you want, you can use a template engine in order to use a different syntax in the views instead of PHP but consider that at the end what a template engine does is convert the special syntax to plain PHP. It will probably add a compile step in the middle to translate the views to the final file. As ZF2 already provides good support for the view using plain PHP, helpers, partials, and so on, we are not going to deal with how to use a template engine. But if you want, take a look at Twig at http://twig.sensiolabs.org or Smarty available here http://www.smarty.net.

We are not going to put the code of the view here because it's huge but we are going to comment on how we print the info coming from the User object. If you want to take a look at the code, just download the code that comes with this book and check it out.

<?php echo $profileData->getLocation() ?>
<?php echo $profileData->getGenderString() ?>
<?php printf(
    '%s %s', 
    $profileData->getName(), 
    $profileData->getSurname()
) ?>

These are a few examples on how we put the info from the User object in the view. As you can see we are just using the getters of the class. The second example is using the helper function we made to get the gender in a string representation.

To be able to test this functionality, we only need to insert data into the table, launch the browser, and point to our client hostname adding the username in the URL. You should be able to see something like the following screenshot:

Outputting the user wall
..................Content has been hidden....................

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