Symfony2 - making a list of entities selectable - php

In my Symfony2, I have a table of a user's emails (entities in my database):
{% for email in emails %}
...
{{ email.subject }}
...
{% endfor %}
I would like to make these selectable by wrapping the table in a form and adding a checkbox to each of these rows.
What's the best way to approach this in Symfony2? I can only think that I'll have to create a Type inside a Type inside a Type, which seems less than ideal:
class SelectableEmailsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('selectableEmails', 'collection', [ 'type' => new SelectableEmailType() ]);
}
public function getName()
{
return 'selectableEmails';
}
}
class SelectableEmailType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email', new EmailType());
$builder->add('selected', 'checkbox');
}
public function getName()
{
return 'selectableEmail';
}
}
class EmailType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('subject', 'text');
...
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => 'EmailOctopus\Bundle\ListsBundle\Entity\ListEntity',
]);
}
public function getName()
{
return 'email';
}
}

This is answering the binding question.
// Query a list of emails
$emails = $emailRepository->findAll();
// Turn them into selectable emails
$selectableEmails = array();
foreach($emails as $email)
{
$selectableEmails[] = array('email' => $email, 'selected' => false);
}
// Pass this to the root form
$formData = array('selectableEmails' => $selectableEmails);
After processing a posted form you would pull out the list of selectableEmails and run through it to get the list actually selected.
This is just one approach. It works well for adding additional form related attributes to an entity without changing the entity itself.

I ended up assigning the id. of each email to a checkbox, using this solution:
Build a form having a checkbox for each entity in a doctrine collection

Related

How can I add a ChoiceType in every field of a CollectionType in Symfony forms?

I want to create a form in Symfony. The form needs a collection of task fields which are loaded from the database. Every single field should have a dropdown to select a person who is supposed to do this task.
What I want to do is to map those two entities together. What I have so far is this:
createFormType.php
class CreateFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("dateValidFrom", DateTimeType::class)
->add("dateValidUntil", DateTimeType::class)
->add("generalTasks", CollectionType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
"data_class" => DTOPlan::class
]);
}
}
DTOPlan.php
class DTOPlan
{
public \DateTimeImmutable $dateValidFrom;
public \DateTimeImmutable $dateValidUntil;
public array $tasks;
public function setGeneralTasks(array $generalTasks): void
{
$this->generalTasks = array_fill_keys($generalTasks, null);
}
...getter and setter
}
Controller.php
public function newPlan(Request $request)
{
$generalTasks = $this->generalTaskRep->findAll();
$dtoPlan = new DTOPlan();
$dtoPlan->setGeneralTasks($generalTasks);
$form=$this->createForm(CreateFormType::class, $dtoPlan);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
$this->planRepository->updatePlan($form->getData());
$this->redirectToRoute("app.plan.show");
}
return $this->render("/Plan/plan_create.html.twig", [
"createForm" => $form->createView()
]);
}
The labels are now correct: Form
Now I want to insert a dropdown into them for selecting firstName and lastName of Person
How can I manage that?

Multiple entity in one form

I have following problem. I would like to create a form which works on two entities. I have followings entities: first entity is user entity, and it is connected relationally to the second entity(column bip relate to entity "BIP").
Now I have following code:
BIPType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'AppBundle\Entity\Bip',
);
}
And UserType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$biptype = new BIPType();
$builder->add('bip', $biptype);
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
// Or for Symfony < 2.8
// return 'fos_user_registration';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
// For Symfony 2.x
public function getName()
{
return $this->getBlockPrefix();
}
Unfortunately, error has occured
Catchable Fatal Error: Argument 1 passed to UserBundle\Entity\User::setBip() must be an instance of AppBundle\Entity\Bip, array given, called in /home/spake/php/gryf/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 556 and defined
What to do, my friends? Thanks in advice.
You need to declare the Entity class of that Form Class like this:
$builder->add('bip', new BipType(), array(
'data_class' => 'namespace/to/BipEntity'
));

Symfony2 - Condition in FormType

