Ορισμοί υπηρεσιών

Η διαμόρφωση είναι το μέρος όπου δίνουμε οδηγίες στο DI container για το πώς να συναρμολογήσει τις επιμέρους υπηρεσίες και πώς να τις συνδέσει με άλλες εξαρτήσεις. Η Nette παρέχει έναν πολύ σαφή και κομψό τρόπο για να το επιτύχουμε αυτό.

Η ενότητα services στο αρχείο ρυθμίσεων NEON είναι το σημείο όπου ορίζουμε τις προσαρμοσμένες υπηρεσίες μας και τις διαμορφώσεις τους. Ας δούμε ένα απλό παράδειγμα ορισμού μιας υπηρεσίας με το όνομα database, η οποία αντιπροσωπεύει μια περίπτωση της κλάσης PDO:

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

Αυτή η διαμόρφωση έχει ως αποτέλεσμα την ακόλουθη εργοστασιακή μέθοδο στο δοχείο DI:

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

Τα ονόματα υπηρεσιών μας επιτρέπουν να τα αναφέρουμε σε άλλα μέρη του αρχείου διαμόρφωσης, χρησιμοποιώντας τη μορφή @serviceName. Εάν δεν υπάρχει ανάγκη να δώσουμε όνομα στην υπηρεσία, μπορούμε απλά να χρησιμοποιήσουμε ένα σημείο αναφοράς:

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

Για να ανακτήσουμε μια υπηρεσία από το δοχείο DI, μπορούμε να χρησιμοποιήσουμε τη μέθοδο getService() με το όνομα της υπηρεσίας ως παράμετρο ή τη μέθοδο getByType() με τον τύπο της υπηρεσίας:

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

Δημιουργία υπηρεσιών

Συνήθως, δημιουργούμε μια υπηρεσία απλά με την ενσάρκωση μιας συγκεκριμένης κλάσης. Για παράδειγμα:

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

Εάν χρειάζεται να επεκτείνουμε τη διαμόρφωση με πρόσθετα κλειδιά, ο ορισμός μπορεί να επεκταθεί σε πολλές γραμμές:

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

Το κλειδί create έχει το ψευδώνυμο factory, και οι δύο εκδοχές είναι κοινές στην πράξη. Ωστόσο, συνιστούμε τη χρήση του κλειδιού create.

Τα ορίσματα του κατασκευαστή ή η μέθοδος δημιουργίας μπορούν εναλλακτικά να γραφτούν στο κλειδί arguments:

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

Οι υπηρεσίες δεν χρειάζεται να δημιουργούνται μόνο με απλή ενσάρκωση μιας κλάσης- μπορούν επίσης να προκύψουν από την κλήση στατικών μεθόδων ή μεθόδων άλλων υπηρεσιών:

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

Σημειώστε ότι για λόγους απλότητας, αντί για ->, χρησιμοποιούμε ::, βλέπε μέσα έκφρασης. Αυτές οι εργοστασιακές μέθοδοι δημιουργούνται:

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

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

Ο περιέκτης DI πρέπει να γνωρίζει τον τύπο της δημιουργούμενης υπηρεσίας. Αν δημιουργήσουμε μια υπηρεσία χρησιμοποιώντας μια μέθοδο που δεν έχει καθορισμένο τύπο επιστροφής, πρέπει να αναφέρουμε ρητά αυτόν τον τύπο στη διαμόρφωση:

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

Επιχειρήματα

Παραδίδουμε ορίσματα σε κατασκευαστές και μεθόδους με τρόπο που μοιάζει πολύ με την κανονική PHP:

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

Για καλύτερη αναγνωσιμότητα, μπορούμε να απαριθμήσουμε τα ορίσματα σε ξεχωριστές γραμμές. Σε αυτή τη μορφή, η χρήση των κομμάτων είναι προαιρετική:

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

Μπορείτε επίσης να ονομάσετε τα ορίσματα, γεγονός που σας επιτρέπει τότε να μην ανησυχείτε για τη σειρά τους:

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

