I have an order and a client entity.
I am wondering if it's possible with the actual Symfony2 form system to create an order form which will allow to:
Select several clients from a dropdown (mix of collection and entity form type)
And to create new clients on the fly (the default way for the collection type) if not in the dropdown list.
I've seen some way to do it by creating multiple forms in the same page, but this is not the way I would like to achieve it.
Are there any better ways to do this?
I had a similar problem which may lead to your resolution:
I have a Category and Item relationship (Many-to-One) and I wanted to either select an existing item or create a new item.
In my Form class:
$builder->add('item', 'entity', array(
'label' => 'Item',
'class' => 'ExampleItemBundle:Item',
));
$builder->add('itemNew', new EmbedItemForm(), array(
'required' => FALSE,
'mapped' => FALSE,
'property_path' => 'item',
));
$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (!empty($data['itemNew']['name'])) {
$form->remove('item');
$form->add('itemNew', new EmbedItemForm(), array(
'required' => TRUE,
'mapped' => TRUE,
'property_path' => 'item',
));
}
});
You can map two fields in a form to the same property using the property_path option. Then, using form events, use the submitted data to make a decision and modify the form so that only one of the fields has a mapped option that is true.
If I have understood, you want to create and store new clients in a Form "on fly", at the moment. I think that you have to do that using JavaScript and set an additional action in your controller.
JS -> Capture the event to add new client to you database (i.e. "Add new" button click event)
JS -> Inside this event, call via AJAX to your controller with the values of new client. (Using FOSJsRoutingBundle is easy to do)
Symfony2 -> Inside your new action, store the new client in your database.
JS -> OnSuccess event, in your AJAX call, add the new Client to your DropDownBox
(ddb.append(new element tag)
Just doing that you have your new client stored in the database and added to your dropdownbox
For my part i had the same kind of problem and i resolved it by creating 2 attribute in my formType;
For example, for you it would be:
customer->entity
new_customer-> collection
In your order entity file you will have to add 3 methods (getter, setter, and remover) getter and remover don't do anything but setter should call the setCustomer(c)
I'm not sure if it is the best way but it's the only way I figure it out!
The collection Form type allows to add and delete on the fly with allow_add and allow_delete attribute.
More informations by following these 2 links :
Official collection form field type reference
Cookbook about add and delete on the fly with collection type
If you don't like to get supplementary forms on the same page, you can integrate them in dialog boxes... But you definitely need a form to create new items...
Related
I've made a custom page in backpack admin panel. This page is non-CRUD (not related to any model). There are several forms on it, with date pickers, select inputs, etc. So I'am trying to find a way to use backpack fields to create these date pickers and select inputs. Because it seems to be awkward to embed custom js-controls into the project, as Backpack already has appropriate fields.
The only solution I came up with, is to create a crud controller for random model, disable all operations except create, use create operation view as custom page (backpack fields are available this way), and finally override store() method - to prevent creating new model entry in DB.
So, is there a proper way to access backpack fields on custom (non-CRUD) page?
Backpack 4.x fields aren't meant to be used outside CRUDs, but you can do that.
Option A
At their core, Backpack fields are just Blade views, so you can load them using the Blade helper #include(). Just make sure to pass along all variables that the blade file needs. I believe in 99% of the fields that will be a $field and a $crud variable, so this will work:
#php
// set the CRUD model to something (anything)
// but ideally it'd be the model of the entity that has the form
$crud = app()->make('crud');
$crud->setModel(\App\Models\Monster::class);
#endphp
#include('crud::fields.number', [
'crud' => $crud,
'field' => [
'name' => 'price',
'label' => 'Price',
'prefix' => '$'
]
])
This way, you only load the bits you actually want (the inputs), without the overhead of a CrudController. You can point the form to your custom controller and do the saving yourself. What you need to pass for a $field above is a Backpack field definition in array form.
This way is super-simple, but it has a big downside if you ask me. The field definition has to be 100% correct and complete, you lose all the magic and assumption logic that Backpack usually does to make your life easier when you add field using addField(). That's why in most cases I think it's more convenient to go with Option B.
Option B
Instead of manually loading all each field Blade view, add them using addField(), then load all of them just like Backpack does it in the Create or Update operation:
#php
$crud = app()->make('crud');
$crud->setModel(\App\Models\Monster::class);
$crud->addField([
'name' => 'price',
'label' => 'Price',
'prefix' => '$'
]);
#endphp
<form method="post">
#include('crud::form_content', [ 'fields' => $crud->fields(), 'action' => 'create' ])
</form>
The above will produce an output like this:
The benefit of this second option is that you can "forget" to mention stuff in the field definition and Backpack will assume it, you can use the fluent syntax, you can use most Backpack features, really...
I have a form that contains a collection field-type.
However I don't know how to add/remove fields to/from the collection.
$builder
// ...
->add('covers', 'collection', array(
'required' => false,
'type' => new BookCoverType(),
'allow_add' => true,
))
;
The rendered form looks like this:
How can I add a new cover using the collection form field?
Symfony does not provide the add/remove JavaScript methods/buttonss or any session-based solution without JavaScript out of the box.
It renders a data-prototype attribute that can be used as described in the documentation chapter How to Embed a Collection of Forms -> Allowing "new" tags with the "prototype".
Some bundles provide this functionality though. Those are primarily the bootstrap bundles:
braincrafted/bootstrap-bundle
mopa/bootstrap-bundle
...
Just dive into their code - i.e. braincrafted/bootstrapbundle's bc-bootstrap-collection.js.
I've got a form in a zf2 CMS application with a standard select list populated by a service and a bespoke form element also populated by a service, the form is setup using a factory call in Module.php:
public function getServiceConfig()
{
return array(
'factories' => array(
'ElmContent\Form\WebpageForm' => function ($sm) {
$service1 = $sm->get('parentPagesService');
$service2 = $sm->get('categoryService');
$form = new Form\WebpageForm;
$form->setService($service1, $service2);
return $form;
},
The categoryService is used to populate my bespoke form element (a list of categories from another table) - if I am editing a page in my CMS then when I'm building the list of categories, I want to reference another table and see which ones have been associated, to do this I need to pass in the page id from the url, e.g.:
http://cms.local/pages/edit/100 where 100 is the page id and can then be passed in to the categoryService:
$this->getCategoryAssociationsTable()->findByPageId(100);
More code can be provided if needed, but essentially, 2 form elements are populated by data from db tables so I setup using a factory call, the second element is bespoke formatted list of checkboxes and I want to set them as checked when editing if they were selected previously. To do this, I need to pass the pageId from the url, but can't see where to do this when setting up the form the way I am.
Thanks in advance.
Pass it from the Controller $form = $sm->get('my-form'); $form->setRequest($this->getRequest()); The Request object would contain all information you need i suppose? – Sam Jan 20 at 18:39
I would like to create a custom form field. For example, select field of cities in the world.
I read this article. In this article, the data are loaded using parameter file config.ynl. I, however, I'd like to upload this data from my database.
http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html
Can somebody tell me how to do this or send the link to the example
In this case, better is to use an Entity Field instead of a Choice Field. It allows you to request your database to load your entities as follow,
$builder->add('MyField', 'entity', array(
'class' => 'MyBundle:MyEntity',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('e');
},
'property' => 'something',
));
The property option define the entity property you want to use.
You can then customize your field using the "multiple" and "exanded" options to behave the way you want. Read the documentation
I want to add same additional fields to my form, but I don't want have ones in data object.
Here is an example:
$formBuilder = $this->get('form.factory')->createBuilder(new LeadType(), new LeadInfo());
$formBuilder->add('newsSubscribe', 'checkbox');
$form = $formBuilder->getForm();
But I get an error, because there is no 'newsSubscribe' field on my object, and I don't want add(because subscription has no relation to LeadInfo)
Is there a way to solve that?
The field type (which most form fields inherit by default) provides a property_path option that denotes which property on the domain object the field represents. You can tell your checkbox not to write to the domain object like so:
$formBuilder->add('newsSubscribe', 'checkbox', array(
'property_path' => false,
));
You may have to define other options for your checkbox as well, since you're passing an array that may overwrite default options, but that will get you started. With this code, newsSubscribe will be available in your POST variables, but Symfony won't attempt to write it to a domain object property.