OroPlatform: override oro_datetime_widget options - symfony

Context
I am actually trying to change the default placeholder for the time input of the OroDateTimeType::class.
I want to have, for example, the text Horaires instead of Temps.
Here is my form field in my FormType :
->add('expirationDate', OroDateTimeType::class, [
'label' => 'app.subscription.fields.expirationDate',
])
And in my twig view :
form_row(form.expirationDate)
Issue
At the beginning, I have tried to used the Symfony 4 placeholder option for DateTime type : https://symfony.com/doc/4.4/reference/forms/types/date.html#placeholder. It doesn't work because OroDateTime use a different datepicker and it override the Symfony values on load :
{# vendor/oro/platform/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig #}
{% block oro_datetime_widget %}
{% set dateValidation = {'Date' : {}} %}
{% set timeValidation = {'Time' : {}} %}
{% if required %}
{% set dateValidation = dateValidation|merge({'NotBlank' : {}}) %}
{% set timeValidation = timeValidation|merge({'NotBlank' : {}}) %}
{% endif %}
{% if attribute(attr, 'class') is defined %}
{% set attrClass = attr['class'] %}
{% else %}
{% set attrClass = '' %}
{% endif %}
{% set options = {
view: 'oroui/js/app/views/datepicker/datetimepicker-view',
nativeMode: isMobileVersion(),
dateInputAttrs: {
placeholder: 'oro.form.choose_date'|trans,
id: id,
name: id,
class: 'input-small datepicker-input ' ~ attrClass,
'data-validation': dateValidation|json_encode(constant('JSON_FORCE_OBJECT')),
'aria-live': 'assertive',
autocomplete: 'off',
autocorrect: 'off',
autocapitalize: 'off'
},
datePickerOptions: {
altFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true,
yearRange: years|default('-80:+1'),
showButtonPanel: true
},
timeInputAttrs: {
placeholder: 'oro.form.choose_time'|trans,
id: 'time_selector_' ~ id,
name: 'time_selector_' ~ id,
class: 'input-small timepicker-input ' ~ attrClass,
'data-validation': timeValidation|json_encode(constant('JSON_FORCE_OBJECT'))
},
timePickerOptions: {
}
} %}
{% set id = 'hidden_' ~ id %}
{% set attr = attr|merge({
'data-page-component-module': 'oroui/js/app/components/view-component',
'data-page-component-options': options|json_encode(constant('JSON_FORCE_OBJECT'))
}) %}
{{ block('datetime_widget') }}
{% endblock oro_datetime_widget %}
If I change the value timeInputAttrs.placeholder from the options variable. It works.
But, I want to pass this variable to my specific form field, not globally.
UPDATE
I finally choose to change the oro.form.choose_time translation in my project globally.
So, in my Resources/translations/messages.fr_FR.yml I've created these lines :
oro:
form:
choose_time: Horaires
auth:
description:
main: Baltimore
Then, I've understand that translations are generated in a file located in var/cache/dev/translations/catalogue.fr_FR :
<?php
use Symfony\Component\Translation\MessageCatalogue;
$catalogue = new MessageCatalogue('fr_FR', array (
'messages' =>
array (
'oro.form.choose_time' => 'Temps',
'oro.auth.description.main' => 'Baltimore',
Here, I can see that the oro.auth.description.main change is applied, but the value for the key oro.form.choose_time is still the same.
Maybe I have a command to run ?

The easiest way to override any text in the Oro application UI is to override a translation for the message used to render it. As the form placeholder is translated as well, you can use this technic. If it's the only customization you need for the form, follow this guide.
If you want to override an HTML, you can extend the template by following the template overriding guide.
But, as you want to modify the label for a single form, then the best way would be to extend the form type and override the single form field with new options.

Related

OroPlatform: override Oro bundle template

Context
I'm trying to override the following template : vendor/oro/platform/src/Oro/Bundle/OrganizationBundle/Resources/views/BusinessUnit/update.html.twig
This template seems to belong to the OroOrganizationBundle bundle.
Issue
So, I have tried to put my override in the following path : templates/bundles/OroOrganizationBundle/BusinessUnit/update.html.twig according to Symfony 4.X documentation : https://symfony.com/doc/4.4/bundles/override.html#templates
I have cleared the cache : symfony console cache:clear but nothing changes.
Here is my override template :
{% extends 'OroOrganizationBundle:BusinessUnit:update.html.twig' %}
{% block content_data %}
{% set id = 'business_unit-profile' %}
{% set dataBlocks = [{
'title': 'General'|trans,
'class': 'active',
'subblocks': [{
'title': '',
'data': [
form_widget(form.appendUsers, {'id': 'businessUnitAppendUsers'}),
form_widget(form.removeUsers, {'id': 'businessUnitRemoveUsers'}),
form_row(form.name),
form_row(form.parentBusinessUnit),
form_row(form.phone),
form_row(form.website),
form_row(form.email),
form_row(form.fax),
]
}]
}] %}
{% set dataBlocks = dataBlocks|merge(oro_form_additional_data(form, 'Additional Override'|trans)) %}
{% set dataBlocks = dataBlocks|merge([{
'title' : 'oro.organization.businessunit.users.label'|trans,
'subblocks': [{
'title' : null,
'useSpan': false,
'data' : [dataGrid.renderGrid(gridName, {business_unit_id: entityId}, { cssClass: 'inner-grid' })]
}]
}] ) %}
{% set data = {
'formErrors': form_errors(form)? form_errors(form) : null,
'dataBlocks': dataBlocks
} %}
{{ parent() }}
{% endblock content_data %}
Here is the output of the following command line : symfony console debug:twig | grep Organization
Finally, I found a solution using this article from Oro documentation : https://doc.oroinc.com/frontend/back-office/templates/
The right path for my case was : src/Resources/OroOrganizationBundle/views/BusinessUnit/update.html.twig
I have tried to use the "extends" method from the Symfony documentation : https://symfony.com/doc/4.4/bundles/override.html#templates which consist to override only a specific block part. In my case, I needed to copy the entire file but it works.

Symfony ChoiceType deep label customization

I want to customize my EntityType's choice labels highly, like creating a table with multiple attributes of my model.
So I want to access my choices class attributes. The choices are my entities of class MyClass through the EntityType. How can I do so in twig?
Currently I do it like this:
1. in my FormClass I json_encode all fields I need in my label
2. in my template I json_decode these information and display according
IN CODE:
1.
$builder
->add('field', EntityType::class, [
'class' => MyClass::class,
'multiple' => false,
'expanded' => true,
],
'choice_label' => function (MyClass $myClass) {
$data = [
'name' => $myClass->getName(),
'description' => $myClass->getDescription(),
];
return json_encode($data);
},
])
2.
{% block my_form_widget %}
...
{# form is my 'field' FormView of the EntityType #}
{% for child in form %}
{# child is a FormView, one choice of my EntityType #}
{# child.vars.data is boolean as its a checkbox #}
{% set data = child.vars.label|json_decode %}
create some complex html here, like tables
...
{% endfor %}
...
{% endblock %}
Working. But is there a better way?
Thanks,
Kim
In a Symfony form (or form field, which is just a form of its own) that is mapped to an entity, you always have access to the underlying data in form.vars.data. So in this case, form.vars.data would either be null or an instance of MyClass.
For ease of use in your template, you might do something like:
{% set my_object = form.field.vars.data %}
{% if my_object %}
{{ my_object.getName() }}
{{ my_object.getDescription() }}
{% endif %}
Thus there is no need to re-encode your entity data for the view layer, since it's always already available.
If you are working with an EntityType and want to access the properties of each choice's entity, they are available as well in the choices array:
{% for choice in form.field.vars.choices %}
{{ choice.data.getName() }}
{{ choice.data.getDescription() }}
{% endfor %}
A nice trick when you're trying to access any form data and aren't sure where to look is to temporarily add a line to your template like:
{{ dump(form.field) }}
This will allow you to look through the available data and see what all is available. Note that it requires the Twig debug extension to be enabled, and XDebug to be enabled in PHP in order to make the output look nice.
Ok I got it, here is an example of how to access the data of your EntityType's choices in twig. You can check the child.parent.vars.choices list.
{% block my_form_widget %}
...
{# form is my 'field' FormView of the EntityType #}
{% for child in form %}
{# child is a FormView, one choice of my EntityType #}
{# child.vars.data is boolean as its a checkbox #}
{% for choice in child.parent.vars.choices if choice.value == child.vars.value %}
{{ choice.data.name }} {# contains MyClass name #}
{{ choice.data.description }} {# contains MyClass description #}
{% endfor %}
...
{% endfor %}
...
{% endblock %}

Override twig variable in included template in Symfony 3

I'm trying to override a variable in the included template.
Can I do this in a Symfony3 & Twig?
My twig template looks like this:
{% set foo = 'bar' %}
{% include 'first.html.twig' %}
{% include 'second.html.twig' %}
// first.html.twig
{{ foo }}
{% set foo = 'second' %}
// second.html.twig
{{ foo }}
I get such a result:
bar bar
But I expect:
bar second
The following Twig code:
{% set a = 42 %}
{{ include("first.twig") }}
Will be compiled to this one:
// line 1
$context["a"] = 42;
// line 2
echo twig_include($this->env, $context, "first.twig");
And twig_include prototype is:
# lib/Twig/Extension/Core.php
function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
So variables are passed by copy, not by reference in included templates. Thus your changes in included templates won't be reflected to including templates.
Moreover, since Twig 2.0, you can't call TwigEnvironment::addGlobal once twig runtime is initialized, so you can't glitch using simple extensions.
All in all, you can understand that if you need to update variables cross templates, it means some template contains business logic and Twig isn't build for that. You need to prepare the whole context in controllers.
Alternatively you may call a PHP class method from TWIG. Example of a page-counter needed when generating a pdf.
Custom class :
class PageCounter
{
private $pageNumber = 0;
public function incrementPageCounter()
{
$this->pageNumber ++;
return $this->pageNumber;
}
}
Controller:
....
$twigVariables = [
...
'pageCounter' => new PageCounter()
];
return $this->render('template.html.twig', $twigVariables);
Twig template (object pageCounter available from any included template)
{{ pageCounter.incrementPageCounter() }} / {{totalPages}}
You just need to do the check and override the variable with another variable :))
{% if name is defined %}
{% set foo = name %}
{% else %}
{% set foo = 'bar' %}
{% endif %}
{% include 'first.html.twig' %}
{% include 'second.html.twig' %}
// first.html.twig
{% set name = 'first' %}
// second.html.twig
{% set name = 'second' %}
Why not override your variable with your include tag/function like :
{% include 'first.html.twig' with {'foo': 'second'} %}
or :
{ include('first.html.twig', {foo: 'second'}) }}

Symfony - easyAdmin changing 'list.row_actions'

Currently I'm using Symfony 3 and implementing Easy Admin backend.
By default, the label available show as something like 'list.row_actions'.
I have read the documentation for Easy Admin, and manage to edit certain label such as Edit and Delete.
But come to confusion why I cannot edit the 'list.row_actions on the list table header.
The same problem I have with the Edit page, specifically the buttons:
Here is some of the configurations I add into config.yml under easy_admin tree:
config.yml
list:
actions:
- { name: 'new', label: 'New' }
- { name: 'search', label: 'Search' }
- { name: 'edit', label: 'Edit' }
- { name: 'delete', label: 'Delete' }
After several tweaking and failures, I have found a solution, it was documented but I did not expect it to be documented there nested.
Here's the github page: Advanced Design Configuration
We will overwrite the default html.twig file by overriding the {{ block }}
Create an Overwrite Folder
First, create a folder easy_admin inside Resources\views.
Suppose you want to change list.row_actions, head over to the source file from easy-admin usually inside:
vendor\javiereguiluz\easyadmin-bundle\views\includes\ In the last version
Finding the source
Find the list.html.twig file and check out its content for a brief. If you CTRL + F (Find) for list.row_actions, it will show you directly something like this. Now copy the whole block
{% block table_head %}
<tr>
{% for field, metadata in fields %}
{% set isSortingField = metadata.property == app.request.get('sortField') %}
{% set nextSortDirection = isSortingField ? (app.request.get('sortDirection') == 'DESC' ? 'ASC' : 'DESC') : 'DESC' %}
{% set _column_label = (metadata.label ?: field|humanize)|trans(_trans_parameters) %}
{% set _column_icon = isSortingField ? (nextSortDirection == 'DESC' ? 'fa-caret-up' : 'fa-caret-down') : 'fa-sort' %}
<th data-property-name="{{ metadata.property }}" class="{{ isSortingField ? 'sorted' }} {{ metadata.virtual ? 'virtual' }} {{ metadata.dataType|lower }} {{ metadata.css_class }}">
{% if metadata.sortable %}
<a href="{{ path('easyadmin', _request_parameters|merge({ sortField: metadata.property, sortDirection: nextSortDirection })) }}">
<i class="fa {{ _column_icon }}"></i>
{{ _column_label|raw }}
</a>
{% else %}
<span>{{ _column_label|raw }}</span>
{% endif %}
</th>
{% endfor %}
{% if _list_item_actions|length > 0 %}
<th>
<span>{{ 'list.row_actions'|trans(_trans_parameters, 'EasyAdminBundle') }}</span>
</th>
{% endif %}
</tr>
{% endblock table_head %}
Pasting to Overwrite File
To paste/overwrite this, you need to create a file with exact name as the filename where you copied it. In this case, list.html.twig. Then paste it inside the file
IMPORTANT : At top of the file, include this tag -
{% extends '#EasyAdmin/default/list.html.twig' %}
{% block table_head %}
<tr>
{% for field, metadata in fields %}
...code continues...
Why overwrite?
If you edit the file from the source code, you will have trouble deploying it especially if you're using git clone and then composer update.
Overwriting make sure that the code persist even when you deploy it.
I've had the same issue. As for me, I fixed it easier.
First of all try to use this
# app/config/config.yml (Symfony3)
# config/packages/framework.yaml (Symfony4)
framework:
translator: { fallbacks: "%locale%" }
But if you want to override with your translation, create this file:
# translations/EasyAdminBundle.en.yaml
list.row_actions: "My actions"

Setting rendered response into a variable twig Symfony2

I have a controller function which return a response with a value, and I want to call this controller from twig so I use:
{% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %}
the problem is that I want to set this returned value into a variable "x"
I tried this, but it doesn't work.
{% set x = {% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %} %}
According to the documentation, you can do:
{% set x %}
{% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %}
{% endset %}

Resources