Build Form with Single Table Inheritance - php

I have my entity Article and one single table inheritance like this :
/**
* Article
*
* #ORM\Table(name="article")
* #ORM\Entity(repositoryClass="PM\PlatformBundle\Repository\ArticleRepository")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="media", type="string")
* #ORM\DiscriminatorMap({"article" = "Article", "movie" = "Movie", "image" = "Image", "text" = "Text"})
*/
class Article
{
protected $id;
protected $title;
protected $description;
protected $author;
//other attributes and setters getters
}
class Image extends Article
{
private $path;
//getter setter
}
class Movie extends Article
{
private $url;
//getter setter
}
So my article's object type is either Image or movie or text only. Ok now I would like build a form wherein users can post a new article : in this form, the user has to choice between tree type (3 radios button) : image OR movie OR text only and of course the other fields : title and description. How I can do that ? Because with the command
php bin/console doctrine:generate:form myBundle:Article
The form rendered is :
class ArticleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class)
->add('description', TextareaType::class)
->add('save', SubmitType::class);
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'PM\PlatformBundle\Entity\Article'
));
}
}
I don't know the way to implement my STI relation in this form. Because I have not field in my Article entity/object for the type (only in my table).
I have to add a Custom ChoiceType() field but it require a attribute.
When I try to add this in the form :
->add('path', SearchType::class)
->add('url', UrlType::class)
I got this error :
Neither the property "path" nor one of the methods "getPath()", "path()", "isPath()", "hasPath()", "__get()" exist and have public access in class "PM\PlatformBundle\Entity\Article".
Because I have create an instance of Article, not an instance of Image or Movie. Initially I created a STI thinking a new instance of Article would allow me also to define the "type" of article. But not ? Right ?

You will have to make three forms (one for an Article, one for a Movie and one for an Image). Then, in your controller, you have to options to deal with them:
Either you use one action to handle the three forms (you can check wich one is submitted by using $form->isSubmitted())
You create one action by form, and set the form action URL for each form to the correct controller.
Finally, in your template, you encapsulate your forms in a div, and use the example in my previous post.
{% extends "CoreBundle::layout.html.twig" %}
{% block title %}{{ parent() }}{% endblock %}
{% block btn_scrollspy %}
{% endblock %}
{% block bundle_body %}
<div class="well">
<div class="selector">
<input type="radio" name="form-selector" value="article-form"> Article
<input type="radio" name="form-selector" value="movie-form"> Movie
<input type="radio" name="form-selector" value="image-form"> Image
</div>
<div class="form article-form" style="display: none;">
{{ form(articleForm) }}
</div>
<div class="form movie-form" style="display: none;">
{{ form(movieForm) }}
</div>
<div class="form image-form" style="display: none;">
{{ form(imageForm) }}
</div>
</div>
{% endblock %}

I agree with dragoste in the comments: you can't expect the form to deduce by himself the type of class you want to instantiate based on a value.
Roughly, Image and Movie are the same type as Article, but an Article is not an Image and/or a Movie.
You will have to check that manually. You can do that server side like explained in the comments, with a field using mapped: false to determine the type of entity you need to instantiate, or client side with javascript by using three forms (one for a movie, one for an article, one for an image) and by displaying the correct one based on your radio button.
Edit: How to display the correct form in JS?
I created a JSFiddle to show you how you can do this using jQuery : https://jsfiddle.net/61gc6v16/
With jQuery documentation, you should be able to quickly understand what this sample do, and to adapt it to your needs. :)

