Custom Query in EntityType
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.
As cool as it is that it's guessing my field type, I am actually going to add
EntityType::class
to use this type explicitly:
// ... lines 1 - 4 | |
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |
// ... lines 6 - 10 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... line 16 | |
->add('subFamily', EntityType::class, [ | |
// ... lines 18 - 22 | |
]) | |
// ... lines 24 - 32 | |
; | |
} | |
// ... lines 35 - 41 | |
} |
I don't have to do this: I just want to show you guys what a traditional setup looks like.
Now, do nothing else and refresh. It'll still work, right? Right? Nope!
The required class
option is missing! As I just finished saying, we must pass
a class
option to the EntityType
. We got away with this before, because when
it's null
, Symfony guesses the form "type" and the class
option.
Set the option to SubFamily::class
- and alternate syntax to the normal AppBundle:SubFamily
:
// ... lines 1 - 4 | |
use AppBundle\Entity\SubFamily; | |
// ... lines 6 - 12 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... line 18 | |
->add('subFamily', EntityType::class, [ | |
// ... line 20 | |
'class' => SubFamily::class, | |
// ... lines 22 - 24 | |
]) | |
// ... lines 26 - 34 | |
; | |
} | |
// ... lines 37 - 43 | |
} |
The query_builder Option
Now that our form is put back together, I have a second challenge: make the select order alphabetically. In other words, I want to customize the query that's made for the SubFamily's and add an ORDER BY.
Head back to the EntityType
docs. One option jumps out at me: query_builder
.
Click to check it out. OK, it says:
If specified, this is used to query the subset of options that should be used for the field.
And actually, I need to search for query_builder
: I know there's a better example
on this page. Here it is!
So, if you pass a query_builder
option and set it to an anonymous function, Doctrine
will pass that the entity repository for this specific entity. All we need to do
is create whatever query builder we want and return it.
In the form, add query_builder
and enjoy that auto-completion. Set this to a
function with a $repo
argument:
// ... lines 1 - 12 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... line 18 | |
->add('subFamily', EntityType::class, [ | |
// ... lines 20 - 21 | |
'query_builder' => function(SubFamilyRepository $repo) { | |
// ... line 23 | |
} | |
]) | |
// ... lines 26 - 34 | |
; | |
} | |
// ... lines 37 - 43 | |
} |
Now, I like to keep all of my queries inside of repository classes because I don't
want queries laying around in random places, like in a form class. But, if you look, I don't
have a SubFamilyRepository
yet.
No worries - copy the GenusRepository
, paste it as SubFamilyRepository
. Rename
that class and clear it out:
// ... lines 1 - 2 | |
namespace AppBundle\Repository; | |
// ... lines 4 - 5 | |
use Doctrine\ORM\EntityRepository; | |
class SubFamilyRepository extends EntityRepository | |
{ | |
// ... lines 10 - 14 | |
} |
Open the SubFamily
entity and hook it up with @ORM\Entity(repositoryClass="")
and fill in SubFamilyRepository
:
// ... lines 1 - 6 | |
/** | |
* @ORM\Entity(repositoryClass="AppBundle\Repository\SubFamilyRepository") | |
// ... line 9 | |
*/ | |
class SubFamily | |
// ... lines 12 - 45 |
Great! Back in our form, we know this repo will be an instance of SubFamilyRepository
:
// ... lines 1 - 5 | |
use AppBundle\Repository\SubFamilyRepository; | |
// ... lines 7 - 12 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... line 18 | |
->add('subFamily', EntityType::class, [ | |
// ... lines 20 - 21 | |
'query_builder' => function(SubFamilyRepository $repo) { | |
// ... line 23 | |
} | |
]) | |
// ... lines 26 - 34 | |
; | |
} | |
// ... lines 37 - 43 | |
} |
Return $repo->
and a new method that we're about to create called createAlphabeticalQueryBuilder()
:
// ... lines 1 - 12 | |
class GenusFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
// ... line 18 | |
->add('subFamily', EntityType::class, [ | |
// ... lines 20 - 21 | |
'query_builder' => function(SubFamilyRepository $repo) { | |
return $repo->createAlphabeticalQueryBuilder(); | |
} | |
]) | |
// ... lines 26 - 34 | |
; | |
} | |
// ... lines 37 - 43 | |
} |
Copy that name and head into the repository to create that function. Inside, return
$this->createQueryBuilder('sub_family'
) and then order by sub_family.name
, ASC
:
// ... lines 1 - 7 | |
class SubFamilyRepository extends EntityRepository | |
{ | |
public function createAlphabeticalQueryBuilder() | |
{ | |
return $this->createQueryBuilder('sub_family') | |
->orderBy('sub_family.name', 'ASC'); | |
} | |
} |
Done! The query_builder
method points here, and we handle the query.
Alright, try it out! Nailed it! As far as form options go, we probably just conquered one of the most complex.
Hi, what if i wan't to limit the number of columns i wan't to query, ex: a.id, a.name ?
Can that be done in the query builder in formtype ?