I'd like to get prefix route in Controller or in Twig.
/**
* #Route("/blog",name="root_post")
*/
class PostController extends Controller
{
/**
* #Route("/{id}",name="post")
*/
public function showAction($id)
{
}
}
I don't know if i can do
name="root_post"
Then I'd like to get this root like (in controller)
$this->get(request')->attributes->get('_route')
or (in Twig)
app.request.attributes.get('_route')
I don't know if I can
To check if your currently routed to the route you want, you can do the following in twig:
{% if app.request.get('_route') == 'root_post' %}
<p>Routed to root_post!</p>
{% endif %}
Related
I'm using Symfony 3 with Twig.
In every route I need to make a call to entity:
$posts = $this->getDoctrine()
->getRepository('AppBundle:Posts')
->findAll();
There is a way that I can do this globally?
And call it from the twig instead of in the route?
You can write a service that will do it and inject it as a twig global
#app/config.yml
twig:
globals:
posts_service: '#app_posts_service'
Then define the service
#app/services.yml
services:
app_posts_service:
class: AppBundle\Service\PostsService
arguments: ["#doctrine"]
Make sure your services file is getting imported into your config:
#app/config.yml
imports:
- { resource: services.yml }
Then define the service:
// src/AppBundle/Service/PostsService.php
namespace AppBundle\Service;
class PostsService
{
protected $doctrine;
public function __construct($doctrine)
{
$this->doctrine = $doctrine;
}
public function getAllPosts()
{
return $this->doctrine
->getManager()
->getRepository('AppBundle:Posts')
->findAll();
}
}
Then use it in any twig file like:
{%for post in posts_service.getAllPosts() %}
{{ post.title }} {# or whatever #}
{% endfor %}
The full error I am getting is this one.
An exception has been thrown during the rendering of a template ("Some mandatory parameters are missing ("id") to generate a URL for route "FooBlogBundle_articles".") in "FooBlogBundle:Article:articles.html.twig".
This is the controller, that handles the action:
public function articlesAction($id)
{
$em = $this->getDoctrine()->getManager();
$blog = $em->getRepository('FooBlogBundle:Blog')->find($id);
if(!$em){
throw $this->createNotFoundException('Unable to find blog posti');
}
return $this->render('FooBlogBundle:Article:articles.html.twig', ['blog'=>$blog]);
}
}
and the routing
FlickBlogBundle_articles:
pattern: /foo/{id}
defaults: { _controller: FooBlogBundle:Article:articles }
requirements:
_method: GET
id: \d+
Twig and database, are completely normal, no type or problems. But this error is kind of hard to spot, where I have gone wrong.
EDIT: Including template:
{% extends 'FooBlogBundle::layout.html.twig' %}
{% block body %}
{{ blog.title }}<br/>
{{ blog.author }}<br/>
{{ blog.blog }}<br/>
{{ blog.tags }}<br/>
{{ blog.comments }}
{% endblock %}
The above template is located in views/article/ it extends another templates found at views/
whic is just
{% extends 'FooBlogBundle::layout.html.twig' %}
In FooBlogBundle:Article:articles.html.twig template you have something like {{ path(FlickBlogBundle_articles) }} (can not tell exactly because I do not see a template). This route requires additional parameter id. So change it to {{ path(FlickBlogBundle_articles, {'id':article.id}) }}
I got the same error and in my case I forgot to set public Getters & Setters for my private foreign Key:
/**
* #var Provider
*
* #ORM\ManyToOne(targetEntity="Provider")
* #ORM\JoinColumn(name="fk_provider", referencedColumnName="id", nullable=true)
*/
private $fkProvider;
And
/**
* #return Provider
*/
public function getFkProvider()
{
return $this->fkProvider;
}
/**
* #param Provider $fkProvider
*/
public function setFkProvider($fkProvider)
{
$this->fkProvider = $fkProvider;
}
I am learning symfony2.3, and I am getting an error when I try to get controller name in twig template.
Controller:
namespace Acme\AdminBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
public function indexAction($name)
{
return $this->render('AcmeAdminBundle:Default:index.html.twig', array('name' => $name));
}
}
In my TWIG template:
{% extends '::base.html.twig' %}
{% block body %}
{{ app.request.get('_template').get('controller') }}
Hello {{ name }}!!!
{% endblock %}
Output:
Impossible to invoke a method ("get") on a NULL variable ("") in AcmeAdminBundle:Default:index.html.twig at line 3
I want output as "Default"
I am using symfony 2.3, I have also tried on symfony 2.1 but on both version generates the same error.
use this line to display a controller name in twig:
{{ app.request.attributes.get("_controller") }}
Many months ago I had the same problem as you, and "googling" I found a working code and I had adapted it to my necessities. Here we go:
1 - We need to define a TWIG extension for that. We create the folder structure Your\OwnBundle\Twig\Extension if you haven't defined yet.
2 - Inside this folder we create the file ControllerActionExtension.php which code is:
namespace Your\OwnBundle\Twig\Extension;
use Symfony\Component\HttpFoundation\Request;
/**
* A TWIG Extension which allows to show Controller and Action name in a TWIG view.
*
* The Controller/Action name will be shown in lowercase. For example: 'default' or 'index'
*
*/
class ControllerActionExtension extends \Twig_Extension
{
/**
* #var Request
*/
protected $request;
/**
* #var \Twig_Environment
*/
protected $environment;
public function setRequest(Request $request = null)
{
$this->request = $request;
}
public function initRuntime(\Twig_Environment $environment)
{
$this->environment = $environment;
}
public function getFunctions()
{
return array(
'get_controller_name' => new \Twig_Function_Method($this, 'getControllerName'),
'get_action_name' => new \Twig_Function_Method($this, 'getActionName'),
);
}
/**
* Get current controller name
*/
public function getControllerName()
{
if(null !== $this->request)
{
$pattern = "#Controller\\\([a-zA-Z]*)Controller#";
$matches = array();
preg_match($pattern, $this->request->get('_controller'), $matches);
return strtolower($matches[1]);
}
}
/**
* Get current action name
*/
public function getActionName()
{
if(null !== $this->request)
{
$pattern = "#::([a-zA-Z]*)Action#";
$matches = array();
preg_match($pattern, $this->request->get('_controller'), $matches);
return $matches[1];
}
}
public function getName()
{
return 'your_own_controller_action_twig_extension';
}
}
3 - After that we need to specify the service for TWIG to be recognized:
services:
your.own.twig.controller_action_extension:
class: Your\OwnBundle\Twig\Extension\ControllerActionExtension
calls:
- [setRequest, ["#?request="]]
tags:
- { name: twig.extension }
4 - Cache clear to make sure everything is ok:
php app/console cache:clear --no-warmup
5 - And now, if I'm not forgetting anything, you will be able to access those 2 methods in a TWIG template: get_controller_name() and get_action_name()
6 - Examples:
You are in the {{ get_action_name() }} action of the {{ get_controller_name() }} controller.
This will output something like: You are in the index action of the default controller.
You can also use to check:
{% if get_controller_name() == 'default' %}
Whatever
{% else %}
Blablabla
{% endif %}
And that's all!! I hope I helped you, mate :)
Edit: Take care about the clearing cache. If you don't use --no-warmup parameter maybe you will realize that nothing is shown in your templates. That's because this TWIG Extension uses the Request to extract the Controller and Action names. If you "warm up" the cache, the Request is not the same as a browser request, and the methods can return '' or null
Since Symfony 3.x, service request is replaced by request_stack, and Twig Extension declaration changed since Twig 1.12.
I will correct the answer of Dani (https://stackoverflow.com/a/17544023/3665477) :
1 - We need to define a TWIG extension for that. We create the folder structure AppBundle\Twig\Extension if you haven't defined yet.
2 - Inside this folder we create the file ControllerActionExtension.php which code is:
<?php
namespace AppBundle\Twig\Extension;
use Symfony\Component\HttpFoundation\RequestStack;
class ControllerActionExtension extends \Twig_Extension
{
/** #var RequestStack */
protected $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('getControllerName', [$this, 'getControllerName']),
new \Twig_SimpleFunction('getActionName', [$this, 'getActionName'])
];
}
/**
* Get current controller name
*
* #return string
*/
public function getControllerName()
{
$request = $this->requestStack->getCurrentRequest();
if (null !== $request) {
$pattern = "#Controller\\\([a-zA-Z]*)Controller#";
$matches = [];
preg_match($pattern, $request->get('_controller'), $matches);
return strtolower($matches[1]);
}
}
/**
* Get current action name
*
* #return string
*/
public function getActionName()
{
$request = $this->requestStack->getCurrentRequest();
if (null !== $request) {
$pattern = "#::([a-zA-Z]*)Action#";
$matches = [];
preg_match($pattern, $request->get('_controller'), $matches);
return $matches[1];
}
}
public function getName()
{
return 'controller_action_twig_extension';
}
}
3 - After that we need to specify the service for TWIG to be recognized:
app.twig.controller_action_extension:
class: AppBundle\Twig\Extension\ControllerActionExtension
arguments: [ '#request_stack' ]
tags:
- { name: twig.extension }
4 - Cache clear to make sure everything is ok:
php bin/console cache:clear --no-warmup
5 - And now, if I'm not forgetting anything, you will be able to access those 2 methods in a TWIG template: getControllerName() and getActionName()
6 - Examples:
You are in the {{ getActionName() }} action of the {{ getControllerName() }} controller.
This will output something like: You are in the index action of the default controller.
You can also use to check:
{% if getControllerName() == 'default' %}
Whatever
{% else %}
Blablabla
{% endif %}
I don't really see WHY you would need this.
You might better send parameters into your view.
But if you really need it this way, here's a solution:
Your error comes from the second get method
request = app.request // Request object
NULL = request.get('_template') // Undefined attribute, default NULL
NULL.get('controller') // Triggers error
If you want to get the controller called during the request you can access it via the key _controller of the request attribute
app.request.attribute.get('_controller')
Will return
Acme\AdminBundle\Controller\DefaultController::indexAction
You can then parse it the way you want.
Note that this won't return the controller instance, only its name and method called
To get the controller - {{ app.request.attributes.get('_controller') }}
To get the Action - {{ app.request.attributes.get('_template').get('name') }}
Found at - http://forum.symfony-project.org/viewtopic.php?f=23&t=34083
It can vary. If you're using annotations in the controller, e.g. #Template("AcmeDemoBundle:Default:index"), trying to access app.request.get('_template') in your Twig template will return a string e.g. "AcmeDemoBundle:Default:index". So you might need to access it like this:
{% set _template = app.request.get('_template')|split(':') %}
{% set controller = _template[1] %}
{% set bundle = _template[0] %}
If you're not using annotations then you can use the app.request.get('_template').get('_controller')
Controller:
{{ app.request.attributes.get('_template').get('controller') }}
Action:
{{ app.request.attributes.get('_template').get('name') }}
enjoy ;)
In the Symfony 2 template documentation it recommends embedding a controller within a template via the render url method and provides the following example:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }) %}
</div>
This is fine, however is it possible to make this route only accessible to templates to prevent a user from accessing the url directly, and if so - what is the recommended way of doing it?
You can define all you rendered controller routes pattern as "/_render/unique_name" or prefix them with "_render" and use access_control to secure the routes from outside world:
# app/config/security.yml
security:
access_control:
- { path: ^/_render, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
- { path: ^/_render, roles: ROLE_NO_ACCESS }
You can do this by not defining a route for this method.
class TestController extends Controller
{
/**
* #Route("/", name="index")
* #Template
*/
public function indexAction()
{
return array();
}
/**
* #Template
*/
public function testAction()
{
return array(
'text' => 'This text is being included'
);
}
}
And then in the template
{% extends "::base.html.twig" %}
{% block body %}
<h1>{{ hello }}</h1>
{% render "TestBundle:Test:test" %}
{% endblock %}
In my Symfony2 bundle, I need to check if a function (an extension) is defined. More specifically, if the KnpMenuBundle is installed I use that one in my bundle, otherwise I will render the plugin myself.
I tried this, but this of course doesn't work:
{% if knp_menu_render() is defined %}
{# do something #}
{% else %}
{# do something else #}
{% endif %}
Is there a test/function/filter to check if a function is defined? If not, is there another way to check if the KnpMenuBundle is installed in the application?
Write a function in a Twig Extension which would check if bundle is enabled.
List of registered bundles is stored in the kernel.bundles parameter.
Twig extensions are registered as services. This means you can pass any other service or a parameter to your extension:
<services>
<service id="acme.twig.acme_extension" class="Acme\DemoBundle\Twig\AcmeExtension">
<argument>%kernel.bundles%</argument>
<tag name="twig.extension" />
</service>
</services>
In your Twig function or filter you can later use a service or a parameter which you've passed to an extension.
I had the same need, so I created my own extension:
class IsLoadedExtension extends \Twig_Extension
{
/**
* #var \Twig_Environment
*/
protected $environment;
public function initRuntime(\Twig_Environment $environment)
{
$this->environment = $environment;
}
/**
* Returns a list of functions to add to the existing list.
*
* #return array An array of functions
*/
public function getTests()
{
return array(
new \Twig_SimpleTest('loaded', [$this, 'hasExtension']),
);
}
/**
* #param string $name
* #return boolean
*/
function hasExtension($name)
{
return $this->environment->hasExtension($name);
}
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName()
{
return 'amce_extension_exists';
}
}
Then registered it in Twig:
services:
acme_somebundle.twig.is_loaded_extension:
class: Acme\SomeBundle\Twig\IsLoadedExtension
tags: [{ name: twig.extension }]
And used it in twig template like this:
{% if 'knp_menu' is loaded %}
{# use knp menu #}
{% endif %}