Αν θέλετε να παραλείψετε ορισμένα ορίσματα και να χρησιμοποιήσετε τις προεπιλεγμένες τιμές τους ή να εισαγάγετε μια υπηρεσία μέσω αυτόματης καλωδίωσης, χρησιμοποιήστε μια υπογράμμιση:

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

Τα επιχειρήματα μπορεί να είναι υπηρεσίες, παράμετροι και πολλά άλλα, δείτε τα μέσα έκφρασης.

Εγκατάσταση

Στην ενότητα setup, ορίζουμε τις μεθόδους που πρέπει να κληθούν κατά τη δημιουργία της υπηρεσίας.

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

Σε PHP, αυτό θα έμοιαζε ως εξής:

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

Εκτός από τις κλήσεις μεθόδων, μπορείτε επίσης να μεταβιβάζετε τιμές σε ιδιότητες. Η προσθήκη ενός στοιχείου σε έναν πίνακα υποστηρίζεται επίσης, αλλά πρέπει να το περικλείσετε σε εισαγωγικά για να αποφύγετε τη σύγκρουση με τη σύνταξη NEON:

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

Στην PHP, αυτό θα μεταφραζόταν ως εξής:

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

Στην εγκατάσταση, μπορείτε επίσης να καλέσετε στατικές μεθόδους ή μεθόδους άλλων υπηρεσιών. Αν πρέπει να περάσετε την τρέχουσα υπηρεσία ως όρισμα, χρησιμοποιήστε το @self:

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

Σημειώστε ότι για λόγους απλότητας, αντί για ->, χρησιμοποιούμε ::, βλέπε μέσα έκφρασης. Αυτό δημιουργεί την ακόλουθη εργοστασιακή μέθοδο:

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

Έκφραση Μέσα

Το Nette DI μας παρέχει εξαιρετικά πλούσιες δυνατότητες έκφρασης, επιτρέποντάς μας να εκφράσουμε σχεδόν τα πάντα. Στα αρχεία ρυθμίσεων, μπορούμε να χρησιμοποιούμε παραμέτρους:

# παράμετρος
%wwwDir%

# τιμή κάτω από ένα κλειδί παραμέτρου
%mailer.user%

# παράμετρος μέσα σε μια συμβολοσειρά
'%wwwDir%/images'

Μπορούμε επίσης να δημιουργήσουμε αντικείμενα, να καλέσουμε μεθόδους και συναρτήσεις:

# δημιουργήστε ένα αντικείμενο
DateTime()

# κλήση μιας στατικής μεθόδου
Collator::create(%locale%)

# κλήση μιας συνάρτησης PHP
::getenv(DB_USER)

Να αναφερόμαστε σε υπηρεσίες είτε με το όνομά τους είτε με τον τύπο τους:

# υπηρεσία με όνομα
@database

# υπηρεσία ανά τύπο
@Nette\Database\Connection

Χρησιμοποιήστε σύνταξη πρώτης κατηγορίας callable:

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

Χρήση σταθερών:

# σταθερά κατηγορίας
FilesystemIterator::SKIP_DOTS

# παγκόσμια σταθερά που λαμβάνεται από τη συνάρτηση constant() της PHP
::constant(PHP_VERSION)

όπως ακριβώς και στην PHP. Για λόγους απλότητας, αντί του ->, χρησιμοποιούμε το :::

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

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

Αυτές οι εκφράσεις μπορούν να χρησιμοποιηθούν οπουδήποτε κατά τη δημιουργία υπηρεσιών, σε ορίσματα, στο τμήμα εγκατάστασης ή σε παραμέτρους:

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

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

Ειδικές λειτουργίες

Μέσα σε αρχεία ρυθμίσεων, μπορείτε να χρησιμοποιήσετε αυτές τις ειδικές λειτουργίες:

  • not() για άρνηση τιμών
  • bool(), int(), float(), string() για μετατροπή τύπου χωρίς απώλειες
  • typed() για τη δημιουργία ενός πίνακα όλων των υπηρεσιών ενός συγκεκριμένου τύπου
  • tagged() για τη δημιουργία ενός πίνακα όλων των υπηρεσιών με μια συγκεκριμένη ετικέτα
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Σε σύγκριση με το συμβατικό typecasting στην PHP, όπως το (int), το lossless type casting θα πετάξει μια εξαίρεση για μη αριθμητικές τιμές.

Η συνάρτηση typed() δημιουργεί έναν πίνακα όλων των υπηρεσιών ενός συγκεκριμένου τύπου (κλάση ή διεπαφή). Εξαιρεί τις υπηρεσίες με απενεργοποιημένη την αυτόματη σύνδεση. Μπορούν να καθοριστούν πολλαπλοί τύποι, χωρισμένοι με κόμμα.

services:
	- BarsDependent( typed(Bar) )

Μπορείτε επίσης να περάσετε αυτόματα έναν πίνακα υπηρεσιών ενός συγκεκριμένου τύπου ως όρισμα χρησιμοποιώντας την αυτόματη καλωδίωση.

Η συνάρτηση tagged() δημιουργεί έναν πίνακα όλων των υπηρεσιών με μια καθορισμένη ετικέτα. Μπορούν να παρατίθενται πολλαπλές ετικέτες, διαχωρισμένες με κόμμα.

services:
	- LoggersDependent( tagged(logger) )

Αυτόματη καλωδίωση

Το κλειδί autowired σας επιτρέπει να τροποποιήσετε τη συμπεριφορά αυτόματης καλωδίωσης για μια συγκεκριμένη υπηρεσία. Για περισσότερες λεπτομέρειες, ανατρέξτε στο κεφάλαιο αυτόματη σύνδεση.

services:
	foo:
		create: Foo
		autowired: false     # η υπηρεσία foo αποκλείεται από την αυτόματη καλωδίωση

Ετικέτες

Οι ετικέτες χρησιμοποιούνται για την προσθήκη συμπληρωματικών πληροφοριών στις υπηρεσίες. Μπορείτε να αντιστοιχίσετε μία ή περισσότερες ετικέτες σε μια υπηρεσία:

services:
	foo:
		create: Foo
		tags:
			- cached

Οι ετικέτες μπορούν επίσης να φέρουν τιμές:

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

Για να ανακτήσετε όλες τις υπηρεσίες με συγκεκριμένες ετικέτες, μπορείτε να χρησιμοποιήσετε τη λειτουργία tagged():

services:
	- LoggersDependent( tagged(logger) )

Στο δοχείο DI, μπορείτε να λάβετε τα ονόματα όλων των υπηρεσιών με μια συγκεκριμένη ετικέτα χρησιμοποιώντας τη μέθοδο findByTag():

$names = $container->findByTag('logger');
// $names είναι ένας πίνακας που περιέχει το όνομα της υπηρεσίας και την τιμή της ετικέτας
// π.χ. ['foo' => 'monolog.logger.event', ...]

Λειτουργία έγχυσης

Η χρήση της σημαίας inject: true ενεργοποιεί τη μεταβίβαση εξαρτήσεων μέσω δημόσιων μεταβλητών με το σχόλιο inject και τις μεθόδους inject*().

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

Από προεπιλογή, το inject είναι ενεργοποιημένο μόνο για τους παρουσιαστές.

Τροποποιήσεις υπηρεσιών

Ο περιέκτης DI περιέχει πολλές υπηρεσίες που προστίθενται είτε από ενσωματωμένες είτε από επεκτάσεις χρηστών. Μπορείτε να τροποποιήσετε τους ορισμούς αυτών των υπηρεσιών απευθείας στη διαμόρφωση. Για παράδειγμα, μπορείτε να αλλάξετε την κλάση της υπηρεσίας application.application, η οποία είναι συμβατικά Nette\Application\Application, σε κάτι άλλο:

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

Η σημαία alteration είναι πληροφοριακή, υποδεικνύοντας ότι απλώς τροποποιούμε μια υπάρχουσα υπηρεσία.

Μπορούμε επίσης να συμπληρώσουμε τη ρύθμιση:

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

Εδώ είναι που το reset είναι χρήσιμο:

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

Αν θέλετε να αφαιρέσετε μια υπηρεσία που προστέθηκε από μια επέκταση, μπορείτε να το κάνετε ως εξής:

services:
	cache.journal: false
έκδοση: 3.x