while twig {% render %} no error page symfony2 - symfony

If I run the controller "normally" the (Booking) Controller throws an exception I get my custom 500 error page.
If I render the controller inside another template, like so:
{% render "BookingBundle:Booking:list" %}
then I don't get anything just blank output.
Is there a way to get the error page to display here with out doing a try catch inside the controller?

When you use the render tag, you can specify some options as the third argument:
ignore_errors default FALSE in debug mode and TRUE otherwise
alt an alternative controller to execute in case of an error
The debug mode is activated by passing true as the value of the second kernel's constructor argument. You can see it in the front controller classes:
$kernel = new AppKernel('dev', true);
If you don't want to ignore errors, even in non-debug mode, you can do:
{% render 'BookingBundle:Booking:list' with {}, {'ignore_errors':false} %}

Related

Cannot render text filtered with trans in twig template using Sandbox Security Policy

I am a little bit confused. First of all, look at my code, I guess.
public function renderTemplate($templateType, $data)
{
$layoutName = "$templateType.layout.html.twig";
$policy = new \Twig_Sandbox_SecurityPolicy(
['if', 'for', 'block', 'set', 'extends'],
['escape', 'format', 'dateformat', 'trans', 'raw', 'striptags'],
self::$allowedMethods,
self::$allowedProperties,
['gettext']
);
$sandboxExt = new \Twig_Extension_Sandbox($policy);
$intlExt = new \Twig_Extensions_Extension_Intl();
$i18nExt = new \Twig_Extensions_Extension_I18n();
$twig = new \Twig_Environment(new \Twig_Loader_Filesystem(__DIR__ . "/../Resources/views/Something/", "__main__"));
$sandboxExt->enableSandbox();
$twig->addExtension($sandboxExt);
$twig->addExtension($intlExt);
$twig->addExtension($i18nExt);
try {
$result = $twig->render($layoutName, $data);
} catch (\Exception $e) {
\Doctrine\Common\Util\Debug::dump($e);die();
}
return $result;
}
Here it is the template I want to render
{% extends 'layout.html.twig' %}
{% block title %}{{ entity.id }}{% endblock %}
{% block bodyTitle %}
{{ entity.id }} {{ 'translation_key.created_at'|trans({}, 'entities', locale) }} {{ entity.createdAt|dateformat(null, locale) }}
{% endblock %}
Here, as you can see, I want to render a template according to its type. The problem is: half of the template renders just fine, and then, when it tries to render the translated string, it throws an error.
Fatal error: Call to undefined function gettext() in /home/dev/vhosts/my-project/vendor/twig/twig/lib/Twig/Environment.php(403) : eval()'d code on line 69
I checked if this function existed right before trying to call render method, and it was really undefined. Basically, I have 2 questions here:
Question 1
How does it work in other parts of my project, but not in this specific handler? See "Important update" below.
Question 2
Can I solve my problem in another way? For example, without using Sandbox or using Sandbox with some kind of a flag "everythingAllowed=true"?
ATTENTION! IMPORTANT UPDATE
Previously, I misunderstood my own question. I thought the error was thrown while rendering the variable, but I re-checked the situation (When Alain Tiemblo asked me for twig template code here in comments) and now 100% sure it's thrown while trying to translate smth. Also, I have translations all over my project, and it works just fine, but in this specific situation it's not. I think it worth to mention, that I also tried to render the template without using Sandbox. I tried to render it directly from Twig Engine like this
return $this->templating->render($layoutName, $data);
//$this->templating is injected in the constructor via services.yml like this
//arguments:
// - "#templating"
The result - not properly translated text. When I dumped "locale" - I got one specific language, but the text was translated in another. But at least using this method - I didn't get any errors.. Can anybody clarify this for me? Because I really don't understand how the Intl/i18n extension works and why it doesn't want to work in Sandbox or not in Sanbox?
P.S. My guess, why it doesn't work directly from Twig Engine - probably I should inject not like "#templating" or it injects just right, but the Intl or I18n extensions are not enabled? How to enable. And I have no clues why it doesn't work with Sandbox

Test if a method exists in entity from twig

I want to edit the default form template to include a thumbnail preview of an image when I display an upload field, so I put a method called getFormThumbnail() in my entity that returns the path. When the entity has the method it works, but when it doens't I get an error:
An exception has been thrown during the rendering of a template ("Warning: call_user_func_array() expects parameter 1 to be a valid callback, class 'Acme\UserBundle\Entity\UserTranslation' does not have a method 'getFormThumbnail' in C:\...\symfony\vendor\knplabs\doctrine-behaviors\src\Knp\DoctrineBehaviors\Model\Translatable\TranslatableMethods.php line 140") in kernel.root_dir/Resources/views/Form/form_div_layout.html.twig at line 43.
500 Internal Server Error - Twig_Error_Runtime
I am editing the code in {% block form_widget_simple %}
I added :
{% if type == 'file' %}
{% if form.vars.form.parent.vars.value.getFormThumbnail is not null %}
<img src="{{ form.vars.form.parent.vars.value.getFormThumbnail | imagine_filter('thumb_250') }}" style="display: block; margin-bottom: 10px">
{% endif %}
{% endif %}
This code works perfectly when getFormThumbnail exists. So I tried adding is defined and it doesn't work, I even tried things like:
form is defined
and
form is not null
and
form.vars is defined
and
form.vars is not null
and
form.vars.form is defined
and
form.vars.form is not null
and
form.vars.form.parent is defined
and
form.vars.form.parent is not null
and
form.vars.form.parent.vars is defined
and
form.vars.form.parent.vars is not null
and
form.vars.form.parent.vars.value is defined
and
form.vars.form.parent.vars.value is not null
and
form.vars.form.parent.vars.value.getFormThumbnail is defined
and
form.vars.form.parent.vars.value.getFormThumbnail is not null
Still, I always get the same error, the line in the error by the way is the line where I test if getFormThumbnail is defined
So if the error is does not have a method is there a way to test if it has a method?
You can create a custom fragment only for that field. So you don't have to check if the method exists or not http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field.
Or you can create a form type extension: http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html

