Jak używać select box powiązanych z innym select box?

Jak używać powiązanych pól wyboru w Symfony ?

Powiedzmy, że mam listę select zawierającą kompagnies i inną zawierającą pracowników wybranej firmy. Jak je zdefiniować w Symfony? Utworzyłem już cały kod związany z Javascript, ale podczas przesyłania formularza i błędów na niektórych polach, wszystkie pola wyboru" sub " są resetowane do wartości null.

Jakieś pomysły?
Dzięki,

EDIT: ponieważ pytanie wydaje się być źle zrozumiane, dodam kilka precisions:

Opis:

  1. mam firmę, która zawiera listę pracowników korzystających z relacji @OneToMany.
  2. kiedy wybieram firmę z listy select/rozwijanej, druga lista rozwijana zawierająca pracowników jest aktualizowana przez jQuery. ta część jest wykonana, działa doskonale
  3. przy przesyłaniu formularza bez błędów, rozwiązanie formularza podmiotu działa dobrze.
  4. podczas przesyłania formularza zawierającego błędy, druga lista rozwijana zawiera wszystkie Możliwe wartości. Nie są one filtrowane w wybranej firmie.

Wypróbowane rozwiązania:

  • moim pierwszym pomysłem było użycie typu form entity, myśląc, że komponent może być w jakiś sposób powiązany z innym polem. ie. zaktualizuj listę pracowników na podstawie wartości wybranej firmy.

nie działa, nie ma wyjścia z pudełka, aby to zrobić. Nawet nie wyjęte z pudełka rozwiązania...

  • Wtedy Ja myślałem o ręcznym przekazaniu wybranej firmy jako parametr do konstruktora zapytań drugiej listy rozwijanej.

Ale kiedy formularz jest tworzony, wartości są puste. Wartości są ustawiane tylko na bindRequest.

  • myślałem o użyciu typu choice. Delegowanie wszystkich funkcji filtra do interfejsu użytkownika za pomocą Javascript. Oznacza to, że po załadowaniu strony pojawia się pusta lista i jest wypełniana przez Javascript w oparciu o wybrane Towarzystwo.

to naprawdę działa, ale myślę, że nie ma tu innego słowa niż naprawdę naprawdę brzydkie Programowanie.

PS:

Pytanie zostało zadane tutaj, na liście dyskusyjnej Symfony2, na Twitterze i forum officiel Symfony 2. Oczywiście przeszukałem każdy z nich kilka razy przed wysłaniem moich pytań.

Author: i.am.michiel, 2012-01-29

3 answers

Odnośnie tego, co już próbowałeś, myślę, że powinieneś spróbować ponownie swoich pierwszych / drugich pomysłów:

Moim pierwszym pomysłem było użycie typu encji formy, myśląc o komponencie można go jakoś związać na innym polu. ie. Aktualizacja listy pracowników na podstawie wartości wybranej firmy.

Możesz wypełnić pole wyboru pracowników za pomocą typu entity. Wszystko, co musisz zrobić, to zdefiniować dobre opcje:

class FooType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('employee', 'entity', array(
                'class' => 'Entity\Employee',
                'query_builder' => function ($repository) use($options) {
                    return $repository
                        ->createQueryBuilder('e')
                        ->where('e.company = :company')
                        ->setParameter('company', $options['companyId'])
                    ;
                },
            ))
        ;
    }

    public function getDefaultOptions(array $options)
    {
        return array('data_class' => 'Entity\Foo', 'companyId' => null);
    }
}

Potem pomyślałem o ręcznym przejściu wybrana firma jako parametr do konstruktora zapytań drugiej listy rozwijanej.

Poniższy przykład filtruje listę pracowników na podstawie opcji formularza companyId. Możesz zmodyfikować to zachowanie, filtrując bezpośrednio Dane firmy obecne w formularzu.

public function buildForm(FormBuilder $builder, array $options)
{
    $companyId = $builder->getData()->getCompanyId();
    $builder
        ->add('employee', 'entity', array(
            'class' => 'Entity\Employee',
            'query_builder' => function ($repository) use ($companyId) {
                return $repository
                    ->createQueryBuilder('e')
                    ->where('e.company = :company')
                    ->setParameter('company', $companyId)
                ;
            },
        ))
    ;
}

Nadal musisz zaimplementować metody getEmployee() i setEmployee() w swojej klasie Entity\Foo.

Ale kiedy formularz jest tworzony, wartości są puste. Wartości są ustawiane tylko na bindRequest.

Nie. Wartości są ustawiane podczas tworzenia formularza za pomocą formularza Factory (trzeci argument), Lub gdy zadzwonisz $form->setData($foo);. Dane są modyfikowane, gdy bind nowe wejścia do formularza.

może wystąpić problem z takim podejściem: możliwe, że identyfikator pracownika powiązany z formularzem nie jest dostępny na liście wyboru formularza, ponieważ zmieniłeś firmę (a tym samym pracowników).

 13
Author: Florian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-02 15:12:47

Miałem ten sam problem. Musisz użyć zdarzeń formularza. Mój przykład kodu z relacji kraju, regionu, miasta.

namespace Orfos\UserBundle\Form\Type;

///import form events namespace
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;

class RegistrationFormType extends BaseType
{

    private $request;

