2012-03-03 9 views
5

jest to bardziej „najlepszej praktyki” kwestii niż rzeczywistego problemu:Symfony2 danych przepływających między wiązkami i kontrolerów

pracuję nad projektem w Symfony 2 i I został zbudowany pakiet do obsługi wszystkich moje webservices. Zasadniczo jeden kontroler pobiera pewne dane JSON, wysyła je do innego kontrolera, aby sprawdzić, czy pasuje do opisanego formatu, a następnie wyłącza go do innego kontrolera, aby obsłużył wywołania bazy danych i ostatecznie powrócił do kontrolera początkowego, aby zwrócić odpowiedź JSON.

jestem wysyłania danych między kontrolerami robiąc coś takiego:

$controller = new \Acme\myBundle\Controller\DefaultController; 
$response = $controller->function(); 

ta działa poprawnie, ale stale napotykając jednego problemu. W kontrolerze przekazuję dane do potrzebuję utworzenia instancji AppKernel i wywołania funkcji rozruchowej dla dowolnej funkcji Symfony. Wydaje mi się to trochę głupie, co prowadzi mnie do przekonania, że ​​robię to wszystko źle.

Wszelkie sugestie i wskazówki doceniane!

EDIT/UPDATE Dziękuję wszystkim za komentarze. Skonfigurowałem moje kontrolery jako usługi, usługi działają, ale nadal potrzebuję ręcznie uruchamiać/tworzyć instancję jądra, gdy wywołuję usługę z poziomu usługi.

#config.yml 
# API Services 
services: 
service.handler: 
    class: Acme\APIBundle\Controller\ServicesController 
    arguments: 
     container: "@service_container" 

service.definitions: 
    class: Acme\APIBundle\Controller\DefinitionController 
    arguments: 
     container: "@service_container" 

Z innego kontrolera wiązki można następnie wywołać funkcję z jednej z tych usług bez problemu:

$test = $this->get("service.handler")->testFunction(); 
$test2 = $this->get("service.definitions")->anotherTestFunction(); 

Gdzie ja mam problem jest, jeśli wywołanie funkcji wewnątrz jednej usługi, a następnie starają się wywołać inną usługę z wewnątrz tej usługi otrzymuję następujący błąd PHP za

Fatal error: Call to a member function get() on a non-object in /vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 188 

mogę uniknąć tego błędu przy użyciu tej funkcji i nazywając ją raczej niż przy użyciu $ to

public function bootKernel(){ 
//boot kernel 
    $controller = new \Acme\myBundle\Controller\DefaultController; 
    $kernel = new \AppKernel('dev', true);$kernel->loadClassCache(); 
    $kernel->boot(); 
    $controller->setContainer($kernel->getContainer()); 
    return($controller);  
} 

Domyślam się, że moje rozwiązanie "działa", ale z pewnością nie wydaje się to skutecznym sposobem działania.

EDIT 2: Jeśli trzymać to w górnej części klasy następnie modyfikować usługi połączeń wydaje się działać ... Nadal nie wiem, czy jest to najlepszy sposób, aby robić różne rzeczy.

protected $container; 

public function __construct($container) { 
    $this->container= $container; 
} 
+1

Myślę, że opcja [przekierowanie] (http://symfony.com/doc/current/book/controller.html#forwarding) może być tutaj dostępna. –

+3

Czy istnieje powód, dla którego nie korzystasz z usług [http://symfony.com/doc/current/cookbook/controller/service.html] do obsługi różnych metod? – richsage

Odpowiedz

10

Zejdę z trasy controller-as-a-service powyżej. Załóżmy, że musisz wywołać 3 metody w ramach przetwarzania. Nazwijmy je foo(), bar() i something(). Każda z tych metod są w oddzielnych regulatorów:

namespace Acme\DemoBundle\Controller; 

class FooController 
{ 
    public function __construct($container, ...) 
    { 
     $this->container = $container; 
     // ... deal with any more arguments etc here 
    } 

    public function foo($params) 
    { 
     // ... 
     return $x; 
    } 

    protected function get($service) 
    { 
     return $this->container->get($service); 
    } 
} 

Ditto dla metod bar() i something(), każdy w swoim kontrolerze. Następnie dodaj je do swojej aplikacji jako usługi.Np w swoim config.yml (inne metody są dostępne):

services: 
    my.foo.service: 
     class: Acme\FooBundle\Controller\FooController 
     arguments: 
      container: "@service_container" 

Zobacz docs Symfony dla more details o tym, jak można skonstruować ten wpis, w tym wstrzykiwanie wszelkie zależności, takich jak zarządcy podmiot lub podobny. Teraz można dostać wystąpienie tego z pojemnika:

public function yourMainAction() 
{ 
    // ... 

    $newData = $this->get("my.foo.service")->fooAction($someData); 

    // ... 

    return new Response(json_encode($newData), ...); 
} 

Podobnie ponownie BarController i SomethingController. Zaletą jest to, że ta usługa może zostać udostępniona w dowolnym momencie w aplikacji (za pośrednictwem kontenera jak wyżej lub jako usługa wstrzykiwana), w pakietach, bez konieczności samodzielnego tworzenia klasy samodzielnie i zapewnienia jakichkolwiek zależności.

Aby uzyskać więcej informacji na temat kontenera itp., Dokumenty Symfony mają na nim numer good section (do którego link znajduje się powyżej).

Edytuj: Dostosowano przykład kodu, aby uwzględnić szczegóły przekazywania argumentów do usługi. Dodano także metodę wygodnego pobierania usług z kontenera.

+0

Dzięki za odpowiedź, Rich. Próbowałem używać kontrolerów jako usług, ale napotkałem dokładnie ten sam problem. Jeśli zadzwonię do jednego kontrolera jako usługi, to od wewnątrz tego kontrolera wywołaj innego kontrolera jako usługę, ale za każdym razem muszę uruchomić jądro. Przeczytałem dokumenty i nie jestem do końca pewien, które "zależności" muszę ustawić, aby za każdym razem uniknąć uruchamiania funkcji rozruchowej. – greg

+0

Bez tworzenia instancji jądra pojawia się następujący błąd: Błąd krytyczny: wywołanie funkcji członkowskiej get() na obiekcie nie-obiektowym w/Users/greg/Repos/Acme/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 188 – greg

+0

Czy twoje pakiety zostały poprawnie dodane do twojego jądra? Wewnątrz 'AppKernel.php'? Powinny one zostać automatycznie uruchomione, jeśli zostały tutaj dodane. – richsage

Powiązane problemy