portaldacalheta.pt
  • หลัก
  • การจัดการวิศวกรรม
  • บุคลากรและทีมงานของผลิตภัณฑ์
  • อื่น ๆ
  • นวัตกรรม
แบ็คเอนด์

True Dependency Injection ด้วยส่วนประกอบของ Symfony



Symfony2 ซึ่งเป็นเฟรมเวิร์ก PHP ที่มีประสิทธิภาพสูงใช้รูปแบบ Dependency Injection Container ที่ส่วนประกอบต่างๆจัดเตรียมอินเทอร์เฟซการฉีดแบบพึ่งพาสำหรับ DI-container สิ่งนี้ช่วยให้แต่ละองค์ประกอบไม่สนใจการอ้างอิงอื่น ๆ คลาส 'Kernel' เริ่มต้น DI-container และฉีดเข้าไปในส่วนประกอบต่างๆ แต่หมายความว่า DI-container สามารถใช้เป็น Service Locator ได้

Symfony2 ยังมีคลาส 'ContainerAware' ด้วย หลายคนมีความเห็นว่า Service Locator เป็นการต่อต้านรูปแบบใน Symfony2 ส่วนตัวไม่เห็นด้วย เป็นรูปแบบที่ง่ายกว่าเมื่อเทียบกับ DI และเหมาะสำหรับโครงการที่เรียบง่าย แต่รูปแบบ Service Locator และรูปแบบ DI-container ที่รวมกันในโครงการเดียวนั้นเป็นรูปแบบที่ต่อต้านอย่างแน่นอน



True Dependency Injection ด้วยส่วนประกอบของ Symfony



ในบทความนี้เราจะพยายามสร้างแอปพลิเคชัน Symfony2 โดยไม่ต้องใช้รูปแบบ Service Locator เราจะปฏิบัติตามกฎง่ายๆข้อเดียว: มีเพียงผู้สร้างคอนเทนเนอร์ DI เท่านั้นที่สามารถรู้เกี่ยวกับ 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

ในการทำให้ตัวโหลดอัตโนมัติของนักแต่งเพลงค้นหาคลาสของเราเองในโฟลเดอร์ 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 และส่วนประกอบ symfony Yaml คุณสามารถดูรายละเอียดได้ในเอกสารอย่างเป็นทางการ ที่นี่ . นอกจากนี้เรายังกำหนดพารามิเตอร์รูทพา ธ 'app_root' ในกรณี เมธอด get จะโอเวอร์โหลดพฤติกรรมรับดีฟอลต์ของคลาสพาเรนต์และป้องกันไม่ให้คอนเทนเนอร์ส่งคืน“ service_container”

ต่อไปเราต้องการจุดเริ่มต้นสำหรับแอปพลิเคชัน



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

อันนี้มีไว้เพื่อจัดการกับคำขอ http เราสามารถมีจุดเริ่มต้นสำหรับคำสั่งคอนโซลงาน cron และอื่น ๆ อีกมากมาย แต่ละจุดเข้าควรได้รับบริการบางอย่างและควรรู้เกี่ยวกับโครงสร้าง DI-container นี่เป็นที่เดียวที่เราสามารถขอรับบริการจากตู้คอนเทนเนอร์ได้ จากช่วงเวลานี้เราจะพยายามสร้างแอปพลิเคชันนี้โดยใช้ไฟล์คอนฟิกูเรชัน DI-container เท่านั้น

HttpKernel

HttpKernel (ไม่ใช่เคอร์เนลเฟรมเวิร์กที่มีปัญหาตัวระบุตำแหน่งบริการ) จะเป็นส่วนประกอบพื้นฐานของเราสำหรับ web part ของแอปพลิเคชัน นี่คือเวิร์กโฟลว์ HttpKernel ทั่วไป:



สี่เหลี่ยมสีเขียวคือเหตุการณ์

HttpKernel ใช้คอมโพเนนต์ HttpFoundation สำหรับอ็อบเจ็กต์ Request and Response และคอมโพเนนต์ EventDispatcher สำหรับระบบเหตุการณ์ ไม่มีปัญหาในการเตรียมใช้งานไฟล์คอนฟิกูเรชัน DI-container 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 และส่งคืนอ็อบเจ็กต์การตอบสนอง สามารถทำได้ในตัวควบคุมด้านหน้า