    public function __construct($class, $request, $doctrine)
    {
        parent::__construct($class);
        $this->request = $request;
        $this->doctrine = $doctrine;
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        parent::buildForm($builder, $options);
        //other fields

        $locale = $this->request->getLocale();

        $builder->add('country', 'entity', array(
            'class' => 'Orfos\CoreBundle\Entity\Country',
            'property' => $locale . 'name',
            'label' => 'register.country.label',
            'query_builder' => function(EntityRepository $er) {
                return $er->createQueryBuilder('c')
                                ->select('c', 't')
                                ->join('c.translations', 't');
            },
        ));

        $factory = $builder->getFormFactory();
        $refreshRegion = function ($form, $country) use ($factory, $locale) {
                    $form->add($factory->createNamed('entity', 'region', null, array(
                                'class' => 'Orfos\CoreBundle\Entity\Region',
                                'property' => $locale . 'name',
                                'label' => 'register.region.label',
                                'query_builder' => function (EntityRepository $repository) use ($country) {
                                    $qb = $repository->createQueryBuilder('region')
                                            ->select('region', 'translation')
                                            ->innerJoin('region.country', 'country')
                                            ->join('region.translations', 'translation');

                                    if ($country instanceof Country) {
                                        $qb = $qb->where('region.country = :country')
                                                ->setParameter('country', $country);
                                    } elseif (is_numeric($country)) {
                                        $qb = $qb->where('country.id = :country_id')
                                                ->setParameter('country_id', $country);
                                    } else {
                                        $qb = $qb->where('country.id = 1');
                                    }

                                    return $qb;
                                }
                            )));
                };
        $factory = $builder->getFormFactory();
        $refreshCity = function($form, $region) use ($factory, $locale) {
                    $form->add($factory->createNamed('entity', 'city', null, array(
                                'class' => 'Orfos\CoreBundle\Entity\City',
                                'property' => $locale . 'name',
                                'label' => 'register.city.label',
                                'query_builder' => function (EntityRepository $repository) use ($region) {
                                    $qb = $repository->createQueryBuilder('city')
                                            ->select('city', 'translation')
                                            ->innerJoin('city.region', 'region')
                                            ->innerJoin('city.translations', 'translation');

                                    if ($region instanceof Region) {
                                        $qb = $qb->where('city.region = :region')
                                                ->setParameter('region', $region);
                                    } elseif (is_numeric($region)) {
                                        $qb = $qb->where('region.id = :region_id')
                                                ->setParameter('region_id', $region);
                                    } else {
                                        $qb = $qb->where('region.id = 1');
                                    }

                                    return $qb;
                                }
                            )));
                };

        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (DataEvent $event) use ($refreshRegion, $refreshCity) {
                    $form = $event->getForm();
                    $data = $event->getData();

                    if ($data == null){
                        $refreshRegion($form, null);
                        $refreshCity($form, null);
                    }

                    if ($data instanceof Country) {
                        $refreshRegion($form, $data->getCountry()->getRegions());
                        $refreshCity($form, $data->getRegion()->getCities());
                    }
                });

        $builder->addEventListener(FormEvents::PRE_BIND, function (DataEvent $event) use ($refreshRegion, $refreshCity) {
                    $form = $event->getForm();
                    $data = $event->getData();

                    if (array_key_exists('country', $data)) {
                        $refreshRegion($form, $data['country']);
                    }
                    if (array_key_exists('region', $data)) {
                        $refreshCity($form, $data['region']);
                    }                    
                });
    }

}
 5
Author: rtyshyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-07 23:00:13

Można utworzyć akcję, która będzie zwracać tablicę json z pracownikami firmy. Po zmianie listy firm musisz zażądać tej akcji przez ajax i utworzyć select list of employees.

Form controller action:

/**
 * @Route("/job", name="_demo_job")
 * @Template()
 */
public function jobAction()
{
    $form = $this->createForm(new JobType());

    $request = $this->getRequest();
    if ($request->getMethod() == 'POST') {
        $form->bindRequest($request);
        $data = $form->getData();
        // some operations with form data
    }

    return array(
        'form' => $form->createView(),
    );
}

Conroller, który zwraca pracowników przez firmę w json:

/**
 * Finds all employees by company
 *
 * @Route("/{id}/show", name="employees_by_category")
 */
public function listByCompanyAction($id)
{
    $request = $this->getRequest();

    if ($request->isXmlHttpRequest() && $request->getMethod() == 'POST') {
        $em = $this->getDoctrine()->getEntityManager();

        $company = $em->getRepository('AcmeDemoBundle:Company')->find($id);

        // create array for json response
        $empoloyees = array();
        foreach ($company->getEmployees() as $employee) {
            $empoloyees[] = array($employee->getId(), $employee->getName());
        }

        $response = new Response(json_encode($empoloyees));
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
    return new Response();
}

Szablon formularza:

<script type="text/javascript">
    $(document).ready(function() {
        $('#form_company').change(function() {
            var companyId = $(this).val();
            $.post('{{ route }}/' + companyId + '/show', function(data) {
                // last selected employee
                var selectedVal = $('option:selected', '#form_employee').attr('value');

                $('#form_employee option').remove();
                for (i in data) {
                    // create option with employee
                    var option = $('<option></option>').
                        attr('value', data[i][0]).
                        text(data[i][1]);
                    // set selected employee
                    if (data[i][0] == selectedVal) {
                        option.attr('selected', 'selected');
                    }
                    // append to employee to employees select
                    $('#form_employee').append(option);
                }
            }, 'json');
        })

        // request employees by company
        $('#form_company').change();
    })

</script>
<form action="{{ path('_demo_job') }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}

    <input type="submit" />
</form>

Aby uzyskać bardziej szczegółowy przykład, powinieneś opisać swój problem bardziej szczegółowo.

 1
Author: Alexander Fedorov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-01 17:15:50