Buy

Controller Magic: Param Conversion

Time to finally make these genus notes dynamic! Woo!

Remember, those are loaded by a ReactJS app, and that makes an AJAX call to an API endpoint in GenusController. Here it is: getNotesAction():

109 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 12
class GenusController extends Controller
{
... lines 15 - 90
/**
* @Route("/genus/{genusName}/notes", name="genus_show_notes")
* @Method("GET")
*/
public function getNotesAction($genusName)
{
... lines 97 - 106
}
}

Step 1: use the genusName argument to query for a Genus object. But you guys already know how to do that: get the entity manager, get the Genus repository, and then call a method on it - like findOneBy():

109 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 12
class GenusController extends Controller
{
... lines 15 - 54
/**
* @Route("/genus/{genusName}", name="genus_show")
*/
public function showAction($genusName)
{
$em = $this->getDoctrine()->getManager();
$genus = $em->getRepository('AppBundle:Genus')
->findOneBy(['name' => $genusName]);
... lines 64 - 88
}
... lines 90 - 107
}

Old news.

Let's do something much cooler. First, change {genusName} in the route to {name}, but don't ask why yet. Just trust me:

110 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 12
class GenusController extends Controller
{
... lines 15 - 90
/**
* @Route("/genus/{name}/notes", name="genus_show_notes")
* @Method("GET")
*/
public function getNotesAction(Genus $genus)
{
... lines 97 - 107
}
}

This doesn't change the URL to this page... but it does break all the links we have to this route.

To fix those, go to the terminal and search for the route name:

git grep genus_show_notes

Oh cool! It's only used in one spot. Open show.html.twig and find it at the bottom. Just change the key from genusName to name:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 30
<script type="text/babel">
var notesUrl = '{{ path('genus_show_notes', {'name': genus.name}) }}';
... lines 33 - 37
</script>
{% endblock %}

Using Param Conversion

So... doing all of this didn't change anything. So why did I make us do all that? Let me show you. You might expect me to add a $name argument. But don't! Instead, type-hint the argument with the Genus class and then add $genus:

110 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 12
class GenusController extends Controller
{
... lines 15 - 90
/**
* @Route("/genus/{name}/notes", name="genus_show_notes")
* @Method("GET")
*/
public function getNotesAction(Genus $genus)
{
... lines 97 - 107
}
}

What? I just violated one of the cardinal rules of routing: that every argument must match the name of a routing wildcard. The truth is, if you type-hint an argument with an entity class - like Genus - Symfony will automatically query for it. This works as long as the wildcard has the same name as a property on Genus. That's why we changed {genusName} to {name}. Btw, this is called "param conversion".

Tip

Param Conversion comes from the SensioFrameworkExtraBundle.

Dump the $genus to prove it's working:

110 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 12
class GenusController extends Controller
{
... lines 15 - 94
public function getNotesAction(Genus $genus)
{
dump($genus);
... lines 98 - 107
}
}

Go back and refresh! We don't see the dump because it's actually an AJAX call - one that happens automatically each second.

Seeing the Profiler for an AJAX Request

But don't worry! Go to /_profiler to see a list of the most recent requests, including AJAX requests. Select one of these: this is the profiler for that AJAX call, and in the Debug panel... there's the dump. It's alive!

So be lazy: setup your routes with a wildcard that matches a property name and use a type-hint to activate param conversion. If a genus can't be found for this page, it'll automatically 404. And if you can't use param conversion because you need to run a custom query: cool - just get the entity manager and query like normal. Use the shortcut when it helps!

Leave a comment!

  • 2017-07-26 Nina

    Thanks for the quick and detailed reply.
    That's very useful.

  • 2017-07-26 Victor Bocharsky

    Hey Nina,

    "git grep genus_show_notes" command will work if you have committed changes about "genus_show_notes" route. If you add this route but do not commit yet - it won't work, because this command search in the current repo state, i.e. only changes you committed. You can use PhpStorm's "Find in path" feature (Edit -> Find -> Find in path) to search for uncommitted changes in your project or commit them and use "git grep".

    Or you can use Symfony Console command:
    $ bin/console debug:router genus_show_notes

    to see the full information about genus_show_notes route in your app.

    Cheers!

  • 2017-07-26 Nina

    Hello, please help me.
    I go to the terminal and search for the route name
    use command :
    git grep genus_show_notes

    but see nothing just go to the next line
    Why? And how to fix this? How to find links on this route ("genus_show_notes")?

  • 2017-04-11 Victor Bocharsky

    Hey maxii123 ,

    Yeah :) Anyway, it's just a quick start. Of course, if you have more complex logic - you can do it manually, but it saves you time because probably you need a complex logic not always. And btw, even if you have more complex logic - you can write your custom param converter and still continue using this magic ;)

    Cheers!

  • 2017-04-10 maxii123

    The param matching is all well and good but god knows I wouldnt want to maintain this stuff down the road ;)

  • 2016-12-26 Victor Bocharsky

    Hey Nefi,

    Hm, you can try to add "\" before like "\dump($genus)" - I hope it helps. But it depends, please, take a look at this explanation: http://stackoverflow.com/a/...

    Cheers!

  • 2016-12-24 Nefi López García

    dump($genus) don't work for me in the controller generates the next error, Attempted to call function "dump" from namespace "AppBundle\Controller". :(

  • 2016-03-29 weaverryan

    Hey Andrew!

    The code is up now - you were working ahead of us :). Sometimes a few of the tutorials are "secretly" available for a few days before we actually put the code blocks up.

    Cheers!

  • 2016-03-24 Andrew Grudin

    No code is bad news for me. It's difficult to follow.