remove submit from query parameter - symfony

I have a search form. Problem is when I post it it creates a variable for the submit button
?search=key&submit=
I cant seem to figure out how to remove this and only show
?search=key
Any Ideas? Thanks
private function createSearchForm()
{
$builder = $this->get('form.factory')->createNamedBuilder(null, 'form',null, array('csrf_protection' => false))
->setAction($this->generateUrl('trips'))
->setMethod('GET')
->getForm()
->add('search', 'text', array('required' => false, 'label' => false))
->add('submit', 'submit')
;
return $builder;
}

I think it would be nicer to use POST for forms.
So I explain to you below how you can have the same functionality (including permalink to searchResult) with POST. The URLs will even look nicer: Instead of ?search=bla it will be /search/bla.
Route setup:
search:
path: /search/
defaults: { _controller: "AcmeDemoBundle:Search:searchRedirect" }
requirements: { _method: POST }
search_result:
path: /search/{search}
defaults: { _controller: "AcmeDemoBundle:Search:search" }
requirements: { _method: GET}
And then in searchRedirectAction(Request $request) just redirect to search_result
return $this->redirect(
$this->generateUrl('search_result', array(
'search'=>$request->get('search', '')
))
);

All form fields with name attribute are in query string. So easy way is just manually render submit in template and omit name.

I solved this a little differently since I had a lot of forms that were going to need this functionality.
Symfony 3.x:
I created a form_theme that overrides 1 block
{# app/Resources/views/twig/form_themes/overrides.html.twig #}
{%- block button_attributes -%}
id="{{ id }}" {% if type|default('button') != 'submit' %}name="{{ full_name }}"{% endif %}{% if disabled %} disabled="disabled"{% endif -%}
{{ block('attributes') }}
{%- endblock button_attributes -%}
Then in my config:
twig:
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
form_themes:
- 'bootstrap_3_layout.html.twig'
- 'twig/form_themes/overrides.html.twig'
This will basically remove the name field from all submit type buttons, and therefor wont be included in your query params for GET requests.
** This may have some unintended side effects like not being able to run ->isClicked() on a submit button. But for my case I dont need that.

Related

Pass custom data to Form Theme in Symfony/Twig

I'm new to Symfony, currently working with 4.4, and am trying to implement a simple form theme for one specific form, i.e. the theme is in the same file as the form's html.twig file. I have my own form_row block and I'm trying to pass in custom data (an icon to use within the div) when calling it, so something like (this is highly summarised!):
{{ form_row(signUpForm.email, {
attr: { placeholder: 'e.g. bobsmith#gmail.com' },
icon: 'envelope'
}) }}
then try to render in the form as
{%- block form_row -%}
<div>
{{ form_label(form) }}
{{ form_widget(form, {attr: class: 'input'}) }}
<i class="icon {{ icon }}"></i>
</div>
I tried also passing icon via the formBuilder, along the lines of
$builder
->add('email', EmailType::class, [
'attr'=> ['icon' => 'envelope']
])
but no joy. Surely this must be possible! Any assistance would be much appreciated. Thanks
I'm not sure but you can access to your form variable with {{form}} in your theme. So you can use it.
Hope this help
Edit:
You can add property in your entity and use it in template like this :
{%- block form_row -%}
<div>
{{ form_label(form) }}
{{ form_widget(form, {attr: class: 'input'}) }}
{% set myData = form.vars.value %}
<i class="icon {% if myData.type == 'mail' %}envelope{% endif %}"></i>
I think you have a better way to do this but i do something like that and it's work.
So, I managed to find the "proper" way to do what I want: a Form Type Extension. The Symfony Casts tutorial on it is pretty good. In short, you create a class to extend your main form input class; in my case I was dealing with a text based input, so I created an App\Form\ypeExtension\TextIconExtension class, extended from FormTypeExtensionInterface, then implemented configureOptions and buildView (I removed the functions in the interface I didn't fill in):
class TextIconExtension implements FormTypeExtensionInterface
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['icon'] = $options['icon'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'icon' => 'user'
]);
}
public function getExtendedType()
{
return TextType::class;
}
public function getExtendedTypes(): iterable
{
return [TextType::class];
}
}
Then, in my form template, I can simply pass a value for icon:
{{ form_row(signUpForm.email, {
attr: { placeholder: 'e.g. bobsmith#gmail.com' },
icon: 'envelope'
}) }}

