Embedded controller being restricted to template rendering only - symfony

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

Related

How to add a "fallback label" in sonata admin list views

I am displaying some entity relations in a Sonata Admin list view. The problem: When no relation exists (what is legal in my case) the table cell stays empty:
What I want is basically this:
I tried to overwrite the default template (base_list_field.html.twig):
$listMapper
->add(
'example',
null,
array(
'template' => 'AppBundle:Admin:listItemWithFallback.html.twig'
)
)
;
But even when I only extend the default template, all links for existing references stop working. Also I cannot figure out where to add my fallback. My AppBundle:Admin:listItemWithFallback.html.twig looks like this:
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
With this result:
Even when I copy the whole code from base_list_field.html.twig into my own template, the links stop to work.
So: How can I add a fallback label without overwriting the whole default templates? I want to modify as less of the base templates as possible.
Edit:
This is a workaround using a kernel.event_listener, hope there is a nicer way to achieve this:
services.yml:
services:
empty_cells.listener:
class: AppBundle\Listener\EmptyAdminTableCellListener
arguments:
- '#translator'
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
EmptyAdminTableCellListener.php:
namespace AppBundle\Listener;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
class EmptyAdminTableCellListener
{
/**
* #var TranslatorInterface
*/
protected $translator;
/**
* #param TranslatorInterface $translator
*/
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* #param FilterResponseEvent $event
*/
public function onKernelResponse(FilterResponseEvent $event)
{
$request = $event->getRequest();
$path = $request->getPathInfo();
if (strpos($path, '/admin/') !== false) {
$emptyText = $this->translator->trans('Not set', [], 'admin');
$response = $event->getResponse();
$content = $response->getContent();
$content = preg_replace(
';(<td[^>]*?>)[\s]+?(</td>);is',
sprintf('$1%s$2', $emptyText),
$content
);
$response->setContent($content);
}
}
}
Here is how to recreate the working links in your custom template:
{{ value }}
with the fallback and all:
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{% if object.species %}
{{ value }}
{% else %}
{{ 'Your fallback text'|trans() }}
{% endif %}
{% endblock %}
Hope that helps

Symfony Twig Call Continer

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

Symfony2 twig function template variable

I'm trying to add a common twig function that will be called in layout but the result will be specific for each page depending on given parameters.
I don't want to add each parameters in the twig function.
Is there any way to find those parameters?
exemple:
layout.html.twig:
{{ my_twig_function() }}
list.html.twig
{% extends "::layout.html.twig" %}
{% if test is defined%}test is defined{% endif %}
myTwigExtension.php:
public function getFunctions()
{
return array(
'my_twig_function' => new \Twig_Function_Method($this, 'getParams'),
);
}
public function getParams()
{
// here a way to find all parameters passed to the list.html.twig
return "ok";
}
Any ideas?
Have you added your MyTwigExtension class as a service ?
services:
twig.twig_extension:
class: Namespace\NameBundle\Twig\MyTwigExtension
tags:
- { name: twig.extension }
arguments: []

Get route Prefix in Twig or Controller

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

Symfony 3: An exception has been thrown during the rendering

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

Resources