lexeme lexeme - 2 months ago 13
Twig Question

Parsing current uri to get the current route params inside a partial. How to avoid?

Inside the base.twig layout I render the toc:

{% block sidebar %}

{{ render(url('toc_documents_categories')) }}

{% endblock %}


The matching partial view for the
'/toc/documents'
action (_toc.documents_categories.twig) is defined as follows:

{% set category_id = (current_uri|split('/'))[4] %}

{% macro recursiveCategory(category, active_category_id) %}

<li>

{% if category.children|length %}

<a><span class="icon icon-plus"></span>{{ category.name_displayed }}</a>

{% else %}

{% set active_class = active_category_id == category.id ? 'active' %}
{% set url = app.url_generator.generate('documents_by_category', {category_id: category.id}) %}

<a href="{{ url }}" class="{{ active_class }}">
{{ category.name_displayed }}
</a>

{% endif %}

{% if category.children|length %}
<ul>
{% for child in category.children %}
{{ _self.recursiveCategory(child, active_category_id) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}

{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category, category_id) }}
{% endfor %}
</ul>
</div>
{% endif %}


As you can see I'm extracting current category's id by parsing current url. This is preceded by setting the current_uri global:

$app->before(function(Request $request) use ($app) {
$app['twig']->addGlobal('current_uri', $request->getRequestUri());
});


The
{{ dump(global.request.attributes.get('_route')) }}
at _toc.documents_categories.twig gives the
'/toc/documents_categories'
route, not the current request route:
'documents_by_category'
.

Is there a way to avoid manually parsing the current uri and to get the current request route params inside the partial view?

Answer

Here's the solution.

render() issues a subrequest, so you have to use the master request context:

use Symfony\Component\HttpFoundation\Request

$app->get('/documents_categories', function(Request $request) use($app) {

    $master_request = $app['request_stack']->getMasterRequest();
    $current_route = $master_request->get('_route');
    $active_category_id = null; 

    if($current_route === 'documents_by_category') {
        $active_category_id = $master_request->get('_route_params')['category_id']; 
    }

    // ... do things: parse toc tree ...

    return $app['twig']->render('_toc.documents.categories.twig', array(
        "categories" => $toc_tree,
        "active_category_id" => $active_category_id
    ));

})->bind('toc_documents_categories');

Then inside the partial view you have to only reference the passed active_category_id parameter:

{% if categories %}
    <div id="categories">
        <ul>
            {% for category in categories %}
                {{ _self.recursiveCategory(category, active_category_id) }}
            {% endfor %}
        </ul>
    </div>
{% endif %}

Thanks to @keyboardSmasher for 'Why not pass the category_id in the render function' comment. Yet I'm not sure if I did it the way he assumed.