portaldacalheta.pt
  • Κύριος
  • Σχεδιασμός Για Κινητά
  • Ευκίνητο Ταλέντο
  • Τεχνολογία
  • Διεπαφή Ιστού
Πίσω Μέρος

Έγχυση πραγματικής εξάρτησης με στοιχεία Symfony



Το Symfony2, ένα υψηλής απόδοσης πλαίσιο PHP, χρησιμοποιεί μοτίβο Dependency Injection Container όπου τα εξαρτήματα παρέχουν διεπαφή εξάρτησης εξάρτησης για το δοχείο DI. Αυτό επιτρέπει σε κάθε στοιχείο να μην νοιάζεται για άλλες εξαρτήσεις. Η κατηγορία «Πυρήνας» αρχικοποιεί το δοχείο DI και το εγχέει σε διαφορετικά εξαρτήματα. Αυτό όμως σημαίνει ότι το DI-container μπορεί να χρησιμοποιηθεί ως Service Locator.

Το Symfony2 έχει ακόμη και την κατηγορία «ContainerAware» για αυτό. Πολλοί πιστεύουν ότι το Service Locator είναι ένα αντι-μοτίβο στο Symfony2. Προσωπικά, δεν συμφωνώ. Είναι ένα απλούστερο μοτίβο σε σύγκριση με το DI και είναι καλό για απλά έργα. Αλλά το μοτίβο Service Locator και το μοτίβο DI-container που συνδυάζονται σε ένα έργο είναι σίγουρα ένα αντίτυπο.



Έγχυση πραγματικής εξάρτησης με στοιχεία Symfony



Σε αυτό το άρθρο θα προσπαθήσουμε να δημιουργήσουμε μια εφαρμογή Symfony2 χωρίς να εφαρμόσουμε το μοτίβο Service Locator. Θα ακολουθήσουμε έναν απλό κανόνα: μόνο ο κατασκευαστής DI-container μπορεί να γνωρίζει για το DI-container.



Δοχείο DI

Στο σχέδιο Dependency Injection, το DI-container καθορίζει τις εξαρτήσεις υπηρεσίας και οι υπηρεσίες μπορούν να δώσουν μόνο μια διεπαφή για ένεση. Υπάρχουν πολλά άρθρα για Ενεση εξάρτησης , και μάλλον έχετε διαβάσει όλα αυτά. Ας μην επικεντρωθούμε στη θεωρία και απλώς ρίξτε μια ματιά στη βασική ιδέα. Το DI μπορεί να είναι 3 τύπων:



Στο Symfony, η δομή έγχυσης μπορεί να οριστεί χρησιμοποιώντας απλά αρχεία διαμόρφωσης. Δείτε πώς μπορούν να διαμορφωθούν αυτοί οι 3 τύποι ένεσης:

services: my_service: class: MyClass constructor_injection_service: class: SomeClass1 arguments: ['@my_service'] method_injection_service: class: SomeClass2 calls: - [ setProperty, '@my_service' ] property_injection_service: class: SomeClass3 properties: property: '@my_service'

Έργο Bootstrapping

Ας δημιουργήσουμε τη βασική μας δομή εφαρμογών. Ενώ είμαστε σε αυτό, θα εγκαταστήσουμε το στοιχείο Symfony DI-container.



$ mkdir trueDI $ cd trueDI $ composer init $ composer require symfony/dependency-injection $ composer require symfony/config $ composer require symfony/yaml $ mkdir config $ mkdir www $ mkdir src

Για να κάνουμε το autoloader του συνθέτη να βρει τα δικά μας μαθήματα στον φάκελο src, μπορούμε να προσθέσουμε την ιδιότητα 'autoloader' στο αρχείο composer.json:

