Symfony 5.1 lista de opciones filtrando

Estoy usando Symfony 5.1 para filtrar una entidad en un tipo de formulario.

->add('ageGroup', EntityType::class, [
    'class' => AgeGroup::class,
    'choice_label' => 'name',
    'choice_filter' => ChoiceList::filter(
        $this,
        function ($ageGroup) {
            if ($ageGroup instanceof AgeGroup) {
                return $ageGroup->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId();
            }
            return false;
        }
    )
])
->add('room', EntityType::class, [
    'class' => Room::class,
    'choice_label' => 'name',
    'choice_filter' => ChoiceList::filter(
        $this,
        function ($room) {
            if ($room instanceof Room) {
                return $room->getBranch()->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId();
            }
            return false;
        }
    ),
])

Tengo un problema interesante. Cualquier cosa ChoiceList::filter es primero funcionará pero ningún otro filtro funcionará después.

Esto es cuando ->add('ageGroup') fue colocado primero. enter image description here

Esto es cuando ->add('room') fue colocado primero. enter image description here

La segunda lista de opciones no se llama. Para nada.

De hecho, ninguna otra ChoiceList::filter se llama si agrego más de 1.

https://symfony.com/doc/current/reference/forms/types/choice.html no pone ninguna limitación sobre cuántos se puede llamar.

Claramente lo estoy haciendo

Ni siquiera puedo empezar a adivinar qué tiene de malo.

Pregunta hecha hace 3 años, 4 meses, 29 días - Por algorithmadeptc6cb


3 Respuestas:

  • El ChoiceList::filter método toma un tercer argumento llamado $vary.

    De acuerdo con el PHP Doc comment:

    /**
     * @param FormTypeInterface|FormTypeExtensionInterface $formType A form type or type extension configuring a cacheable choice list
     * @param mixed                                        $option   Any pseudo callable, array, string or bool to define a choice list option
     * @param mixed|null                                   $vary     Dynamic data used to compute a unique hash when caching the option
     */
    

    La función de corte usada dentro de este método utiliza php incorporado spl_object_hash() sobre $formType objeto, que dará el mismo id para ambos callbacks. Pase el nombre de campo (o cualquier otra cosa que sea única) como un tercer argumento:

    ->add('ageGroup', EntityType::class, [
        'class' => AgeGroup::class,
        'choice_label' => 'name',
        'choice_filter' => ChoiceList::filter(
            $this,
            function ($ageGroup) {
                if ($ageGroup instanceof AgeGroup) {
                    return $ageGroup->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId();
                }
                return false;
            },
            'ageGroup'
        )
    ])
    ->add('room', EntityType::class, [
        'class' => Room::class,
        'choice_label' => 'name',
        'choice_filter' => ChoiceList::filter(
            $this,
            function ($room) {
                if ($room instanceof Room) {
                    return $room->getBranch()->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId();
                }
                return false;
            },
            'room'
        ),
    ])
    

    Respondida el Dec 17, 2020 a las 19:25 - por codergeek24

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando se debe a cómo se están aplicando los filtros en tus campos de formulario. En Symfony, cuando se utilizan filtros en campos de tipo EntityType, estos deben ser aplicados a nivel de consulta en el repositorio de la entidad, en lugar de utilizar ChoiceList::filter directamente en el campo.

    Para filtrar las opciones de forma adecuada en Symfony 5.1, puedes hacer lo siguiente:

    • Define un EntityType personalizado que extienda de EntityType y sobrescribe el método finishView:
    php
    namespace App\Form\Type;
    
    use Symfony\Bridge\Doctrine\Form\Type\EntityType;
    use Symfony\Component\Form\FormInterface;
    use Symfony\Component\Form\FormView;
    
    class FilteredEntityType extends EntityType
    {
        protected function finishView(FormView $view, FormInterface $form, array $options)
        {
            parent::finishView($view, $form, $options);
    
            $filterFunction = $options['filter'];
    
            $view->vars['choices'] = array_filter($view->vars['choices'], function ($choice) use ($filterFunction) {
                return $filterFunction($choice->data);
            });
        }
    }
    
    • Luego, utiliza este nuevo tipo de campo en tus formularios:
    php
    use App\Form\Type\FilteredEntityType;
    
    // En tu formulario
    
    • >add('ageGroup', FilteredEntityType::class, [
    'class' => AgeGroup::class, 'choice_label' => 'name', 'filter' => function ($ageGroup) { return $ageGroup->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId(); }, ])
    • >add('room', FilteredEntityType::class, [
    'class' => Room::class, 'choice_label' => 'name', 'filter' => function ($room) { return $room->getBranch()->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId(); }, ])

    Al hacerlo de esta manera, aseguras que los filtros se aplicarán correctamente a nivel de consulta en el repositorio de la entidad cuando se renderice el campo en el formulario. Esto debería solucionar el problema que estás experimentando con los filtros en tus campos de formulario.

    Respondida el Dec 18, 2020 a las 19:25 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando con los filtros de ChoiceList en Symfony 5.1 probablemente se deba a que estás usando el mismo callable para filtrar múltiples campos de entidad.

    Cuando utilizas ChoiceList::filter, estás creando un nuevo filtro para un campo de entidad específico. En tu caso, estás utilizando el mismo callable para filtrar tanto el campo ageGroup como el campo room. Esto significa que Symfony solo aplicará el último filtro que agregaste, que en este caso es el filtro para el campo room.

    Para resolver este problema, debes crear un callable único para cada campo de entidad que desees filtrar. Aquí tienes un ejemplo actualizado de tu código:

    php
    
    • >add('ageGroup', EntityType::class, [
    'class' => AgeGroup::class, 'choice_label' => 'name', 'choice_filter' => ChoiceList::filter( $this, function ($ageGroup) { if ($ageGroup instanceof AgeGroup) { return $ageGroup->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId(); } return false; } ) ])
    • >add('room', EntityType::class, [
    'class' => Room::class, 'choice_label' => 'name', 'choice_filter' => ChoiceList::filter( $this, function ($room) { if ($room instanceof Room) { return $room->getBranch()->getOrganization()->getId() == $this->security->getUser()->getOrganization()->getId(); } return false; } ), ])

    Al crear callables únicos para cada filtro, te aseguras de que cada campo de entidad se filtre correctamente. Esto debería resolver el problema de que no se llamen los filtros posteriores.

    Respondida el Dec 18, 2020 a las 19:38 - por Gemini

    Votos positivos: 0 | Votos negativos: 0