Symfony3.1 & Sonata Admin - list field's template is ignored

I use Sonata Admin 3.13 with Symfony 3.1 and want to display the uploaded image in the listview. I have a PaintingAdmin with the following ListFields:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name', null, ['label' => 'Name'])
->add('category', null, ['label' => 'Kategorie'])
->add('size', null, ['label' => 'Größe'])
->add('imageFilename', null, [
'template' => 'sonata:imagepreview.html.twig',
'label' => 'Bild'
]);
;
}
And a template at app/Resources/views/sonata/imagepreview.html.twig
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
<div>
{% if object.imageFilename != null %}
<img src="{{ asset('uploads/images/' ~ object.imageFilename) }}" class="img-responsive" />
{% else %}
<div class="warn">Kein Bild</div>
{% endif %}
</div>
{% endblock %}
but the template is completly ignored, it shows only the value imageFilename. Everything else works fine (i.e. the label is shown as Bild)
You need to tell Sonata that you are using a custom template.
You can do it in your admin service declaration:
librinfo_crm.admin.organism:
class: Librinfo\CRMBundle\Admin\OrganismAdmin
arguments: [~, Librinfo\CRMBundle\Entity\Organism, LibrinfoCRMBundle:OrganismAdmin]
tags:
- name: sonata.admin
manager_type: orm
group: Customers Relationship Management
label: librinfo.crm.organism_admin.label
label_translator_strategy: blast_core.label.strategy.librinfo
calls:
- [ setTemplate, [list, LibrinfoCRMBundle:OrganismAdmin:list.html.twig]]
or you can override the $templates array() of your admin class.
If you want to use 'classic' symfony template inheritance your custom template should have the same path ant name than the original one so if you are trying to replace SonataAdminBundle:CRUD:base_list_field.html.twig your custom template should be in app/Resources/view/CRUD/base_list_field.html.twig
I suggest that you use full path to template:
app/Resources/views/sonata/imagepreview.html.twig
->add('imageFilename', null, [
'template' => 'sonata\imagepreview.html.twig',
'label' => 'Bild'
]);
So, as you can sonata\imagepreview.html.twig is relative to app/Resources/views/ folder.
In symfony of version < 4.x we have two ways of placing the twig tempates:
Inside the bundle
RealPath: `src\AppBundle\Resources\views\MyCustomFolder\my_file.html.twig`
Path: `AppBundle::MyCustomFolder\my_file.html.twig`
Outside the bundle in app folder
RealPath: `app\Resources\views\MyCustomFolder\my_file.html.twig`
Path: `MyCustomFolder\my_file.html.twig`
You can read more in Official Symfony documantation

Symfony Easyadmin - How to add a custom action near "btn action-new"?

