2016-04-25 19 views
5

Sto utilizzando Slim Framework 3 per creare un'API. La struttura dell'app è: MVCP (Modello, Visualizza, Controller, Provider).Iniezione delle dipendenze Slim Framework 3

E 'possibile avere Dipendenza Slim Iniettare tutte le mie classi?

Sto utilizzando il compositore per caricare automaticamente tutte le mie dipendenze.

mia struttura di directory simile a questo:

/app 
    - controllers/ 
    - Models/ 
    - services/ 
    index.php 
/vendor 
composer.json 

Ecco il mio file composer.json.

{ 
    "require": { 
    "slim/slim": "^3.3", 
    "monolog/monolog": "^1.19" 
    }, 
    "autoload" : { 
    "psr-4" : { 
     "Controllers\\" : "app/controllers/", 
     "Services\\" : "app/services/", 
     "Models\\" : "app/models/" 
    } 
    } 
} 

Ecco il mio file index.php. Anche in questo caso, le dipendenze vengono automaticamente iniettati dal compositore

<?php 
use \Psr\Http\Message\ServerRequestInterface as Request; 
use \Psr\Http\Message\ResponseInterface as Response; 

require '../vendor/autoload.php'; 

$container = new \Slim\Container; 
$app = new \Slim\App($container); 

$app->get('/test/{name}', '\Controllers\PeopleController:getEveryone'); 

$app->run(); 

mio regolatore di simile a questa

<?php #controllers/PeopleController.php 

namespace Controllers; 

use \Psr\Http\Message\ServerRequestInterface as Request; 
use \Psr\Http\Message\ResponseInterface as Response; 


class PeopleController 
{ 
    protected $peopleService; 

    protected $ci; 
    protected $request; 
    protected $response; 

    public function __construct(Container $ci, PeopleService $peopleService) 
    { 
     $this->peopleService = $peopleService; 
     $this->ci = $ci; 
    } 

    public function getEveryone($request, $response) 
    { 
     die($request->getAttribute('name')); 

     return $this->peopleService->getAllPeoples(); 
    } 
} 

Il mio file PeopleService assomiglia a questo:

<?php 

namespace Services; 

use Model\PeopleModel; 
use Model\AddressModel; 
use Model\AutoModel; 


class PeopleService 
{ 
    protected $peopleModel; 
    protected $autoModel; 
    protected $addressModel; 

    public function __construct(PeopleModel $peopleModel, AddressModel $addressModel, AutoModel $autoModel) 
    { 
     $this->addressModel = $addressModel; 
     $this->autoModel = $autoModel; 
     $this->peopleModel = $peopleModel; 
    } 

    public function getAllPeopleInfo() 
    { 
     $address = $this->addressModel->getAddress(); 
     $auto = $this->autoModel->getAutoMake(); 
     $person = $this->peopleModel->getPeople(); 

     return [ 
      $person[1], $address[1], $auto[1] 
     ]; 
    } 
} 

Models/AddressModels.php

<?php 

namespace Model; 

class AddressModel 
{ 

    public function __construct() 
    { 
     // do stuff 
    } 

    public function getAddress() 
    { 
     return [ 
      1 => '123 Maple Street', 
     ]; 
    } 
} 

Models/AutoModel.php

namespace Model; 

class AutoModel 
{ 

    public function __construct() 
    { 
     // do stuff 
    } 

    public function getAutoMake() 
    { 
     return [ 
      1 => 'Honda' 
     ]; 
    } 
} 

Models/PeopleModel.php

<?php 
namespace Model; 

class PeopleModel 
{ 

    public function __construct() 
    { 
     // do stuff 
    } 

    public function getPeople() 
    { 
     return [ 
      1 => 'Bob' 
     ]; 
    } 

} 

ERRORE sto ottenendo il seguente errore ora:

PHP Catchable fatal error: Argument 2 passed to Controllers\PeopleController::__construct() must be an instance of Services\PeopleService, none given, called in /var/www/vendor/slim/slim/Slim/CallableResolver.php on line 64 and defined in /var/www/app/controllers/PeopleController.php on line 21 

LA QUESTIONE Come faccio a dipendenza iniettare tutta la mia cl asini? C'è un modo per dire automaticamente a Slim's DI Container di farlo?

+2

Quindi si desidera iniettarli o caricarli automaticamente? Se intendi l'autoloading, probabilmente hai dimenticato di includere il file 'vendor/autoload.php' all'inizio di index.php. Contiene caricatori automatici generati. –

+0

Beh, quello era uno dei miei problemi. Grazie! Ho aggiornato l'indice.php per includere il file PHP del caricatore automatico. Ho aggiornato la domanda per includere l'errore che sto ottenendo. Ancora una volta, il problema è come la dipendenza Iniettare le mie classi. –

+0

Bene, l'errore è auto-esplicativo. Cosa non è chiaro qui? –

risposta

4

Quando si fa riferimento a una classe nella route richiamabile, Slim richiederà il DIC. Se il DIC non ha una registrazione per quel nome di classe, allora istanzia la classe stessa, passando il contenitore come unico argomento della classe.

Quindi, per iniettare le dipendenze corrette per il controller, è sufficiente creare il proprio stabilimento DIC:

$container = $app->getContainer(); 
$container['\Controllers\PeopleController'] = function ($c) { 
    $peopleService = $c->get('\Services\PeopleService'); 
    return new Controllers\PeopleController($c, $peopleService); 
}; 

Naturalmente, è ora necessario una fabbrica DIC per i PeopleService:

$container['\Services\PeopleService'] = function ($c) { 
    $peopleModel = new Models\PeopleModel; 
    $addressModel = new Models\AddressModel; 
    $autoModel = new Models\AutoModel; 
    return new Services\PeopleService($peopleModel, $addressModel, $autoModel); 
}; 

(Se PeopleModel, AddressModel o AutoModel aveva dipendenze, quindi si creerebbero fabbriche DIC anche per quelle.)

+0

Slim richiede di passare il contenitore a * ogni * classe che ne ha bisogno? Questo non sembra un approccio molto ASCIUTTO. Sono abituato a lavorare con CakePHP e sembra che le cose siano disponibili "globalmente" quando lo si utilizza (probabilmente a causa di AppModel e AppController). In Slim sembra che tu debba passare cose come il contenitore ogni volta che ne hai bisogno? Quindi se ho 100 classi, devo usare un codice equivalente a quello che hai messo sopra 100 volte? – Andy

+0

Dipende da voi. Non c'è niente che ti impedisca di creare una funzione statica globale che ti permetta di afferrare il contenitore. Personalmente, non mi piace quel livello di accoppiamento, quindi non farlo in quel modo. –