Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [SF2][Symfony] Rozszerzony Form Type
Forum PHP.pl > Forum > PHP > Frameworki
basso
Witam,
już wymiękam... no nie mogę tego nigdzie znaleźć, co chcę zrobić .

Mam formularz w którym są jakieś tam pola i w nim są dwa wyjątkowe: categoria i podkategoria. Są one połączone z innymi dwoma tabelami. Teraz chcę zrobić tak, że jak wybieram najpierw kategorię, to przeładowuje mi się strona (ewentulanie asynchronicznie ajax) i ładuje dla tej wybranej kategorii odpowiedniego selecta z podkategoriami. Chodzi o to, że dane kategorie są w odpowiednich kategoriach i nie mogą wybrać byle jaką podkategorię .

Próbowałem tego: http://symfony.com/doc/current/cookbook/fo...dification.html
Ale nie widzę tutaj możliwości wrzucenia akcji onchage, ani przekazania argumentu do tych listenerów, bo muszę odpowiednie ID przekazać kategorii, by na postawie tego id zaciągnać odpowiednie kategorie.

Czy może ktoś budował taki formularz albo taki mechanizm i mógłby pomóc.


Ogólnie jak wywołuje jakiego kolwiek listenera czy to w formie:
  1. $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
  2. // ... add a choice list of friends of the current application user
  3. });


czy w to formie

  1. $factory = $builder->getFormFactory();
  2.  
  3. $builder->addEventListener(
  4. FormEvents::PRE_SET_DATA,
  5. function(FormEvent $event) use($user, $factory){
  6. $form = $event->getForm();
  7.  
  8. $formOptions = array(
  9. 'class' => 'Acme\DemoBundle\Entity\User',
  10. 'multiple' => false,
  11. 'expanded' => false,
  12. 'property' => 'fullName',
  13. 'query_builder' => function(EntityRepository $er) use ($user) {
  14. // build a custom query, or call a method on your repository (even better!)
  15. },
  16. );
  17.  
  18. // create the field, this is similar the $builder->add()
  19. // field name, field type, data, options
  20. $form->add($factory->createNamed('friend', 'entity', null, $formOptions));
  21. }
  22. );



Zawsze mam komunikat jakby nie działał ten lister jakby go nie było:
  1. FatalErrorException: Error: Class 'Backend\CmsBundle\Form\FormEvents' not found in C:\wamp\www\rw\src\Backend\CmsBundle\Form\PagesType.php line 30
  2.  
destroyerr
Cytat
Zawsze mam komunikat jakby nie działał ten lister jakby go nie było:

Przecież to nie ma związku z Symfony2, tylko z przestrzeniami nazw w PHP.
basso
Ok brakło mi use. Dzięki smile.gif

Crozin
Klasa jaka Ciebie interesuje to Symfony\Component\Form\FormEvenets, nie Backend\CmsBundle\Form\FormEvents. Absolutne podstawy składni języka... http://php.net/manual/en/language.namespaces.importing.php
basso
W jaki sposób mogę dodać listę (selecta), używając tego rozwiązania?


  1. // src/Acme/DemoBundle/Form/Type/FriendMessageFormType.php
  2. namespace Acme\DemoBundle\Form\Type;
  3.  
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Component\Form\FormBuilderInterface;
  6. use Symfony\Component\Form\FormEvents;
  7. use Symfony\Component\Form\FormEvent;
  8. use Symfony\Component\Security\Core\SecurityContext;
  9. use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  10.  
  11. class FriendMessageFormType extends AbstractType
  12. {
  13. public function buildForm(FormBuilderInterface $builder, array $options)
  14. {
  15. $builder
  16. ->add('subject', 'text')
  17. ->add('body', 'textarea')
  18. ;
  19. $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
  20. // ... add a choice list of friends of the current application user
  21.  
  22.  
  23.  
  24. PRÓBOWAŁEM TAK TESTOWO: $builder->add('description'); => zapętla się
  25. PRÓBOWAŁEM TAK $this->add('description); => błąd ;/
  26.  
  27.  
  28.  
  29. });
  30. }
  31.  
  32. public function getName()
  33. {
  34. return 'acme_friend_message';
  35. }
  36.  
  37. public function setDefaultOptions(OptionsResolverInterface $resolver)
  38. {
  39. }
  40. }



Wewnątrz addEventListener nie wiem jak dodać pola do formularza. Kojarzy ktoś jak to dodać będe bardzo wdzięczny.
destroyerr
Jakoś mi nie po drodze ostatnio z Symfony2, więc mogę się mylić.

Sposób z cookbooka nie działa? Spójrz co się dzieje teraz w Twoim kodzie. Budujesz sobie formularz poprzez dodanie do niego odpowiednich pól. Dodajesz także obsługę zdarzenia, a zdarzenie to wywoływane jest w momencie gdy podpinasz do niego dane czyli już dawno po zbudowaniu formularza. Wynika z tego, że w reakcji na zdarzenie do formularza musisz dodać już gotowe (tzn. zbudowane) pole select.
basso
Ok... udało mi się zrobić, zgodnie z dokumentacją. Tylko mam kolejny problem... jak podpiąć do tego <select> czyli mojego category... zdarzenie ONCHANGE . Nie chcę tego robić za pomocą jquery tylko jako atrybut pola select czyli <select onChagne="formularz.submit()"></select>

I jeszcze jedno pytanko: Czy można w jakikolwiek sposób zmienić pozycje elementów w formularzu ?

A to co zrobiłem i to co mi działa smile.gif

  1. class PagesType extends AbstractType
  2. {
  3. public function buildForm(FormBuilderInterface $builder, array $options)
  4. {
  5. $builder
  6.  
  7. ->add('lead')
  8. ->add('description')
  9. ->add('showDate')
  10. ->add('createdAt')
  11. ->add('slug')
  12. ->add('status')
  13. // ->add('category')
  14.  
  15. ->add('gallery');
  16.  
  17. // ->addEventSubscriber(new AddNameFieldSubscriber());
  18.  
  19.  
  20. $factory = $builder->getFormFactory();
  21.  
  22. $builder->addEventListener
  23. (
  24. FormEvents::PRE_SET_DATA,
  25. function(FormEvent $event) use( $factory,$category)
  26. {
  27. $form = $event->getForm();
  28. $formOptions = array(
  29. 'class' => 'Backend\CmsBundle\Entity\PagesCategory',
  30. 'multiple' => false,
  31. 'expanded' => false,
  32.  
  33. 'query_builder' => function(EntityRepository $er) use ($category)
  34. {
  35. return $er->createQueryBuilder('c')
  36. ->where('c.id = :category')
  37. ->setParameter('category', $category);
  38. },
  39. );
  40.  
  41. $form->add($factory->createNamed('category', 'entity', null, $formOptions));
  42. }
  43. );
  44.  
  45.  
  46. }
  47.  
Crozin
Po co chcesz podpinać to przez atrybut HTMLa onchange? Dlaczego nie zrobisz tego normalnie, poprzez JS/DOM:
[JAVASCRIPT] pobierz, plaintext
  1. document.getElementById("id elementu wygenerowane przez symfony").addEventListener("change", function() {
  2. formularz.submit();
  3. }, false);
[JAVASCRIPT] pobierz, plaintext
Czy tam wykorzystując jQuery/inną tego typu bibliotekę:
[JAVASCRIPT] pobierz, plaintext
  1. $("#id elementu wygenerowane przez symfony").on("change", function() {
  2. formularz.submit();
  3. });
[JAVASCRIPT] pobierz, plaintext
basso
Hej, dzięki Crozin za pomoc.

No tak to podpiąłem przez jquery bez problemu... tylko że ja piszę sobie Generator i wiesz... generator mi nie dopisze kodu do pliku .js , a tak to tam będę miał <select onChange="this.submit()"> ).
Dlatego chcę to wrzucić do atrybutu... wtedy każdy select który będę chciał przy generowaniu będzie miał z buta tą metodę... bez bawienia się we wskazywanie id czy klasę po którym js ma wywołać metodę onChange().


No ale zrobiłem to po jquery bo testuje teraz coś innego... mam problem. Bo jak wysyłam formularz to teraz w tej klasie public function buildForm(FormBuilderInterface $builder, array $options) {....} potrzebuje odebrać Request aby wydrzeć z niego wysłane pola => chodzi mi o id kategorii...

Niby jest bind dla $form w metoddzi create ... ale jak wywołuj Request to go nie widzi ;/ . Kojarzy ktoś jak wyświetlić w tej klasie wysłane pola ?
Oczywiście chcę ominąć metodę $_GET czy $_POST .... bo tak to na luzie sobie wydrę, ale chcę mieć to zabezpieczone przez Request Symfonii.

Ok ROZWIĄZAŁEM TO TAK ALE DZIWADŁA MI SIĘ DZIEJĄ.

W kontrolerze:
  1. /**
  2.   * Creates a new Pages entity.
  3.   *
  4.   */
  5. public function createAction(Request $request)
  6. {
  7.  
  8. $entity = new Pages();
  9. $form = $this->createForm(new PagesType(), $entity , array('attr' => array('request'=>$request)));


i teraz w PAGES TYPE w formularzu:


  1.  
  2. use Symfony\Component\HttpFoundation\Request;
  3.  
  4. class PagesType extends AbstractType
  5. {
  6. public function buildForm(FormBuilderInterface $builder, array $options)
  7. {
  8.  
  9. if(isset($options['attr']['request']))
  10. {
  11. $request=($options['attr']['request']);
  12.  
  13. $rq=$request->request;
  14.  
  15. print_r($rq);
  16. print_r($rq->get("lead"));
  17.  
  18. }
  19.  


I teraz jest problem... bo jak wyświetlacm sobie print_r($rq) czyli mój request to dostaję wszystkie dane tak jak chce tj:
  1. Symfony\Component\HttpFoundation\ParameterBag Object ( [parameters:protected] => Array ( [backend_cmsbundle_pagestype] => Array ( [title] => [lead] => sdfsadfsdf sda fsadf [description] => [showDate] => Array ( [date] => Array ( [month] => 1 [day] => 1 [year] => 2008 ) [time] => Array ( [hour] => 0 [minute] => 0 ) ) [createdAt] => Array ( [date] => Array ( [month] => 1 [day] => 1 [year] => 2008 ) [time] => Array ( [hour] => 0 [minute] => 0 ) ) [slug] => [status] => [category] => 3 [_token] => f8f4786b632794b59eda94bfa0541f1d783dc058 ) ) )



Tylko, że jak daję print_r($rq->get("lead")); TO MI NIE POKAZUJE tego pola hmmm

Pytanie1 : Czy muszę mieć to w routingu? E no ... chyba nie, bo przecież to jest post wysłany z formularza... nawet w develope jest :
  1. Request POST Parameters
  2. Key Value
  3. backend_cmsbundle_pagestype {"title":"","lead":"sdfsadfsdf sda fsadf","description":"","showDate":{"date":{"month":"1","day":"1","year":"2008"},"time":{"hour":"0","minute":"0"}},"createdAt":{"date":{"month":"1","day":"1","year":"2008"},"time":{"hour":"0","minute":"0"}},"slug":"","status":"","category":"3","_token":"f8f4786b632794b59eda94bfa0541f1d783dc058"}



W jaki zatem sposób mogę z $request-a pobrać dane bo niby w dokumentacji jest $request->request->get("lead") a mi nei działa sad.gif pomożecie?

m44
Jeśli chcesz mieć do każdego pola typu select dodatkowo dodaną jakąś funkcjonalność po stronie JS, to i tak dużo lepszy sposobem będzie stworzenie własnego typu formularza z odpowiednim szablonem w Twig-u lub PHP. W tym szablonie możesz dodać jakąś wstawkę w JS-ie tylko dla tego pola (z poziomu szablonów masz dostęp do zmiennych formularza, czyli atrybutów i całej reszty).

Natomiast drugi problem rozwiązujesz źle. Jeśli chcesz mieć dostęp do jakiegokolwiek obiektu w klasie formularza, musisz stworzyć formularz jako usługę - wtedy masz możliwość przekazywania innych usług, np. request lub całego kontenera usług, żeby pobrać request.
destroyerr
@basso zgaduję, że kombinujesz z ajaxem i chcesz dobrać się do danych, których nie masz. Lepiej byłoby gdybyś trochę dokładniej opisał przepływ który masz i na którym etapie masz błąd.

Przesyłanie obiektu $request jako atrybut html do dość ciekawe rozwiązanie.
Crozin
1. Formularze nie powinny mieć bezpośredniego kontaktu z obiektem Request.
2. Dane z formularze, które bindujesz przy jego tworzeniu masz dostępne spod $builder->getData().
3.
basso
Witam,
"Przesyłanie obiektu $request jako atrybut html do dość ciekawe rozwiązanie."
Nie jako atrubuty html tylko jako argumentu Form TYpe. I ten request jest tam przekazywany i jest wszystko git, tylko nie mogę z niego wydrzeć pól.

Pytanie mam, bo w kontrolerze/akcji dzieje mi się to samo.
1. Jak w akcji wyświetlić wysłany formularz

Robie tak : print_r($request->request);
Wyświetla mi się obiekt request z wszystkimi polami...


  1. Symfony\Component\HttpFoundation\ParameterBag Object ( [parameters:protected] => Array ( [backend_cmsbundle_pagestype] => Array ( [title] => sdf [lead] => fsda [description] => fsd [showDate] => Array ( [date] => Array ( [month] => 1 [day] => 1 [year] => 2008 ) [time] => Array ( [hour] => 0 [minute] => 0 ) ) [createdAt] => Array ( [date] => Array ( [month] => 1 [day] => 1 [year] => 2008 ) [time] => Array ( [hour] => 0 [minute] => 0 ) ) [slug] => [status] => 1 [category] => 2 [gallery] => Array ( [0] => 1 ) [_token] => a97265043ce27df850327959bbe3d7404d4d5f6c ) ) )


Ale jak biorę pojedyńczą wartość to:
  1. class PagesController extends Controller
  2. {
  3. public function createAction(Request $request)
  4. {
  5. print_r($request->request->get("lead");


Dziwne to nie da rady, biała karta, null po prostu ;/ W sumie ta sama sytuacja co w FormType... no ale, żeby w kontrolerze nie można było odebrać requesta i go pojedyńczo wyświetlić no to mi się nie chce wierzyć. Chyba coś źle robię ;/
destroyerr
No to zauważ, że tablica zawierająca klucz "lead" znajduje się w tablicy z kluczem "backend_cmsbundle_pagestype".

Cytat
Nie jako atrubuty html tylko jako argumentu Form TYpe. I ten request jest tam przekazywany i jest wszystko git, tylko nie mogę z niego wydrzeć pól.

No jednak raczej jako atrybuty html. I nie jest git o czym napisał Ci też Crozin.
m44
Cytat(basso @ 13.05.2013, 12:25:18 ) *
Ale jak biorę pojedyńczą wartość to:
  1. class PagesController extends Controller
  2. {
  3. public function createAction(Request $request)
  4. {
  5. print_r($request->request->get("lead");


Dziwne to nie da rady, biała karta, null po prostu ;/ W sumie ta sama sytuacja co w FormType... no ale, żeby w kontrolerze nie można było odebrać requesta i go pojedyńczo wyświetlić no to mi się nie chce wierzyć. Chyba coś źle robię ;/


A jak niby ma Ci to działać, skoro nawet w ParameterBag nie ma takiego klucza? Musisz najpierw wyciągnąć "backend_cmsbundle_pagestype" i z niego pozostałe lub spróbować za pomocą $request->get('backend_cmsbundle_pagestype[lead]', array(), true);.
basso
A no to działa działa smile.gif Ja sobie po tablicy mogłem iść... ale w życiu bym na to nie wpadł, że trzeba podawać ścieżkę namespace/bundle i nazwa pola smile.gif Szkoda, że w dokumentacji o tym nie wspominają... tylko -> get () nazwa pola z formularza... myślałem, że ta get się domyśli i wyszuka w tablicy Post moją zmienną. Bynajmniej tak w Zendzie jest. No nic, zatem będę tak to robił smile.gif

Dzięki za pokazanie... ale serio Wy tak ścieżki całe ładujecie by odebrąć 1 pole z formularza?

Crozin a "2. Dane z formularze, które bindujesz przy jego tworzeniu masz dostępne spod $builder->getData()."

1. Nie rozumiem tego troszkę, bo bindowane mam do formularze $request. Czy muszę jeszcze coś przybindować dodatkowo?.
2. W FormType ( u mnie PagesType) jak var_dump($builder->getData()) to wyświetla mi pusty obiekt... no a formularz jest wysłany:

  1. Backend\CmsBundle\Entity\Pages Object ( [id:Backend\CmsBundle\Entity\Pages:private] => [title:Backend\CmsBundle\Entity\Pages:private] => [lead:Backend\CmsBundle\Entity\Pages:private] => [description:Backend\CmsBundle\Entity\Pages:private] => [category:Backend\CmsBundle\Entity\Pages:private] => [subcategory:Backend\CmsBundle\Entity\Pages:private] => [gallery:Backend\CmsBundle\Entity\Pages:private] => Doctrine\Common\Collections\ArrayCollection Object ( [_elements:Doctrine\Common\Collections\ArrayCollection:private] => Array ( ) ) [showDate:Backend\CmsBundle\Entity\Pages:private] => [createdAt:Backend\CmsBundle\Entity\Pages:private] => [slug:Backend\CmsBundle\Entity\Pages:private] => [status:Backend\CmsBundle\Entity\Pages:private] => )


Uczę się powoli, i dzięki za poradę, bo faktycznie mogę robić praktyki których stosować się nie powinno... prośba jeszcze o pomoc z ww.


Crozin mógłbyś mi pomóc , bo ja jak wyświetlam to FormType ( u mnie PagesType) jak var_dump($builder->getData()) to wyświetla mi pusty obiekt... no a formularz jest wysłany sad.gif

I wszystko jasne... błąd Symfonii, czyli się nie da, a ja tydzień się już męczę sad.gif https://github.com/symfony/symfony/issues/6128 ;/
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.