I would like to add a custom action near " btn action-new" in list page.
I try:
entities:
Pratiquant:
class: AppBundle/Entity/Pratiquant
actions:
- {name: 'fichePresence', type: 'method', action: 'fichePresence', label: 'fiche de presence' }
I don't need this:
entities:
Pratiquant:
class: AppBundle/Entity/Pratiquant
list:
actions:
- {name: 'fichePresence', type: 'method', action: 'fichePresence', label: 'fiche de presence' }
Hope someone understand me!
Your configuration is correct ... but it doesn't do what you want to achieve. Right now, all the actions configured for the list view are considered actions for the items displayed in the listing. There is no built-in way to define "global actions" for list view.
In any case, you can do what you want by overriding a small fragment of the list template. To do so, create the following Twig template (it's very important to store it in that exact location):
{# app/Resources/views/easy_admin/Pratiquant/list.html.twig #}
{% extends '#EasyAdmin/default/list.html.twig' %}
{% block view_actions %}
{{ parent() }}
Fiche de presence
{% endblock %}
This will execute the fichePresenceAction() method of your custom AdminController.
With EasyAdmin 3 :
public function configureActions(Actions $actions): Actions
{
$fichePresence = Action::new('fichePresence', 'fiche de presence', 'fa fa-download')
->linkToCrudAction('fichePresenceAction')
->createAsGlobalAction();
return $actions
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_INDEX, $fichePresence);
}
See documentation

edit only the first entity inside an embedded collection

I have a parent entity called Publisher and a child entity called User with a ManyToMany relation.
Inside the publisher form, I want to create/edit also the first user, which I achieve like this:
$builder
->add('title')
->add('users', 'collection', array(
'type' => new UserType(),
'allow_add' => true,
))
and in my twig template, I do
{{ form_row(edit_form.users.0.firstname) }}
{{ form_row(edit_form.users.0.lastname) }}
{{ form_row(edit_form.users.0.email) }}
This obviously only works as long as there is just one user assigned to the publisher, because otherwise symfony tries to validate the other users as well, whose data is missing.
Can someone give me a hint how to edit only the first user item in the collection from the publisher form?
You can set the field users "rendered" after having displayed the firt user:
{{ form_row(edit_form.users.0.firstname) }}
{{ form_row(edit_form.users.0.lastname) }}
{{ form_row(edit_form.users.0.email) }}
{% do edit_form.users.setRendered %}
With setRendered, Symfony2 won't try to validate the next users.
I solved the problem using Cerad's solution by introducing a getter and setter for the first user.
public function setFirstUser($user)
{
$this->users[0] = $user;
return $this;
}
public function getFirstUser()
{
return $this->users[0];
}
and in the form doing this
$builder
->add('title')
->add('firstUser', new UserType())
and calling the fields of the firstUser in the twig template The setRendered line just supresses other properties of the user object.
{{ form_row(edit_form.firstUser.firstname) }}
{{ form_row(edit_form.firstUser.lastname) }}
{{ form_row(edit_form.firstUser.email) }}
{% do edit_form.firstUser.setRendered %}
EDIT: because of Cerads feedback about the non-deterministic ordering of SQL rows I chose to create a real property "adminUser", which is a OneToOne relation to the first user attached to the entity.

How to get params in twig file

how can i use $_GET params in TWIG file like using PHP and alerting with JS.
URI-> ?comment=added...
in TWIG,
if($_GET['comment'] == "added"){
...echo '<script>alert("in TWIG file!");</script>';
}
hope it will help you
{% if app.request.get('comment') == "added" %}
<script>alert("in TWIG file!");</script>
{% endif %}
Depending on what you're really trying to achieve, the "Symfony way" of showing confirmation messages would be to use "Flash Messages":
YourController.php:
public function updateAction()
{
$form = $this->createForm(...);
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
// do some sort of processing
$this->get('session')->getFlashBag()->add(
'notice',
'Your changes were saved!'
);
return $this->redirect($this->generateUrl(...));
}
return $this->render(...);
}
Your TwigTemplate.twig:
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="flash-notice">
{{ flashMessage }}
</div>
{% endfor %}
This way you have multiple advantages:
Redirecting after action prevents form reloading.
Message cannot be triggered from outside.
Flash messages are only fetched once.
See the official documentation on this topic.
The "correct" solution would be use your controller to provide a function to Twig rather than switching on the querystring. This will be more robust and provide better security:
Controller:
function someAction()
{
$params = array('added' => false);
if( /* form logic post */ )
{
//some logic to define 'added'
$params['added'] = true;
}
$this->render('template_name', $params);
}
view:
{% if added %}
<script>alert('added');</script>
{% endif %}
The reasoning is that this is more secure (I can't trigger the alert by just browsing to the url), it maintains all business logic in the controller and you're also able to handle any errors - e.g. if you browse to foo.php?comment=added and there is an error wherein your comment isn't added, the user will still receive the alert.

Resources