Get current URL in Twig template? - symfony

I looked around for the code to get the current path in a Twig template (and not the full URL), i.e.
I don't want http://www.sitename.com/page, I only need /page.

{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) }}
If you want to read it into a view variable:
{% set currentPath = path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) %}
The app global view variable contains all sorts of useful shortcuts, such as app.session and app.security.token.user, that reference the services you might use in a controller.

Get current url: {{ app.request.uri }} in Symfony 2.3, 3, 4, 5
Get path only: {{ app.request.pathinfo }} (without parameters)
Get request uri: {{ app.request.requesturi }} (with parameters)

In symfony 2.1 you can use this:
{{ path(app.request.attributes.get('_route'),
app.request.attributes.get('_route_params')) }}
In symfony 2.0, one solution is to write a twig extension for this
public function getFunctions()
{
return array(
'my_router_params' => new \Twig_Function_Method($this, 'routerParams'),
);
}
/**
* Emulating the symfony 2.1.x $request->attributes->get('_route_params') feature.
* Code based on PagerfantaBundle's twig extension.
*/
public function routerParams()
{
$router = $this->container->get('router');
$request = $this->container->get('request');
$routeName = $request->attributes->get('_route');
$routeParams = $request->query->all();
foreach ($router->getRouteCollection()->get($routeName)->compile()->getVariables() as $variable) {
$routeParams[$variable] = $request->attributes->get($variable);
}
return $routeParams;
}
And use like this
{{ path(app.request.attributes.get('_route'), my_router_params()|merge({'additional': 'value'}) }}
You won't need all this unless you want to add additional parameters to your links, like in a pager, or you want to change one of the parameters.

You can get the current URL in Twig like this:
{{ app.request.schemeAndHttpHost ~ app.request.requestUri }}

It should be noted that if you have additional query parameters in your URL, which are not part of the configured route, the accepted answer will not include them in the current URL (path).
Why would you want extra parameters?
For example, if you have a list page with records that can be filtered by keyword and the page has pagination, most likely the query variables for "keyword" and "page" will not be in your route. But in your forward and back buttons for paging, you need the full current URL (that contains the keywords so the next page is still filtered). And you need to modify the page variable.
How to Merge In Extra Query Parameters
So you can get the current route, and merge in the extra variables (after modifying one or more of those extra variables). Note that you are merging in your own variables to the app.request.query.all, and then merging that array into the app.request.attributes.get('_route_params'). The path() method requires that you provide all the required parameters of the route, which is why you need to include the _route_params.
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge(app.request.query.all|merge({'page': 2 }))) }}
That's really ugly, but if you are developing pagination, you will need to modify the page variable on each separate link, so you have to include the whole thing each time. Perhaps others have a better solution.

Using Symfony 5 you can use this:
{{ app.request.uri }}

If you are using Silex 2 you can not access the Request object anymore.
You can access the current request attributes this way.
app.request_stack.currentrequest.attributes.get('_route')
And to generate the full current URL :
path(app.request_stack.currentrequest.attributes.get('_route'), app.request_stack.currentrequest.attributes.get('_route_params'))

Related

How to embed Comment on Custom Template in Drupal 8 Twig

I have a content type named Project and I created a template for it page--project.html.twig I am new with Drupal and I want to include a comment box and comment list on this page but not sure what to do. I already added a comment field on my content type. I tried rendering it using {{ node.field_comments }} but I am getting error. How can I include a comment on a
Because variable node is not available in template page so you have to get field comment, render it and then append it to your template by implementing hook_preprocess_page:
<your_theme>.theme
/**
* Implements hook_preprocess_HOOK().
*/
function <your_theme>_preprocess_page(array &$variables) {
$node = \Drupal::routeMatch()->getParameter('node');
if (!empty($node)) {
$variables['field_comment'] = $node->comment->view('full');
}
}
page--project.html.twig
{{ field_comment }}

Timber - Group ACF fields

