minychillo
minychillo

Reputation: 515

Symfony - Filter entities in custom EntityType Field by custom option

How to use a dynamic query on a custom field type ? What I mean by that: I want to create a custom Entity Type form field which lists all the my supplier entities ... but, I want that custom form field to have an additional option byStatus. That option should then be used ( if set ) to set the query_builder option in order to retrieve only the suppliers where the status is equal to the byStatus option.

So here is my SupplierType:

class SupplierType extends AbstractType
{

    public function configureOptions(OptionsResolver $resolver)
    {

        $resolver->setDefaults(array(
            'class' => 'AppBundle:Supplier',
            'byStatus' => 1,
            'query_builder' => function (EntityRepository $er) {
                $q = $er->createQueryBuilder('s')
                    ->orderBy('s.name', 'ASC')
                    ->andWhere('s.status = :status')
                    ->setParameter('status', ????);

                return $q;
            }
        ));
    }

    public function getParent()
    {
        return EntityType::class;
    }
}

So how can I replace the ???? by the byStatus option value. And of course it should be possible to change the byStatus option when using the field type.

Like so:

$formMapper->add('supplier', SupplierType::class, [
    'byStatus' => -1,
]);

Upvotes: 1

Views: 1846

Answers (2)

minychillo
minychillo

Reputation: 515

Ok, I found it. Actually very easy:

public function configureOptions(OptionsResolver $resolver)
{

    $resolver->setDefaults(array(
        'class' => 'AppBundle:Supplier',
        'byStatus' => 1,
    ));

    $resolver->setDefault('query_builder', function (Options $options) {
        return function (EntityRepository $er) use ($options) {
            return $er->createQueryBuilder('s')
                ->orderBy('s.name', 'ASC')
                ->andWhere('s.status = :status')
                ->setParameter('status', $options['byStatus']);
        };
    });

}

Upvotes: 2

dbrumann
dbrumann

Reputation: 17166

If you want to pass in the option from another field I recommend using the setNormalizers as it allows you to pass in the options, i.e. other values, like this:

public function configureOptions(OptionsResolver $resolver)
{
    // ... your setup without the query builder...

    $resolver->setNormalizers([
        'query_builder' => function (Options $options, $value) {
            return function (EntityRepository $er) use ($options) {
                return $er->createQueryBuilder('s')
                    ->orderBy('s.name', 'ASC')
                    ->andWhere('s.status = :status')
                    ->setParameter('status', $options['byStatus'] ?? 1);
            };
        },
    ]);
}

See the docs for the OptionsResolver: https://symfony.com/doc/current/components/options_resolver.html#option-normalization

edit: I added the ?? 1 which will only work with PHP7+, but it provides some safety when the option was not set. Search for null coalesce operator in the php docs if you don't know what it is.

Upvotes: 1

Related Questions