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.
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.
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.
Hey rafaelmansilha!
Sorry for my extra slow reply! Yea, I think I understand what you're asking. The answer is: maybe :). y You probably do "really need to create a FormType for it"... but avoiding it may be possible.
When you render a form page in EasyAdmin, the form class is actually this one - https://github.com/EasyCorp/EasyAdminBundle/blob/1.x/src/Form/Type/EasyAdminFormType.php - it's a super-dynamic form type that builds itself based on the entity and your admin options. So, in theory, you could create a form with this, pass in whatever entity you want with an "entity" option, and it will build itself. And then you could embed it. It would look something like this inside of your "main" form type:
$builder
->add('genusScientists', CollectionType::class, [
'entry_type' => EasyAdminFormType::class,
'entry_options' => [
'entity' => GenusScientist::class
],
'allow_delete' => true,
'allow_add' => true,
'by_reference' => false,
])
Will that work? I have no idea :). But now you have me interested ;). Let me know if you try this and whether it works or not.
Cheers!
Hi !
I tried your method, but it missing the 'view' option in the 'entry_option'. What should we add in this field ?
Thank you in advance for your help !
Hey Edouard Pihet
By looking at this class https://github.com/EasyCorp... I understand that the view option contains the data you defined for such entity and view (create or edit). I find it difficult to extend so I suggest to create your own FormType, it would be cleaner and easier
Cheers!
Hi everyone,
I am having an issue with easyadmin. It is a kind of issue I saw in Ryan tutorials, but I never saw this issue resolved. Basically, when I edit an entry and one particular field is a ManyToOne relation, EasyAdmin (by default) generate an autocomplete dropdown field. Now, assuming I have two entities User and Product, when I try to edit a product, I can see who is the user owing that product. The issue is that inside that dropdown, I can only see the name of the user as oppose to name and surname. I can see that easyadmin calls getName from the User entity, but I don't know how to tell easyAdmin to call a different method from inside the User Entity.
Any idea?
Hey Alessandro D.
EasyAdmin fully relies on the Symfony Form component, so you can do the exact same thing EasyAdmin forms as you would do with "normal" forms. What you need to do is to specify the "choice_label" option (Docs: https://symfony.com/doc/current/reference/forms/types/entity.html#choice-label)
easy_admin:
entities:
Genus:
form:
fields:
-
property: 'genusScientists'
type: 'collection'
type_options:
choice_label: 'some_property_field"
I hope it helps :)
Cheers!
Hi Diego,
I have tried what you suggested, but I get the following error:
"The option "choice_label" does not exist".
Here is my code:
`
form:
fields:
- title
- revision
- { property: 'createdAt', type: 'datetime', type_options: { widget: 'single_text' } }
- author
-
property: 'usedBy'
type: 'collection'
type_options:
choice_label: 'surname'
- tags
-
property: 'path'
label: 'Upload Script'
type: 'file_upload'
type_options: { upload_dir: public/screenplays }
- active
`
If I change all the block for 'usedBy' from this to normal '-usedBy' I do get the dropdown, but only the name is displayed
Hey Alessandro D.
Oh, sorry my bad, instead of specifying type: collection
, use entity
Docs about EntityType: https://symfony.com/doc/current/reference/forms/types/entity.html#basic-usage
Then, you will be able to specify its choice_label
attribute. Let me know if it worked :)
Hi Diego,
That is great. It works like a charm.
Thanks a lot. I can't believe I actually spent an entire evening trying to figure that out. !!! :(
Thanks again.
Alessandro
I hear you man. Symfony Forms are complex but the documentation is great. Every time I'm in doubt I go to the docs and check for any option that may fit my needs.
Cheers!
Hi Team !
I faced a funny behaviour with embed form (collection).
So I have this in easy_admin.yaml
- { property: 'files', type: 'collection', type_options: { entry_type: 'App\Form\ResourceFileFormType', allow_delete: true, allow_add: true , by_reference: false, block_name: 'resource_file' }}
It works fine, except for the validation.
All fields are required, but there is no small red asterisk and the form can submit with all fields empty.
Even the html5 validation doesn't work.
Any clue about how to fix this ?
Here is the formType
namespace App\Form;
use App\Entity\Language;
use App\Entity\ResourceFile;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class ResourceFileFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'name',
TextType::class,
[
'required' => true,
]
)
->add(
'language',
EntityType::class,
[
'class' => Language::class,
'required' => true,
]
)
->add(
'file',
VichFileType::class,
[
'required' => true,
'allow_delete' => true,
'label' => 'File',
'download_uri' => true,
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => ResourceFile::class,
]
);
}
}
Hey Kaizoku!
Hmm. So, it sounds like there are two things going on: the HTML5 validation doesn't work AND the server-side validation also does not work. Is that right? These sound like similar systems, but actually they are quite separate.
First, about the HTML 5 validation, I see that you have 'required' => true
for your "name" and "language" fields. If you look in the HTML for those fields, do you see a required
attribute or not?
Second, about the server-side validation, you may need to add the @Valid
constraint above the files
property on your entity so that the validation applies to this sub-entity.
Let me know if either of these things helps!
Cheers!
First of all thank you so much Ryan for your answer.
> do you see a required attribute or not?
nope ! So maybe this an issue with the easy_admin form theme file ?
> you may need to add the @Valid constraint above the files property on your entity
yep ! I added validation constraint in the entity and it's now working. At least there is doctrine exception no more.
Don't bother about the HTML5 (unless you know why) since there is form validation it's good enough.
Hey Kaizoku!
> nope ! So maybe this an issue with the easy_admin form theme file ?
Hmm, maybe - I'm not sure. I would look click on the form icon on the web debug toolbar (the clipboard icon), select one of the fields that should be required, and see if the "required" option and "required" view variables are indeed set correctly.
That will at least give you something to check out ;).
Cheers!
Hi,
Something cool in sonata is the ability to create a new entry directly from the form containing the relation:
By example: Posts have many tags. When I create a new Post, I select one or many tags. If a tag is missing I can create a new tag in a modal without leaving the post form.
Pretty easy to setup in sonata, is there a trick to do the same in easyAdmin ?
Hey Geoffrey M.!
Actually, this is also one of my favorite features of Sonata! Unfortunately, it's not something that exists in EasyAdminBundle :/. So, it would need to be added custom :/ - no easy way! If you have enough of these things, then using Sonata starts to make more sense.
Cheers!
Hi! I'm following your course for my project but I've an issue.
I've two entities "shop" and "pictures" OneToMany relationship, one shop many pictures. Easy!
I can manage "shop" and "pictures" entites fine from EasyAdminBundle, the problem is when I try to delete or add new photos from "shop" entity, nothing happens it's so weird.
The error is:
Expected value of type "AppBundle\Entity\Shop" for association field "AppBundle\Entity\Picture#$shop", got "string" instead.
Any ideas?
Thanks!
Hey Roberto S.
When you try to add a new photo to a shop, don't you get any error message ? try checking the logs, or if you click in the profiler bar, there is a section of "Requests", where you can check older requests, I believe this "add photo action" is handled via AJAX, maybe you could find out what's going on in there.
Cheers!
The error is:
Expected value of type "AppBundle\Entity\Shop" for association field "AppBundle\Entity\Picture#$shop", got "string" instead.
The request isn't via AJAX :(
Hey Roberto,
Hm, it's weird. Are you sure it's directly related to EasyAdminBundle? Please, make sure you don't call "$picture->setShop('some-string');" manually somewhere in your code. Also, could you show us your easy_admin configuration for Shop and Picture entities?
Cheers!
I've identified the problem.
My Entity "Picture" doesn't initialize the "Shop" field so I've changed the field "Shop" in my PictureEmbeddedForm to 'JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\EasyAdminAutocompleteType' because I've more than 30.000 shops. But it doesn't work when I add new Pictures, only to update or delete.
How can I initialize the "Shop" field of "Picture" entity when I clic on "add new item" on the Collection?
I don't really need a select field for that, It's enough with a hidden field to save the relationship.
Thanks for your help.
Problem solved!!!
I forgot to add $foto->setShop($this); on addPicture method.
public function addPicture(Picture $picture {
$foto->setShop($this);
return $this->pictures->add($picture);
}
Thanks!
Ohh, so the problem was that you forgot to setup the relationship when adding a picture. Good job debugging the problem, the part of the error message "got string instead" confused me.
Cheers!
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.3.*", // v3.3.18
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
"symfony/swiftmailer-bundle": "^2.3", // v2.6.7
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.17.0
"sensio/distribution-bundle": "^5.0", // v5.0.25
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
"incenteev/composer-parameter-handler": "^2.0", // v2.1.4
"knplabs/knp-markdown-bundle": "^1.4", // 1.7.1
"doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
"stof/doctrine-extensions-bundle": "^1.2", // v1.3.0
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"javiereguiluz/easyadmin-bundle": "^1.16" // v1.17.21
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.7
"symfony/phpunit-bridge": "^3.0", // v3.4.40
"nelmio/alice": "^2.1", // v2.3.5
"doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
}
}
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?