ស្វែងយល់អំពី EventDispatcher Component នៅក្នុង Symfony3
EventDispatcher Component គឺជា component មួយក្នុងចំណោម components ជាច្រើនផ្សេងទៀតរបស់ Symfony។ EventDispatcher Component ផ្ដល់នូវ tools ដែលអនុញ្ញាតអោយ application component របស់អ្នកអាចធ្វើការទំនាក់ទំនងជាមួយនឹង component ដទៃទៀតបានដោយធ្វើការ បញ្ជូន events និងស្ដាប់បញ្ជារបស់ពួកគេ។
១) សេចក្ដីណែនាំអំពី EventDispatcher Component
Object-oriented កូដបានបោះបង់ចោលនូវវិធីដែលវែងឆ្ងាយក្នុងការធានានូវកូដដែលបានថែម ។ ដោយគ្រាន់តែធ្វើការបង្កើត classes ដែលមាននូវការកំណត់ទិសដៅច្បាស់លាស់ នោះកូដរបស់អ្នកនឹងក្លាយទៅជា កូដដែលមានលក្ខណៈបត់បែន ហើយ developer អាច extend class ជាមួយនឹង subclasses ដើម្បីធ្វើការកែប្រែលក្ខណៈរបស់គេ។ ប៉ុន្តែប្រសិនបើពួកគេត្រូវការ ចែករំលែកនូវការផ្លាស់ប្ដូរជាមួយនឹង developers ដទៃទៀតដែលបានបង្កើតនូវ subclasses ផ្ទាល់ខ្លួន នោះ កូដ inheritance នឹងបង្ហាញថាវាជាចម្លើយ។
សូមក្រលេកទៅមើលឧទាហរណ៏ពិតជាក់ស្ដែង កន្លែងដែលអ្នកចង់ផ្ដល់នូវ plugin system សម្រាប់ project របស់អ្នក។ Plugin គួរតែអាចបន្ថែមនូវ methods រឺក៏ធ្វើអ្វីផ្សេងមុនរឺបន្ទាប់ពី method ធ្វើការ execute ដោយមិនគិតពីការជ្រៀតជ្រែកនូវ plugin ផ្សេងៗ។ វាមិនមែនជាបញ្ហាដែលងាយស្រួលក្នុងការដោះស្រាយជាមួយនឹង single inheritance នោះទេ ហើយបើទោះបីជា inheritance ច្រើនយ៉ាងណាអាចទៅរួចជាមួយនឹង PHP គឺវាត្រូវបានមកជាមួយនឹង drawbacks របស់វាផ្ទាល់ដែរ។
Symfony EventDispatcher component ធ្វើការ implements នូវ Mediator pattern ក្នុងលក្ខណៈសាមញ្ញានិង ជាវិធីដែលមានប្រសិទ្ធភាពដើម្បីបង្កើតវត្ថុទាំងអស់នោះ អាចធ្វើការបាន និងដើម្បីធ្វើអោយ projects របស់អ្នកធ្វើការពង្រីកបានយ៉ាងត្រឹមត្រូវ។
សូមយកឧទាហរណ៏សាមញ្ញពី HttpKernel component ។ នៅពេលដែល Response object បានបង្កើតឡើង វាអាចនឹងមានប្រយោជន៏ក្នុងការអនុញ្ញាតអោយ elements ផ្សេងៗដែលមាននៅក្នុង system ដើម្បីធ្វើការកែប្រែវា (ដូចជា ការបន្ថែម cache headers) មុននឹងវាត្រូវបានគេយកមកប្រើមែន។ ដើម្បីធ្វើដូចនេះបាន Symfony kernel បោះនូវ event – kernel.response ។ នេះគឺជារបៀបធ្វើការរបស់វា៖
- Listener (PHP object) ប្រាប់ទៅ dispatcher object កណ្ដាលដែលវាចង់ធ្វើការ listen ទៅកាន់ response event
- ត្រង់ចំណុចមួយចំនួន Symfony kernel ប្រាប់ទៅ dispatcher object ដើម្បីបញ្ជូន (dispatch) response event , ធ្វើការ pass ជាមួយ Event object ដែលបាន access ទៅកាន់ Response object របស់វា
- Dispatcher notifies (ហៅ method) listeners នៃ response event ទាំងអស់, ធ្វើការអនុញ្ញាតអោយពួកគេនីមួយៗ ធ្វើការ កែប្រែទៅកាន់ Response object។
២) ការតម្លើង
មាន២របៀបដែលអ្នកអាចតម្លើង EventDispatcher Component បានគឺ៖
ទី១៖ តម្លើងតាមរយៈ Composer (symfony/event-dispatcher នៅលើ កញ្ចប់មួយនេះ)
ទី២៖ ប្រើ official Git repository (https://github.com/symfony/event-dispatcher)
បន្ទាប់ពីនេះ គឺវាទាមទារអោយមាននូវ vendor/autoload.php file ដើម្បីធ្វើការ enable នូវការធ្វើautoload mechanism ដែលបានផ្ដល់ដោយ Composer។ បើមិនដូច្នោះទេ application របស់អ្នកនឹងមិនអាចស្វែងរកឃើញនូវ classes នៃ Symfony component នេះបានទេ។
៣) ការប្រើប្រាស់
៣.ក) Events
ពេលដែល event បានធ្វើការបញ្ជូន គឺវាត្រូវបានកំណត់ដោយ unique name (ដូចជា kernel.response) ដែលតួលេខណាមួយនៃ listeners អាចនឹងប្រហែលជាកំពុង listen ទៅកាន់។ Event instace គឺក៏ត្រូវបានបង្កើតនិង pass ទៅកាន់ listeners ទាំងអស់ផងដែរ។ អ្នកនឹងបានឃើញនៅពេលក្រោយទៀត Event object គឺខ្លួនវាផ្ទាល់តែងតែមាននូវទិន្នន័យអំពី event ដែលនឹងកំពុង dispatch។
៣.ក.១) Naming Conventions
Unique event name អាចជា string ផ្សេងៗ ប៉ុន្តែ ជាទូទៅគឺតែងតែស្របទៅនឹង naming conventions សាមញ្ញាមួយចំនួនដូចជា៖
ទី១៖ ប្រើប្រាស់តែ អក្សរតូចៗ (lowercase letters) លេខ សញ្ញាចុច (.) និង underscores ( _ );
ទី២៖ ឈ្មោះបន្ថែមដើម ជាមួយនឹង namespace ដែលស្របតាម សញ្ញាចុចមួយ (ដូចជា order. , user.*)
ទី៣៖ បញ្ចប់ឈ្មោះជាមួយនឹង កិរិយាស័ព្ទដែលបង្ហាញថាតើសកម្មភាពណាដែលបានធ្វើ (ដូចជា order.placed)
៣.ក.២) Event Names និង Event Objects
ពេលដែល dispatcher ធ្វើការប្រាប់ទៅ listeners វា passes នូវ Event object ពិតប្រាកដទៅកាន់ listeners ទាំងនោះ។ base Event class គឺសាមញ្ញាណាស់ វាផ្ទុកនូវ method សម្រាប់បញ្ឈប់នូវ event propagation ប៉ុន្តែមិនមានច្រើនឡើយ។
ជាញឹកញាប់ ទិន្នន័យអំពី event ជាក់លាក់មួយដែលត្រូវការ pass រួមជាមួយនឹង Event object ដូចនេះ listeners នោះ ត្រូវការនូវព័ត៌មាន។ ក្នុងដំណាក់កាលនេះ subclass ពិសេសមួយដែលមាន methods សម្រាប់ទទួលយកនិង ធ្វើការ override នូវព័ត៌មានអាចនឹង pass ពេលដែលកំពុង dispatch នូវ event។ សម្រាប់ឧទាហរណ៏ kernel.response event ប្រើនូវ FilterResponseEvent ដែលផ្ទុកនូវ methods ដើម្បីទទួលនិង replace នូវ Response object។
៣.ខ) Dispatcher
Dispatcher គឺជា object ដែលនៅកណ្ដាលនៃ event dispatcher system។ ជាទូទៅ single dispatcher គឺបានបង្កើត ដែលរក្សានូវ បញ្ជីនៃ listeners។ ពេលដែល event បានបញ្ជូន តាមរយៈ dispatcher វាធ្វើការជូនដំណឹងទៅកាន់ listeners ដែលបានចុះឈ្មោះទាំងអស់ជាមួយនឹង event មួយនោះ៖
៣.គ) ការតភ្ជាប់ Listeners
ដើម្បីទទួលបានប្រយោជន៏នៃ event ដែលមាននោះ អ្នកត្រូវការភ្ជាប់ Listener ទៅកាន់ dispatcher ដូចនេះ វាអាចនឹងជូនដំណឹងពេលដែល event បានបញ្ជូន។ ដើម្បីហៅទៅ addListener() method នៃ dispatcher ដែលមានទំនាក់ទំនងទៅនឹង PHP callable ណាមួយទៅកាន់ event សូមមើលរូបភាពខាងក្រោម៖
addListener() method ត្រូវប្រើរហូតទៅដល់ ៣ arguments៖
Argument ទី១៖ ឈ្មោះ event (string) ដែល listener នេះចង់ listen ទៅកាន់
Argument ទី២៖ PHP callable ដែលនឹងត្រូវ execute ពេលដែល event ជាក់លាក់ណាមួយបាន dispatch
Argument ទី៣៖ integer ដែលមិនមានអាទិភាពខ្ពស់ ដែលកំណត់នៅពេលដែល listener គឺបង្ករឲ្យមានការប្រឆាំងទៅនឹង listeners ផ្សេងទៀត។ ប្រសិនបើ listeners ២ មានអាទិភាពដូចគ្នា ពួកគេគឺធ្វើការ execute ទៅតាមលំដាប់ដែលពួកគេបានបន្ថែមទៅក្នុង dispatcher។
នៅពេលដែល listener មួយបានចុះឈ្មោះជាមួយនឹង dispatcher វាត្រូវរង់ចាំរហូតដល់ event ធ្វើការជូនដំណឹងមកវិញ។ ក្នុងឧទាហរណ៏ខាងលើ ពេលដែល acme.foo.action event គឺបានបញ្ជូន ហើយ dispatcher ហៅ AcmeListener::onFooAction() method និង pass នូវ Event object ជា single argument៖
$event argument គឺជា event object ដែលបាន pass នៅពេលដែលធ្វើការបញ្ជូននូវ event ។ មានការងារជាច្រើន event subclass ពិសេសមួយ គឺបាន pass ជាមួយនឹងព័ត៌មានបន្ថែម។ អ្នកអាចពិនិត្យទៅលើឯកសាររឺក៏ implementation នៃ event នីមួយៗដើម្បីធ្វើការកំណត់ថាតើ instance ណាមួយដែលបាន pass ។
៣.ឃ) ការបង្កើត និង ការ dispatch Event
ដើម្បីចុះឈ្មោះ listeners ជាមួយនឹង events ដែលមានរួច អ្នកអាចបង្កើត និង dispatch events ផ្ទាល់របស់អ្នកបាន។ វាមានប្រយោជន៏ពេលដែលធ្វើការបង្កើត third-party library និងក៏ដូចជាពេលដែលអ្នកចង់រក្សានូវ components ផ្សេងៗពីគ្នានៃ system ដែលមានលក្ខណៈបត់បែនរបស់អ្នក។
- ការបង្កើត Event Class
ឧបមាថាអ្នកចង់បង្កើត event ថ្មីមួយ – order.placed – នោះគឺ បញ្ជូននៅរាល់ពេលដែលអតិថិជនធ្វើការកុម្មង់ផលិតផលជាមួយនឹង application របស់អ្នក។ ពេលដែលធ្វើការបញ្ជូន event នេះ អ្នកនឹងធ្វើការ pass នូវ custom event instance ដែលបាន access ដើម្បីដាក់ពីលើការកុម្មង់ (place order)។ ចាប់ផ្ដើមដោយការបង្កើត custom event class នេះនិងធ្វើឯកសារវា៖
Listener នីមួយៗនាពេលនេះបាន access ទៅកាន់ទីតាំងតាមរយៈ getOrder() method។
- Dispatch the Event
dispatch() method កំណត់ទៅលើ listeners ទាំងអស់នៃ events ដែលបានអោយ។ វាប្រើ arguments ចំនួន២ ដូចជា ឈ្មោះនៃ event ដែលនឹងបញ្ជូននិង Event instance ដើម្បី pass ទៅកាន់ listener នីមួយៗ នៃ event នោះ៖
ត្រូវចំណាំថា OrderPlacedEvent object ពិសេសនេះគឺបានបង្កើតនិង pass ទៅកាន់ dispatch() method។ ពេលនេះ listener រហូតដល់ order.placed event ផ្សេងទៀតនិងទទួលយកនូវ OrderPlacedEvent ។
៣.ង) ការប្រើប្រាស់ Event Subscribers
វិធីសាមញ្ញបំផុតដើម្បី listen ទៅកាន់ event គឺត្រូវចុះឈ្មោះនូវ event listener ជាមួយនឹង dispatcher។ listener នេះអាច listen ទៅកាន់ events មួយរឺច្រើនហើយវាគឺកំណត់រាល់ពេលដែល events ទាំងនោះបានបញ្ជូន។
វិធីផ្សេងទៀតដើម្បី listen ទៅកាន់ event គឺតាមរយៈ event subscriber ។ event subscriber គឺជា PHP class ដែលមានលទ្ធភាពប្រាប់ទៅ dispatcher យ៉ាងច្បាស់ថាតើ events ណាមួយដែលវាគួរតែ subscribe ។ វា implements នូវ EventSubscriberInterface interface ដែលទាមទារនូវ single static method ដែលហៅថា getSubscribedEvents()។ សូមមើលឧទាហរណ៏ខាងក្រោមនៃ subscriber ដែលធ្វើការ subscribes ទៅកាន់ kernel.response និង order.placed events៖
វាពិតជាស្រដៀងគ្នាទៅនឹង listener class លើកលែងតែ class របស់វាផ្ទាល់ដែលអាចប្រាប់ទៅ dispatcher ថា events មួយណាដែលវាគួរតែ listen ទៅកាន់។ ដើម្បីចុះឈ្មោះ subscriber ជាមួយនឹង dispatcher សូមប្រើ addSubcriber() method៖
Dispatcher នឹងចុះឈ្មោះ subscriber សម្រាប់ event នីមួយៗដែលបាន return ដោយ getSubscribedEvents() method ដោយស្វ័យប្រវត្តិ។ method នេះ returns នូវ array indexed ដោយ event names និង តម្លៃដែលមាន គឺជា method name ដើម្បីហៅ រឺ array composed នៃ method name ដើម្បីហៅ និងអាទិភាព។ ឧទាហរណ៏ខាងលើ បង្ហាញពីរបៀបនៃការចុះឈ្មោះ listener methods ច្រើនសម្រាប់ event ដែលដូចគ្នានៅក្នុង subscriber ហើយក៏បង្ហាញពីរបៀប pass នូវអាទិភាពនៃ listener method នីមួយៗ។ អាទិភាពដែលខ្ពស់ជាងគេ កាលពីដំបូងត្រូវបាន method ហៅ។ ក្នុងឧទាហរណ៏ខាងក្រោម ពេលដែល kernel.response event ជាអ្នកបានបង្ករឡើងនូវ methods onKernelResponsePre() និង onKernelResponsePost() គឺបានហៅក្នុងលំដាប់នោះ។
៣.ច) ការបញ្ឈប់ Event Flow/Propagation
ដំណាក់កាលខ្លះ វាប្រហែលជាធ្វើអោយមានការភ្ញាក់ផ្អើលសម្រាប់ listener ដើម្បីបង្ការនូវ listeners ផ្សេងៗពីការដែលកំពុងហៅ។ ក្នុងន័យផ្សេង listener ត្រូវការមានសិទ្ធដើម្បីប្រាប់ទៅ dispatcher ដើម្បីបញ្ឈប់នូវ ការផ្សព្វផ្សាយទាំងអស់នៃ event ដើម្បី listeners នាថ្ងៃខាងមុខ។ ដូចនេះវាអាចនឹងសម្រេចពីខាងក្នុងនៃ listener តាមរយៈ stopPropagation() method៖
ពេលនេះ listeners ផ្សេងៗរហូតដល់ order.placed ដែលមិនទាន់មានការហៅអាចនឹងមិនត្រូវបានហៅ។
វាអាចទៅរួចដើម្បីរកឃើញប្រសិនបើ event បានបញ្ឈប់ដោយការប្រើប្រាស់ isPropagationStopped() method ដែល return នូវតម្លៃជា boolean៖
៣.ឆ) EventDispatcher Aware Events និង Listeners
EventDispatcher តែងតែ pass នូវ dispatched event ហើយឈ្មោះរបស់ event និង reference ទៅកាន់វាផ្ទាល់ដើម្បី listeners។ នេះគឺអាចនាំអោយមាន applications នៃ EventDispatcher កម្រិតខ្លាំងដែលកំពុងបញ្ចូលនូវការ dispatch នូវ events ផ្សេងទៀតខាងក្នុង Listeners ។
៣.ជ) Dispatcher Shortcuts
ប្រសិនបើអ្នកមិនត្រូវការ custom event object អ្នកអាចពឹងផ្អែកទៅលើ Event object ធម្មតាមួយ។ អ្នកមិនចាំបាច់ pass វាទៅ dispatcher ដូចដែលវានឹងបង្កើតមួយជា default លុះត្រាណាតែអ្នក pass ជាពិសេសមួយ៖
លើសពីនេះ event dispatcher គឺតែងតែ return event object ណាដែលបាន dispatch។ នេះគឺអនុញ្ញាតសម្រាប់ nice shortcuts៖
រឺក៏៖
និងមានច្រើនទៀត។
៣.ឈ) Event Name Introspection
EventDispatcher instance ដូចទៅនឹងឈ្មោះនៃ event ដែល dispatch នោះ គឺបាន pass ជា arguments ទៅកាន់ listener៖
៤) Dispatchers ផ្សេងៗ
ក្រៅពី EventDispatcher ប្រើជាទូទៅហើយ component មកជាមួយនឹង dispatchers មួយចំនួនផ្សេងទៀត៖
The Container Aware Event Dispatcher
The Immutable Event Dispatcher
The Traceable Event Dispatcher (ដែលផ្ដល់ដោយ the HttpKernel component)