Ορισμός υπηρεσιών
Η διαμόρφωση είναι το μέρος όπου διδάσκουμε στο DI container πώς να συναρμολογεί τις επιμέρους υπηρεσίες και πώς να τις συνδέει με άλλες εξαρτήσεις. Το Nette παρέχει έναν πολύ σαφή και κομψό τρόπο για να το πετύχουμε αυτό.
Η ενότητα services
στο αρχείο διαμόρφωσης μορφής NEON είναι το μέρος
όπου ορίζουμε τις δικές μας υπηρεσίες και τις διαμορφώσεις τους. Ας
δούμε ένα απλό παράδειγμα ορισμού μιας υπηρεσίας με όνομα database
,
η οποία αντιπροσωπεύει μια παρουσία της κλάσης PDO
:
services:
database: PDO('sqlite::memory:')
Η παραπάνω διαμόρφωση θα οδηγήσει στην ακόλουθη μέθοδο factory στο DI container:
public function createServiceDatabase(): PDO
{
return new PDO('sqlite::memory:');
}
Τα ονόματα των υπηρεσιών μας επιτρέπουν να αναφερόμαστε σε αυτές σε
άλλα μέρη του αρχείου διαμόρφωσης, με τη μορφή @ονομαΥπηρεσιας
.
Εάν δεν χρειάζεται να ονομάσουμε την υπηρεσία, μπορούμε απλά να
χρησιμοποιήσουμε μόνο μια παύλα:
services:
- PDO('sqlite::memory:')
Για να λάβουμε μια υπηρεσία από το DI container, μπορούμε να
χρησιμοποιήσουμε τη μέθοδο 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
έχει ένα alias 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()
Σημειώστε ότι για λόγους απλότητας, αντί για ->
χρησιμοποιείται ::
, δείτε Εκφραστικά μέσα.
Θα δημιουργηθούν αυτές οι μέθοδοι factory:
public function createServiceDatabase(): PDO
{
return DatabaseFactory::create();
}
public function createServiceRouter(): RouteList
{
return $this->getService('routerFactory')->create();
}
Το DI container πρέπει να γνωρίζει τον τύπο της δημιουργημένης υπηρεσίας. Εάν δημιουργούμε μια υπηρεσία χρησιμοποιώντας μια μέθοδο που δεν έχει καθορισμένο τύπο επιστροφής, πρέπει να δηλώσουμε ρητά αυτόν τον τύπο στη διαμόρφωση:
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'
)
Εάν θέλετε να παραλείψετε ορισμένα ορίσματα και να χρησιμοποιήσετε την προεπιλεγμένη τους τιμή ή να εισαγάγετε μια υπηρεσία χρησιμοποιώντας autowiring, χρησιμοποιήστε την κάτω παύλα:
services:
foo: Foo(_, %appDir%)
Ως ορίσματα μπορούν να παραδοθούν υπηρεσίες, να χρησιμοποιηθούν παράμετροι και πολλά άλλα, δείτε Εκφραστικά μέσα.
Setup
Στην ενότητα 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;
}
Εκτός από την κλήση μεθόδων, μπορούν επίσης να παραδοθούν τιμές σε properties. Υποστηρίζεται επίσης η προσθήκη ενός στοιχείου σε έναν πίνακα, το οποίο πρέπει να γραφτεί σε εισαγωγικά για να μην συγκρούεται με τη σύνταξη 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;
}
Στο setup, ωστόσο, μπορούν να κληθούν και στατικές μέθοδοι ή μέθοδοι
άλλων υπηρεσιών. Εάν χρειάζεται να παραδώσετε την τρέχουσα υπηρεσία ως
όρισμα, δηλώστε την ως @self
:
services:
foo:
create: Foo
setup:
- My\Helpers::initializeFoo(@self)
- @anotherService::setFoo(@self)
Σημειώστε ότι για λόγους απλότητας, αντί για ->
χρησιμοποιείται ::
, δείτε Εκφραστικά μέσα.
Θα δημιουργηθεί μια τέτοια μέθοδος factory:
public function createServiceFoo(): Foo
{
$service = new Foo;
My\Helpers::initializeFoo($service);
$this->getService('anotherService')->setFoo($service);
return $service;
}
Εκφραστικά μέσα
Το Nette DI μας δίνει εξαιρετικά πλούσια εκφραστικά μέσα, με τα οποία μπορούμε να γράψουμε σχεδόν οτιδήποτε. Στα αρχεία διαμόρφωσης μπορούμε έτσι να χρησιμοποιούμε παραμέτρους:
# παράμετρος
%wwwDir%
# τιμή παραμέτρου κάτω από κλειδί
%mailer.user%
# παράμετρος μέσα σε string
'%wwwDir%/images'
Επίσης, να δημιουργούμε αντικείμενα, να καλούμε μεθόδους και συναρτήσεις:
# δημιουργία αντικειμένου
DateTime()
# κλήση στατικής μεθόδου
Collator::create(%locale%)
# κλήση συνάρτησης PHP
::getenv(DB_USER)
Να αναφερόμαστε σε υπηρεσίες είτε με το όνομά τους είτε με τον τύπο τους:
# υπηρεσία βάσει ονόματος
@database
# υπηρεσία βάσει τύπου
@Nette\Database\Connection
Να χρησιμοποιούμε first-class callable syntax:
# δημιουργία callback, αντίστοιχο του [@user, logout]
@user::logout(...)
Να χρησιμοποιούμε σταθερές:
# σταθερά κλάσης
FilesystemIterator::SKIP_DOTS
# καθολική σταθερά λαμβάνεται με τη συνάρτηση PHP constant()
::constant(PHP_VERSION)
Οι κλήσεις μεθόδων μπορούν να αλυσιδωθούν όπως στην PHP. Απλώς για
λόγους απλότητας, αντί για ->
χρησιμοποιείται ::
:
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')
@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
Αυτές τις εκφράσεις μπορείτε να τις χρησιμοποιείτε οπουδήποτε, κατά τη δημιουργία υπηρεσιών, στα ορίσματα, στην ενότητα setup ή στις παραμέτρους:
parameters:
ipAddress: @http.request::getRemoteAddress()
services:
database:
create: DatabaseFactory::create( @anotherService::getDsn() )
setup:
- initialize( ::getenv('DB_USER') )
Ειδικές συναρτήσεις
Στα αρχεία διαμόρφωσης μπορείτε να χρησιμοποιείτε αυτές τις ειδικές συναρτήσεις:
not()
άρνηση της τιμήςbool()
,int()
,float()
,string()
μετατροπή τύπου χωρίς απώλειες στον καθορισμένο τύποtyped()
δημιουργεί έναν πίνακα όλων των υπηρεσιών του καθορισμένου τύπουtagged()
δημιουργεί έναν πίνακα όλων των υπηρεσιών με το δεδομένο tag
services:
- Foo(
id: int(::getenv('ProjectId'))
productionMode: not(%debugMode%)
)
Σε αντίθεση με την κλασική μετατροπή τύπου στην PHP, όπως π.χ.
(int)
, η μετατροπή τύπου χωρίς απώλειες θα προκαλέσει εξαίρεση για
μη αριθμητικές τιμές.
Η συνάρτηση typed()
δημιουργεί έναν πίνακα όλων των υπηρεσιών του
δεδομένου τύπου (κλάση ή interface). Παραλείπει τις υπηρεσίες που έχουν
απενεργοποιημένο το autowiring. Μπορούν να δηλωθούν και περισσότεροι τύποι
διαχωρισμένοι με κόμμα.
services:
- BarsDependent( typed(Bar) )
Μπορείτε επίσης να παραδώσετε αυτόματα έναν πίνακα υπηρεσιών ενός συγκεκριμένου τύπου ως όρισμα χρησιμοποιώντας autowiring.
Η συνάρτηση tagged()
στη συνέχεια δημιουργεί έναν πίνακα όλων των
υπηρεσιών με ένα συγκεκριμένο tag. Και εδώ μπορείτε να καθορίσετε
περισσότερα tags διαχωρισμένα με κόμμα.
services:
- LoggersDependent( tagged(logger) )
Autowiring
Το κλειδί autowired
επιτρέπει την επίδραση στη συμπεριφορά του
autowiring για μια συγκεκριμένη υπηρεσία. Για λεπτομέρειες, δείτε το κεφάλαιο για το autowiring.
services:
foo:
create: Foo
autowired: false # η υπηρεσία foo εξαιρείται από το autowiring
Lazy υπηρεσίες
Το Lazy loading είναι μια τεχνική που αναβάλλει τη δημιουργία μιας υπηρεσίας μέχρι τη στιγμή που πραγματικά χρειάζεται. Στην καθολική διαμόρφωση, μπορείτε να ενεργοποιήσετε την τεμπέλικη δημιουργία για όλες τις υπηρεσίες ταυτόχρονα. Για μεμονωμένες υπηρεσίες, μπορείτε στη συνέχεια να παρακάμψετε αυτή τη συμπεριφορά:
services:
foo:
create: Foo
lazy: false
Όταν μια υπηρεσία ορίζεται ως lazy, κατά την αίτησή της από το DI container, λαμβάνουμε ένα ειδικό αντικείμενο υποκατάστατο. Αυτό φαίνεται και συμπεριφέρεται το ίδιο με την πραγματική υπηρεσία, αλλά η πραγματική αρχικοποίηση (κλήση του κατασκευαστή και του setup) πραγματοποιείται μόνο κατά την πρώτη κλήση οποιασδήποτε μεθόδου ή property της.
Το Lazy loading μπορεί να χρησιμοποιηθεί μόνο για κλάσεις χρήστη, όχι για εσωτερικές κλάσεις PHP. Απαιτεί PHP 8.4 ή νεότερη έκδοση.
Tags
Τα tags χρησιμοποιούνται για την προσθήκη συμπληρωματικών πληροφοριών στις υπηρεσίες. Μπορείτε να προσθέσετε ένα ή περισσότερα tags σε μια υπηρεσία:
services:
foo:
create: Foo
tags:
- cached
Τα tags μπορούν επίσης να φέρουν τιμές:
services:
foo:
create: Foo
tags:
logger: monolog.logger.event
Για να λάβετε όλες τις υπηρεσίες με συγκεκριμένα tags, μπορείτε να
χρησιμοποιήσετε τη συνάρτηση tagged()
:
services:
- LoggersDependent( tagged(logger) )
Στο DI container, μπορείτε να λάβετε τα ονόματα όλων των υπηρεσιών με ένα
συγκεκριμένο tag χρησιμοποιώντας τη μέθοδο findByTag()
:
$names = $container->findByTag('logger');
// Το $names είναι ένας πίνακας που περιέχει το όνομα της υπηρεσίας και την τιμή του tag
// π.χ. ['foo' => 'monolog.logger.event', ...]
Λειτουργία Inject
Με τη χρήση της σημαίας inject: true
ενεργοποιείται η παράδοση
εξαρτήσεων μέσω δημόσιων μεταβλητών με την annotation inject και μεθόδων inject*().
services:
articles:
create: App\Model\Articles
inject: true
Στην προεπιλεγμένη ρύθμιση, το inject
ενεργοποιείται μόνο για
τους presenters.
Τροποποίηση υπηρεσιών
Το DI container περιέχει πολλές υπηρεσίες που έχουν προστεθεί μέσω
ενσωματωμένης ή επέκτασης χρήστη. Μπορείτε να
τροποποιήσετε τους ορισμούς αυτών των υπηρεσιών απευθείας στη
διαμόρφωση. Για παράδειγμα, μπορείτε να αλλάξετε την κλάση της
υπηρεσίας application.application
, η οποία είναι συνήθως
Nette\Application\Application
, σε άλλη:
services:
application.application:
create: MyApplication
alteration: true
Η σημαία alteration
είναι πληροφοριακή και λέει ότι απλώς
τροποποιούμε μια υπάρχουσα υπηρεσία.
Μπορούμε επίσης να συμπληρώσουμε το setup:
services:
application.application:
create: MyApplication
alteration: true
setup:
- '$onStartup[]' = [@resource, init]
Κατά την αντικατάσταση μιας υπηρεσίας, μπορεί να θέλουμε να
αφαιρέσουμε τα αρχικά ορίσματα, στοιχεία setup ή tags, για τα οποία
χρησιμοποιείται το reset
:
services:
application.application:
create: MyApplication
alteration: true
reset:
- arguments
- setup
- tags
Εάν θέλετε να αφαιρέσετε μια υπηρεσία που προστέθηκε από επέκταση, μπορείτε να το κάνετε ως εξής:
services:
cache.journal: false