This tutorial has a new version, check it out!

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.

Start your All-Access Pass
Buy just this tutorial for $12.00

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.

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}