// 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();

หรือการตอบกลับสามารถกำหนดเป็นบริการในการกำหนดค่าโดยใช้คุณสมบัติ 'factory'

c++ จะเริ่มต้นที่ไหน
# 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' จากแอตทริบิวต์ของบริการ Request เพื่อแก้ไขคอนโทรลเลอร์ แอตทริบิวต์เหล่านี้สามารถกำหนดได้ใน container 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-container ในคอนโทรลเลอร์และใช้เป็นตัวระบุตำแหน่งบริการ เราจะไม่ทำอย่างนั้น ดังนั้นเรามากำหนดตัวควบคุมเป็นบริการและฉีดบริการคำขอเข้าไป นี่คือการกำหนดค่า:

# 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-component ใช้ '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 มีระบบเหตุการณ์สำหรับวัตถุประสงค์นี้

การกำหนดเส้นทาง

เห็นได้ชัดว่าเราต้องการมีตัวควบคุมที่แตกต่างกันสำหรับคำขอที่แตกต่างกัน ดังนั้นเราจึงต้องการระบบเส้นทาง มาติดตั้งส่วนประกอบการกำหนดเส้นทางสัญลักษณ์กัน

$ composer require symfony/routing

ส่วนประกอบการกำหนดเส้นทางมีคลาสเราเตอร์ซึ่งสามารถใช้ไฟล์คอนฟิกูเรชันการกำหนดเส้นทาง แต่การกำหนดค่าเหล่านี้เป็นเพียงพารามิเตอร์คีย์ - ค่าสำหรับคลาสเส้นทาง เฟรมเวิร์ก Symfony ใช้ตัวแก้ไขคอนโทรลเลอร์ของตัวเองจาก FrameworkBundle ซึ่งฉีดคอนเทนเนอร์ในคอนโทรลเลอร์ด้วยอินเทอร์เฟซ 'ContainerAware' นี่คือสิ่งที่เราพยายามหลีกเลี่ยง ตัวแก้ไขตัวควบคุม HttpKernel จะส่งคืนอ็อบเจ็กต์คลาสเหมือนกับที่มีอยู่แล้วในแอตทริบิวต์ '_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' ]

หลักคำสอน

Doctrine เป็น 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 ที่เป็นประโยชน์อื่น ๆ อีกมากมายเช่นฟอร์มคำสั่งและสินทรัพย์ พวกเขาได้รับการพัฒนาเป็นส่วนประกอบอิสระดังนั้นการรวมโดยใช้ DI-container จึงไม่น่าจะมีปัญหา

แท็ก

DI-container ยังมีระบบแท็ก แท็กสามารถประมวลผลโดยคลาส Compiler Pass คอมโพเนนต์ Event Dispatcher มี Compiler Pass ของตัวเองเพื่อลดความซับซ้อนของการสมัครสมาชิก event listener แต่ใช้คลาส ContainerAwareEventDispatcher แทนคลาส EventDispatcher เราจึงใช้ไม่ได้ แต่เราสามารถใช้คอมไพเลอร์พาสของเราเองสำหรับเหตุการณ์เส้นทางการรักษาความปลอดภัยและวัตถุประสงค์อื่น ๆ

ตัวอย่างเช่นเรามาติดตั้งแท็กสำหรับระบบเส้นทาง ตอนนี้ในการกำหนดเส้นทางเราต้องกำหนดบริการเส้นทางในไฟล์กำหนดเส้นทางในโฟลเดอร์ config / route จากนั้นเพิ่มไปยังบริการรวบรวมเส้นทางในไฟล์ 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-container ได้ดังนั้นจึงเป็นการดีกว่าที่จะไม่แก้ไขตรรกะที่มีอยู่เช่นการเปลี่ยนอาร์กิวเมนต์การเรียกใช้เมธอดหรือชื่อคลาส เพียงเพิ่มอันใหม่ที่มีอยู่เหมือนเดิมโดยใช้แท็ก

