How to show symfony validation errors? - symfony

I try to visualize my error messages from the validator.
When i write the following example:-
{{ form_errors(form.pGWeek) }}
it works fine and i get the message. But my form has 200 fields and so it's not practical.
So i want to iterate over an Array with all messages, at the end of the form like this:
{% if form.name.vars.errors|length > 0 %}
<ul class="form-errors name">
{% for error in form.name.vars.errors %}
{{ error }}
{% endfor %}
</ul>
{% endif %}
But i did not get some messages. As well i tried some another versions.. but nothing worked. I'm using Symfony 2.7.
Can give me somebody a tip?
Thanks for a short feedback.

So you just want to show all errors for all children of a form without displaying them beside each input field?
Then you could iterate over all the children of your form, check if any errors appeared on this children and if so, iterate over all errors of this children. That could be something like that:
{% for children in form.children %}
{% if children.vars.errors is defined %}
{% for error in children.vars.errors %}
{#{{ dump(children) }}#}
{#{{ dump(error) }}#}
{{ dump(children.vars.name ~ ': ' ~ error.message) }}
{% endfor %}
{% endif %}
{% endfor %}
Which result in an error like description: This value should not be blank..

You can make that loop and condition in your controller using dependency injector, and then in your view you iterate that array of errors and put it into a div o wherever you want, I guess there is something like this:
$errors = $this->get('validator')->validate(yourObject);
if (!empty($errors)) {
foreach ($errors as $error)
throw new \Exception($error->getMessage());
}
That is if you want to stop the process and get an Exception, but you want to show that errors, then you make something similar, you only needs to delete that foreach and render your twig template and give it the $errors variable, in your template then you only need to make a for loop for get the errors!

Related

Symfony flashbag get multiple time

In my app I work with flashbag in multiple place. To know if I need to display it to a place or another place I use an associative array as message :
$this->container->get('session')->getFlashBag()->add("info", ["category" => "mycat", "message" => "mymessage"]);
And in my twig :
{% for type in ['info', 'success', 'warning', 'danger'] %}
{% for message in app.session.flashbag.get(type) %}
{% if message.category is defined and message.category == "mycat" %}
<div class="col-md-12 alert alert-{{ type }}">
{{ message.message|raw }}
</div>
{% endif %}
{% endfor %}
{% endfor %}
It works fine, but I got an issue when I have this code in multiple place. The first time app.session.flashbag.get(type) is called it remove my messages from flashbag and the second time I call it the flashbag is empty...
Is there a way to put my message again in my flashbag if I do not display it ? Or to force it to keep in my flashbag until I manualy remove it ?
Edit:
I tried with app.session.flashbag.peek(type) and it works fine. But now my message is never removed from my flashbag is display on every page load.
Edit2:
I got this way :
{% for type in ['info', 'success', 'warning', 'danger'] %}
{% for message in app.session.flashbag.get(type) %}
{% if message.category is defined and message.category == "mycat" %}
<div class="col-md-12 alert alert-{{ type }}">
{{ message.message|raw }}
</div>
{% else %}
{{ app.session.flashbag.add(type, message) }}
{% endif %}
{% endfor %}
{% endfor %}
But I find it a little dirty. It there a better way to do it ?
Type does not have to be info, success, warning, danger. You can use type to store your categories, this would mean you can then get and clear ONLY the messages you want based on category, then store the what you are currently calling type as something else, i.e class.
Here is a useful list of methods you may not know about:
https://symfony.com/doc/current/components/http_foundation/sessions.html#flash-messages
Once you use your category as the type instead you simply can do get('mycat') as needed, ones that do not match will not be cleared
$this->container->get('session')->getFlashBag()->add("mycat", ["class" => "info", "message" => "mymessage"]);
{% for message in app.session.flashbag.get("mycat") %}
<div class="col-md-12 alert alert-{{ message.class }}">
{{ message.message|raw }}
</div>
{% endfor %}
Sometimes we get stuck on a certain path and then the way becomes distorted, I think sometimes we can forget that 'type' does not have to be the class thing despite how commonly it is used as that

Symfony 3.3 - uncaught Twig Runtime Exception when attempting to access a flash message in a template

I have a flashbag that's not guaranteed to actually have a message in it. If it does have a message, I'd like to display it, otherwise just continue with rendering the template. To that end, I have the following Twig if block:
{% if app.flashes.has('success') %}
{% set flashbag = app.flashes.get('success') %}
{% set message = flashbag[0] %}
<div id="flash">
{{ message }}
</div>
{% endif %}
An uncaught Twig Runtime Exception is occurring at the first line, leading me to believe my syntax is wrong. I'm not sure what the correct syntax would be, however.
Try looping through it instead of setting a variable, and leave out the if statement:
{% for message in app.flashes('success') %}
<div class="flash">
{{ message }}
</div>
{% endfor %}
This may also need your attention: New in Symfony 3.3: Improved flash messages

Issues with passing a variable to a macro

I have a menu block that shows 4 links. I'd like to remove the last one if the user has a specific role.
The menu block is created in a specific twig file, and inside a macro, as follows:
{% import _self as menus %}
{#
We call a macro which calls itself to render the full tree.
#see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}
{% set role = user.role %}
{% macro menu_links(items, attributes, menu_level, elements) %}
{% import _self as menus %}
{% if items %}
<span class='arrow-down'></span>
<ul{{ attributes.setAttribute('id', 'edit-profil-nav') }}>
{% for item in items %}
{% set item_classes = [
'col-xs-12',
'col-sm-12',
items|length == 3 ? 'col-md-4' : 'col-md-3',
item.in_active_trail ? 'active' : 'notactive',
] %}
<li{{ item.attributes.addClass(item_classes) }}>
{{ link(item.title, item.url) }}
</li>
{% endfor %}
</ul>
{{ attach_library('cnas/responsive-navigation') }}
{% endif %}
{% endmacro %}
The major issue I have is that I can't interfere with the macro: I'd like to be able to make comparisons with the user variable, but when I dump it while being in the macro, user shows null.
I found a lot of stuff while looking for an answer, but I've seen everything and its opposite, so I'd like to know if I can do that, and how
Thank you a lot!
macro's in twig have their own scope. You will need to pass the variable user as an argument towards the macro in order to access it.
You could also pass the special variable _context to the macro.
This variables holds all the variables you passed towards the template.

compare a input field value to a string or text symfony2

I was trying to learn about framework and Ill be starting under "Symfony", then i got this problem, I create a
{{ form_widget(form.type) }}
equivalent to
<input type="text" class="type" id="type"/>
this element "input" have a value that given by a tab or menu if i click on it, example jumping.how do i compare it to a text using "Symfony" if statement like the logic below.
{% if jumping == "text" %}
//it will do something
{% endif %}
as explained nicely in the symfony docs here you need to use the form.vars.value to get the input field's value
so for someting like {{ form_widget(form.name) }} you would access the values by doing {{ form.vars.value.name }}
in your case it would be
{% if form.vars.value.name == "text" %}
//do something
{% endif %}

Twig: filter in an if condition

I want to use an filter in an if condition in Twig. The reason for this is a Symfony2 attribute, which I can't compare directly, I have to change it beforehand. I have started with this code:
{% if app.request.attributes.get('_controller')|split('::')|first == 'some\controller\name' %}
do something
{% endif %}
Unfortunately this does not function. So I thought I would use set before the comparison:
{% set controller = app.request.attributes.get('_controller')|split('::')|first %}
{% if controller == 'some\controller\name' %}
do something
{% endif %}
{{ controller }} {# would print 'some\controller\name' #}
Guess what? "do something" is not printed, even if the variable controller now exists and has the value I compare it with. What am I doing wrong?
Ok I tested it, Twig has a strange behavior. "\" is escaped or something like this.
I extended my twig environement with the var_dump function, check this:
{{ var_dump("Sybio\Bundle\WebsiteBundle\Controller\MainController") }}
//string(48) "SybioBundleWebsiteBundleControllerMainController"
{{ var_dump(app.request.attributes.get('_controller')|split('::')|first) }}
// string(52) "Sybio\Bundle\WebsiteBundle\Controller\MainController"
{{ var_dump("Sybio\\Bundle\\WebsiteBundle\\Controller\\MainController") }}
// string(52) "Sybio\Bundle\WebsiteBundle\Controller\MainController"
That's why your test is always false.
You need to double the backslashes of your compared string...
{% if app.request.attributes.get('_controller')|split('::')|first == 'some\\controller\\name' %}
do something
{% endif %}

Resources