add link in #UniqueEntity message - symfony

hi i am using symfony 5.4, and trying to add html code to uniqueentity message:
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #ORM\Table(indexes={#ORM\Index(name="user",columns={"id","credential","nickname","email","status"})})
* #UniqueEntity(
* fields={"email"},
* message="este Correo ya esta en Uso; Dirigete a la Activacion de Cuentas! <a href='/account_activation'>Activate</a>"
* )
*/
class User implements UserInterface, PasswordAuthenticatedUserInterface
in this case I want a link to be shown in the error but I don't get it:
this is the twig template:
{% extends 'base.html.twig' %}
{% block body %}
{# display any flash message #}
{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="alert alert-{{ label }} alert-dismissible fade show">
{{ message }}
</div>
{% endfor %}
{% endfor %}
{{ form(registration_form) }}
{% endblock %}
any idea how i can achieve it?
update
i try to add raw error filter:
{% extends 'base.html.twig' %}
{% block body %}
{{ error.message|raw }}
{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="alert alert-{{ label }} alert-dismissible fade show">
{{ message }}
</div>
{% endfor %}
{% endfor %}
{{ form(registration_form) }}
{% endblock %}
but get this error:

How do you display it on the front? If you use Twig, maybe you forgot to use raw filter?
{{ error.message|raw }}

After two weeks of research:
Use the message property that uses uniqueentity in annotation, it is not the correct way (is a bad practice) if you want to implement any element/structure html.
all properties are encoded to avoid xss attacks, there are 2 ways to follow using the controller:
forget about the html tag and use a direct redirect to the desired path instead of a link:
if (count($form['email']->getErrors(true)) > 0) {
return $this->redirectToRoute('account_activation');
}
implement a custom error handler and display the error concatenated to the html tag:
if (count($form['email']->getErrors(true)) > 0) {
$this->addFlash(
'warning',
'your account need to be activated! Click Here!'
);
}
Note: implementing the second option requires adding the Flash Messages output to the form template.
There is another unverified method that the github site gave me but I could not verify its functionality:
https://github.com/symfony/symfony/issues/44755#issuecomment-999156755
{% extends 'base.html.twig' %}
{% form_theme registration_form _self %}
{% block form_errors %}
{%- for error in errors -%}
{{ error.message | raw }}
{%- endfor -%}
{% endblock %}
{% block body %}
{{ form_errors(registration_form) }}
{{ form(registration_form) }}
{% endblock %}

Related

symfony's form_errors displays list item instead of just text

[ Symfony 4 ]
I've this template code in Symfony:
{{ form_widget(registrationForm.username, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(registrationForm.username) }}
Instead of just displaying error text, it's generating a list item like this:
<ul><li> Username already exists </li></ul>
How to not have it generate this list item and just get the text?
I guess it is correct behavior, cause you can have multiple errors for one field for example "Username is too short" and "Field Username contains inappropriate characters", but to get only first error you can use:
{{ form_errors(registrationForm.username|first) }}
Or you can customize your form_errors rendering, first create file for form_errors, for example your_form/custom_form_errors.html.twig :
{% block form_errors %}
{% spaceless %}
<div class="error">{{ errors|first }}</div>
{% endspaceless %}
{% endblock %}
And after that include it to your view file:
{% form_theme form 'your_form/custom_form_errors.html.twig' %}
...
{{ form_errors(registrationForm.username) }}
just to extend #Andrii Filenko 's answer. You can modify the output the form_errors or any other form twig function pretty easily. it's called custom theming in Symfony.
Consider this:
// templates/register.html.twig
{% extends "base.html.twig" %}
{% form_theme registrationForm _self %}
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<ul class="changed list">
{% for error in errors %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
{% block body %}{% endblock %}
Output:
<ul class="changed list"><li> Username already exists </li></ul>

Twig Runtime Error: Impossible to invoke a method ("test") on a string variable

I have the following twig template (the code is in the same file):
{% macro renderJob(fields) %}
// renders the job UI block, but I've removed it for simplicity
Hello world.
{% endmacro %}
{% block _jobs_widget %}
<div id="jobsContainer">
{% for fields in form.children %}
{% dump fields %}
{{ _self.renderJob(fields) }}
{% endfor %}
</div>
{% endblock %}
For some reason, after upgrading to twig/twig = v2.1.0 I'm receiving the follwing error:
Impossible to invoke a method ("renderJob") on a string variable ("#AppBundle/Jobs/form/job.html.twig").
I have been trying to figure out what's causing this without any luck. This used to work just fine in 1.3.x. The fields variable contains the proper data, but it appears it can't pass it to the renderJob macro or it can't find the macro (which is kind of odd)?
Have you tried the following ?
{% import _self as renderJobMacro %}
{% macro renderJob(fields) %}
// renders the job UI block, but I've removed it for simplicity
Hello world.
{% endmacro %}
{% block _jobs_widget %}
<div id="jobsContainer">
{% for fields in form.children %}
{{ renderJobMacro.renderJob(fields) }}
{% endfor %}
</div>
{% endblock %}
I think _self is depricated from twigg 2.0, May be you need to check without _self.
Check {{ renderJob(fields) }} instead of {{ _self.renderJob(fields) }}

Custom form field template with twig

I'd like to create a custom template in twig to render a form field.
Example:
{{ form_row(form.field) }}
This can be overriden by form theming
{% block form_row %}
... custom code
{% endblock form_row %}
What I would like to do is this:
{% block custom_row %}
... custom code
{% endblock custom_row %}
and use it like this:
{{ custom_row(form.field }}
however, this throws an exception that method custom_row is not found.
My understanding is that this can be done with Twig extension, but I don't know how to register a block to be a function.
Update
what I actually want:
I use twitter bootstrap and a bundle which overrides all the form themes. And it renders a div around a radio, so it can't be inlined. So I wanted to do something like this:
copy their template and get rid of the div:
{% block inline_radio_row %}
{% spaceless %}
{% set col_size = col_size|default(bootstrap_get_col_size()) %}
{% if attr.label_col is defined and attr.label_col is not empty %}
{% set label_col = attr.label_col %}
{% endif %}
{% if attr.widget_col is defined and attr.widget_col is not empty %}
{% set widget_col = attr.widget_col %}
{% endif %}
{% if attr.col_size is defined and attr.col_size is not empty %}
{% set col_size = attr.col_size %}
{% endif %}
{% if label is not sameas(false) %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %}
{% endif %}
{% if required %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' radio-inline')|trim}) %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ block('radio_widget') }}
{{ label|trans({}, translation_domain) }}
</label>
{% else %}
{{ block('radio_widget') }}
{% endif %}
{{ form_errors(form) }}
{% endspaceless %}
{% endblock inline_radio_row %}
and then
{{ inline_radio_row(form.field) }}
I ended up just overriding the whole theme, and added ifs around the div in question, a the class (radio-inline). But I'm still wondering if there's a way to make this work. Seems like it makes you work so hard for something so simple.
Update 2
I found the functionality:
class FormExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
'inline_radio_row' => new \Twig_Function_Node(
'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode',
array('is_safe' => array('html'))
),
);
}
}
This does exactly what I want, but it says it's deprecated. Anyone knows an updated version of how to use this?
Update 3
Similar functionality can be also achieved with http://twig.sensiolabs.org/doc/tags/include.html
You can use the twig functions for each part of a form row:
form_label(form.field)
form_widget(form.field)
form_errors(form.field)
For example:
<div class="form_row">
{{ form_label(form.field) }} {# the name of the field #}
{{ form_errors(form.field) }} {# the field #}
{{ form_widget(form.field) }} {# the errors associated to the field #}
</div>
You can use form theming.
Step by step:
1. Form Type Class
Check the name in your class
public function getName() {
return 'hrQuestionResponse';
}
2. Include a custom theme in your template
{% form_theme form 'InterlatedCamsBundle:Form:fields.html.twig' %}
3. Find the block
Can be quite difficult. For the bootstrap bundle, as you seem to have found it is in ./vendor/braincrafted/bootstrap-bundle/Braincrafted/Bundle/BootstrapBundle/Resources/views/Form/bootstrap.html.twig and you have found the block radio_row. I have been finding the block by putting output in the source template and overriding more blocks than I need. In 2.7 there is a theme 'rendering call graph'.
4. Override the block
Copy the block from the master template and call it replace the standard term with the name of in the FormType found in step 1.
Don't forget to also change the endblock name.
e.g.
{% block hrQuestionResponse_widget %}
hrQuestionResponse_row
{% spaceless %}
{% set class = '' %}
...
{% endspaceless %}
{% endblock hrQuestionResponse_widget %}
In your case because you can only call form_widget() you will need to override _widget. You could extract only the content that you need, or you can override the block chain to radio_row.

Symfony2 and form theming/customization (required/help/errors)

Maybe I'm overlooking something, and hopefully this is done very easy.
I have a form and what I want in the end is the following result:
Fields which:
are mandatory/required
have an error currently
have help
should get an extra a-Tag after the label and an extra div, filled with the help and/or the error, if applicable.
What I got to work is, that required fields get the a-Tag by using this:
{% use 'form_div_layout.html.twig' with field_label as base_field_label %}
{% block field_label %}
{{ block('base_field_label') }}
{% if required %}
<span> </span>
{% endif %}
{% endblock %}
So, what I tried already were different versions of this:
{% use 'form_div_layout.html.twig' with field_label as base_field_label %}
{% block field_label %}
{{ block('base_field_label') }}
{% if required or help is defined %}
<span> </span>
{% endif %}
{% endblock %}
{% block field_row %}
{% spaceless %}
<div class="row">
{% if required or help is defined %}
<div>
{{ form_errors(form) }}
{{ help }}
</div>
{% endif %}
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'grid_4'} }) }}
</div>
{% endspaceless %}
{% endblock field_row %}
And I can't get this to work.
So my questions are:
Where do I get the help text from, which can also contain HTML? I tried this within the form builder without success - but at least with an exception:
$builder ->add('subject', 'text', array(
'label' => 'Subject',
'help' => 'Can be formatted content with <strong>HTML-Elements</strong>',
));
How can I tell that the current field has an error (to add a class to the row) and if so also display it? {{ form_errors(form) }} did not output anything, no matter where I place it within `field_row˚.
There is no help text, you have to create Form Extension for field and add it to default options.
Example in SF 2.1 Beta 1:
namespace Webility\Bundle\WebilityBundle\Form\Extension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HelpFormTypeExtension extends AbstractTypeExtension
{
public function buildView(FormViewInterface $view, FormInterface $form, array $options){
$view->setVar('help', $options['help']);
}
public function getExtendedType(){
return 'field';
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'help' => null
));
}
}
And register it as a service:
<service id="webility.form.extension.help" class="Webility\Bundle\WebilityBundle\Form\Extension\HelpFormTypeExtension">
<tag name="form.type_extension" alias="field" />
</service>
For the errors question:
Do you have any errors to print? Check that in controller if validation fails:
echo '<pre>'; print_r( $form->getErrorsAsString() ); echo '</pre>'; exit;
To solve it as stated in my question Maciej Pyszyński's anwser was very helpful.
I solved it in this case in another way, which I also want to post here. According to the manual "Adding "help" messages" I build this:
Note This solution won't work together with the formbuilder and needs some tweaking in twig.
To get the help ''-tags (actually they are divs now) …
{% block field_label %}
{{ block('base_field_label') }}
{% if attr.class is defined and '_hint' == attr.class %}
<div>
<a><span class="help">Help Icon</span></a>
<div class="tooltip">
{% if help is defined %}
{{ help|raw }}
{% else %}
Somebody forgot to insert the help message
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}
To get the right class on an error
{% block field_row %}
{% spaceless %}
<div class="row{% if form_errors(form) %} error{% endif %}">
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'grid_4'} }) }}
</div>
{% endspaceless %}
{% endblock field_row %}
And the call from the template
<div class="row{% if form_errors(form.url) %} _error{% endif %}">
{{ form_label(form.field, null, { 'attr': {'class': '_hint'}, 'help': 'Help text or variable containing it' }) }}
{{ form_widget(form.field, { 'attr': {'class': 'grid_4'} }) }}
</div>

Control the way form validation errors are displayed in Symfony2

How do I globally change the way form validation errors are displayed in Symfony2? For example, if I want to wrap each one of my error messages in a <span class="error"> or something like that, how would that be done?
Note: I'm aware of this question/answer, but I'm not sure that it's the same question as mine, and I don't understand how to apply the selected answer.
Take a look at the docs: custom global theme, customizing error output
{# SomeBundle:Layout:fields.html.twig #}
{% block field_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<span class="error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}<br />
{% endfor %}
</span>
{% endif %}
{% endspaceless %}
{% endblock field_errors %}
{# In your form template #}
{% form_theme form 'SomeBundle:Layout:fields.html.twig' %}

Resources