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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
/** @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.
1
2
3
4
5
6
7
8
9
10
11
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.php
file that we created earlier. Copy the following code into
/module/Application/src/Application/Mvc/Controller/AbstractActionController.php
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
:
1
2
3
4
5
6
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.
1
2
3
4
5
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.