Definiowanie usług
Konfiguracja to miejsce, w którym instruujemy kontener DI, jak składać poszczególne usługi i jak łączyć je z innymi zależnościami. Nette zapewnia bardzo przejrzysty i elegancki sposób na osiągnięcie tego celu.
Sekcja services
w pliku konfiguracyjnym NEON to miejsce, w którym definiujemy nasze niestandardowe usługi i ich
konfiguracje. Przyjrzyjmy się prostemu przykładowi definiowania usługi o nazwie database
, która reprezentuje
instancję klasy PDO
:
services:
database: PDO('sqlite::memory:')
Ta konfiguracja skutkuje następującą metodą fabryczną w kontenerze DI:
public function createServiceDatabase(): PDO
{
return new PDO('sqlite::memory:');
}
Nazwy usług pozwalają nam odwoływać się do nich w innych częściach pliku konfiguracyjnego, używając formatu
@serviceName
. Jeśli nie ma potrzeby nazywania usługi, możemy po prostu użyć punktora:
services:
- PDO('sqlite::memory:')
Aby pobrać usługę z kontenera DI, możemy użyć metody getService()
z nazwą usługi jako parametrem lub
metody getByType()
z typem usługi:
$database = $container->getService('database');
$database = $container->getByType(PDO::class);
Tworzenie usług
Najczęściej tworzymy usługę po prostu poprzez instancjonowanie określonej klasy. Na przykład:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Jeśli musimy rozszerzyć konfigurację o dodatkowe klucze, definicję można rozszerzyć na wiele linii:
services:
database:
create: PDO('sqlite::memory:')
setup: ...
Klucz create
ma alias factory
, obie wersje są powszechne w praktyce. Zalecamy jednak używanie
create
.
Argumenty konstruktora lub metoda tworzenia mogą być alternatywnie zapisane w kluczu arguments
:
services:
database:
create: PDO
arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]
Usługi nie muszą być tworzone tylko przez prostą instancję klasy; mogą one również wynikać z wywoływania metod statycznych lub metod innych usług:
services:
database: DatabaseFactory::create()
router: @routerFactory::create()
Zauważ, że dla uproszczenia, zamiast ->
, używamy ::
, patrz wyrażenie oznacza. Te metody fabryczne są generowane:
public function createServiceDatabase(): PDO
{
return DatabaseFactory::create();
}
public function createServiceRouter(): RouteList
{
return $this->getService('routerFactory')->create();
}
Kontener DI musi znać typ tworzonej usługi. Jeśli tworzymy usługę przy użyciu metody, która nie ma określonego typu zwracanego, musimy wyraźnie wspomnieć o tym typie w konfiguracji:
services:
database:
create: DatabaseFactory::create()
type: PDO
Argumenty
Przekazujemy argumenty do konstruktorów i metod w sposób bardzo podobny do zwykłego PHP:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Dla lepszej czytelności możemy wypisać argumenty w osobnych wierszach. W tym formacie użycie przecinków jest opcjonalne:
services:
database: PDO(
'mysql:host=127.0.0.1;dbname=test'
root
secret
)
Można również nazwać argumenty, co pozwala nie martwić się o ich kolejność:
services:
database: PDO(
username: root
password: secret
dsn: 'mysql:host=127.0.0.1;dbname=test'
)
Jeśli chcesz pominąć niektóre argumenty i użyć ich wartości domyślnych lub wstawić usługę poprzez autowiring, użyj podkreślenia:
services:
foo: Foo(_, %appDir%)
Argumentami mogą być usługi, parametry i wiele innych, patrz środki wyrazu.
Konfiguracja
W sekcji setup
definiujemy metody, które powinny być wywoływane podczas tworzenia usługi.
services:
database:
create: PDO(%dsn%, %user%, %password%)
setup:
- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
W PHP wyglądałoby to następująco:
public function createServiceDatabase(): PDO
{
$service = new PDO('...', '...', '...');
$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $service;
}
Oprócz wywoływania metod, można również przekazywać wartości do właściwości. Dodawanie elementu do tablicy jest również obsługiwane, ale należy je ująć w cudzysłów, aby uniknąć kolizji ze składnią NEON:
services:
foo:
create: Foo
setup:
- $value = 123
- '$onClick[]' = [@bar, clickHandler]
W PHP tłumaczyłoby się to na:
public function createServiceFoo(): Foo
{
$service = new Foo;
$service->value = 123;
$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
return $service;
}
W konfiguracji można również wywoływać metody statyczne lub metody innych usług. Jeśli chcesz przekazać bieżącą
usługę jako argument, użyj @self
:
services:
foo:
create: Foo
setup:
- My\Helpers::initializeFoo(@self)
- @anotherService::setFoo(@self)
Zauważ, że dla uproszczenia, zamiast ->
, używamy ::
, patrz środki wyrazu. Spowoduje to wygenerowanie następującej metody fabrycznej:
public function createServiceFoo(): Foo
{
$service = new Foo;
My\Helpers::initializeFoo($service);
$this->getService('anotherService')->setFoo($service);
return $service;
}
Środki wyrazu
Nette DI zapewnia nam wyjątkowo bogate możliwości wyrażania, pozwalając nam wyrazić prawie wszystko. W plikach konfiguracyjnych możemy używać parametrów:
# parametr
%wwwDir%
# wartość pod kluczem parametru
%mailer.user%
# parametr w ciągu znaków
'%wwwDir%/images'
Możemy również tworzyć obiekty, wywoływać metody i funkcje:
# utworzyć obiekt
DateTime()
# wywołać metodę statyczną
Collator::create(%locale%)
# wywołać funkcję PHP
::getenv(DB_USER)
Odnosić się do usług poprzez ich nazwę lub typ:
# usługa według nazwy
@database
# usługa według typu
@Nette\Database\Connection
Używaj składni wywoływalnej pierwszej klasy:
# creating a callback, equivalent to [@user, logout]
@user::logout(...)
Użyj stałych:
# stała klasy
FilesystemIterator::SKIP_DOTS
# stała globalna uzyskana przez funkcję PHP constant()
::constant(PHP_VERSION)
Wywołania metod mogą być łańcuchowane, tak jak w PHP. Dla uproszczenia, zamiast ->
, używamy
::
:
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')
@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
Wyrażenia te mogą być używane w dowolnym miejscu podczas tworzenia usług, w argumentach, w sekcji konfiguracji lub w parametrach:
parameters:
ipAddress: @http.request::getRemoteAddress()
services:
database:
create: DatabaseFactory::create( @anotherService::getDsn() )
setup:
- initialize( ::getenv('DB_USER') )
Funkcje specjalne
W plikach konfiguracyjnych można korzystać z tych funkcji specjalnych:
not()
dla negacji wartościbool()
,int()
,float()
,string()
do bezstratnego rzutowania typówtyped()
do generowania tablicy wszystkich usług określonego typutagged()
do tworzenia tablicy wszystkich usług z danym tagiem
services:
- Foo(
id: int(::getenv('ProjectId'))
productionMode: not(%debugMode%)
)
W porównaniu do konwencjonalnego rzutowania typów w PHP, takiego jak (int)
, bezstratne rzutowanie typów rzuci
wyjątek dla wartości nienumerycznych.
Funkcja typed()
tworzy tablicę wszystkich usług określonego typu (klasy lub interfejsu). Wyklucza ona usługi
z wyłączonym autowiringiem. Można określić wiele typów, oddzielając je przecinkami.
services:
- BarsDependent( typed(Bar) )
Można również automatycznie przekazać tablicę usług określonego typu jako argument przy użyciu autowiring.
Funkcja tagged()
tworzy tablicę wszystkich usług z określonym tagiem. Można wymienić wiele tagów,
oddzielając je przecinkami.
services:
- LoggersDependent( tagged(logger) )
Okablowanie
Klucz autowired
pozwala modyfikować zachowanie autoprzewodowania dla określonej usługi. Więcej szczegółów
można znaleźć w rozdziale autowiring.
services:
foo:
create: Foo
autowired: false # usługa foo jest wyłączona z automatycznego okablowania
Tagi
Tagi służą do dodawania dodatkowych informacji do usług. Do usługi można przypisać jeden lub więcej tagów:
services:
foo:
create: Foo
tags:
- cached
Tagi mogą również zawierać wartości:
services:
foo:
create: Foo
tags:
logger: monolog.logger.event
Aby pobrać wszystkie usługi z określonymi tagami, można użyć funkcji tagged()
:
services:
- LoggersDependent( tagged(logger) )
W kontenerze DI można uzyskać nazwy wszystkich usług z określonym tagiem za pomocą metody findByTag()
:
$names = $container->findByTag('logger');
// $names to tablica zawierająca nazwę usługi i wartość tagu
// np. ['foo' => 'monolog.logger.event', ...].
Tryb wstrzykiwania
Użycie flagi inject: true
aktywuje przekazywanie zależności poprzez zmienne publiczne z adnotacją inject i metodami inject*().
services:
articles:
create: App\Model\Articles
inject: true
Domyślnie flaga inject
jest aktywowana tylko dla prezenterów.
Modyfikacje usługi
Kontener DI zawiera wiele usług dodanych przez rozszerzenia wbudowane lub użytkownika. Definicje tych usług można modyfikować bezpośrednio w konfiguracji. Na przykład
można zmienić klasę usługi application.application
, która jest konwencjonalnie
Nette\Application\Application
, na coś innego:
services:
application.application:
create: MyApplication
alteration: true
Flaga alteration
ma charakter informacyjny, wskazując, że jedynie modyfikujemy istniejącą usługę.
Możemy również uzupełnić konfigurację:
services:
application.application:
create: MyApplication
alteration: true
setup:
- '$onStartup[]' = [@resource, init]
Podczas nadpisywania usługi może być konieczne usunięcie oryginalnych argumentów, elementów konfiguracji lub tagów, co
jest przydatne w przypadku reset
:
services:
application.application:
create: MyApplication
alteration: true
reset:
- arguments
- setup
- tags
Jeśli chcesz usunąć usługę dodaną przez rozszerzenie, możesz to zrobić w następujący sposób:
services:
cache.journal: false