If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
Let's finally make this page real with a template. Return
$this->render('genus/list.html.twig') and pass it a genuses variable:
| ... lines 1 - 11 | |
| class GenusController extends Controller | |
| { | |
| ... lines 14 - 33 | |
| public function listAction() | |
| { | |
| $em = $this->getDoctrine()->getManager(); | |
| $genuses = $em->getRepository('AppBundle:Genus') | |
| ->findAll(); | |
| return $this->render('genus/list.html.twig', [ | |
| 'genuses' => $genuses | |
| ]); | |
| } | |
| ... lines 45 - 89 | |
| } |
You know what to do from here: in app/Resources/views/genus, create the new
list.html.twig template. Don't forget to extend base.html.twig and then override
the body block. I'll paste a table below to get us started:
| {% extends 'base.html.twig' %} | |
| {% block body %} | |
| <table class="table table-striped"> | |
| <thead> | |
| <tr> | |
| <th>Genus</th> | |
| <th># of species</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| ... lines 12 - 14 | |
| </tbody> | |
| </table> | |
| {% endblock %} |
Since genuses is an array, loop over it with {% for genus in genuses %} and add
the {% endfor %}. Next, just dump out genus inside:
| ... lines 1 - 10 | |
| <tbody> | |
| {% for genus in genuses %} | |
| {{ dump(genus) }} | |
| {% endfor %} | |
| </tbody> | |
| ... lines 16 - 18 |
Looks like a good start - try it out!. Ok cool - this dumps out 4 Genus objects.
Open up the tr. Bring this to life with a td that prints {{ genus.name }}
and another that prints {{ genus.speciesCount }}. And hey, we're getting autocompletion,
that's kind of nice:
| ... lines 1 - 10 | |
| <tbody> | |
| {% for genus in genuses %} | |
| <tr> | |
| <td>{{ genus.name }}</td> | |
| <td>{{ genus.speciesCount }}</td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| ... lines 19 - 21 |
Refresh! Easy - it looks exactly how we want it. But wait a second... something
cool just happened in the background. We printed genus.name... but name is a
private property - so we should not be able to access it directly. How is this
working?
| ... lines 1 - 10 | |
| class Genus | |
| { | |
| ... lines 13 - 22 | |
| private $name; | |
| ... lines 24 - 39 | |
| public function getName() | |
| { | |
| return $this->name; | |
| } | |
| ... lines 44 - 79 | |
| } |
This is Twig to the rescue! Behind the scenes, Twig noticed that name was private
and called getName() instead. And it does the same thing with genus.speciesCount:
| ... lines 1 - 10 | |
| class Genus | |
| { | |
| ... lines 13 - 32 | |
| private $speciesCount; | |
| ... lines 34 - 59 | |
| public function getSpeciesCount() | |
| { | |
| return $this->speciesCount; | |
| } | |
| ... lines 64 - 79 | |
| } |
Twig is smart enough to figure out how to access the data - and this lets us keep the template simple.
With that in mind, I have a challenge! Add a third column to the table called "Last Updated":
| ... lines 1 - 4 | |
| <thead> | |
| <tr> | |
| <th>Genus</th> | |
| <th># of species</th> | |
| <th>Last updated</th> | |
| </tr> | |
| </thead> | |
| ... lines 12 - 23 |
This won't work yet, but what I I want to be able to say is {{ genus.updatedAt }}.
If this existed and returned a DateTime object, we could pipe it through the built-in
Twig date filter to format it:
| ... lines 1 - 11 | |
| <tbody> | |
| {% for genus in genuses %} | |
| <tr> | |
| <td>{{ genus.name }}</td> | |
| <td>{{ genus.speciesCount }}</td> | |
| <td>{{ genus.updatedAt|date('Y-m-d') }}</td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| ... lines 21 - 23 |
But this won't work - there is not an updatedAt property. We'll add one later,
but we're stuck right now.
Wait! We can fake it! Add a public function getUpdatedAt() and return a random
DateTime object:
| ... lines 1 - 10 | |
| class Genus | |
| { | |
| ... lines 13 - 79 | |
| public function getUpdatedAt() | |
| { | |
| return new \DateTime('-'.rand(0, 100).' days'); | |
| } | |
| } |
Try that out. It works! Twig doesn't care that there is no updatedAt property - it happily
calls the getter function. Twig, you're awesome.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.1.*", // v3.1.4
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.6.4
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // 2.11.1
"symfony/polyfill-apcu": "^1.0", // v1.2.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
"doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.7
"symfony/phpunit-bridge": "^3.0", // v3.1.3
"nelmio/alice": "^2.1", // 2.1.4
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}