Opredelitve storitev

Konfiguracija je mesto, kjer vsebniku DI naročimo, kako naj sestavi posamezne storitve in kako naj jih poveže z drugimi odvisnostmi. Nette ponuja zelo jasen in eleganten način za doseganje tega cilja.

V razdelku services v konfiguracijski datoteki NEON opredelimo svoje storitve po meri in njihove konfiguracije. Oglejmo si preprost primer opredelitve storitve z imenom database, ki predstavlja primerek razreda PDO:

services:
	database: PDO('sqlite::memory:')

Rezultat te konfiguracije je naslednja tovarniška metoda v vsebniku DI:

public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}

Imena storitev nam omogočajo sklicevanje nanje v drugih delih konfiguracijske datoteke v obliki @serviceName. Če storitve ni treba poimenovati, lahko preprosto uporabimo točko:

services:
	- PDO('sqlite::memory:')

Za pridobitev storitve iz vsebnika DI lahko uporabimo metodo getService() z imenom storitve kot parametrom ali metodo getByType() s tipom storitve:

$database = $container->getService('database');
$database = $container->getByType(PDO::class);

Ustvarjanje storitev

Najpogosteje ustvarimo storitev tako, da instanciramo določen razred. Na primer:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

Če moramo konfiguracijo razširiti z dodatnimi ključi, lahko definicijo razširimo v več vrstic:

services:
	database:
		create: PDO('sqlite::memory:')
		setup: ...

Ključ create ima vzdevek factory, obe različici sta v praksi pogosti. Vendar priporočamo uporabo ključa create.

Argumente konstruktorja ali metodo ustvarjanja lahko alternativno zapišete v ključu arguments:

services:
	database:
		create: PDO
		arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]

Storitve niso nujno ustvarjene samo z enostavno instanciacijo razreda; lahko so tudi posledica klica statičnih metod ali metod drugih storitev:

services:
	database: DatabaseFactory::create()
	router: @routerFactory::create()

Upoštevajte, da zaradi enostavnosti namesto -> uporabljamo ::, glej izrazna sredstva. Te tovarniške metode so ustvarjene:

public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

public function createServiceRouter(): RouteList
{
	return $this->getService('routerFactory')->create();
}

vsebnik DI mora poznati vrsto ustvarjene storitve. Če ustvarimo storitev z metodo, ki nima določene vrnitvene vrste, moramo to vrsto izrecno navesti v konfiguraciji:

services:
	database:
		create: DatabaseFactory::create()
		type: PDO

Argumenti

Argumente konstruktorjem in metodam posredujemo na zelo podoben način kot v običajnem jeziku PHP:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

Za boljšo berljivost lahko argumente navedemo v ločenih vrsticah. V tej obliki je uporaba vejic neobvezna:

services:
	database: PDO(
		'mysql:host=127.0.0.1;dbname=test'
		root
		secret
	)

Argumente lahko tudi poimenujete, kar vam omogoča, da se ne ukvarjate z njihovim vrstnim redom:

services:
	database: PDO(
		username: root
		password: secret
		dsn: 'mysql:host=127.0.0.1;dbname=test'
	)

Če želite določene argumente izpustiti in uporabiti njihove privzete vrednosti ali vstaviti storitev prek samodejnega napeljevanja, uporabite podčrtaj:

services:
	foo: Foo(_, %appDir%)

Argumenti so lahko storitve, parametri in še veliko več, glejte izrazna sredstva.

Nastavitev

V razdelku setup opredelimo metode, ki jih je treba poklicati pri ustvarjanju storitve.

services:
	database:
		create: PDO(%dsn%, %user%, %password%)
		setup:
			- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)

V jeziku PHP bi bilo to videti takole:

public function createServiceDatabase(): PDO
{
	$service = new PDO('...', '...', '...');
	$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	return $service;
}

Poleg klicev metod lahko lastnostim posredujete tudi vrednosti. Podprto je tudi dodajanje elementa v polje, vendar ga morate zapreti v narekovaje, da ne pride do kolizije s sintakso NEON:

services:
	foo:
		create: Foo
		setup:
			- $value = 123
			- '$onClick[]' = [@bar, clickHandler]

V jeziku PHP bi to pomenilo:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	$service->value = 123;
	$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
	return $service;
}

V nastavitvi lahko kličete tudi statične metode ali metode drugih storitev. Če morate kot argument posredovati trenutno storitev, uporabite @self:

services:
	foo:
		create: Foo
		setup:
			- My\Helpers::initializeFoo(@self)
			- @anotherService::setFoo(@self)

Upoštevajte, da zaradi enostavnosti namesto -> uporabimo ::, glejte izrazna sredstva. To ustvari naslednjo tovarniško metodo:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	My\Helpers::initializeFoo($service);
	$this->getService('anotherService')->setFoo($service);
	return $service;
}

Sredstva za izražanje

Nette DI nam zagotavlja izjemno bogate izrazne možnosti, s katerimi lahko izrazimo skoraj vse. V konfiguracijskih datotekah lahko uporabljamo parametre:

# parameter
%wwwDir%

# vrednost pod ključem parametra
%mailer.user%

# parameter v nizu
'%wwwDir%/images'

Prav tako lahko ustvarjamo predmete, kličemo metode in funkcije:

# ustvariti predmet
DateTime()

# klic statične metode
Collator::create(%locale%)

# klic funkcije PHP
::getenv(DB_USER)

Na storitve se lahko sklicujemo po imenu ali vrsti:

# storitev po imenu
@database

# storitev po vrsti
@Nette\Database\Connection

Uporabite sintakso prvega razreda za klicanje:

# creating a callback, equivalent to [@user, logout]
@user::logout(...)

Uporabite konstante:

# razred stalnica
FilesystemIterator::SKIP_DOTS

# globalna konstanta, pridobljena s funkcijo PHP constant()
::constant(PHP_VERSION)

Tako kot v PHP lahko klice metod verižite. Zaradi preprostosti namesto -> uporabimo :::

DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()

Te izraze lahko pri ustvarjanju storitev uporabite kjer koli, v argumentih, v nastavitvenem delu ali parametrih:

parameters:
	ipAddress: @http.request::getRemoteAddress()

services:
	database:
		create: DatabaseFactory::create( @anotherService::getDsn() )
		setup:
			- initialize( ::getenv('DB_USER') )

Posebne funkcije

V konfiguracijskih datotekah lahko uporabite te posebne funkcije:

  • not() za zanikanje vrednosti
  • bool(), int(), float(), string() za brezizgubno ulivanje tipov
  • typed() za ustvarjanje polja vseh storitev določenega tipa
  • tagged() za ustvarjanje polja vseh storitev z določeno oznako
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

V primerjavi z običajnim tipiziranjem v PHP, kot je (int), bo brezizgubno tipiziranje vrglo izjemo za neštevilčne vrednosti.

Funkcija typed() ustvari polje vseh storitev določene vrste (razreda ali vmesnika). Izključuje storitve z izklopljenim samodejnim vgrajevanjem. Določite lahko več vrst, ki jih ločite z vejicami.

services:
	- BarsDependent( typed(Bar) )

Kot argument lahko samodejno posredujete tudi polje storitev določene vrste z uporabo samodejnega napeljevanja.

Funkcija tagged() ustvari polje vseh storitev z določeno oznako. Navedete lahko več oznak, ki jih ločite z vejicami.

services:
	- LoggersDependent( tagged(logger) )

Avtomatska napeljava

Ključ autowired omogoča spreminjanje obnašanja samodejnega ožičenja za določeno storitev. Za več podrobnosti glejte poglavje o samodejnem ožičenju.

services:
	foo:
		create: Foo
		autowired: false     # storitev foo je izključena iz samodejnega ožičenja

Oznake

Oznake se uporabljajo za dodajanje dodatnih informacij storitvam. Storitvi lahko dodelite eno ali več oznak:

services:
	foo:
		create: Foo
		tags:
			- cached

Oznake lahko nosijo tudi vrednosti:

services:
	foo:
		create: Foo
		tags:
			logger: monolog.logger.event

Če želite priklicati vse storitve z določenimi oznakami, lahko uporabite funkcijo tagged():

services:
	- LoggersDependent( tagged(logger) )

V vsebniku DI lahko z metodo findByTag() pridobite imena vseh storitev z določeno oznako:

$names = $container->findByTag('logger');
// $names je polje, ki vsebuje ime storitve in vrednost oznake
// npr. ['foo' => 'monolog.logger.event', ...]

Način vbrizgavanja

Uporaba oznake inject: true aktivira posredovanje odvisnosti prek javnih spremenljivk z opombo inject in metodami inject*( ).

services:
	articles:
		create: App\Model\Articles
		inject: true

Privzeto je funkcija inject aktivirana samo za predstavnike.

Spremembe storitev

Vsebnik DI vsebuje številne storitve, ki so dodane z vgrajenimi ali uporabniškimi razširitvami. Definicije teh storitev lahko spreminjate neposredno v konfiguraciji. Tako lahko na primer spremenite razred storitve application.application, ki je običajno Nette\Application\Application, v drug razred:

services:
	application.application:
		create: MyApplication
		alteration: true

Oznaka alteration je informativna in pomeni, da zgolj spreminjamo obstoječo storitev.

Nastavitev lahko tudi dopolnimo:

services:
	application.application:
		create: MyApplication
		alteration: true
		setup:
			- '$onStartup[]' = [@resource, init]

Pri prepisovanju storitve boste morda želeli odstraniti prvotne argumente, nastavitvene elemente ali oznake, pri čemer vam pride prav reset:

services:
	application.application:
		create: MyApplication
		alteration: true
		reset:
			- arguments
			- setup
			- tags

Če želite odstraniti storitev, ki jo je dodala razširitev, lahko to storite na naslednji način:

services:
	cache.journal: false
različica: 3.x