Overlapping forms - symfony

I have a problem with overlapping forms in Symfony 2. I'm trying to create an application with photos albums.
To do so, I need to create an album and adding him photos during this process.
Photos are link with onl one album.
I think that my code is right on backend but the photo's form never shown inside the album's form. I think the problem is in the form himself.
A photo have to attribute: a file and a name.
This is my form.
<script type="text/javascript">
$(document).ready(function() {
var $container = $('#thelink_albumbundle_albumtype_photos');
function add_photo() {
index = $container.children().length;
$container.append(
$($container.attr('data-prototype').replace(/\$\$picture\$\$/g, index))
);
}
if($container.children().length == 0)
add_tag();
$('#add_photo').click(function() {
add_photo();
});
});
<form method="post" enctype="multipart/form-data">
{{ form_widget(form) }}
<div id="thelink_albumbundle_albumtype_photos" data-prototype="<div>
<label class=" required">$$photo$$</label>
<div id="thelink_albumbundle_albumtype_photos$$photo$$">
<div><label for="thelink_albumbundle_albumtype_photos$$photo$$_photo"
class=" required">Photo</label>
<input type="file" id="thelink_albumbundle_albumtype_photos$$photo$$_photo"
name="thelink_albumbundle_albumtype[photos][$$photo$$][picture]" required="required"
maxlength="255" value="" /></div></div></div>">
</div>
<br />
<a href="{{ path('TheLinkAlbumBundle_index') }}" title="Retourner sur la liste des Albums">
Annuler la {% if news is defined %}Modification{% else %}Création{% endif %}
</a>
<input type="submit" value="{% if album is defined %}Modifier{% else %}Créer{% endif %} l'Album" />
Do you have any idea ? Or the problem is else where ?

It looks like you're manually entering the data prototype? Assuming "photos" is a collection type. Make sure you have the "allow_add", "allow_delete", and "prototype" options set to true:
->add('photos', 'collection', array(
'type' => new PhotoType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true
))
Then you can just do {{ form_row(form.photos) }} and it should render the prototype automatically.
It would help more if you could post your form type as well.

Related

Symfony 3 : How to Embed a Collection of Forms - after submit I only have one element in the array instead of many