#Boulzy I did this and it works:
class ArticleController extends Controller
{
public function addAction(Request $request)
{
$form1 = $this->get('form.factory')->create(TextOnlyType::class);
$form2 = $this->get('form.factory')->create(ImageType::class);
$form3 = $this->get('form.factory')->create(MovieType::class);
return $this->render('PMPlatformBundle:Article:add.html.twig', array(
'ArticleTextform' => $form1->createView(),
'ArticleImageform' => $form2->createView(),
'ArticleMovieform' => $form3->createView(),
));
}
public function addArticleTextAction(Request $request)
{
$ArticleText = new TextOnly;
$form = $this->get('form.factory')->create(TextOnlyType::class, $ArticleText);
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
$ArticleText->setAuthor(5);
$ArticleText->setLikes(0);
$em = $this->getDoctrine()->getManager();
$em->persist($ArticleText);
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Annonce bien enregistrée.');
$listComments = $ArticleText->getComments();
return $this->render('PMPlatformBundle:Article:view.html.twig', array(
'article' => $ArticleText,
'listComments' => $listComments
));
}
return $this->render('PMPlatformBundle:Article:add.html.twig', array(
'form' => $form->createView(),
));
}
public function addArticleImageAction(Request $request)
{
//the same system as TextOnly
}
public function addArticleMovieAction(Request $request)
{
//the same system as TextOnly
}
}
(I override action directly in my template. With POST method.)
addAction is my contoller which is called by route for display the view of three forms. As you can see this code works as long as there is no error on submitted form. Because, in this case (when error occured when a form is submitted) each controller needs to return the initial view with the 3 forms. How I can do that ?

Related

Symfony - how to get data from select html tag in view

