PageSourceSearch

https://docs.phpvms.net/assets/js/1ecd346d.a5f28145.js

js phpvms.net collected 2026-10-04 13:24:12 UTC 10,653 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkphpvms_docs=self.webpackChunkphpvms_docs||[]).push([[2403],{79094(e,n,s){s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>o});const t=JSON.parse('{"id":"developers/addons/events","title":"Events & Listeners","description":"phpvms dispatches a number of events you can subscribe to from your module \u2014","source":"@site/docs/developers/addons/events.md","sourceDirName":"developers/addons","slug":"/developers/addons/events","permalink":"/8.x/developers/addons/events","draft":false,"unlisted":false,"editUrl":"https://github.com/phpvms/docs/tree/master/docs/developers/addons/events.md","tags":[],"version":"current","frontMatter":{"id":"events","title":"Events & Listeners"},"sidebar":"docs","previous":{"title":"Templating & Assets","permalink":"/8.x/developers/addons/templating"},"next":{"title":"Patterns & Conventions","permalink":"/8.x/developers/addons/patterns"}}');var r=s(74848),d=s(28453);const i={id:"events",title:"Events & Listeners"},l=void 0,c={},o=[{value:"Listening to phpvms events",id:"listening-to-phpvms-events",level:2},{value:"1. Generate a listener",id:"1-generate-a-listener",level:3},{value:"2. Implement handle()",id:"2-implement-handle",level:3},{value:"3. Register the listener",id:"3-register-the-listener",level:3},{value:"Dispatching your own events",id:"dispatching-your-own-events",level:2},{value:"Listening to module lifecycle events",id:"listening-to-module-lifecycle-events",level:2},{value:"Dependency injection",id:"dependency-injection",level:2}];function a(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,d.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:["phpvms dispatches a number of events you can subscribe to from your module \u2014\nwhen a PIREP is filed, a flight is bid on, a user registers, and so on. The full\nlist of available events lives in the core\n",(0,r.jsx)(n.a,{href:"https://github.com/nabeelio/phpvms/tree/master/app/Events",children:"app/Events"}),"\ndirectory."]}),"\n",(0,r.jsxs)(n.p,{children:["Subscribing follows the standard\n",(0,r.jsx)(n.a,{href:"https://laravel.com/docs/events",children:"Laravel events"})," pattern."]}),"\n",(0,r.jsx)(n.h2,{id:"listening-to-phpvms-events",children:"Listening to phpvms events"}),"\n",(0,r.jsx)(n.h3,{id:"1-generate-a-listener",children:"1. Generate a listener"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-shell",children:"php artisan module:make-listener PirepAcceptedListener Sample --event=PirepAccepted\n# \u2192 Modules/Sample/app/Listeners/PirepAcceptedListener.php\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Pass ",(0,r.jsx)(n.code,{children:"--queued"})," if you want the listener to run on a queue rather than\nsynchronously:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-shell",children:"php artisan module:make-listener PirepAcceptedListener Sample \\\n    --event=PirepAccepted --queued\n"})}),"\n",(0,r.jsx)(n.h3,{id:"2-implement-handle",children:"2. Implement handle()"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"namespace Modules\\Sample\\Listeners;\n\nuse App\\Events\\PirepAccepted;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass PirepAcceptedListener\n{\n    public function handle(PirepAccepted $event): void\n    {\n        Log::info('Received PIREP', [$event->pirep]);\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The argument passed to ",(0,r.jsx)(n.code,{children:"handle()"})," is the event class itself \u2014 open the event\nunder ",(0,r.jsx)(n.code,{children:"app/Events"})," to see what data is exposed (e.g. ",(0,r.jsx)(n.code,{children:"$event->pirep"}),",\n",(0,r.jsx)(n.code,{children:"$event->user"}),")."]}),"\n",(0,r.jsx)(n.h3,{id:"3-register-the-listener",children:"3. Register the listener"}),"\n",(0,r.jsxs)(n.p,{children:["Register it in the module's ",(0,r.jsx)(n.code,{children:"EventServiceProvider"}),". If you don't have one yet,\ngenerate it:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-shell",children:"php artisan module:make-event-provider EventServiceProvider Sample\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Then add your listeners to the ",(0,r.jsx)(n.code,{children:"$listen"})," array:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"namespace Modules\\Sample\\Providers;\n\nuse App\\Events\\PirepAccepted;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Modules\\Sample\\Listeners\\PirepAcceptedListener;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    protected $listen = [\n        PirepAccepted::class => [\n            PirepAcceptedListener::class,\n        ],\n    ];\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"Finally, register the new provider from your module's main service provider:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"// Modules/Sample/app/Providers/SampleServiceProvider.php\n\npublic function register(): void\n{\n    $this->app->register(RouteServiceProvider::class);\n    $this->app->register(EventServiceProvider::class);\n}\n"})}),"\n",(0,r.jsx)(n.h2,{id:"dispatching-your-own-events",children:"Dispatching your own events"}),"\n",(0,r.jsx)(n.p,{children:"Modules can dispatch their own events too \u2014 useful when other addons (or the\noperator's customisations) might want to react to something that happens inside\nyour module."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-shell",children:"php artisan module:make-event PostWasPublished Sample\n# \u2192 Modules/Sample/app/Events/PostWasPublished.php\n\nphp artisan module:make-listener NotifyAdminListener Sample --event=PostWasPublished\n"})}
1),"\n",(0,r.jsx)(n.p,{children:"Then dispatch from anywhere \u2014 controllers, services, observers:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"use Modules\\Sample\\Events\\PostWasPublished;\n\nPostWasPublished::dispatch($post);\n// or\nevent(new PostWasPublished($post));\n"})}),"\n",(0,r.jsx)(n.h2,{id:"listening-to-module-lifecycle-events",children:"Listening to module lifecycle events"}),"\n",(0,r.jsx)(n.p,{children:"The module system itself dispatches events when modules are enabled, disabled,\ncreated, or destroyed. You can hook into them to run setup, teardown, or\nnotification logic."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"use Nwidart\\Modules\\Events\\ModuleEvent;\n\nprotected $listen = [\n    ModuleEvent::ENABLED => [\n        \\Modules\\Sample\\Listeners\\OnModuleEnabled::class,\n    ],\n    ModuleEvent::DISABLING => [\n        \\Modules\\Sample\\Listeners\\OnModuleDisabling::class,\n    ],\n];\n"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Constant"}),(0,r.jsx)(n.th,{children:"When it fires"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"BOOT"})}),(0,r.jsx)(n.td,{children:"Each module finishes booting on every request."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"REGISTER"})}),(0,r.jsx)(n.td,{children:"Each module is registered."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ENABLING"})}),(0,r.jsx)(n.td,{children:"Just before a module is enabled."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ENABLED"})}),(0,r.jsx)(n.td,{children:"After a module is enabled."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DISABLING"})}),(0,r.jsx)(n.td,{children:"Just before a module is disabled."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DISABLED"})}),(0,r.jsx)(n.td,{children:"After a module is disabled."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CREATING"})}),(0,r.jsxs)(n.td,{children:["Before a module is created via ",(0,r.jsx)(n.code,{children:"module:make"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CREATED"})}),(0,r.jsxs)(n.td,{children:["After ",(0,r.jsx)(n.code,{children:"module:make"})," completes."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DELETING"})}),(0,r.jsxs)(n.td,{children:["Before ",(0,r.jsx)(n.code,{children:"module:delete"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DELETED"})}),(0,r.jsxs)(n.td,{children:["After ",(0,r.jsx)(n.code,{children:"module:delete"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"USED"})}),(0,r.jsxs)(n.td,{children:["A module is selected with ",(0,r.jsx)(n.code,{children:"module:use"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"UNUSED"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"module:unuse"}),"."]})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"dependency-injection",children:"Dependency injection"}),"\n",(0,r.jsx)(n.p,{children:"Listeners are resolved out of the Laravel container, so any constructor\ndependencies (services, core models, clients) are auto-injected:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-php",children:"namespace Modules\\Sample\\Listeners;\n\nuse App\\Events\\PirepAccepted;\nuse App\\Services\\PirepService;\n\nclass PirepAcceptedListener\n{\n    public function __construct(\n        private PirepService $pirepSvc,\n    ) {}\n\n    public function handle(PirepAccepted $event): void\n    {\n        // $this->pirepSvc is ready to use\n    }\n}\n"})}),"\n",(0,r.jsxs)(n.p,{children:["See\n",(0,r.jsx)(n.a,{href:"/8.x/developers/addons/patterns#dependency-injection",children:"Patterns & Conventions \u2192 Dependency injection"}),"\nfor the recommended constructor-injection style."]})]})}function h(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},28453(e,n,s){s.d(n,{R:()=>i,x:()=>l});var t=s(96540);const r={},d=t.createContext(r);function i(e){const n=t.useContext(d);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),t.createElement(d.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.