Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

2 Stron V   1 2 >  
Reply to this topicStart new topic
> [Symfony]Construct w kontrolerze
Szymciosek
post
Post #1





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Witam,
próbowałem zrobić taki myk, że po uruchomieniu jakiegokolwiek routingu uruchamiany jest zawsze konstruktor klasy, a on wywołuje mi metodę setExistingColumns(), w której mam:

  1. $entityManager = $this->getDoctrine()->getEntityManager();
  2. $this->existingColumns = $entityManager->getClassMetadata('BundleName:Users')->getFieldNames();


Lecz niestety otrzymuję błąd:
Kod
Fatal error: Call to a member function has() on a non-object in F:\WORK\author\bundleName\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\Controller.php on line 191


Ta metoda tyczy się linii 191:
  1. public function getDoctrine()
  2. {
  3. if (!$this->container->has('doctrine')) {
  4. throw new \LogicException('The DoctrineBundle is not registered in your application.');
  5. }
  6.  
  7. return $this->container->get('doctrine');
  8. }


Moim zdaniem takie coś jest nierealne, ponieważ chcę to uruchomić poza metodą, która ma przypisany routing, ale mogę się mylić, stwierdzam to po tym, że w każdej innej metodzie typu indexAction taki myk działa.

Czy jest możliwość zrobienia tego żebym nie musiał 100x powtarzać kodu w każdej metodzie, która ma przypisany do siebie routing ?

Ten post edytował Szymciosek 4.12.2012, 01:01:36
Go to the top of the page
+Quote Post
Crozin
post
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Nie do końca rozumiem czemu ma to służyć, ale jeżeli chcesz podpiąć jakiś kod pod każde żądanie najprawdopodobniej powinieneś skorzystać nasłuchiwać zdarzenia KernelEvents::REQUEST, bądź KernelEvents::CONTROLLER.
2. Dostajesz błąd, ponieważ w konstruktorze nie masz jeszcze dostępu do właściwości Controller::$container. A konkretnie, to nie jest do niej przypisany jeszcze DIC.
Go to the top of the page
+Quote Post
misi3kk
post
Post #3





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


Jeśli ta metoda potrzebna jest w tylko jednym kontrolerze to proponuję wydzielić kod z konstruktora do innej metody i wywoływać ją kiedy jest potrzebna.

Jeśli planujesz używać tej metody w kilku kontrolerach to poza podpinaniem Eventów można jeszcze dodać sobie Service który będzie dostarczał takie dane.


--------------------
Accesto.pl
Go to the top of the page
+Quote Post
Szymciosek
post
Post #4





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Możesz napisać coś więcej o service ? Jak z tego korzystać itd ?
Taka metoda będzie wykorzystywana praktycznie za każdym razem w moim przypadku ze względu na to, że nie chcę powtarzać zbędnego kodu w każdej uruchamianej metodzie i myślałem nad wykorzystaniem do tego właśnie konstruktora, który będzie uruchamiany za każdym razem.
Go to the top of the page
+Quote Post
misi3kk
post
Post #5





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


http://symfony.com/doc/current/book/service_container.html

Idąc tą drogą, możesz nawet Twój kontroler zdefiniować jako service - wtedy możesz wymóc wywołanie odpowiednich metod z odpowiednimi parametrami:
http://symfony.com/doc/current/cookbook/co...er/service.html


--------------------
Accesto.pl
Go to the top of the page
+Quote Post
Crozin
post
Post #6





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


@misi3kk: Utworzenie samego serwisu/usługi nie powoduje kompletnie niczego - i tak trzeba to podpiąć pod jakieś zdarzenie.
Go to the top of the page
+Quote Post
misi3kk
post
Post #7





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


Może swobodnie utworzyć controller jako service i w definicji podać wywołanie metody, która wczyta interesujące go dane.

Zdarzenie jest OK, ale nie wydaje mi się, aby potrzebne było wywoływanie zdarzenia dla każdego wywołania strony, w przypadku gdy te dane potrzebne są tylko dla jednego kontrolera (lub kilku, ale w mniejszości).

Service domyślnie wywołuje konstruktor, a entity manager można mu swobodnie przekazać. Dodatkowo można wywołać dowolną metodę w czasie jego tworzenia.