I am learning Symfony so I am testing various ways to work with database. The idea is to make select dropdown list that contains data from table in database. Each option in select returns value that is id of column from table. Dropdown list is defined in View in this way ('find_res' in action is route to controller):
<form action="{{ path('find_res') }}" method="POST" name="formpt">
<select name="patientId">
{% for patient in patients %}
{{dump(patient)}}
<option value="{{patient.id}}">{{patient.lastname}}{{patient.firstname}}</option><br />
{% endfor %}
</select>
<button type="submit" name="submit">Find results</button>
</form>
so that for chosen patient.id it should show results in table which is defined in code bellow this as standard html table.
In controller method I created list of all patients from table in database and sent it as parameter to this view. And that works just fine. Also, I would not get into details how query is built because the problem is that any $request I try does not return anything, just null. I tried:
$request->request->get('patientId'); //returns null always
$request->get('patientId'); //also null
I even tried to give name to form in view like for instance 'formpt' and then tried it with:
$request->request->get('formpt')['patientId'];
still nothing. This test code:
if($request->getMethod() == 'POST' ) {
\Doctrine\Common\Util\Debug::dump($request->request->get('patientId'));
exit;
}
always returns NULL or string(0) "" for whatever I put in "dump".
What I am doing wrong?
Thanks!
The following is a simple way to implement what you're trying to do with the standard form component (note that I explicitly didn't create a dedicated form type!).
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\NotBlank;
use AppBundle\Entity\Patient;
class DefaultController extends Controller
{
/**
* #Route("/", name="index")
*
* #param Request $request
*
* #return Response
*/
public function indexAction(Request $request)
{
$form = $this->createFormBuilder()
->add('patient', EntityType::class, [
'required' => false,
'placeholder' => '--- Select ---',
'class' => Patient::class,
'choice_label' => function (Patient $patient) {
return sprintf(
'%s, %s',
$patient->getLastname(),
$patient->getFirstname()
);
},
'constraints' => [
new NotBlank()
],
])
->getForm()
->handleRequest($request)
;
if ($form->isSubmitted() && $form->isValid()) {
/** #var $selected Patient */
$selected = $form->get('patient')->getData();
dump($selected);
}
return $this->render('default/index.html.twig', [
'form' => $form->createView()
]);
}
}
the view being:
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
{{ form_widget(form) }}
<button>Find results</button>
{{ form_end(form) }}
{% endblock %}
I understand that the form component (especially form customization) has it's learning curve, but ultimately, if you want to use symfony fully you'll end up using it anyway (why reinvent the wheel). So the sooner you start with it the better.
Maybe try this
For mapped field
public function yourAction(Request $request){
$patient = new Patient();
$form = $this->createForm('AppBundle\Form\PatientType', $patient);
$form->handleRequest($request);
if ($form->isSubmitted())
{
$patientId = $patient->getId();
}
}
If you need to get a non mapped field (field that's not a Patient property)
public function yourAction(Request $request){
$patient = new Patient();
$form = $this->createForm('AppBundle\Form\PatientType', $patient);
$form->handleRequest($request);
if ($form->isSubmitted())
{
$patientCustomField = $form['customField']->getData();
}
}

What is VOLT macro for rendering a <form> tag?

In Phalcon one can create a custom form extending Phalcon\Form\Form. This class has method called setAction, but I cannot find any info on how to automatically render a <form> tag with action that I specified.
My form is called RegisterForm, and I am passing it to VOLT view like this:
$this->view->registerForm = new RegisterForm(new UserModel());
In my VOLT template I can use the registerForm.render('username') macro to automatically render input field registered in my form.
Is there any macro that will create the following?
<form action="/register" method="post">
assuming that I've used:
$this->setAction($this->url->get('index/register'));
in the form definition.
After another day of research, and chatting at Phalcon's Slack channel, I've came to realization that, there is no built-in way of doing what I intended.
Simplest solution is to create a BaseForm class that extends Phalcon\Forms\Form. Here is an example:
<?php
namespace MyNamespace\Common\Form;
use Phalcon\Forms\Form;
class BaseForm extends Form {
/**
* Creates <form> tag in VOLT view.
*/
public function startForm($method = 'post') {
return '<form action="'.$this->getAction().'" method="'.$method.'">';
}
/**
* Creates </form> tag in VOLT view.
*/
public function endForm() {
return '</form>';
}
/**
* Pushes all errors to flash container.
*/
public function error($name) {
if($this->hasMessagesFor($name)) {
foreach($this->getMessagesFor($name) as $message) {
$this->flash->error($message);
}
return true;
}
return false;
}
}
With this, after extending a custom form definition, I'm able to use:
# IndexController.php
public function index() {
$this->view->registerForm = new RegisterForm();
}
# index.volt
{{ registerForm.startForm() }}
{{ registerForm.endForm() }}
{{ registerForm.error('username') }}
Here is how to render a form in Volt:
{{ form('products/save', 'method': 'post') }}
<label for="name">Name</label>
{{ text_field("name", "size": 32) }}
<label for="type">Type</label>
{{ select("type", productTypes, 'using': ['id', 'name']) }}
{{ submit_button('Send') }}
{{ end_form() }}
More info in the Docs.
You can also check Phalcon's project Vokuro for more examples.
Update: Lukasz asked for a solution to render form tag from custom form element with it's properties. Phlacon Form Decorators is the closest solution to the problem I can find.

Symfony3 CollectionType, Data returns as null

I have little problem creating collectiontype with symfony..
I have tried to follow multiple tutorial,like
http://symfony.com/doc/current/cookbook/form/form_collections.html or
http://toni.uebernickel.info/2012/03/15/an-example-of-symfony2-collectiontype-form-field-prototype.html..
but always with same result.
$tags = $form->get('tags')->getData(); returns null.
I'm able to generate add/remove link and indexing is working aswell, but getting data into controller...
Am I missing something important or doing something wrong? Hope someone can help me out or give tip(s).
what I currently have
Task entity
/**
* #ORM\OneToMany(targetEntity="Tag", mappedBy="task",
cascade={"persist", "remove"})
* / protected $tags;
Tag entity
/**
* #ORM\ManyToOne(targetEntity="Task", inversedBy="tags")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
* /
protected $task;
TaskType
->add('tags', CollectionType::class, array(
'entry_type' => TagType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype_name' => '__tag__name__',))
TagType
$builder->add('name', TextType::class, array()));
Macro
{% macro widget_prototype(widget, remove_text) %}
{% if widget.vars.prototype is defined %}
{% set form = widget.vars.prototype %}
{% set name = widget.vars.prototype.vars.name %}
{% else %}
{% set form = widget %}
{% set name = widget.vars.full_name %}
{% endif %}
<div data-content="{{ name }}">
<a class="btn-remove" data-related="{{ name }}">{{ remove_text }}</a>
{{ form_widget(form) }}
</div>
{% endmacro %}
Twig
<div id="post_tags" data-prototype="{{ _self.widget_prototype(form.tags, 'Remove tag')|escape }}">
{% for widget in form.tags.children %}
{{ _self.widget_prototype(widget, 'Remove tag') }}
{% endfor %}
</div>
<a class="btn-add" data-target="post_tags">Add tag</a>
JS
jQuery(function($) {
$(document).on('click', '.btn-add[data-target]', function(event) {
var collectionHolder = $('#' + $(this).attr('data-target'));
if (!collectionHolder.attr('data-counter')) {
collectionHolder.attr('data-counter', collectionHolder.children().length);
}
var prototype = collectionHolder.attr('data-prototype');
var form = prototype.replace(/__tag__name__/g, collectionHolder.attr('data-counter'));
collectionHolder.attr('data-counter', Number(collectionHolder.attr('data-counter')) + 1);
collectionHolder.append(form);
event && event.preventDefault();
});
$(document).on('click', '.btn-remove[data-related]', function(event) {
var name = $(this).attr('data-related');
$('*[data-content="'+name+'"]').remove();
event && event.preventDefault();
});
});
and in Controller
$form = $this->createForm(TaskType::class, $task);
EDIT / UPDATE
Task Entity setters and getters for tags
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
public function add(Tag $tag)
{
$this->tags[] = $tag;
return $this;
}
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag);
}
public function getTags()
{
return $this->tags;
}
Controller:
$task = new Task();
$form = $this->createForm(TaskType::class, $task);
$form->handleRequest($request);
if($form->isValid()){
$tags = $form->get('tags')->getData();
foreach($tags as $tag){
//Here var_dump, echo, print, array_push etc tricks = empty
}
//Also without foreach var_dump = empty
}
Thanks for updating your question with more details.
To solve your problem right away, remember that Doctrine cascade only checks the owning side (the side that has inversedBy - which in this case needs to stay where it is). So you should manually set the task a tag should have.
public function add(Tag $tag)
{
$this->tags[] = $tag;
$tag->task = $this;//added this line
return $this;
}
Assumption - I believe that you haven't examined what you actually need. For the proper solution, I assume you need this functionality, one task has multiple tags, and a tag can be re-used across multiple tasks.
In this case:
1. You're using a OneToMany relationship. If you look at the first tutorial you refer to, you need ManyToMany (http://symfony.com/doc/current/cookbook/form/form_collections.html)
2. Furthermore, you need a uni-directional ManyToMany. Why? You are assigning tags inside a task, not the other way around. Plus, maybe you'll need to tag other entities.
For documentation on ManyToMany (uni-directional) have a look at http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-unidirectional
Task entity
/**
* #var ArrayCollection
*
* #Assert\Valid
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="tasks_tags",
* joinColumns={#ORM\JoinColumn(name="task_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
protected $tasks;
Tag entity
protected $tasks;
Note: When you delete tags from a task, and no other tasks are using a tag you deleted, the tag will be left as an "orphan". Doctrine doesn't work well with orphan removal on ManyToMany relationships, so you'll have to remove these orphans manually. Or you can leave the tag lying around, unused, to be added at a later time.

Symfony & Doctrine: persisting a many to one entity on an embedded form collection

Currently in a bit of a pickle. I have 2 entities: Main and Sub, it is a OneToMany relationship (one main can have many subs) I made a collection of form embedded together. I first had a search form where a user can search a Main by one of its attributes, then it sends them to a page where there is a form with the searched Main, its attributes listed on the form but is disabled so users cannot edit them, and the enabled fields are from the embedded Sub form which users need to enter in for submission.
1) User searches Main by its attribute, i.e. "pono" (PO number)
2) User is redirected to a page that shows the row that he/she searched for with the listed (pono), (cano), (bano) - it is disabled so it cannot be edited
3) Enabled fields are empty and users must enter the information that would be submitted into the Sub entity.
In my Main entity
/**
* #var Sub
* #ORM\OneToMany(targetEntity="Sub", mappedBy="mainId")
*/
protected $sub;
public function __construct() {
$this->sub = new ArrayCollection();
}
And my Sub entity:
/**
* #var integer
*
* #ORM\Column(name="main_id", type="integer")
*/
protected $mainId;
/**
* #ORM\ManyToOne(targetEntity="Main", inversedBy="sub", cascade={"persist"})
* #ORM\JoinColumn(name="main_id", referencedColumnName="id")
*/
protected $main;
In my Main form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pono', 'text', array(
'label' => 'PO: ',
'disabled' => true
))
->add('cano','text', array(
'label' => 'CA: ',
'disabled' => true
))
->add('bano', 'text', array(
'label' => 'BA: ',
'disabled' => true
))
->add('sub', 'collection', array('type' => new SubType()));
}
In my Sub form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('qty','integer', array(
'label' => 'Qty: '
))
->add('location','text', array(
'label' => 'Location: '
))
->add('priority','text', array(
'label' => 'Priority: '
));
}
So on my controller
public function submitItemAction(Request $request, $pono) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ItemBundle:Main')
->findOneByPono($pono);
$cano = $entity->getCano();
$bano = $entity->getBano();
$main = new Main();
$main->setPono($pono);
$main->setCano($cano);
$main->setBano($bano);
$sub = new Sub();
$sub->setMain($main);
$main->getSub()->add($sub);
$form = $this->createForm(new MainType(), $main, array(
'method' => 'POST'
))
->add('submit','submit');
$form->handleRequest($request);
if($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($sub);
$em->flush();
return $this->redirect($this->generateUrl('success'));
}
Now when this is submitted, it's submitting BOTH Main and Sub. It's giving me a duplicate Main and the newly added Sub. I know it is what it's supposed to do, but I need it to only submit the Sub. I tried retrieving the id from Main with a $mainid = $entity->getId(); and putting it into $sub->setMainId($mainid) and I keep getting the error message that main_id cannot be null.
Any takers?
Edit: Twig template:
{{ form_start(form) }}
{{ form_label(form.pono) }}
{{ form_widget(form.pono) }} <br>
{{ form_label(form.cano) }}
{{ form_widget(form.cano) }}<br>
{{ form_label(form.bano) }}
{{ form_widget(form.bano) }} <br>
{% for sub in form.sub %}
{{ form_label(sub.qty) }}
{{ form_widget(sub.qty) }} <br>
{{ form_label(sub.location) }}
{{ form_widget(sub.location) }} <br>
{{ form_label(sub.priority) }}
{{ form_widget(sub.priority) }}<br>
{% endfor %}
{{ form_widget(form.submit) }}
{{ form_end(form) }}
After looking at your code, I think it is possible to make it work, there are a few things you will need to fix. I will edit this answer in a few steps.. Also make a backup/commit of your code before you start changing it.
1) In your MAIN entity (add cascade persist)
/**
* #var Sub
* #ORM\OneToMany(targetEntity="Sub", mappedBy="main", cascade={"persist"})
*/
protected $sub;
2) SUB entity:
Remove protected $mainId; and it's annotation.
Remove cascade={"persist"} from ManyToOne
3) Look at your controller action.
$sub = new Sub();
$sub->setMain($main);
$main->getSub()->add($sub);
Pay attention to the setMain() method. You do not want to do this in controller, but automatically in entity. And also you should add to collection manually, but make a method for it. So you will only have this:
$sub = new Sub();
$main->addSub($sub);
4) In MAIN entity add (you might need to import Sub):
public function addSub(Sub $sub) {
$sub->setMain($this);
$this->sub->add($sub);
return $this;
}
You should also add other methods like removeSub(), removeSub(), getSub(). getSub() returns collection, while the first two will return $this.
5) Controller
Do not persist Sub, but Main. (Doctrine will cascade persistance to Sub)
$em->persist($main);
6) You will need to add 'by_reference' option to sub collection inside you Main Form Type.
->add('sub', 'collection', array('type' => new SubType(), 'by_reference' => false));
This will call the actual addSub() method and not call the add method directly.
7) I do not know why you make a new Main entity below.
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ItemBundle:Main')
->findOneByPono($pono);
$cano = $entity->getCano();
$bano = $entity->getBano();
$main = new Main();
$main->setPono($pono);
$main->setCano($cano);
$main->setBano($bano);
Try to change to:
$em = $this->getDoctrine()->getManager();
$main = $em->getRepository('ItemBundle:Main')
->findOneByPono($pono);
You probably should define Pono as unique.