At the moment all the ACF fields attached to a post get attached to the TimberPost object without any grouping. I'd like to be able to separate them based on what Field Group they belong to. That way I could create cleaner templates in Twig.
I.e.:
Let b be the name of the Field Group which has two fields field1 and field2
Instead of current solution:
{{ post.b_field1}} and {{ post.b_field2}}
Can we do this:
{{ post.b.field1}} and {{ post.b.field2}}
I know I can get the fields for specific field group using acf_get_fields($field_group_id) but the result is an array instead of a Timber object. Is there a way to feed those fields into a TimberPost object?
SpuriouslyAwake: Try extending TimberPost with your own class, it'd look something like...
class MyPost extends TimberPost {
function field_group($field_group_id) {
return acf_get_fields($field_group_id);
}
}
In theory, this would let you do something like.. {{ post.field_group('b').field1 }} (in theory, that's untested code, but you get the gist)

Symfony project; SonataUser, FOSUser and their registration_content.html.twig

Solved -- see bottom of entry
I'm trying to get familiar with the SonataUserBundle extending the FOSUserBundle.
The installation worked fine (as far as I can tell) and now I want to customize
the login and registration forms.
I overwrote templates in app/Resources and it worked fine.
However, for the registration form I do not understand why it works...
Here's my problem:
The SonataUserBundle registration controller (RegistrationFOSUser1) sets up the form
and renders it with FOSUserBundle:Registration:register.html.twig as template:
$form = $this->container->get('sonata.user.registration.form');
$formHandler = $this->container->get('sonata.user.registration.form.handler');
[...]
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
'form' => $form->createView(),
));
register.html.twig includes FOSUserBundle:Registration:register_content.html.twig:
{% block fos_user_content %}
{% include "FOSUserBundle:Registration:register_content.html.twig" %}
{% endblock fos_user_content %}
register_content.html.twig contains the twig code to render the form.
However, what is actually rendered is SonataUserBundle:Registration:register_content.html.twig
I just can't figure out where, when and how SonataUserBundle substitutes FOSUserBundle here...
Thanks for any hints!
Ok, I now see that the solution to my question is well documented in the symfony cookbook:
http://symfony.com/doc/current/cookbook/bundles/inheritance.html
For those as new to symfony as myself:
If you define a parent 'ParentBundle' for another bundle 'ChildBundle', then everytime a function, template etc. from ParentBundle is called, symfony will first look whether there is a file with the same name in ChildBundle.
The parent bundle is defined in the ChildBundle.php:
public function getParent()
{
return 'ParentBundle';
}
This works, as long as the file of the parent bundle is called via the usual ParentBundle:path:file notation.
Ok, I now see that the solution to my question is well documented in the symfony cookbook: http://symfony.com/doc/current/cookbook/bundles/inheritance.html
For those as new to symfony as myself:
If you define a parent 'ParentBundle' for another bundle 'ChildBundle', then everytime a function, template etc. from ParentBundle is called, symfony will first look whether there is a file with the same name in ChildBundle.
The parent bundle is defined in the ChildBundle.php:
public function getParent()
{
return 'ParentBundle';
}
This works, as long as the file of the parent bundle is called via the usual ParentBundle:path:file notation.

Twig CamelCase Filter in Symfony2

So I'm pretty new to Symfony2 and I'm trying to use the camelize filter in a twig template. However when I request the page I get an error saying that the filter doesn't exist:
The filter "camelize" does not exist in ::base.html.twig
Here's the line from my template file:
{{ 'hello world' | camelize }}
The filter is listed on Twig's quick reference page.
I'm confused, doesn't Symfony2 support all of twig's filters? There seem to be quite a few missing, why? And if it doesn't support them, then is there any way to add the missing ones in?
Thanks in advance!
edit Ok, so it turns out I'm retarded and I need to remember to check that I've actually got the right git project. No wonder I was confused. Thanks replies!
Symfony 2 has title filter for camel case use
{{ entity.yourstring | title }}
to camel case your string
Your link points to a fork on GitHub, meaning a modified copy of the original project. The original project is https://github.com/fabpot/Twig.
There is no camelize filter in Twig. Built-in filters are here. You can write your own camilize filter (it's easy, actually...) following this tutorial: How to write a custom Twig Extension.
EDIT: just for fun, you can write something like:
class MyTwigExtension extends Twig_Extension
{
public function getFilters()
{
return array(
'camelize' => new Twig_Filter_Method($this, 'camelizeFilter'),
);
}
public function camelizeFilter($value)
{
if(!is_string($value)) {
return $value;
}
$chunks = explode(' ', $value);
$ucfirsted = array_map(function($s) { return ucfirst($s); }, $chunks);
return implode('', $ucfirsted);
}
public function getName()
{
return 'my_twig_extension';
}
}
Note that this is a quick and dirty filter! Take a look at the built-in filters to learn best practice!
The filter you're looking for is named "title": http://twig.sensiolabs.org/doc/filters/title.html
Here is the best solution by default in Craft CMS 3
Craft 3 now has a |camel filter for twig
https://docs.craftcms.com/v3/dev/filters.html#camel
{{ 'foo bar'|camel }}
{# Output: fooBar #}

Symfony2 + Twig get real/full current route

I have a routing with optional parameters:
/**
* #Route( "/route/{id}", name="_route", defaults={"id" = ""} )
* #Template()
*/
In the template I have a form and I want the form to be send to either:
/route
or:
/route/10
/route/10/mail – if there were more than just one parameter
At the moment I'm solving it like this:
{{ path(app.request.attributes.get('_route')) }}/{{ object.id }}
Which works fine, but I have to add all possible parameters by myself. Is there a way to get the full current path from within twig? I don't want to add an extra variable in my controller to be send to the template.
The Request class has a getRequestUri() method. You can access it in twig like
{{ app.request.requesturi }}
There is one more way (not sure whether it is a good practice or not):
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) }}
And in this case you can add an additional parameter to it:
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')|merge({'p': 10})) }}
Are different actions. Different actions that have different templates. With twig you can have 2 or 3 templates that extends a third one. In third one you can define the bloc of the list. And a blok of the form. In twig you can extends templates.
I still, ... think you need different templates and different actions. Each action's template, extends a "super" template with the list.
You can use multiple #Route in you action:
/**
* #Route( "/route/{id}", name="_route" )
* #Route( "/route/{id}/hello", name="_route_hello" )
* #Route( "/route/{id}/hello/{world}", name="_route_hello_world" )
* #Template()
*/
And check if a variable exists ...
But ... I do not understand you need to use same action with different route. I prefer use one action for each "purpose". And to follow DRY pattern, I like to write some private method for not rewrite code ...

Resources