I have a class RegisterType for my form:
<?php
class RegisterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('price');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Register'
));
}
public function getName()
{
return 'register';
}
}
?>
The Register Entity has a relation with an Entity called Product
I would like to add this condition to the buildForm function:
<?php
if ($product->getTitle() == 'SuperProduct') {
$builder->add('amount', 'money', [
'required' => FALSE,
]);
}
?>
If the product title has the value 'SuperProduct' then I add a field in the the form.
But I have no idea about the syntax I have to use to call another Entity value in a FormType.
Thanks in advance for your help.
Ah good you've implemented your FormType as an independent class rather than in a controller, so what I'd do is pass in your product entity as an option to a private variable within your FormType class. I'm not sure what class your product is or the name space it resides in, so you'll have to fill that in.
I've also written this in the expectation that you could have more than one option to pass through in the future, so it'll be useful to other FormType classes you write. Each variable you define in the class scope can be set when you create an instance of the FormType class. Be sure to initialise these variables as false instead of null, or the code in the constructor function won't see them.
<?php
class RegisterType extends AbstractType
{
private $product = false;
public function __construct(array $options = [])
{
foreach ($options as $name => $value) {
if (isset($this->$name)) {
$this->$name => $value;
}
}
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('price')
;
if ($this->product && is_a("\Namespace\To\Your\Entity\Called\Product", $this->product)) {
if ($this->product->getTitle() == 'SuperProduct') {
$builder
->add('amount', 'money', [
'required' => FALSE,
])
;
}
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Register'
));
}
public function getName()
{
return 'register';
}
}
?>
That "is_a()" function checks that the product variable passed in through the form type class constructor really is an instance of your product entity, so you can be sure that the getTitle() function exists.
Now when you create a new instance of your RegisterType class, you need to pass through an options array including your product. Two conceptual variable names for you to rename here.
<?php
$form = $this->createForm(new RegisterType([
"product" => $instanceOfProductEntityOrNull,
]), $theEntityTheFormWillBeHandling);
?>
Try something like this:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$product = $event->getData();
$form = $event->getForm();
if ($product->getTitle() == 'SuperProduct') {
$form->add('name', 'text');
}
});
And do not forget the specific use
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

Symfony form dropdown for entries

I am starting with coding in Symfony and I have the following problem:
Assume I have two Entities 'Client' and 'Project'. They are stored with Doctrine.
A Client has a Id, Name and an Email
A Project has a Id, client_id, name
So basically a project belongs to a Client and a Client has many projects.
My problem now:
When I'm creating a project, I want a dropdown with all possible clients. As I might be using a client drowpown somewhere else in my project I'm asking myself if there is a smart way to something like this:
class ProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
$builder->add('client', new ClientListType());
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Project'
));
}
public function getName()
{
return 'project';
}
}
class ProjectController extends Controller
{
public function createAction(Request $request)
{
$project = new Project();
$options = array( ... );
$form = $this->createForm(new ProjectType(), $project, $options);
$form->handleRequest($request);
if($form->isValid()){
// persist project
return $this->redirectToRoute('show_projects');
}
return $this->render('AppBundle:Client:create.html.twig', array(
'form' => $form->createView()
));
}
}
Where ClientListType adds a select statement for all possible Clients to the form.
And $form->isValid() checks if the client (id) is valid or not.
At the moment I have the followin code in ProjectType to generate the dropdown entries:
function __construct($clients)
{
$this->clients = $clients;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
$builder->add('client', 'choice', array(
'choices' => $this->buildChoices()
));
}
public function buildChoices()
{
$res = array();
foreach ($this->clients as $client) {
$res[$client->getId()] = $client->getName();
}
return $res;
}
But I'm assuming there is a much better way to do this, because this seems like a common problem.
What I would do is simply this :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text')
->add('client', 'entity', array(
'class'=>'AppBundle\Entity\Client',
'property'=>'name'
));
}
Hope this helps.

Symfony forms from entity with additional fields

As I know I could create form using form type: $form = $this->createForm(new RegistrationType(), $user);
And here is form type:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text');
$builder->add('email', 'email');
$builder->add('terms', 'checkbox', array(
'mapped' => false
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'App\UsersBundle\Entity\User'
));
}
public function getName()
{
return 'user_registration';
}
}
So I could add field term and don't map it to entity. But what is the way to validate this field? Sure I can do something like if ($form->get('terms')->getData()) in my controller but I want to use one function $form->isValid() to validate all fields (mapped and don't mapped)? May be any validate hooks or events exists?
It's covered in the Adding Validation section of the Forms chapter.

Categories