howto handle edit forms with FileType inputs in symfony2

in a symfony2 application a entity Message has a one-to-many relation to documents. Documents represents user uploads. i created a form. I realized two Forms: MessageForm and DocumentForm. DocumentForm lives inside a collection FormField in MessageForm. Uploading and processing files does work.
But if i want to edit the entity Message the Form contains as many empty FileInputs as there are Documents existing. desired behaviour would be:
FileInputs to upload new files
Filename (link) to existing files
Possibility to delete existing files
This should be handled inside the form. Changes should be done when the form is submitted.
How can this be realized?
Solution is to write a custom form type extension. as described on http://symfony.com/doc/2.1/cookbook/form/create_form_type_extension.html.
filetype extension
<?php
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* Class FileTypeExtension
*
* #see http://symfony.com/doc/2.1/cookbook/form/create_form_type_extension.html
*/
class FileTypeExtension extends AbstractTypeExtension
{
/**
* Returns the name of the type being extended.
*
* #return string The name of the type being extended
*/
public function getExtendedType()
{
return 'file';
}
/**
* Add the image_path option
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setOptional(array('file_path', 'file_name'));
}
/**
* Pass the image url to the view
*
* #param FormView $view
* #param FormInterface $form
* #param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (array_key_exists('file_path', $options)) {
$parentData = $form->getParent()->getData();
if (null !== $parentData) {
$propertyPath = new PropertyPath($options['file_path']);
$fileUrl = $propertyPath->getValue($parentData);
} else {
$fileUrl = null;
}
$view->set('file_url', $fileUrl);
}
if (array_key_exists('file_name', $options)) {
$parentData = $form->getParent()->getData();
if (null !== $parentData) {
$propertyPath = new PropertyPath($options['file_name']);
$fileName = $propertyPath->getValue($parentData);
} else {
$fileName = null;
}
$view->set('file_name', $fileName);
}
}
}
customized file_widget
{% block file_widget %}
{% spaceless %}
{% if file_url is not null %}
<div>{{ file_name }}</div>
<div style="display:none">{{ block('form_widget') }}</div>
{% else %}
{{ block('form_widget') }}
{% endif %}
{% endspaceless %}
{% endblock %}
services.yml
parameters:
foobar.file_type_extension.class: Foobar\Form\Extension\FileTypeExtension
services:
foobar.file_type_extension:
class: %replacethis.file_type_extension.class%
tags:
- { name: form.type_extension, alias: file }
inside a formtype
$builder->add('file','file', array(
"label" => "Datei",
"required" => true,
"attr" => array(),
"file_path" => "webPath",
"file_name" => "name"
));
that's it ;)
In addition to the above answere - wich will let you build a file input wich can be rendered as a link (if it has an url) or a field (if it doesn't) - you might take a look at
http://symfony.com/doc/2.0/cookbook/form/form_collections.html
Wich in conjunction with some jQuery will let you add fields in UI.

Categories