Symfony2: Set flash message after UNsuccessful login

I am using FOSUSerBundle and have successfully overwritten Controllers, Forms and Views.
But I cannot find the correct place to set a flash message after unsuccessful login.
I already tried modifying the checkAction() in SecurityController.php, but it doesnt work.
Where is the correct place to set my flash message?
Thank you very much in advance!
I solved the problem pretty straight-forward:
1.) have overwritten the SecurityController and edited the loginAction
2.) hooked into the case where the login process returns an not empty $error
// in case the login process returns an error...
if ($error) {
$error = $error->getMessage();
// ... add the desired flash message to display
$session->getFlashBag()->add('error', 'my error message here');
}
You dont need to overwrite the controller for it.
I overwrite the login.html.twig file and give the user the errors with the following line:
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}

Using repository class methods inside twig

In a Symfony2.1 project, how to call custom entity functions inside template? To elaborate, think the following scenario; there are two entities with Many-To-Many relation: User and Category.
Doctrine2 have generated such methods:
$user->getCategories();
$category->getUsers();
Therefore, I can use these in twig such as:
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for user in category.users %}
{{ user.name }}
{% endfor %}
{% endfor %}
But how can I get users with custom functions? For example, I want to list users with some options and sorted by date like this:
{% for user in category.verifiedUsersSortedByDate %}
I wrote custom function for this inside UserRepository.php class and tried to add it into Category.php class to make it work. However I got the following error:
An exception has been thrown during the rendering of
a template ("Warning: Missing argument 1 for
Doctrine\ORM\EntityRepository::__construct(),
It's much cleaner to retrieve your verifiedUsersSortedByDate within the controller directly and then pass it to your template.
//...
$verifiedUsersSortedByDate = $this->getYourManager()->getVerifiedUsersSortedByDate();
return $this->render(
'Xxx:xxx.xxx.html.twig',
array('verifiedUsersSortedByDate' => $verifiedUsersSortedByDate)
);
You should be very carefull not to do extra work in your entities. As quoted in the doc, "An entity is a basic class that holds the data". Keep the work in your entities as basic as possible and apply all the "logic" within the entityManagers.
If you don't want get lost in your code, it's best to follow this kind of format, in order (from Entity to Template)
1 - Entity. (Holds the data)
2 - Entity Repositories. (Retrieve data from database, queries, etc...)
3 - Entity Managers (Perform crucial operations where you can use some functions from your repositories as well as other services.....All the logic is in here! So that's how we can judge if an application id good or not)
4 - Controller(takes request, return responses by most of the time rendering a template)
5 - Template (render only!)
You need to get the users inside your controller via repository
$em = $this->getDoctrine()->getEntityManager();
$verifiedusers = $em->getRepository('MYBundle:User')->getVerifiedUsers();
return array(
'verifiedusers' => $verifiedusers,
);
}

How to get the current page name in Silex

I'm wondering how to get the current page name, basically 'just' the last parameter in the route (i.e. /news or /about). I'm doing this because I want to be able to have the current page in the navigation highlighted.
Ideally, I'd like to store the current page name in a global variable so that in Twig I can just compare the current page name against the link and add a class accordingly.
I can't figure out how to add the current page name to a global variable though. I've tried using something like this:
$app['twig']->addGlobal('current_page_name', $app['request']->getRequestUri());
at the top of my app.php file, but an 'outside of request scope' error. But I wouldn't like to have to include this in every route.
What's the best way to do this?
If you put it into an app-level before middleware like this, that'll work:
$app->before(function (Request $request) use ($app) {
$app['twig']->addGlobal('current_page_name', $request->getRequestUri());
});
The "page name" part of your question is unclear, are you looking for the current route's name? You can access that via $request->get("_route") even in the before middleware, as it gets called when routing is already done.
You could also generate navigation list directly in stand alone nav twig template. And then import it in to the main template. Then you would only have to get silex to pass to the view the current page identifier. Simplest way... for example from Silex you would have to pass in the "path" variable to your view. Probably it would more convenient to to fetch nav_list from database and pass it in to twig template as global array variable instead. However this example is the simplest you could get to do what you intend.
nav.twig
{% set nav_list = [
["./", "home"],
["./contact", "contact"],
["./about", "about us"]
{# ... #}
] %}
{% set link_active = path|default("") %}
{% for link in nav_list %}
<li><a href="{{ link[0] }}" class="{% if link[0] == link_active %} activeClass {% endif %}" >{{ link[1] }}</a></li>
{% endfor %}
app.php
//...
$app->match('/about', function (Request $request) use ($app) {
return $app['twig']->render('about.twig', array(
'path' => './'.end(explode('/', $request->getRequestUri()))
));
});
//...

Resources