Buy

Ok! Let's see if we can use this new service. First, some setup: in the template, remove the fun fact text and move it into GenusController by creating a new $funFact variable:

44 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 10
class GenusController extends Controller
{
/**
* @Route("/genus/{genusName}")
*/
public function showAction($genusName)
{
$funFact = 'Octopuses can change the color of their body in just *three-tenths* of a second!';
... lines 19 - 23
}
... lines 25 - 42
}

Let's make things interesting by adding some asterisks around three-tenths - Markdown should eventually turn that into italics.

Pass funFact into the template:

44 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 10
class GenusController extends Controller
{
... lines 13 - 15
public function showAction($genusName)
{
$funFact = 'Octopuses can change the color of their body in just *three-tenths* of a second!';
return $this->render('genus/show.html.twig', array(
'name' => $genusName,
'funFact' => $funFact,
));
}
... lines 25 - 42
}

And render it with the normal {{ funFact }}:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 4
{% block body %}
... lines 6 - 7
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 15
<dt>Fun Fact:</dt>
<dd>{{ funFact }}</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 23 - 40

When we refresh the browser, we have the exact same text, but with the unparsed asterisks.

Now, how the heck can we use the new markdown.parser service to turn those asterisks into italics?

Fetch the Service and Use it!

Remember: we have access to the container from inside a controller. Start with $funFact = $this->container->get('markdown.parser'). Now we have that parser object and can call a method on it. The one we want is ->transform() - pass that the string to parse:

46 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 10
class GenusController extends Controller
{
... lines 13 - 15
public function showAction($genusName)
{
$funFact = 'Octopuses can change the color of their body in just *three-tenths* of a second!';
$funFact = $this->container->get('markdown.parser')
->transform($funFact);
... lines 21 - 25
}
... lines 27 - 44
}

So.... how did I know this object has a transform() method? Well, a few ways. First, PhpStorm knows what the markdown.parser object is, so it gives me autocompletion. But you can always read the documentation of the bundle: it'll tell you how to use any services it gives us.

Ok team - time to try this out. Refresh! And hey, it's working! Ok, it's not exactly working. Open the page source: it looks like the parser is working its magic, but the HTML tags are being escaped into HTML entities.

This is Twig at work! One of the best features of Twig is that it automatically escapes any HTML that you render. That gives you free security from XSS attacks. And for those few times when you do want to print HTML, just add the |raw filter:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 15
<dt>Fun Fact:</dt>
<dd>{{ funFact|raw }}</dd>
... lines 18 - 40

Refresh again: it's rending in some lovely italics.

Fetching Services the Lazy Way

One more thing! We can actually do all of this with less code. In the controller, replace $this->container->get() with just $this->get():

46 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 10
class GenusController extends Controller
{
... lines 13 - 15
public function showAction($genusName)
{
$funFact = 'Octopuses can change the color of their body in just *three-tenths* of a second!';
$funFact = $this->get('markdown.parser')
->transform($funFact);
... lines 21 - 25
}
... lines 27 - 44
}

This does the same thing as before.

Ok: here's the big, giant important takeaway so far: why do we add bundles to our app? Because bundles put more services in our container. And services are tools.

So my question now is: how can we configure these services so that they do exactly what we need them to?

Leave a comment!

  • 2016-04-21 Roy Hochstenbach

    The Synchronize option seems to be improving the auto-complete issues at some moments.

  • 2016-04-20 weaverryan

    Ah, interesting! Usually, when you say "extends Controller", it would offer you *both* choices - the one from HttpKernel\Tests and FrameworkBundle (since these are both called Controller). Obviously, you should use the one from FrameworkBundle. But if the one from FrameworkBundle isn't being offered as a choice, then it seems that PhpStorm doesn't see it at all (which is especially weird). Assuming the app works, then the problem is definitely with PhpStorm and you're doing good things by Invalidation the cache. I would also try to browser directly to the path - in vendor/symfony/symfony/src/Symfony/Bundle to see if the file is there. You can right-click on any directory and select "Synchronize" to (hopefully) make PhpStorm see the files in the directory (though Invalidating the Cache is similar).

    Let me know if you figure it out!

  • 2016-04-19 Roy Hochstenbach

    Thanks for your quick response ;-)

    I've tried marking the var/caches folder as Excluded, but the issue remains. I've also chosen the Invalidate Caches option, but that doesn't seem to have any effect.

    Also when i append 'extends Controller' next to a class statement, it automatically includes the file "Symfony\Component\HttpKernel\Tests\Controller" instead of "Symfony\Bundle\FrameworkBundle\Controller\Controller"

  • 2016-04-19 weaverryan

    Hi Roy!

    I think I know the problem. Also right-click on the var/cache directory and mark this as excluded. Before you did this, I bet that if you hovered over the word Controller (in extends Controller), you would have seen some message like "Multiple references found". The Controller class is cached in the var/cache directory (for performance), and this confuses PhpStorm and it quits auto-completing some things from Controller.

    Let me know if this was the problem! No auto-complete is no fun :)

  • 2016-04-19 Roy Hochstenbach

    For some reason PHPStorm is not autocompleting it properly. When I hover over $this->container, it shows me: "Field 'container' not found in GenusController". I have both the Symfony2 plugin and PHP Annotations plugin installed and enabled. Is there some sort of a 'magic switch' to get it to work? I've marked the 'src' directory as Sources Root.