Symfony2 + Twig get real/full current route - symfony

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 ...

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 }}

Drupal 8 - Accessing _entity in content variable in template to print out content

I am trying to print out a view, field by field so I can apply my style to it and customize the look of it.
When I copy over the views-view-unformatted--MY-TEMPLATE.html.twig
I can see these variables in the default view:
{#
/**
* #file
* Default theme implementation to display a view of unformatted rows.
*
* Available variables:
* - title: The title of this group of rows. May be empty.
* - rows: A list of the view's row items.
* - attributes: The row's HTML attributes.
* - content: The row's content.
* - view: The view object.
* - default_row_class: A flag indicating whether default classes should be
* used on rows.
*
* #see template_preprocess_views_view_unformatted()
*
* #ingroup themeable
*/
#}
After using {{ kint(content) }}, I can see that I have an
_entity field as show
However I can't figure out how to print out those specific fields, or even use Kint to find out how to separate them. I've tried doing something like so:
{{ kint(content._entity) }}
to no avail, and a tonne of other ways of trying to print it out.
Any help is appreciated!
It's probably because Content._entity is a node entity, not a renderable array that you can print.

stripslashes inside Twig template

i want to use the php stripslashes function inside a twig template but this function is not a standard twig function, so i have to add it to twig as an extension, i tried this code inside a controller, but it doesnt work:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class XController extends Controller
{
public function YAction($page)
{
$twig=$this->get('twig');
$twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
...
do i need a use statement for the "Twig_Function_Function" class?
am i doing this wrong?
If you want to use it in your twig templates, you don't need to make any add or call inside your controller, Read the How to write a custom Twig Extension section of the documentation.
Basicaly, you need to create an Extension Class that extends \Twig_Extension , then you need to register it as a service using the twig.extension tag. And finally you need to implement the getFunctions() method in order to add customized twig functions.
But in your case better is to add a filter, with the same logic you can also add a getFilters() method in your extension class so that you can specify your customized filters.
Also, take a deeper look at the Extending Twig section of the documentation to understand all the ways twig can be extended.
Or {{ function('stripslashes', "This\\'ll do") }}
(or apply stripslashes() when building your Twig context)
But, also, if you do this in php:
add_filter('timber/twig', function(\Twig_Environment $twig) {
$twig->addFunction(new Twig\TwigFunction('stripslashes', 'stripslashes'));
return $twig;
});
Then this works in twig:
{{ stripslashes("This\'ll do...") }}

How can I set the url for the form to POST using the FormBuilder in Symfony2?

I'm dynamically loading different form classes in my Controller and displaying them in my template. This works fine, except that the Symfony2 docs show adding the route for the form to POST to in the template by hand.
<form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>
I need to set that form action in the FormBuilder class-- the POST routes (e.g. 'task_new') are different depending on the form class I'm using. Is there a way to set the form action url in the FormBuilder class? How can we get {{ form_widget(form) }} to render the complete form, and not just the rows? Thanks!
It is possible out of the box -- http://symfony.com/doc/current/book/forms.html#changing-the-action-and-http-method
$form = $this->createFormBuilder($task)
->setAction($this->generateUrl('target_route'))
->setMethod('GET')
->add('task', 'text')
->add('dueDate', 'date')
->add('save', 'submit')
->getForm();
I had the same problem. I was using a simple FormType class and wanted to set the action url in buildForm function. I tried different things, but couldn't do it that way.
Eventually I used a Form option called 'action'. I don't think it's documented in the Symfony Reference, I have found it by accident while reading some error report :).
You can set the option when creating the form within your controller like this:
$form = $this->createForm(new FormType(), $obj, array( 'action' => 'whatever you want'));
It's not as pretty as having it encapsulated in the form class, but it works..
I hope this helps.
It's bad practice to change submit route in form type. It not form type responsibility. If you added form from not handle form route, you can just change action url in template:
{{ form_start(yourForm,{action:path('yourSubmitRoute')}) }}
I solved this problem by injecting the router into my form type. In my application I have created a zip code search form called ZipCodeSearchType:
Form Class
use Symfony\Component\Form\AbstractType;
/*
* I'm using version 2.6. At this time 2.7 has introduced a
* new method for the Option Resolver. Refer to the documentation
* if you are using a newer version of symfony.
*/
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Routing\Router;
/**
* Class ZipCodeSearchType is the form type used to search for plans. This form type
* is injected with the container service
*
* #package TA\PublicBundle\Form
*/
class ZipCodeSearchType extends AbstractType
{
/**
* #var Router
*/
private $router;
public function __construct(Router $router)
{
//Above I have a variable just waiting to be populated with the router service...
$this->router = $router;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('zipCode', 'text', [
'required' => true,
])
/*
* Here is where leverage the router's url generator
*/
//This form should always submit to the ****** page via GET
->setAction($this->router->generate('route_name'))
->setMethod("GET")
;
}
...
}
The next step is to configure your form as a service, and let symfony know that you need the router service injected into your class:
Define Form as Service
/*
* My service is defined in app/config/services.yml and you can also add this configuration
* to your /src/BundleDir/config/services.yml
*/
services:
############
#Form Types
############
vendor_namespace.zip_search_form:
class: VENDOR\BundleNameBundle\Form\ZipCodeSearchType
arguments: [#router]
tags:
- { name: form.type, alias: zip_code_search }
Use It In Your Controller
/**
* #param Request $request
* #return Form
*/
private function searchByZipAction(Request $request)
{
...
$zipForm = $this
->createForm('zip_code_search', $dataModel)
;
...
}
I don't think it's possible out-of-box today (Mar 18 '12). You could, however, do something like this:
in your controller:
....
....
$post_route = null;
if ( $something ){
$post_route = "some_post_route";
}else if ( $something_else ){
$post_route = "some_other_post_route"
}else{
$post_route = "my_default_route";
}
....
....
return array(
'post_route' => $post_route
);
... and in you template:
<form action="{ path(post_route) }" method="post" {{ form_enctype(form) }}>
Similar approach would be to generate URL (not just route name) within your controller and pass it to template, in which case you don't need path function there.

Get current URL in Twig template?

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'))

Resources