{ // ... 'autoload': { 'psr-4': { '': 'src/' } } }

Ας δημιουργήσουμε το εργαλείο δημιουργίας κοντέινερ και απαγορεύστε τις ενέσεις κοντέινερ.



// in src/TrueContainer.php use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentConfigFileLocator; use SymfonyComponentDependencyInjectionLoaderYamlFileLoader; use SymfonyComponentDependencyInjectionContainerInterface; class TrueContainer extends ContainerBuilder { public static function buildContainer($rootPath) { $container = new self(); $container->setParameter('app_root', $rootPath); $loader = new YamlFileLoader( $container, new FileLocator($rootPath . '/config') ); $loader->load('services.yml'); $container->compile(); return $container; } public function get( $id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE ) { if (strtolower($id) == 'service_container') { if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior ) { return; } throw new InvalidArgumentException( 'The service definition 'service_container' does not exist.' ); } return parent::get($id, $invalidBehavior); } }

Εδώ χρησιμοποιούμε τα στοιχεία Config και Yaml symfony. Μπορείτε να βρείτε λεπτομέρειες στην επίσημη τεκμηρίωση εδώ . Επίσης, ορίσαμε την παράμετρο root path «app_root» για κάθε περίπτωση. Η μέθοδος get υπερφορτώνει την προεπιλεγμένη συμπεριφορά λήψης της μητρικής κλάσης και εμποδίζει το κοντέινερ να επιστρέψει το 'service_container'.

Στη συνέχεια, χρειαζόμαστε ένα σημείο εισόδου για την εφαρμογή.



// in www/index.php require_once('../vendor/autoload.php'); $container = TrueContainer::buildContainer(dirname(__DIR__));

Αυτό προορίζεται για τον χειρισμό αιτημάτων http. Μπορούμε να έχουμε περισσότερα σημεία εισόδου για εντολές κονσόλας, εργασίες cron και πολλά άλλα. Κάθε σημείο εισόδου υποτίθεται ότι λαμβάνει συγκεκριμένες υπηρεσίες και πρέπει να γνωρίζει για τη δομή DI-container. Αυτό είναι το μόνο μέρος όπου μπορούμε να ζητήσουμε υπηρεσίες από το κοντέινερ. Από αυτήν τη στιγμή θα προσπαθήσουμε να δημιουργήσουμε αυτήν την εφαρμογή χρησιμοποιώντας μόνο αρχεία διαμόρφωσης κοντέινερ DI.

HttpKernel

Το HttpKernel (όχι ο πυρήνας πλαισίου με το πρόβλημα εντοπισμού υπηρεσίας) θα είναι το βασικό μας στοιχείο για το τμήμα ιστού της εφαρμογής. Ακολουθεί μια τυπική ροή εργασίας HttpKernel:



Τα πράσινα τετράγωνα είναι γεγονότα.

Το HttpKernel χρησιμοποιεί το στοιχείο HttpFoundation για αντικείμενα αιτήματος και απόκρισης και το στοιχείο EventDispatcher για το σύστημα συμβάντων. Δεν υπάρχουν προβλήματα κατά την προετοιμασία τους με αρχεία διαμόρφωσης κοντέινερ DI. Το HttpKernel πρέπει να αρχικοποιηθεί με το EventDispatcher, το ControllerResolver και προαιρετικά με υπηρεσίες RequestStack (για δευτερεύοντα αιτήματα).

Εδώ είναι η διαμόρφωση κοντέινερ για αυτό:

# in config/events.yml services: dispatcher: class: SymfonyComponentEventDispatcherEventDispatcher # in config/kernel.yml services: request: class: SymfonyComponentHttpFoundationRequest factory: [ SymfonyComponentHttpFoundationRequest, createFromGlobals ] request_stack: class: SymfonyComponentHttpFoundationRequestStack resolver: class: SymfonyComponentHttpKernelControllerControllerResolver http_kernel: class: SymfonyComponentHttpKernelHttpKernel arguments: ['@dispatcher', '@resolver', '@request_stack'] #in config/services.yml imports: - { resource: 'events.yml' } - { resource: 'kernel.yml' }

Όπως μπορείτε να δείτε, χρησιμοποιούμε την ιδιότητα «εργοστάσιο» για να δημιουργήσουμε την υπηρεσία αιτήματος. Η υπηρεσία HttpKernel λαμβάνει μόνο αντικείμενο Request και επιστρέφει αντικείμενο Response. Μπορεί να γίνει στον μπροστινό ελεγκτή.

// in www/index.php require_once('../vendor/autoload.php'); $container = TrueContainer::buildContainer(dirname(__DIR__)); $HTTPKernel = $container->get('http_kernel'); $request = $container->get('request'); $response = $HTTPKernel->handle($request); $response->send();

Εναλλακτικά, η απόκριση μπορεί να οριστεί ως υπηρεσία στο config χρησιμοποιώντας την ιδιότητα 'factory'.

πώς να σχεδιάσετε για κινητά
# in config/kernel.yml # ... response: class: SymfonyComponentHttpFoundationResponse factory: [ '@http_kernel', handle] arguments: ['@request']

Και μετά το παίρνουμε στον μπροστινό ελεγκτή.

// in www/index.php require_once('../vendor/autoload.php'); $container = TrueContainer::buildContainer(dirname(__DIR__)); $response = $container->get('response'); $response->send();

Η υπηρεσία επίλυσης ελεγκτή λαμβάνει την ιδιότητα «_controller» από τα χαρακτηριστικά της υπηρεσίας Αίτημα για επίλυση του ελεγκτή. Αυτά τα χαρακτηριστικά μπορούν να οριστούν στο config κοντέινερ, αλλά φαίνεται λίγο πιο δύσκολο επειδή πρέπει να χρησιμοποιήσουμε ένα αντικείμενο ParameterBag αντί για έναν απλό πίνακα.

# in config/kernel.yml # ... request_attributes: class: SymfonyComponentHttpFoundationParameterBag calls: - [ set, [ _controller, AppControllerDefaultController::defaultAction ]] request: class: SymfonyComponentHttpFoundationRequest factory: [ SymfonyComponentHttpFoundationRequest, createFromGlobals ] properties: attributes: '@request_attributes' # ...

Και εδώ είναι η κλάση DefaultController με τη μέθοδο defaultAction.

// in src/App/Controller/DefaultController.php namespace AppController; use SymfonyComponentHttpFoundationResponse; class DefaultController { function defaultAction() { return new Response('Hello cruel world'); } }

Με όλα αυτά στη θέση τους, θα πρέπει να έχουμε μια εφαρμογή εργασίας.

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

# in config/controllers.yml services: controller.default: class: AppControllerDefaultController arguments: [ '@request'] # in config/kernel.yml # ... request_attributes: class: SymfonyComponentHttpFoundationParameterBag calls: - [ set, [ _controller, ['@controller.default', defaultAction ]]] request: class: SymfonyComponentHttpFoundationRequest factory: [ SymfonyComponentHttpFoundationRequest, createFromGlobals ] properties: attributes: '@request_attributes' # ... #in config/services.yml imports: - { resource: 'events.yml' } - { resource: 'kernel.yml' } - { resource: 'controllers.yml' }

Και ο κωδικός ελεγκτή:

// in src/App/Controller/DefaultController.php namespace AppController; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; class DefaultController { /** @var Request */ protected $request; function __construct(Request $request) { $this->request = $request; } function defaultAction() { $name = $this->request->get('name'); return new Response('Hello $name'); } }

Τώρα ο ελεγκτής έχει πρόσβαση στην υπηρεσία αιτήσεων. Όπως μπορείτε να δείτε, αυτό το σχήμα έχει κυκλικές εξαρτήσεις. Λειτουργεί επειδή το DI-container μοιράζεται την υπηρεσία μετά τη δημιουργία και πριν από τη μέθοδο και την εισαγωγή ιδιοτήτων. Έτσι, όταν δημιουργείται η υπηρεσία ελεγκτή, η υπηρεσία αιτήσεων υπάρχει ήδη.

Ετσι δουλευει:

πώς να αναπτύξετε μια γλώσσα προγραμματισμού

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

Υπάρχει όμως ένα άλλο πρόβλημα. Το DI-container θα προετοιμάσει κάθε ελεγκτή με εξαρτήσεις. Έτσι θα προετοιμάσει όλες τις υπάρχουσες υπηρεσίες, ακόμη και αν δεν είναι απαραίτητες. Ευτυχώς, το κοντέινερ έχει τεμπέλη λειτουργικότητα φόρτωσης. Το στοιχείο Symfony DI χρησιμοποιεί το 'ocramius / proxy-manager' για τάξεις μεσολάβησης. Πρέπει να εγκαταστήσουμε μια γέφυρα μεταξύ τους.

$ composer require symfony/proxy-manager-bridge

Και ορίστε το στο στάδιο κατασκευής εμπορευματοκιβωτίων:

// in src/TrueContainer.php //... use SymfonyBridgeProxyManagerLazyProxyInstantiatorRuntimeInstantiator; // ... $container = new self(); $container->setProxyInstantiator(new RuntimeInstantiator()); // ...

Τώρα μπορούμε να ορίσουμε τεμπέλης υπηρεσίες.

# in config/controllers.yml services: controller.default: lazy: true class: AppControllerDefaultController arguments: [ '@request' ]

Έτσι, οι ελεγκτές θα προκαλέσουν αρχικοποίηση εξαρτημένων υπηρεσιών μόνο όταν καλείται μια πραγματική μέθοδος. Επίσης, αποφεύγει το σφάλμα κυκλικής εξάρτησης επειδή μια υπηρεσία ελεγκτή θα κοινοποιηθεί πριν από την πραγματική εκκίνηση. αν και πρέπει να αποφύγουμε κυκλικές αναφορές. Σε αυτήν την περίπτωση δεν πρέπει να εισάγουμε την υπηρεσία ελεγκτή στην υπηρεσία αιτήματος ή στην υπηρεσία αιτήματος στην υπηρεσία ελεγκτή. Προφανώς, χρειαζόμαστε μια υπηρεσία αιτήματος στους ελεγκτές, οπότε ας αποφύγουμε την ένεση στην υπηρεσία αιτήσεων στο στάδιο έναρξης του κοντέινερ. Το HttpKernel διαθέτει σύστημα εκδηλώσεων για το σκοπό αυτό.

Δρομολόγηση

Προφανώς θέλουμε να έχουμε διαφορετικούς ελεγκτές για διαφορετικά αιτήματα. Χρειαζόμαστε λοιπόν ένα σύστημα δρομολόγησης. Ας εγκαταστήσουμε το στοιχείο δρομολόγησης symfony.

$ composer require symfony/routing

Το στοιχείο δρομολόγησης έχει δρομολογητή κλάσης που μπορεί να χρησιμοποιήσει αρχεία διαμόρφωσης δρομολόγησης. Αλλά αυτές οι διαμορφώσεις είναι απλώς παράμετροι κλειδιού-τιμής για την κλάση Route. Το Symfony framework χρησιμοποιεί το δικό του πρόγραμμα ανάλυσης ελεγκτή από το FrameworkBundle που εισάγει κοντέινερ σε ελεγκτές με τη διεπαφή «ContainerAware». Αυτό ακριβώς προσπαθούμε να αποφύγουμε. Το HttpKernel controller resolver επιστρέφει αντικείμενο κλάσης σαν να υπάρχει ήδη στο χαρακτηριστικό '_controller' ως πίνακας με αντικείμενο ελεγκτή και συμβολοσειρά μεθόδου δράσης (στην πραγματικότητα, ο ελεγκτής ελεγκτή θα το επιστρέψει σαν να είναι απλά ένας πίνακας). Πρέπει λοιπόν να ορίσουμε κάθε διαδρομή ως υπηρεσία και να εισάγουμε έναν ελεγκτή σε αυτήν. Ας προσθέσουμε κάποια άλλη υπηρεσία ελεγκτή για να δούμε πώς λειτουργεί.

# in config/controllers.yml # ... controller.page: lazy: true class: AppControllerPageController arguments: [ '@request'] // in src/App/Controller/PageController.php namespace AppController; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; class PageController { /** @var Request */ protected $request; function __construct(Request $request) { $this->request = $request; } function defaultAction($id) { return new Response('Page $id doesn’t exist'); } }

Το στοιχείο HttpKernel έχει την κλάση RouteListener που χρησιμοποιεί το συμβάν «kernel.request». Ακολουθεί μια πιθανή διαμόρφωση με τεμπέλης ελεγκτές:

# in config/routes/default.yml services: route.home: class: SymfonyComponentRoutingRoute arguments: path: / defaults: _controller: ['@controller.default', 'defaultAction'] route.page: class: SymfonyComponentRoutingRoute arguments: path: /page/{id} defaults: _controller: ['@controller.page', 'defaultAction'] # in config/routing.yml imports: - { resource: ’routes/default.yml' } services: route.collection: class: SymfonyComponentRoutingRouteCollection calls: - [ add, ['route_home', '@route.home'] ] - [ add, ['route_page', '@route.page'] ] router.request_context: class: SymfonyComponentRoutingRequestContext calls: - [ fromRequest, ['@request'] ] router.matcher: class: SymfonyComponentRoutingMatcherUrlMatcher arguments: [ '@route.collection', '@router.request_context' ] router.listener: class: SymfonyComponentHttpKernelEventListenerRouterListener arguments: matcher: '@router.matcher' request_stack: '@request_stack' context: '@router.request_context' # in config/events.yml service: dispatcher: class: SymfonyComponentEventDispatcherEventDispatcher calls: - [ addSubscriber, ['@router.listener']] #in config/services.yml imports: - { resource: 'events.yml' } - { resource: 'kernel.yml' } - { resource: 'controllers.yml' } - { resource: 'routing.yml' }

Επίσης, χρειαζόμαστε μια γεννήτρια διευθύνσεων URL στην εφαρμογή μας. Εδώ είναι:

# in config/routing.yml # ... router.generator: class: SymfonyComponentRoutingGeneratorUrlGenerator arguments: routes: '@route.collection' context: '@router.request_context'

Η γεννήτρια διευθύνσεων URL μπορεί να εισαχθεί σε ελεγκτές και υπηρεσίες απόδοσης. Τώρα έχουμε μια βασική εφαρμογή. Οποιαδήποτε άλλη υπηρεσία μπορεί να οριστεί με τον ίδιο τρόπο που το αρχείο διαμόρφωσης εισάγεται σε ορισμένους ελεγκτές ή διεκπεραιωτές συμβάντων. Για παράδειγμα, ακολουθούν ορισμένες διαμορφώσεις για το Twig και το Doctrine.

Κλαδάκι

Το Twig είναι η προεπιλεγμένη μηχανή προτύπου στο πλαίσιο Symfony2. Πολλά στοιχεία του Symfony2 μπορούν να το χρησιμοποιήσουν χωρίς προσαρμογείς. Είναι λοιπόν μια προφανής επιλογή για την εφαρμογή μας.

$ composer require twig/twig $ mkdir src/App/View # in config/twig.yml services: templating.twig_loader: class: Twig_Loader_Filesystem arguments: [ '%app_root%/src/App/View' ] templating.twig: class: Twig_Environment arguments: [ '@templating.twig_loader' ]

Δόγμα

Το δόγμα είναι ένα ORM που χρησιμοποιείται στο πλαίσιο του Symfony2. Μπορούμε να χρησιμοποιήσουμε οποιοδήποτε άλλο ORM, αλλά τα στοιχεία του Symfony2 μπορούν ήδη να χρησιμοποιούν πολλές δυνατότητες Docrine.

$ composer require doctrine/orm $ mkdir src/App/Entity # in config/doctrine.yml parameters: doctrine.driver: 'pdo_pgsql' doctrine.user: 'postgres' doctrine.password: 'postgres' doctrine.dbname: 'true_di' doctrine.paths: ['%app_root%/src/App/Entity'] doctrine.is_dev: true services: doctrine.config: class: DoctrineORMConfiguration factory: [ DoctrineORMToolsSetup, createAnnotationMetadataConfiguration ] arguments: paths: '%doctrine.paths%' isDevMode: '%doctrine.is_dev%' doctrine.entity_manager: class: DoctrineORMEntityManager factory: [ DoctrineORMEntityManager, create ] arguments: conn: driver: '%doctrine.driver%' user: '%doctrine.user%' password: '%doctrine.password%' dbname: '%doctrine.dbname%' config: '@doctrine.config' #in config/services.yml imports: - { resource: 'events.yml' } - { resource: 'kernel.yml' } - { resource: 'controllers.yml' } - { resource: 'routing.yml' } - { resource: 'twig.yml' } - { resource: 'doctrine.yml' }

Μπορούμε επίσης να χρησιμοποιήσουμε αρχεία διαμόρφωσης χαρτογράφησης YML και XML αντί για σχολιασμούς. Απλώς πρέπει να χρησιμοποιήσουμε τις μεθόδους «createYAMLMetadataConfiguration» και ‘createXMLMetadataConfiguration’ και να ορίσουμε διαδρομή σε ένα φάκελο με αυτά τα αρχεία ρυθμίσεων.

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

# in config/controllers.yml services: controller.base_web: lazy: true abstract: true class: AppControllerBaseWebController arguments: request: '@request' templating: '@templating.twig' entityManager: '@doctrine.entity_manager' urlGenerator: '@router.generator' controller.default: class: AppControllerDefaultController parent: controller.base_web controller.page: class: AppControllerPageController parent: controller.base_web // in src/App/Controller/Base/WebController.php namespace AppControllerBase; use SymfonyComponentHttpFoundationRequest; use Twig_Environment; use DoctrineORMEntityManager; use SymfonyComponentRoutingGeneratorUrlGenerator; abstract class WebController { /** @var Request */ protected $request; /** @var Twig_Environment */ protected $templating; /** @var EntityManager */ protected $entityManager; /** @var UrlGenerator */ protected $urlGenerator; function __construct( Request $request, Twig_Environment $templating, EntityManager $entityManager, UrlGenerator $urlGenerator ) { $this->request = $request; $this->templating = $templating; $this->entityManager = $entityManager; $this->urlGenerator = $urlGenerator; } } // in src/App/Controller/DefaultController // … class DefaultController extend WebController { // ... } // in src/App/Controller/PageController // … class PageController extend WebController { // ... }

Υπάρχουν πολλά άλλα χρήσιμα στοιχεία της Symfony, όπως Form, Command και Assets. Αναπτύχθηκαν ως ανεξάρτητα συστατικά, οπότε η ενσωμάτωσή τους χρησιμοποιώντας το DI-container δεν πρέπει να αποτελεί πρόβλημα.

Ετικέτες

Το DI-container διαθέτει επίσης σύστημα ετικετών. Η επεξεργασία των ετικετών γίνεται από τάξεις Compiler Pass. Το στοιχείο Event Dispatcher έχει το δικό του Compiler Pass για να απλοποιήσει τη συνδρομή ακροατή συμβάντων, αλλά χρησιμοποιεί την κατηγορία ContainerAwareEventDispatcher αντί για την κατηγορία EventDispatcher. Έτσι δεν μπορούμε να το χρησιμοποιήσουμε. Αλλά μπορούμε να εφαρμόσουμε τις δικές μας κάρτες μεταγλωττιστών για εκδηλώσεις, διαδρομές, ασφάλεια και για οποιονδήποτε άλλο σκοπό.

Για παράδειγμα, ας εφαρμόσουμε ετικέτες για το σύστημα δρομολόγησης. Τώρα για να καθορίσουμε μια διαδρομή πρέπει να καθορίσουμε μια υπηρεσία διαδρομής σε ένα αρχείο config διαδρομής στο φάκελο config / Routes και στη συνέχεια να την προσθέσουμε στην υπηρεσία συλλογής διαδρομών στο αρχείο config / routing.yml. Φαίνεται ασυνεπές επειδή ορίζουμε παραμέτρους δρομολογητή σε ένα μέρος και ένα όνομα δρομολογητή σε άλλο.

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

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

// in src/CompilerPass/RouterTagCompilerPass.php namespace CompilerPass; use SymfonyComponentDependencyInjectionCompilerCompilerPassInterface; use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentDependencyInjectionDefinition; use SymfonyComponentDependencyInjectionReference; class RouterTagCompilerPass implements CompilerPassInterface { /** * You can modify the container here before it is dumped to PHP code. * * @param ContainerBuilder $container */ public function process(ContainerBuilder $container) { $routeTags = $container->findTaggedServiceIds('route'); $collectionTags = $container->findTaggedServiceIds('route_collection'); /** @var Definition[] $routeCollections */ $routeCollections = array(); foreach ($collectionTags as $serviceName => $tagData) $routeCollections[] = $container->getDefinition($serviceName); foreach ($routeTags as $routeServiceName => $tagData) { $routeNames = array(); foreach ($tagData as $tag) if (isset($tag['route_name'])) $routeNames[] = $tag['route_name']; if (!$routeNames) continue; $routeReference = new Reference($routeServiceName); foreach ($routeCollections as $collection) foreach ($routeNames as $name) $collection->addMethodCall('add', array($name, $routeReference)); } } } // in src/TrueContainer.php //... use CompilerPassRouterTagCompilerPass; // ... $container = new self(); $container->addCompilerPass(new RouterTagCompilerPass()); // ...

Τώρα μπορούμε να τροποποιήσουμε τη διαμόρφωσή μας:

# in config/routing.yml # … route.collection: class: SymfonyComponentRoutingRouteCollection tags: - { name: route_collection } # ... # in config/routes/default.yml services: route.home: class: SymfonyComponentRoutingRoute arguments: path: / defaults: _controller: ['@controller.default', 'defaultAction'] tags: - { name: route, route_name: 'route_home' } route.page: class: SymfonyComponentRoutingRoute arguments: path: /page/{id} defaults: _controller: ['@controller.page', 'defaultAction'] tags: - { name: route, route_name: 'route_page' }

Όπως μπορείτε να δείτε, λαμβάνουμε συλλογές διαδρομών με το όνομα της ετικέτας αντί για το όνομα υπηρεσίας, οπότε το σύστημα ετικετών διαδρομής δεν εξαρτάται από την πραγματική διαμόρφωση. Επίσης, οι διαδρομές μπορούν να προστεθούν σε οποιαδήποτε υπηρεσία συλλογής με μια μέθοδο «προσθήκης». Οι περαστικοί μεταγλωττιστές μπορούν να απλοποιήσουν σημαντικά τις διαμορφώσεις εξαρτήσεων. Αλλά μπορούν να προσθέσουν μια απροσδόκητη συμπεριφορά στο κοντέινερ DI, οπότε είναι καλύτερο να μην τροποποιήσετε την υπάρχουσα λογική, όπως αλλαγή ορισμάτων, κλήσεις μεθόδου ή ονόματα τάξεων. Απλώς προσθέστε ένα νέο που υπήρχε όπως κάναμε χρησιμοποιώντας ετικέτες.

Τύλιξε

Τώρα έχουμε μια εφαρμογή που χρησιμοποιεί μόνο μοτίβο κοντέινερ DI και είναι κατασκευασμένη χρησιμοποιώντας μόνο αρχεία διαμόρφωσης κοντέινερ DI. Όπως μπορείτε να δείτε, δεν υπάρχουν σοβαρές προκλήσεις δημιουργία μιας εφαρμογής Symfony με αυτόν τον τρόπο. Και μπορείτε απλώς να απεικονίσετε όλες τις εξαρτήσεις της εφαρμογής σας. Ο μόνος λόγος για τον οποίο οι άνθρωποι χρησιμοποιούν το DI-container ως εντοπιστής υπηρεσιών είναι ότι η έννοια του εντοπισμού υπηρεσιών είναι πιο κατανοητή. Και μια τεράστια βάση κώδικα με το DI-container που χρησιμοποιείται ως εντοπιστής σέρβις είναι πιθανώς συνέπεια αυτού του λόγου.

Μπορείτε να βρείτε τον πηγαίο κώδικα αυτής της εφαρμογής στο GitHub .

Safe and Sound - Πώς να προσεγγίσετε τον κωδικό πρόσβασης UX

Σχεδιασμός Ux

Safe and Sound - Πώς να προσεγγίσετε τον κωδικό πρόσβασης UX
DevOps: Τι είναι και γιατί έχει σημασία

DevOps: Τι είναι και γιατί έχει σημασία

Καινοτομία

Δημοφιλείς Αναρτήσεις
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Top 10 UX Παραδοτέα Χρήση κορυφαίων σχεδιαστών
Top 10 UX Παραδοτέα Χρήση κορυφαίων σχεδιαστών
Evolving Emoji: Σχεδιασμός για το νέο πρόσωπο των μηνυμάτων
Evolving Emoji: Σχεδιασμός για το νέο πρόσωπο των μηνυμάτων
Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας
Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας
Τεχνικές έρευνας UX και οι εφαρμογές τους
Τεχνικές έρευνας UX και οι εφαρμογές τους
 
Power Pivot for Excel Tutorial: Κορυφαίες περιπτώσεις και παραδείγματα χρήσης
Power Pivot for Excel Tutorial: Κορυφαίες περιπτώσεις και παραδείγματα χρήσης
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Εργασία με React Hooks και TypeScript
Εργασία με React Hooks και TypeScript
Κοιτάζοντας το μέλλον - Τάσεις σχεδιασμού του 2020
Κοιτάζοντας το μέλλον - Τάσεις σχεδιασμού του 2020
Ας επανασχεδιάσουμε το Facebook: 10 παραδείγματα για να εμπνεύσετε και να σας βοηθήσουμε να ξεκινήσετε
Ας επανασχεδιάσουμε το Facebook: 10 παραδείγματα για να εμπνεύσετε και να σας βοηθήσουμε να ξεκινήσετε
Δημοφιλείς Αναρτήσεις
  • τι είναι ένα οικογενειακό γραφείο για τη διαχείριση περιουσίας
  • πώς να συλλέξετε δεδομένα από το twitter
  • πώς να σπουδάσετε για την πιστοποίηση aws
  • διαφορά μεταξύ τέχνης και σχεδίου
  • γλώσσα προγραμματισμού c++
  • χακαρισμένοι αριθμοί πιστωτικών καρτών με cvv και ταχυδρομικό κώδικα 2017
Κατηγορίες
  • Σχεδιασμός Για Κινητά
  • Ευκίνητο Ταλέντο
  • Τεχνολογία
  • Διεπαφή Ιστού
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt