Ορισμοί υπηρεσιών
Η διαμόρφωση είναι το μέρος όπου δίνουμε οδηγίες στο 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