5 – Create Blog index page

Now that we have set up the Post entity and have some data in the database, let’s show this data in the index view we created earlier.

First, lets create the index.phtml, copy in the following code, which, when it receives it’s data, should just loop through it and display all of the posts in the database.

/** @var Blog\Entity\Post[] $posts */
?>
<section>
    <?php foreach ($posts as $post) : ?>
        <article class="blogPost">
            <header>
                <h2>
                    <?= $this->escapeHtml($post->getTitle()) ?>
                </h2>
                <h3>
                    <?= $this->translate('Created') ?>: <?= $post->getCreated()->format('d-m-Y') ?>
                </h3>
            </header>
            <div class="blogBody">
                <?= $this->escapeHtml($post->getBody()) ?>
            </div>
        </article>
    <?php endforeach ?>
</section>

As you can see, we create a single section, which is to hold our articles, or posts. For each article we print the header and it’s other contents in their own div. You might notice that we haven’t used $post->getSlug(). This is because that would link to a specific post for which we would need to create a link to a route, function and page we haven’t yet made. Which would cause an error.

However, if you were to go the page right now, you would get an error. The error you should see is an “ServiceNotFoundException”. If, at this point, you see another error, please go back and check your work against mine.

The error occurs because we have not yet setup our PostController. Let’s do this now, copy in the following code.

namespace Blog\Controller;

class PostController
{
    public function indexAction()
    {
        return [
            'posts' => $this->getEntityManager()->getRepository('Blog\Entity\Post')->findAll(),
        ];
    }
}

When you’ve done this and refresh the blog page you’ll find you are faced with an “InvalidControllerException”. A few lines further the error mentions that the controller must implement the “DispatchableInterface”.

Everytime we wish to view a page, this will have to be implemented. To prevent that we have to do this everytime, let’s setup the AbstractActionController.phpfile that we created earlier. Copy the following code into /module/Application/src/Application/Mvc/Controller/AbstractActionController.php.

namespace Application\Mvc\Controller;

use Application\Doctrine\ConnectionString;
use Doctrine\ORM\EntityManager;
use Zend\Mvc\Controller\AbstractActionController as ZendAbstractActionController;

/**
* AbstractActionController
*/
abstract class AbstractActionController extends ZendAbstractActionController
{
    /**
    * @var EntityManager
    */
    protected $entityManager;

    /**
    * Max results per page
    * @var integer
    */
    protected $maxResults = 10;

    /**
    * Gets the entity manager
    * @return EntityManager
    */
    public function getEntityManager()
    {
        if (null === $this->entityManager) {
            $this->entityManager = $this->getServiceLocator()->get(ConnectionString::DOCTRINE_DEFAULT);
        }

        return $this->entityManager;
    }
}

A few things to note about this piece of code. First of all that we create it in the Application module and not in the Blog module. This is because the Blog module will not be the only class using this functionality. Furthermore, it’s an Abstract class, please read up on these when you get the chance.

Next, we create a few protected variables. The one to note is the $entityManager variable. Before we discussed that Doctrine uses an EntityManager to use entities, this is the place where we set it to a variable so that we always have it available.

Next up is that we use the Zend ServiceManager (named ServiceLocator) to get the Doctrine connection, linking the two, using a class ConnectionString and a class constant variable.

After you’ve copied over the code above, you should’ve noticed that using the ConnectionString class throws an error. It doesn’t yet exist, however, it’s no biggy, so let’s quickly create it. Copy the code blow into /module/Application/src/Application/Doctrine/ConnectionString.php:

namespace Application\Doctrine;

class ConnectionString
{
    const DOCTRINE_DEFAULT = 'doctrine.entitymanager.orm_default';
}

Yep, that’s all. Why do we use it if the only thing it contains is a string? And what is it used for?

Well, the string is translated by some Zend Framework under the hood magic into an array path to follow. So the string translates to: doctrine->entitymanager->orm_default.

This is the location in our configuration that we have set in our global and local configuration for the database. But then, why do we use it? We use it because this makes it easy and quick to select an EntityManager for another database.

Imagine that we create another set of Doctrine configurations in our global and local config files and instead of putting them in the array orm_default we put them in orm_alternative.

Still, it would be easy to use the string name doctrine.entitymanager.orm_alternative. However, when we have expanded our application and add a third database, which would require us to rename orm_alternative to something sensible, such as orm_session_db, we would rename it in just 1 location.

Continuing on. If you now return to the AbstractActionController you’ll find you no longer get an error from your editor. So that’s fixed.

Lets return to PostController.php and use our new Abstract controller class. As with the Post entity, we now have to extend it.

Include the namespace and modify the class declaration to extend the Abstract controller, like below.

namespace Blog\Controller;

use Application\Mvc\Controller\AbstractActionController;

class PostController extends AbstractActionController

Now refresh your page and you should see all of the posts in our database! Yes! Finally!

To quickly sum up what we’ve done to create the index page. We started with filling in the view, even though it wouldn’t yet work, but we know what we were supposed to get. Following this we created the PostController with an indexAction. This function is executed by Zend because of our earlier created route when we visit the /blog URL. We received an error because of a missing interface and fixed that by creating an AbstractActionController which we then used to extend our PostController class.

The AbstractActionClass made use of a class we hadn’t yet made but could make future maintenance easier, the ConnectionString class.

Well, that sums up creating the index page. Now would be a good moment to grab a coffee before we start the remainder of this tutorial. Next we’ll be doing a few small modifications to the layout.phtml, create a view for a single post and update our index view to link to it. After this we’ll start on creating, editing and deleting posts.