Change Layout in Controllers and Actions in Zend Framework 2
If you want to change a layout for one or all actions in a controller, how do you do it without overriding the layout globally? Today’s post shows how.
In today’s tutorial, we’re going to learn how to retrieve and display an Instagram photostream in Zend Framework 2.
One of the best things about being online is the ability to consume and share photos. They let us share our life with others and let us participate, if via proxy, in the lives of others. We can see what our friends, family, acquaintance have been up to and we can share this with others.
So in today’s tutorial, we’re going to learn how to retrieve and display an Instagram photo stream in Zend Framework 2. We’re going to cover the essentials of adding the libraries we’ll need to composer.json, handling authentication and then retrieving and displaying our photo stream in a controller action.
We’ll be doing all of this by using composer to create a new Zend Framework 2 project, based on the ZF2 Skeleton App project and then add a new controller and action which will handle the work involved.
Here’s what you’ll need to complete this tutorial:
We’ll take care of the rest during the tutorial; so let’s get underway.
I’ve created a basic project using composer which we’ll build on in this tutorial and am running it on port 8080 using PHP’s built in CLI web server.
If you’ve not setup a Zend Framework 2 project before, checkout the Running the ZF2Skeleton with PHP’s Built-in Webserver, which will step you through getting up and running, using PHP 5’s built in web server.
First we need to bring in the external dependencies, which are ZFTool and the PHP Instagram API by Galen. So in composer.json, add in the following entry in the require section,
"php-instagram-api/php-instagram-api": "dev-master"
And the next one, for ZFTool in the require-dev section:
"zendframework/zftool": "dev-master",
Then run composer update to bring the libraries in to the vendor directory. With that done, all the dependencies we’ll need are satisfied.
Before we go any further, we need to register an application which has the ability to interact with our photo stream. To do so, go to http://instagram.com/developer/. There you’ll see a page like the following.
Click on Register Your Application and click Register a New Client. There you’ll be asked to add a name, website and OAuth redirect uri. Add what you like for the first two, but for the last one, add in http://localhost:8080/application/instagram/photos.
Once you’ve created the app, you’ll be given a client id and client secret. You’ll need these for the application configuration which we’ll now create. Firstly create a new file in config/autoload called instagram.global.php and add in the following:
<?php
return array(
'instagram' => array(
'redirect_uri' => 'http://localhost:8080/application/instagram/photos',
'scope' => array( 'likes', 'comments', 'relationships' )
)
);
Then, create a second file in config/autoload called instagram.local.php and add in the following:
<?php
return array(
'instagram' => array(
'client_id' => '',
'client_secret' => '',
)
);
Add in your client id and secret which you received just before.
Next, we’re going to create a new controller, Photos, in the Application module which comes with the ZF2 Skeleton application that composer generated. This will keep it logically separate from the existing code. So run the following command to create it:
vendor/bin/zf.php create controller instagram Application
We’ll then use ZFTool again to create a photos action (and view template), where we’ll add the code to retrieve and render our photo stream. The following code will do this:
vendor/bin/zf.php create action photos instagram Application
Before we can use the controller, we have to activate it. As we don’t need to inject any external dependencies in to it, adding it to the invokables element of the controller configuration in module.config.php will be sufficient. So update module.config.php under module/Application/config to look like the following:
'controllers' => array(
'invokables' => array(
'ApplicationControllerIndex' => 'ApplicationControllerIndexController',
'ApplicationControllerInstagram' => 'ApplicationControllerInstagramController'
),
),
To work with the Instagram API we’re going to use sessions. That’s because of the way that the Instagram authentication works. If you’ve not worked with OAuth 2 before, which is what Instagram uses, in a nutshell, you make a request to use the service, which directs you to a page asking you to allow access to your account.
If you allow access, then you’re redirected back to a callback url with an code in the query string. You then use that query string to request an access token which you use to create an Instagram connection object. So we use sessions as part of the handshake process.
So add in the following use statements at the top of Module.php
use ZendSessionConfigSessionConfig;
use ZendSessionSessionManager;
use ZendSessionContainer;
Then add in the following code at the end of the onBootstrap method, which is already available in Module.php.
$this->initSession(array(
'use_cookies' => true,
'cookie_httponly' => true,
));
This will initialise session support in Zend Framework 2, which we’ll call on later in the controller action.
With all this setup done, we’re almost there. We now need to update the action to perform the authentication handshake, make the request for the photo stream and to store the returned results in the ViewModel object.
So firstly add the following 3 use statements in module/Application/src/Application/Controller/InstagramController.php
use InstagramAuth;
use InstagramInstagram;
use InstagramCoreApiException;
Then update the photos action have the following code, which we’ll step through.
public function photosAction()
{
$viewModel = new ViewModel();
We’re instantiating a new variable instead of returning an instantiated variable so that we can call setVariable on it if we have a photo stream available.
$config = $this->getServiceLocator()->get('Config')['instagram'];
$auth = new Auth($config);
We get access to the configuration we added via instagram.global.php and instagram.local.php and pass the instagram element to the Auth object constructor, which handles the Instagram authentication for us.
$sessionInstagram = new Container('instagram');
if (!$sessionInstagram || !$sessionInstagram->instagram\_access\_token) {
We then get/retrieve the instagram session container. If it was created previously, it’s returned. If this is the first request to it, it’s created and returned. We then check if we have a token available. If not, we step through the authentication handshake.
$code = $this->getRequest()->getQuery('code');
if (isset($code)) {
try {
$sessionInstagram->instagram\_access\_token = $auth->getAccessToken($code);
return $this->redirect()->toUrl(
'/application/instagram/photos'
);
} catch (ApiException $e) {
$error = ucwords($e->getMessage());
exit;
}
} else {
$auth->authorize();
}
exit;
If we have a code, we then attempt to create an access token. If the token’s created, , we then redirect, using the redirect method to &’/application/instagram/photos’ so that the process requires no further input from us.
If something goes wrong, we catch the error, but don’t display it. If a code’s not available, we call authorize which starts the authentication process.
} else {
$instagram = new Instagram($sessionInstagram->instagram\_access\_token);
$user = $instagram->getCurrentUser();
$viewModel->setVariable('mediaList', $user->getMedia());
}
return $viewModel;
}
If we have an access token, we then initialise a new Instagram object with it, retrieve the current user and then retrieve all of the user’s photos and videos by calling the getMedia method and set the result as a view template variable, by calling setVariable on the view model object, returning it at the end of the action.
Finally, we finish up updating the view template, module/Application/view/application/instagram/photos.phtml to look as follows:
<h1>Photos List</h1>
<?php if ($this->mediaList) : ?>
<table>
<?php foreach ($this->mediaList as $mediaItem) : ?>
<tr>
<td><img src="<?php print $mediaItem->getThumbnail()->url; ?>"
title="<?php print $mediaItem->getCaption(); ?>" /> </td>
<td><?php print $mediaItem->getCaption(); ?><br /></td>
<td><?php print $mediaItem->getLikesCount(); ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
This iterates over all of the items in the mediaList template variable, assuming that they’re images and displays in a table the thumbnail image, caption and likes count. The result looks something like the following
And there you have it. We’ve now created an action which can manage the authentication with Instagram, retrieve and render your photo stream. If you’ve got any questions or would like to know more, add your questions in the comments.
If you want to change a layout for one or all actions in a controller, how do you do it without overriding the layout globally? Today’s post shows how.
In this tutorial, we’re going to step beyond the in-built ZFTool Diagnostic class and write our own custom checks, specifically to lint a Zend Framework 2 module configuration file.
In this screencast we’ll create an application from the ZF2Skeleton project on Github and getting it up and running, using PHP’s built-in web server.
Please consider buying me a coffee. It really helps me to keep producing new tutorials.
Join the discussion
comments powered by Disqus