Hello guys,
On Symfony 3 :
I tried to follow the requirements of "How to Embed a Collection of Forms" from Symfony 3 Documentation. It works for a defined list as they propose first. But when I try the next step: Allowing new Tags with the Prototype, it only returns my last embed Form.
So I know that my Entity works, aswell as the EntityType. The error must be on the Twig.
Thanks in advance for your help!
It works for a defined list as they propose in the first part.
So I know that my Entity works, aswell as the EntityType.
enter code here
{% extends "#App/baseAdmin.html.twig" %} .
{% block contenu %} .
{#{{ dump(formreservation) }}#} .
{#{{ form(formreservation) }}#} .
<div> .
Date : {{ "now"|date("d/m/Y") }} .
{{ form_start(formreservation, {'attr': {'class': 'form'}}) }} .
{#{{ dump(formreservation) }}#} .
<p> .
{#retourne message erreur si besoin après méthode isValid dans Controleur#} .
{{ form_errors(formreservation.spectacle) }} .
{{ form_label(formreservation.spectacle, null,
{'label_attr': {'class': 'form-label'}}) }} :
{{ form_widget(formreservation.spectacle, {'attr':
{'class': 'form-control'}}) }} .
</p>
<p>
{{ form_label(formreservation.spectateur, null,
{'label_attr': {'class': 'form-label'}}) }}
<ul class="spectateur" data-prototype="{{ form_widget(formreservation.spectateur.vars.prototype)|e('html_attr') }}">
</ul>
</p>
<p>
{#retourne message erreur si besoin après méthode isValid dans Controleur#}
{{ form_errors(formreservation.client) }}
{{ form_label(formreservation.client, null,
{'label_attr': {'class': 'form-label'}}) }} :
{{ form_widget(formreservation.client, {'attr':
{'class': 'form-control'}}) }}
</p>
{# génération du champ CSRF - _token# (Cross Site Request Forgeries en champ caché #}
{{ form_rest(formreservation) }}
{{ form_end(formreservation) }}
</div>
{# Partie JavaScript #}
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous">
</script>
<script>
var $collectionHolder;
// setup an "add a tag" link
var $addTagButton = $('<button type="button" class="add_tag_link">Ajoutez un spectateur</button>');
var $newLinkLi = $('<li></li>').append($addTagButton);
jQuery(document).ready(function() {
// Get the ul that holds the collection of tags
var $collectionHolder = $('ul.spectateur');
// add a delete link to all of the existing tag form li elements
//inutile pour le moment, ajoute un bouton qui créé la confusion
/* $collectionHolder.find('li').each(function() {
addTagFormDeleteLink($(this));
});*/
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addTagButton.on('click', function(e) {
// add a new tag form (see next code block)
e.preventDefault();
addTagForm($collectionHolder, $newLinkLi);
});
});
function addTagForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
//console.log($collectionHolder);
var prototype = $collectionHolder.data('prototype');
//console
// get the new index
var index = $collectionHolder.data('index');
var newForm = prototype;
// You need this only if you didn't set 'label' => false in your tags field in TaskType
// Replace '__name__label__' in the prototype's HTML to
// instead be a number based on how many items we have
newForm = newForm.replace(/__name__label__/g, 'Spectateur n° '+ index);
//newForm = newForm.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1 );
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
// add a delete link to the new form
addTagFormDeleteLink($newFormLi);
}
function addTagFormDeleteLink($tagFormLi) {
var $removeFormButton = $('<button type="button">enlever ce spectateur</button><br>');
$tagFormLi.append($removeFormButton);
$removeFormButton.on('click', function(e) {
// remove the li for the tag form
e.preventDefault();
$tagFormLi.remove();
});
}
</script>
{% endblock %}
Expected result : a collection containing all the embed Forms.
Actually it only returns the last element in the embed Form. I did check on the Entity and it doesn't use the "add" method that I did add to the entity.
here the add part of ReservationType builder:
->add('spectateurs', CollectionType::class, [
'entry_type' => SpectateurReservationType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
] .
) .
)
You just have commented a part of JS code
newForm = newForm.replace(/__name__/g, index);
Uncomment this and anything would be nice
my line was:
newForm = newForm.replace(/name__label/g, 'Spectateur n° '+ index);
My mistake was, I thought I could change this as a textlabel:
Great it only was this! many thanks, you save me! Now it works perfectly!

Empty $request->files (FileBag) when using a custom form (not the built in Type from SF)

I'm having issues with file uploads... I'm adding manually a few inputs within a Symfony form (Offer) to allow the user to create a new Company if he doesn't want to use one that already exists, it works very well for the text/textarea fields, but my file Input doesn't work properly. Its content appears in the request parameters instead of in the files parameters of my Request, see below what I get when I dump($request) :
OfferController.php on line 173:
Request {#86 ▼
+attributes: ParameterBag {#70 ▶}
+request: ParameterBag {#69 ▼
#parameters: array:2 [▼
"offer" => array:15 [▶]
"company" => array:6 [▼
"name" => "entreprise"
"pic_logo" => "ah.png" //THIS SHOULD NOT BE HERE BUT IN THE FILEBAG
"sector" => "2"
"status" => "fdsfds"
"revenues" => "sdfsdf"
"content" => "<p>sdfdsf</p>\r\n"
]
]
}
+query: ParameterBag {#49 ▶}
+server: ServerBag {#73 ▶}
+files: FileBag {#63 ▼
#parameters: [] //NO FILE HERE :'(
}
Here is the code that produces this :
View :
{{ form_start(form) }}
<h2>Employeur</h2>
{{ form_row(form.company) }}
<a class="company-new" href="#" id="toggleCompanyForm">Ajouter une nouvelle entreprise...</a>
<div id="form_company" style="display:none">
<div class="row">
<div class="large-6 small-12">
<label>Nom de l'entreprise</label>
<input type="text" name="company[name]">
</div>
<div class="large-6 small-12">
<label>Logo de l'entreprise</label>
{% for message in app.session.flashBag.get('warning_logo') %}
<div class="alert alert-warning">
{{ message }}
</div>
{% endfor %}
<input type="file" name="company[pic_logo]"> {# MY FILE INPUT #}
</div>
And the controller :
public function createAction(Request $request)
{
$confirmed = false;
$entity = new Offer();
$em = $this->getDoctrine()->getManager();
$sectors = $em->getRepository('ModelBundle:Sector')->findAll();
$form = $this->createForm('ModelBundle\Form\OfferType', $entity);
$session = $request->getSession();
die(dump($request));
To upload a file through HTML form you have to add enctype="multipart/form-data" to the tag:
<form action="..." method="post" enctype="multipart/form-data">
Or change opening form tag in twig:
{{ form_start(form, {'multipart': true}) }}

OneupUploaderBundle and jQuery-File-Upload on symfony 2

I've been trying this but I'm confused since I'm new to Symfony Events and stuff.
This is where I've got so far:
composer bundle installation
AppKernel.php, routing.yml, services.yml, config.yml, UploadListener.php file modifications
And it works, the file I put is actually being uploaded to the folder, and I got the status bar filling... but I need something else:
somehow I need to post (and read) an item id (integer) along with the file (or to be able to set the filename when the file is being copied to the output folder)
if something goes wrong with the upload, how do I send an error message back?
In the example (jQuery-File-Uploader), the code returns the filename of the file that was uploaded, my code doesn't do that, I mean the code is there, but it doesn't work
I'm posting the code I have.
HTML code (here is the piece where I call the jQuery-File-Upload
<tr>
<td>{{ clienteCorporativo.nombreComercial|upper }}</td>
<td>{% if clienteCorporativo.afiliadosUploads|length == 0 %}Nunca{% else %}{{ (clienteCorporativo.afiliadosUploads|last).fecha|date('d/mmm/y') }}{% endif %}</td>
<td>
{% if clienteCorporativo.formatoExcelAfiliados == null %}
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-upload"></i>
<span>Seleccionar Excel</span>
<input id="fileupload_{{ clienteCorporativo.id }}" class="fileupload" data-id="{{ clienteCorporativo.id }}" type="file" name="files[]" multiple>
</span>
{#<span style="color: #8c8c8c"><span class="glyphicon glyphicon-upload"></span> Seleccionar Excel </span>#}
{% else %}
<input id="fileupload_{{ clienteCorporativo.id }}" class="fileupload" type="file" name="files[]" data-url="{{ oneup_uploader_endpoint('gallery') }}" />
{#<a role="button" data-toggle="modal" data-target="#myModal" data-operation="loadOne" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-upload"></span> Seleccionar Excel</a> #}
{% endif %}
<a role="button" data-toggle="modal" data-target="#myModal" data-operation="defineFormat" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-list-alt"></span> Definir Formato</a>
{% if clienteCorporativo.afiliadosUploads|length == 0 %}
<span style="color: #8c8c8c"><span class="glyphicon glyphicon-repeat"></span> Revertir Última Carga </span>
{% else %}
<a role="button" data-toggle="modal" data-target="#myModal" data-operation="undoLast" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-repeat"></span> Revertir Última Carga</a>
{% endif %}
</td>
<td>
<div id="progress_{{ clienteCorporativo.id }}" class="progress text-center">
<div class="progress-bar progress-bar-success">
<span id="files_{{ clienteCorporativo.id }}"></span>
</div>
</div>
</td>
</tr>
js script (the "each" sentence does nothing)
<script>
/*jslint unparam: true */
/*global window, $ */
var idFile = 0;
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
$('.fileupload').fileupload({
url: '{{ oneup_uploader_endpoint('xlsfile') }}',
dataType: 'json',
done: function (e, data) {
var eventTrigger = $(this)
idFile = eventTrigger.data('id')
$.each(data.result.files, function (index, file) {
$('#files_'+idFile).html(file.name);
});
},
progressall: function (e, data) {
var eventTrigger = $(this)
idFile = eventTrigger.data('id')
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress_'+idFile+' .progress-bar').css(
'width',
progress + '%'
);
},
formData: [ {"id":idFile} ]
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
//
});
</script>
The other files (AppKernel.php, routing.yml, services.yml, config.yml, UploadListener.php) are just like the OneupUploaderBundle documentation says (I've changed things and then rolled back since I didn't got the results I expected). I think I chew more that I could swallow on this one...
Your form fields will be posted with the file upload. Or you can use the form_data: {} option in your $('#myFile').fileUploader() constructor. But it will submit your form fields by default and you can handle those in the usual way.
$('#myFile').fileupload({
dataType: 'json',
formData: {
'file_id': 1
},
You have to craft your own return response in your UploadListener. Then parse the results on the front-end (Javascript).
$response = $event->getResponse();
$response['success'] = true;
$response['files'] = [
'file' => [
'name' => $event->getFile()->getPathname()
]
];
return $response;

Get selected option and all request data in twig form

I have this form in twig, and I want to get the selected option and the value of the input field from a simple html form:
(PS: Don't say 'You'd better generate a form using the controller!' I know that, but I have a reason why I want to create a form in twig: because that allows me to create as many forms as I want using a for loop.)
I tried to pass arguments in the action path, but that didn't work.
<form action="{{ path('changeProf') }}" method="post" id="form">
<section class="col-lg-9 col-md-9 col-sm-9 col-xs-9" style="position: relative; left: 35%;top: 6vmin">
<label style="display:inline-table;">
<span> <input type="text" value="{{ user.id }}" disabled="true" id="iduser"style="max-width: 18vmin;"/></span>
</label>
</section>
<section class="col-lg-9 col-md-9 col-sm-9 col-xs-9"style="position: relative; left: 35%;top: 6vmin">
<label style="display:inline-table;">
<span>{% set k=1 %}
<select id="profil">
{% for prof in profArr %}
<option value="{{ prof }}"> {{ prof }} </option>
{% endfor %}
</select>
</span>
</label>
</section>
<input type="submit" class="btn btn-info btn-xs" style="position: relative;top:18vmin;left:-28%">
</form>
This is the action that handles the form :
/**
* #Route("/profile/chProf",name="changeProf")
* Method ("POST")
* #Template()
*/
public function changeProfAction(Request $request)
{
$session = new Session();
$session->start();
$search = $session->get('user');
$gestAcces = $session->get('acces');
$gestEtat = $session->get('etatUser');
$gestCont = $session->get('contenu');
$repMsg = $session->get('repMsg');
$gestRec = $session->get('Reclam');
$gestMess = $session->get('gestMess');
$gestMp = $session->get('gestMp');
if ($search == Null) {
return $this->redirectToRoute('empty', array('search' => $search,
'contenu' => $gestCont,
'gestAcces' => $gestAcces,
'gestEtat' => $gestEtat,
'repMsg' => $repMsg,
'gestRec' => $gestRec,
'gestMess' => $gestMess,
'gestMp' => $gestMp,
));
}
$em = $this
->getDoctrine()
->getManager();
$reposit = $em->getRepository("CNAMCMSBundle:userprof");
$rep = $em->getRepository("CNAMCMSBundle:profil");
$userprof=new userprof();
$libprof=$request->request->get('profil');
$iduser=$request->request->get('iduser');
$idprof=$rep->findOneBy(array('libelle'=>$libprof));
$userprof->setIdUser($iduser);
$userprof->setIdProfil($idprof);
$em->persist($userprof);
$em->flush();
return $this->render('CNAMCMSBundle:Default:userProf.html.twig', array(
'search'=>$search,
'contenu'=>$gestCont,
'gestAcces'=>$gestAcces,
'gestEtat'=>$gestEtat,
'repMsg'=>$repMsg,
'gestRec'=>$gestRec,
'gestMess'=>$gestMess,
'gestMp'=>$gestMp,
));
}
I think I found out what caused the error you receive.
$request->request->get('profil'); returns NULL.
This means, the form did not send a profil entry.
Look where is the profil in the form:
<input type="text" value="{{ user.id }}" disabled="true" id="iduser"style="max-width: 18vmin;"/>
There is no name attribute! Which is actually what is sent with the request. The name attribute, not the id. The id is used only for local styles and javascripts.
The solution:
<input type="text" value="{{ user.id }}" disabled="true" id="iduser" name="iduser" style="max-width: 18vmin;"/>
Do the same for profil
Hope this helps.

How to access each items of form_widget(form.**)

How to access the each form item
$builder->add('icon', 'entity', array(
'class' => 'UserBundle:IconPics',
'property' => ‘label', 'expanded' => true, 'multiple' => false,
));
in twig
{{ form_label(form.icon) }}
{{ form_widget(form.icon) }}
it show this codes automatically and works well as radio button selector.
<div id="fos_user_registration_form_icon">
<input type="radio" id="fos_user_registration_form_icon_1" name="fos_user_registration_form[icon]" required="required" value="1" />
<label for="fos_user_registration_form_icon_1" class="required">pictureA.jpg</label>
<input type="radio" id="fos_user_registration_form_icon_2" name="fos_user_registration_form[icon]" required="required" value="2" />
<label for="fos_user_registration_form_icon_2" class="required">pictureB.jpg</label></div>
But I want to access each items in this code manually.
Since,I want to change code like this.
pictureB.jpg --> <img src="pictureB.jpg">
pictureA.jpg --> <img src="pictureA.jpg">
Is it possible??
If you want to customise the way any form widget is rendered, you've then to override it. Take a deeper look at How to customize Form Rendering section of the documentation.
You can find here the default behaviour of all the form fields widget blocks. As described in the documentation, you've to,
First, know which block to override.
Then, Override the block using form theming (the documentation
is full of examples whether you need to override your widget only
when a given template is concerned or globally on your application)

Resources