--------------------
Accesto.pl
Go to the top of the page
+Quote Post
Crozin
post
Post #8





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Cytat
[...] w przypadku gdy te dane potrzebne są tylko dla jednego kontrolera (lub kilku, ale w mniejszości).
Już dwa razy napisano, że ma to być dla niemal każdego kontrolera odpalane.

Samo zdefiniowanie usługi nie powoduje jej uruchomienia. Musi być ona jawnie pobrana z DIC-a, użyta jako zależność czy też przekazana jako innego rodzaju argument obsługiwany przez DIC-a (np. jako listener dla zdarzenia).

Ten post edytował Crozin 4.12.2012, 13:18:56
Go to the top of the page
+Quote Post
misi3kk
post
Post #9





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


Napisane zostało, że metoda ta uruchamiana będzie prawie za każdym razem, ale nie napisanego czy dla każdego kontrolera. Kod metody pobiera dane powiązane z użytkownikami, dlatego założyłem, że będzie to używane tylko w części serwisu.

Opisywałem moją propozycję rozwiązania, nie dlatego, aby powiedzieć, że Twój pomysł jest zły - jest dobry i w wybranych zastosowaniach znacznie lepszy od mojego. Po prostu chciałem pokazać alternatywne wyjście, na wypadek gdyby całość była używana np. w jednym kontrolerze.


--------------------
Accesto.pl
Go to the top of the page
+Quote Post
Szymciosek
post
Post #10





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


No akurat panowie powiem wam, że będzie to używane w każdym przypadku, bo za każdym razem, gdy coś będzie uruchomione muszę pobrać listę dostępnych kolumn z entity = bazy danych. Więc w każdym kontrolerze i każdej metodzie, która będzie publiczna - mam na myśli uruchamia z poziomu routingu.

Zacząłem coś czytać np tutaj: http://symfony.com/doc/2.0/book/internals....ontroller-event czy http://symfony.com/doc/current/cookbook/se...t_listener.html

ale pytanie skąd symfony wie, że EventListener ma być odpalany przed kontrolerem i ma być wykonana akcja ? Gdzieś to deklaruję ?
Go to the top of the page
+Quote Post
Crozin
post
Post #11





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Przeczytaj sobie dokumentację EventDispatchera, który jest jednym z kluczowych mechanizmów całego FW. Wszelkie wątpliwości powinny się rozwiać.
Go to the top of the page
+Quote Post
Szymciosek
post
Post #12





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Ciężko mi coś wchodzą te eventy itd, ale znalazłem: https://groups.google.com/d/msg/symfony2/qP...LU/sw3ueQh0n_oJ

Możesz mi wytłumaczyć ? To jest jakiś container, ale do czego ?

Tutaj wynalazłem Twoje posty jakieś chyba na ten temat http://forum.php.pl/index.php?showtopic=192743 ? To jest to samo ?
Go to the top of the page
+Quote Post
Crozin
post
Post #13





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Tworzysz sobie usługę, tj.:
1. Klasę która w konstruktorze przyjmuje wszystkie wymagane zależności (tutaj: DoctrineRegistry, czyli to co masz dostępne pod kluczem "doctrine" w DIC-u) dla jej poprawnego działania.
2. Odpowiedni wpis w definicji DIC-a. Chodzi o element <service /> w XML-owskiej konf. DIC-a.

Następnie taką klasę-usługę musisz zarejestrować jako listener dla danego zdarzenia. Możesz zrobić to bezpośrednio w konf. DIC-a: http://symfony.com/doc/current/cookbook/se...t_listener.html
Go to the top of the page
+Quote Post
Szymciosek
post
Post #14





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Opisałeś mi tutaj ten container czy to coś na zasadzie services ? Czym jest DIC ?
Go to the top of the page
+Quote Post
Crozin
post
Post #15





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


DIC: Dependency Injection Container: http://symfony.com/doc/current/book/service_container.html
Go to the top of the page
+Quote Post
Szymciosek
post
Post #16





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Zaczynam ogólnie pojmować DI, ale pytanie co do tego:
  1. <?php
  2.  
  3. namespace ApiRest\ServiceBundle;
  4.  
  5. use Symfony\Component\HttpKernel\Bundle\Bundle;
  6.  
  7. class ApiRestServiceBundle extends Bundle
  8. {
  9. private static $containerInstance = null;
  10.  
  11. public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null)
  12. {
  13. parent::setContainer($container);
  14. self::$containerInstance = $container;
  15. }
  16. public static function getContainer()
  17. {
  18. return self::$containerInstance;
  19. }
  20. }


a w controller / construct:
  1. $em = \ApiRest\ServiceBundle\ApiRestServiceBundle::getContainer()->get('doctrine')->getEntityManager();
  2. var_dump($em);


Czemu działa tylko w ten sposób ?
Gdy zrobię:
  1. ...->getDoctrine()->getEntityManager();


to dostaję błąd:
Kod
Call to undefined method appDevDebugProjectContainer::getDoctrine() in F:\WORK\author\service_rest_api\src\ApiRest\ServiceBundle\Controller\UserController.php on line 17


Ten post edytował Szymciosek 5.12.2012, 16:04:23
Go to the top of the page
+Quote Post
misi3kk
post
Post #17





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


To co wkleiłeś zupełnie nie ma związku z tym o czym było pisane wcześniej. W Twoim przypadku konieczne jest dodanie listenera - linki do tego jak to zrobić są już podane, podobnie jak podane były przez Crozin eventy które powinieneś nasłuchiwać.

Mam wrażenie, że brakuje Ci wielu informacji dotyczących Sf2. Naprawdę warto odłożyć projekty i przeczytać to co jest w Book + chociaż część tego co jest w Cookbook. Bez znajomości podstaw ciężko pisać sensowne projekty. Niestety, ale Sf2 nie jest łatwy do zrozumienia i trochę czasu należy na naukę poświęcić.

Przykład jak dodać listener: http://symfony.com/doc/current/cookbook/se...t_listener.html
Tylko Event Ci się zmienia. Nie rób tego w klasie bundla, bo to nie jest miejsce na to.


--------------------
Accesto.pl
Go to the top of the page
+Quote Post
Crozin
post
Post #18





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Nie używaj static o ile nie wiesz co dokładnie robisz. Tutaj używasz go źle, wręcz fatalnie, a co za tym idzie tracisz zalety OOP i IoC (zrealizowanego przez DI). Co więcej nie ma tutaj w ogóle potrzeby do jego stosowania.
2. Klasa appDevDebugProjectContainer() najzwyczajniej w świecie nie definiuje metody getDoctrine() więc masz błąd. To czego szukasz, to getDoctrineService().
3. Dlaczego ciągle brniesz w uruchomienie tego kodu w konstruktorze klasy konstruktora (po którym dziedziczą wszystkie inne), zamiast skorzystać z poprawnego rozwiązania, wspomnianego przeze mnie już kilkukrotnie, tj. listenera dla zdarzenia KernelEvents::REQUEST?

Ten post edytował Crozin 5.12.2012, 16:26:05
Go to the top of the page
+Quote Post
Szymciosek
post
Post #19





Grupa: Zarejestrowani
Postów: 1 168
Pomógł: 126
Dołączył: 5.02.2010
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


Service:
  1. services:
  2. kernel.listener.check:
  3. class: ApiRest\ServiceBundle\Listener\CheckListener
  4. arguments: [@doctrine]
  5. tags:
  6. - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }


Listener:
  1. <?php
  2.  
  3. namespace ApiRest\ServiceBundle\Listener;
  4.  
  5. use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine;
  6.  
  7. class CheckListener
  8. {
  9. private $entityManager;
  10.  
  11. public function __construct(Doctrine $doctrine)
  12. {
  13. $this->entityManager = $doctrine->getEntityManager();
  14. }
  15.  
  16. public function onKernelRequest()
  17. {
  18.  
  19. }
  20. }


Czy to jest dobrze ?
Jeśli tak, to jak odebrać te dane z kontrolera ?
Go to the top of the page
+Quote Post
misi3kk
post
Post #20





Grupa: Zarejestrowani
Postów: 26
Pomógł: 4
Dołączył: 14.05.2010

Ostrzeżenie: (0%)
-----


O ile się nie mylę, musisz je zapisać w obiekcie Request


--------------------
Accesto.pl
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 19:59