adbacz
11.11.2011, 03:41:32
Jak napisać model, który nie dziedziczyłby po głównej klasie Controller SF2? Chodzi mi o to, że jeśli idziemy śladami podręcznika, i robimy wszystko tak jak jest tam napisane to kod sie "pisze" ładnie. Ale jak zaczniemy (przynajmniej ja) bajerować po staremu (do tej pory korzystałem z CodeIgniter), to wszystko się wali.
Chciałem podzielić w bundlu aplikację na kontroler i model (chciałem użyć MVC), ale nie mogę w żaden sposób odwołać się do Doctrine nie korzystając z dziedziczenia po klasie Symfony\Bundle\FrameworkBundle\Controller\Controller. Ma może ktoś jakieś pomysły, jak to zrobić?
A może napisać własnego bundle'a, który będzie mi robił jako nakładka na bazę danych (będe używał tylko MySQL w aktualnym projekcie)? Akurat tutaj mogę się mylić, zaczynam pracę dopiero z SF2 i wolałbym prosić o zdanie bardziej doświadczonych.
destroyerr
11.11.2011, 07:51:22
Cytat
Jak napisać model, który nie dziedziczyłby po głównej klasie Controller SF2?
Ja się pytam, jak można pisać model dziedziczący po kontrolerze.
Jeśli chodzi o bajerowanie po staremu, to powinieneś o tym zapomnieć, zwłaszcza o CodeIgniter.
Napisz może gdzie się chcesz odwoływać do tego Doctrine, bo tego nie wiem. Generalnie jest tak, że Doctrine (to znaczy to co zwraca metoda
getDoctrine w kontrolerze) siedzi w kontenerze jako serwis "doctrine". Wystarczy więc przekazać go tam gdzie potrzebujesz.
adbacz
11.11.2011, 08:12:24
Fakt, źle to zabrzmiało, ale po przeczytaniu podręcznika na symfony.com nigdzie nie znalazłem informacji na ten temat i dlatego takie dziwactwa piszę. Potrzebuje zrobić model z którego będzie korzystać klasa do logowania, aby nie pisać wszystkiego w jednej klasie, bo to nie do tego służy. Obiekt tej klasy jest tworzony za każdym razem gdy otwieramy jakąkolwiek stronę, więc to jest zwykła biblioteka, która kożysta z klasy sesji SF.
Próbowałem przed klasą deklarować (tak to się mówi?) bundla Doctrine ale nic z tego nie wychodziło. Próbowałem też prześledzić wykonywanie skryptu od tyłu i faktycznie istnieje tam to co napisałeś, ale jak próbowałem sie do tego odwoływać to dostawałem różne ostrzeżenia, od PHP warning po błedy wyłapane przez SF.
Mógłbyś mnie naprowadzić, jak zrobić to co napisałeś? Jakiś link albo hasło, to poszukam coś...
destroyerr
11.11.2011, 11:45:33
Piszesz enigmatycznie, więc ciężko zrozumieć co chcesz zrobić.
Chcesz zrobić model, co masz na myśli? Ma to być encja czy co? W którym momencie potrzebne Ci Doctrine?
Cytat
ale jak próbowałem sie do tego odwoływać to dostawałem różne ostrzeżenia, od PHP warning po błedy wyłapane przez SF.
Podaj konkretne błędy, wtedy będzie można Ci pomóc.
adbacz
11.11.2011, 12:10:50
Mam główny Bundle i w nim kontroler, który jest dziedziczony przez wszystkie inne kontrolery wywoływane przez SF poprzez routing. W tym bundle'u, w klasie po której dziedziczą kontrolery tworzę nową instancję klasy autoryzacji i ta nie dziedziczy po niczym ale sama korzysta z osobnej klasy która jest modelem. W tej właśnie klasie potrzebuję mieć Doctrine.
Wiem, że może to być troszkę nie tak jak powinno być, ale na razie powiedzmy, że tak powinno być.
Czytałem o Dependency Injection na symfony.com i przeczytałem kilka innych artykułów i wpisów na blogach o tym ale nie znalazłem nic na temat tego, jak dodać DI do klasy modelu autoryzacji ani jak się z tamtąd odwoływać do kontenera DI.
Encje mam zrobione, potrzebuje teraz uzyskać obiekt Doctrine właśnie w tym modelu autoryzacji, żeby móc korzystać z tej encji.
destroyerr
11.11.2011, 12:36:02
Taki kawałek powinien znaleźć się w kontrolerze:
$model = $this->get('model');
new KlasaAutoryzacji($model);
Chociaż moim zdaniem ta klasa autoryzacji też mogłaby być serwisem tworzonym przez kontener.
Jak konfigurować serwisy masz podane w dokumentacji, w rozdziale "Service Container".
adbacz
11.11.2011, 13:48:26
Konfigurować serwisy umiem. Klase do autoryzacji też wrzuciłem jako serwis. Zastanawia mnie tylko jak zrobić teraz, aby mozna było sie odwoływać do metody $this->get('serwis'); w konstruktorzemojego głównego kontrolera. Jaki problem? Otóż wyskakuje mi błąd PHP, że ta metoda jest niedostępna. Ale to pewnie dlatego, że PHP nie zdążył jeszcze załadowac poprzedniej klasy (Controller()) po której dziedziczy mój głowny kontroler, a to przecież w nim siedzi ta metoda. A nie warto ingerować w strukturę plików dostarczonych z FW bo to nie działa na takiej zasadzie. A z drugiej strony - nie mam zamiaru w każdej metodzie wywoływać metody z mojego głównego kontrolera, żeby dostać się do klasy aytoryzacji.
PS: Co do tego kawałka kodu, to już zrobiłem tak, ale w konstruktorze, i dlatego mam ten błąd PHP:
$this->BH_objAuthorisation = new Authorisation($this->container->get('doctrine'));
destroyerr
11.11.2011, 14:11:41
Jeżeli Twój kontroler rozszerza Symfony\Bundle\FrameworkBundle\Controller\Controller[\i] to nie ma takiej możliwości, żeby wywalało błąd [i]Call to undefined method. Nie ma też możliwości, że PHP nie zdążył czegoś załadować. Sprawdź kod jeszcze raz, albo go pokaż.
adbacz
11.11.2011, 14:46:35
Konstruktor mojego głównego kontrolera, który to dziedziczy po klasie którą wymieniłeś:
public function __construct() {
//Ustawiamy, czy użytkownik jest zalogowany.
$this->BH_isLogged = true; //linijka 24
$this->BH_objAuthorisation = new Authorisation($this->get('doctrine')); //linijka 25
} //linijka 26
A taki wyrzuca mi błąd PHP:
Cytat
Fatal error: Call to a member function get() on a non-object in C:\VertrigoServ\www\vendor\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\Controller.php on line 189
Przepraszam, z tym błędem to mój błąd. Źle napisałem w poprzednim poście.
Obojetnie w którym konstruktorze klasy dziedziczącej, czy to będzie mój główny, wywołany przez routing czy nawet w klasie którą wymieniłeś, zawsze mi pokazuje taki błąd. Linijka, na którą wskazuje błąd to ta:
public function get($id)
{
return $this->container->get($id); //linia 189
}
EDIT: Ja się nie dziwię teraz, że mi wyskakuje błąd. Pole this->container przy wywołaniu z konstruktora ma wartość
null a to samo wywołane z osobnej metody w tej samej klasie ma już tyle wartości, że var_dump() nie może ich pomieścić.
destroyerr
11.11.2011, 16:50:47
Jeśli nadpisałeś konstruktor, to nie dziw się, że coś Ci nie działa. Wypadałoby go wywołać.
Żeby pracować z Symfony2 trzeba mieć pojęcie o programowaniu obiektowym, to jest niezbędne minimum.
adbacz
11.11.2011, 17:16:19
Chodzi Ci o konstruktor klasy
Symfony\Bundle\FrameworkBundle\Controller\Controller? Nie ma tam jawnego konstruktora. A poza tym, jak wywołuje tak:
public function __construct() {
parent::__construct(); //linijka 23
//Ustawiamy, czy użytkownik jest zalogowany.
$this->BH_isLogged = true;
$this->BH_objAuthorisation = new Authorisation($this->get('doctrine'));
}
To mi pokazuje bląd:
Cytat
Fatal error: Cannot call constructor in "moj\glowny\kontroller" on line 23
Jakieś sugestie? Bo ja nie mam pojęcia dlaczego tak jest. Nie ma w tej klasie żadnego jawnego konstruktora, w którym byłby kod odpowiedzialny za przypisanie do pola $this->container jakiś wartości czy obiektów. Ale jak dopiszę konstruktor do tej klasy i w moim konstruktorze dodam to
parent::__construct(); to wszystko działa, ale nadal nie ma to pole żadnej wartości.
destroyerr
11.11.2011, 18:25:31
Przepraszam, mój błąd. Powinienem był najpierw sam sprawdzić, a nie jechać z pamięci.
Sprawdziłem i kontener jest wstrzykiwany do kontrolera za pomocą metody setContainer, więc dzieje się to stworzeniu. Możesz więc albo się podpiąć do metody setContainer. Możesz też wykorzystać do autoryzacji listeners z Event Dispatcher.
adbacz
12.11.2011, 21:43:56
Niezbyt wiem jak sie podpiąć do metody setContainer. Tam jest tylko jedna metoda w tej klasie i jak dla mnie, jest ona troszkę dziwna, bo przypisuje tylko dane do pola, ale nawet nie wiem gdzie jest ona wywoływana (prawdopodobnie gdzieś w kernelu, ale nie znam się). Gdyby udało mi sie ustalic gdzie ta metoda jest wywoływana i w którym momencie, może coś bym wymyślił, ale za mało znam SF.
Z tego co piszesz, wnioskuję, że robiłeś już coś w SF2, możesz powiedzieć coś więcej na temat tego, jak używałeś DB w swoich projektach? Tylko tak, jak to jest w dokumentacji, czyli pobranie instancji Doctrine w metodzie wywołanej na podstawie routingu itd, czy może jeszcze inaczej?
PS. A co mi da Event Dispatcher? Ja potrzebuję dostac się do Dictrine, żeby miec połączenie z bazą. Równie dobrze mógłbym napisać sobie prostą klasę, która mi wygeneruje osobne połączenie z DB i sobie w niej na sztywno napisać pytania SQL, ale jaki to ma sens?
destroyerr
12.11.2011, 22:02:09
Pisząc o podpięciu się do metody
setContainer miałem na myśli:
class TwojKontroler
{
public function setContainer($container)
{
parent::setContainer($container);
//tutaj Twoj kod dla autoryzacji
}
}
Event Dispatcher jest częścią architektury Symfony2, cały request jest obsługiwany przy pomocy właśnie zdarzeń. Powinieneś przejrzeć sobie kod frameworka, chociażby
HttpKernel, wtedy zrozumiesz o co chodzi z zdarzeniami.
Jeśli chodzi o mnie to bazy danych staram się używać tylko w modelu, tak aby kontroler i widok nic o niej nie wiedział.
adbacz
12.11.2011, 22:47:51
Takie "podpiecie się", co napisałeś, niestety kończy się błędem:
Cytat
Fatal error: Declaration of "moj_glowny_kontroler"::setContainer() must be compatible with that of Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() in "plik_mojego_kontrolera" on line 11
Gdzie linia 11 to definicja klasy:
class MojKontroler extends Controller { /* Kod klasy */ }
Ale tylko w tedy, jak dodam tą metodę do mojego kontrolera. Dodam, że implementowałem interfejs, który jest w błedzie i który inplementuje klasa
Symfony\Component\DependencyInjection\ContainerAware ale to nic nie dawało.
Może zamiast uganiania się za rozwiązaniem problemu, pomysleć nad innym rozwiązaniem. Co masz na myśli w tym zdaniu:
Cytat
Jeśli chodzi o mnie to bazy danych staram się używać tylko w modelu, tak aby kontroler i widok nic o niej nie wiedział.
Ja rozumiem, model to model, ale używałeś go zgodnie z dokumentacją? Tzn pobierałeś Doctrine przez metodę $this->getDoctrine() i później operowałes na encjach i metodach w nich zawartych, tak? Myślę właśnie, czy nie lepszym rozwiązaniem na chwile obecną będzie napisanie prostej klasy, tylko dla tej autoryzacji, a później ewentualnie, jak juz znajde rozwiązanie, zmodyfikować kod. Nie chcę używać czegoś innego bo wiem jaki jest mój kod, wiem jak go używac a, że jest on dość sporych rozmiarów (jak na klase autoryzacji) i jest dość rozbudowany (wg mnie) wiec szkoda mi go nie użyć, używałem go już w innych projektach i nie było żadnych problemów.
destroyerr
12.11.2011, 23:06:53
Jeżeli chodzi o błąd, to domyślałem się, że właśnie tak będzie. Trochę inwencji, skoro deklaracja jest niekompatybilna, to sprawdź w interfejsie jak ma wyglądać i po prostu uzupełnij.
Nie używałem modelu zgodnie z dokumentacją, bo Symfony2 nie dostarcza modelu. Mam swoją implementację, nic nie podobną do kawałków z dokumentacji. Kontroler nie wie o istnieniu Doctrine, więc nie może go pobierać.
Szybciej byś zrobił jakbyś wykorzystał autoryzacje z frameworka, ale skoro wolisz swoje, to musisz wiedzieć jak ją podpiąć.
adbacz
12.11.2011, 23:36:51
No dobrze, a jeśli kontroler nie wie o istnieniu Doctrine, to korzystasz z Doctrine czy z innego rozwiązania? Po tym jak piszesz sugeruję, że niezbyt chcesz sie tym dzielić, więc jak mam rację to OK, dam sobie radę jakoś, cos wymyslę. Ale wychodzę z założenia, że jak juz sie uczyć to porzadnie i od lepszych.
PS. Próbowałem chyba juz na wszystkie sposoby, ale za każdym razem dostaje to samo ostrzeżenie od PHP.
EDIT: Tak się zastanawiam. Czy tylko Ty masz coś do powiedzenia na ten temat czy tylko Ty jesteś taki pomocny, a może jestes jedynym który przeczytał temat. Bo jak narazie to nikt oprócz Ciebie nie napisał ani słowa na ten temat.
Twój problem idealnie rozwiążą zdarzenia. Zrób tą klasę do autentyfikacji jako Service.
Pewnie to Ci pomoże:
http://forum.php.pl/index.php?showtopic=17...mp;#entry876774Entity managera będziesz mógl wstrzykiwać po przez dodanie do arguments:
doctrine.orm.entity_managerI koniec problemu
adbacz
14.11.2011, 01:13:47
ano dziękuję za linka. Bardzo mi pomógł. Faktycznie zdarzenia to rozwiązanie. Szkoda tylko, że dokumentacja SF jest tak kiepsko napisana,.
Dziekuję wam za pomoc Panowie.
EDIT: Wszystko działa, dzięki jeszcze raz za pomoc.
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.