CollectionType Field
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeThe form system does a pretty good job guessing the correct field types... but nobody is perfect. For example, the genusScientists
field is not setup correctly. Click the clipboard icon to open the form profiler.
Yep, genusScientists
is currently an EntityType
with multiple
set to true. Thanks to EasyAdminBundle, it renders this as a cool, tag-like, auto-complete box. Fancy!
But... that's not going to work here: the GenusScientist
entity has an extra field called yearsStudied
:
// ... lines 1 - 17 | |
class GenusScientist | |
{ | |
// ... lines 20 - 38 | |
/** | |
* @ORM\Column(type="integer") | |
* @Assert\NotBlank() | |
*/ | |
private $yearsStudied; | |
// ... lines 44 - 83 | |
} |
When you link a Genus
and a User
, we need to allow the admin to also fill in how many years the User
has studied the Genus
.
In the Symfony series, we did a lot of work to create a CollectionType
field that used GenusScientistEmbeddedForm
:
// ... lines 1 - 20 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... lines 26 - 48 | |
->add('genusScientists', CollectionType::class, [ | |
'entry_type' => GenusScientistEmbeddedForm::class, | |
'allow_delete' => true, | |
'allow_add' => true, | |
'by_reference' => false, | |
]) | |
; | |
// ... lines 56 - 57 | |
} | |
// ... lines 59 - 106 | |
} |
Thanks to that, in the admin, we just need to update the form to look like this.
Change genusScientists
to use the expanded syntax. From here, you can guess what's next! Set type: collection
and then add type_options
with the 4 options you see here: entry_type:
AppBundle\Form\GenusScientistEmbeddedForm, allow_delete: true
, allow_add: true
, by_reference: false
:
// ... lines 1 - 80 | |
easy_admin: | |
// ... lines 82 - 91 | |
entities: | |
Genus: | |
// ... lines 94 - 114 | |
form: | |
fields: | |
// ... lines 117 - 125 | |
- | |
property: 'genusScientists' | |
type: 'collection' | |
type_options: | |
entry_type: AppBundle\Form\GenusScientistEmbeddedForm | |
allow_delete: true | |
allow_add: true | |
by_reference: false | |
// ... lines 134 - 145 |
Let's see what happens! Woh! Ignore how ugly it is for a minute. It does work! We can remove items and add new ones.
But it looks weird. When we created this form for our custom admin area - we hid the user field when editing... which looks really odd now. Open the GenusScientistEmbeddedForm
. We used a form event to accomplish this: if the GenusScientist
had an id, we unset the user
field. Comment that out for now and refresh:
// ... lines 1 - 14 | |
class GenusScientistEmbeddedForm extends AbstractType | |
{ | |
// ... lines 17 - 34 | |
public function onPostSetData(FormEvent $event) | |
{ | |
if ($event->getData() && $event->getData()->getId()) { | |
$form = $event->getForm(); | |
// unset($form['user']); | |
} | |
} | |
// ... lines 42 - 50 | |
} |
Cool: this section at least makes more sense now.
The CollectionType Problems
But... there are still some problems! First, it's ugly! I know this is just an admin area... but wow! If you want to use the CollectionType
, you'll probably need to create a custom form theme for this one field and render things in a more intelligent way. We'll do something similar in a few minutes.
Second... this only works because we already did a lot of hard work setting up the relationships to play well with the CollectionType. Honestly, the CollectionType is both the best and worst form type: you can do some really complex stuff... but it requires some seriously tough setup. You need to worry about the owning and the inverse sides of the relationship, and things called orphanRemoval
and cascading. There is some significant Doctrine magic going on behind the scenes to get it working.
So in a few minutes, we're going to look at a more custom alternative to using the collection type.
Virtual Form Field
But first, I want to show you one more thing. Go to the User
section and edit a User. We haven't touched any of this config yet. In config.yml
, under User
, add form
then fields
. Let's include email
and isScientist
:
// ... lines 1 - 80 | |
easy_admin: | |
// ... lines 82 - 91 | |
entities: | |
// ... lines 93 - 145 |
Right now, the form has firstName
and lastName
fields... which makes sense: there are firstName
and lastName
properties in User
. But just like we did earlier under the list
view, instead of having firstName
and lastName
, we could actually have, just fullName
. And nope... there is not a fullName
property. But as long as we create a setFullName()
method, we can totally add it to the form:
// ... lines 1 - 16 | |
class User implements UserInterface | |
{ | |
// ... lines 19 - 225 | |
public function setFullName($fullName) | |
{ | |
$names = explode(' ', $fullName); | |
$firstName = array_shift($names); | |
$lastName = implode(' ', $names); | |
$this->setFirstName($firstName); | |
$this->setLastName($lastName); | |
} | |
// ... lines 235 - 279 | |
} |
Actually, this isn't special to EasyAdminBundle
, it's just how the form system works!
Now... this example is a little crazy. This code will take everything before the first space as the first name, and everything after as the last name. Totally imperfect, but you guys get the idea.
And now that we have getFullName()
and setFullName()
, add that as a field: property:
fullName, type: text
and a help message:
// ... lines 1 - 80 | |
easy_admin: | |
// ... lines 82 - 91 | |
entities: | |
// ... lines 93 - 145 |
Keep going to add avatarUri
and universityName
:
// ... lines 1 - 80 | |
easy_admin: | |
// ... lines 82 - 91 | |
entities: | |
// ... lines 93 - 145 |
Try it out! Yes! It looks great... and... it even submits! Next up, let's add a field that needs custom JavaScript to work.
Hi everyone,
I'm stating now with EasyAdmin, and I'm struggling with collection type, I see that you use a FormType to build the Collection in entry_type. How do I tell it to use another admin? I want to use a collection of a entity mapped with the admin, do I really need to create de FormType for it?