สรุป

ตอนนี้เรามีแอปพลิเคชันที่ใช้เฉพาะรูปแบบคอนเทนเนอร์ DI และสร้างขึ้นโดยใช้ไฟล์คอนฟิกูเรชัน DI-container เท่านั้น อย่างที่คุณเห็นไม่มีความท้าทายที่ร้ายแรงใน การสร้างแอปพลิเคชัน Symfony ทางนี้. และคุณสามารถเห็นภาพการอ้างอิงแอปพลิเคชันทั้งหมดของคุณ เหตุผลเดียวที่ผู้คนใช้ DI-container เป็นตัวระบุตำแหน่งบริการคือแนวคิดเกี่ยวกับตัวระบุตำแหน่งบริการนั้นเข้าใจง่ายกว่า และฐานรหัสขนาดใหญ่ที่มีคอนเทนเนอร์ DI ที่ใช้เป็นตัวระบุตำแหน่งบริการอาจเป็นผลมาจากเหตุผลนั้น

คุณสามารถค้นหาซอร์สโค้ดของแอปพลิเคชันนี้ บน GitHub .

ข้อมูลเบื้องต้นเกี่ยวกับการเทรดแบบ Deep Learning ในกองทุนป้องกันความเสี่ยง

แบ็คเอนด์

ข้อมูลเบื้องต้นเกี่ยวกับการเทรดแบบ Deep Learning ในกองทุนป้องกันความเสี่ยง
Embracing Sass: ทำไมคุณควรหยุดใช้ Vanilla CSS

Embracing Sass: ทำไมคุณควรหยุดใช้ Vanilla CSS

เทคโนโลยี

โพสต์ยอดนิยม
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
วิธีออกแบบประสบการณ์ที่ยอดเยี่ยมสำหรับอินเทอร์เน็ตในทุกสิ่ง
วิธีออกแบบประสบการณ์ที่ยอดเยี่ยมสำหรับอินเทอร์เน็ตในทุกสิ่ง
กลยุทธ์การสื่อสารที่มีประสิทธิภาพสำหรับนักออกแบบ
กลยุทธ์การสื่อสารที่มีประสิทธิภาพสำหรับนักออกแบบ
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
แนวโน้มต่อไปนี้: การแสดงความเคารพกับการลอกเลียนแบบการออกแบบ
แนวโน้มต่อไปนี้: การแสดงความเคารพกับการลอกเลียนแบบการออกแบบ
 
คู่มือสไตล์ Sass: บทช่วยสอน Sass เกี่ยวกับวิธีการเขียนโค้ด CSS ที่ดีขึ้น
คู่มือสไตล์ Sass: บทช่วยสอน Sass เกี่ยวกับวิธีการเขียนโค้ด CSS ที่ดีขึ้น
ทำลายกระบวนการคิดเชิงออกแบบ
ทำลายกระบวนการคิดเชิงออกแบบ
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
ทำคณิตศาสตร์: การปรับขนาดแอปพลิเคชันไมโครเซอร์วิสด้วย Orchestrators
ทำคณิตศาสตร์: การปรับขนาดแอปพลิเคชันไมโครเซอร์วิสด้วย Orchestrators
การปฏิวัติหุ่นยนต์เชิงพาณิชย์ที่กำลังจะเกิดขึ้น
การปฏิวัติหุ่นยนต์เชิงพาณิชย์ที่กำลังจะเกิดขึ้น
โพสต์ยอดนิยม
  • วิธีใช้ rest api ใน javascript
  • วิธีเล่นไฟล์ m3u8 บน Android
  • ตัว s กับ ตัว c
  • สร้างราสเบอร์รี่ pi ตั้งแต่เริ่มต้น
  • iot และเทคโนโลยีสมาร์ทโฮม
  • ที่จะเรียนรู้การเขียนโปรแกรม C
หมวดหมู่
  • การจัดการวิศวกรรม
  • บุคลากรและทีมงานของผลิตภัณฑ์
  • อื่น ๆ
  • นวัตกรรม
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt