diff --git a/models/BaseEntity.cfc b/models/BaseEntity.cfc index a3f7a943..96d100d1 100644 --- a/models/BaseEntity.cfc +++ b/models/BaseEntity.cfc @@ -76,6 +76,11 @@ component accessors="true" { */ property name="_queryOptions" persistent="false"; + /** + * A map of lifecycle event names to custom interception points. + */ + property name="_dispatchesEvents" persistent="false"; + /** * Boolean flag to prevent inserts and updates on the entity. */ @@ -277,6 +282,7 @@ component accessors="true" { param variables._discriminators = []; param variables._loadChildren = true; param variables._queryOptions = {}; + param variables._dispatchesEvents = {}; param variables._attributes = {}; param variables._columns = {}; param variables._virtualAttributes = []; @@ -3343,19 +3349,32 @@ component accessors="true" { { eventData : arguments.eventData } ); } - if ( !isNull( variables._interceptorService ) ) { - param variables.useAnnounceMethodForInterceptorService = structKeyExists( - variables._interceptorService, - "announce" - ); - if ( variables.useAnnounceMethodForInterceptorService ) { - variables._interceptorService.announce( "quick" & arguments.eventName, arguments.eventData ); - } else { - variables._interceptorService.processState( "quick" & arguments.eventName, arguments.eventData ); + announceInterceptionPoint( "quick" & arguments.eventName, arguments.eventData ); + if ( variables._dispatchesEvents.keyExists( arguments.eventName ) ) { + for ( var interceptionPoint in arrayWrap( variables._dispatchesEvents[ arguments.eventName ] ) ) { + announceInterceptionPoint( interceptionPoint, arguments.eventData ); } } } + /** + * Announces an interception point using the configured interceptor service. + * + * @interceptionPoint The interception point to announce. + * @eventData The data associated with the interception point. + */ + private void function announceInterceptionPoint( required string interceptionPoint, required struct eventData ) { + if ( isNull( variables._interceptorService ) ) { + return; + } + param variables.useAnnounceMethodForInterceptorService = structKeyExists( variables._interceptorService, "announce" ); + if ( variables.useAnnounceMethodForInterceptorService ) { + variables._interceptorService.announce( arguments.interceptionPoint, arguments.eventData ); + } else { + variables._interceptorService.processState( arguments.interceptionPoint, arguments.eventData ); + } + } + /** * Returns true if the event method exists on the entity. * diff --git a/tests/resources/app/models/Song.cfc b/tests/resources/app/models/Song.cfc index cdab6483..a19c584d 100644 --- a/tests/resources/app/models/Song.cfc +++ b/tests/resources/app/models/Song.cfc @@ -6,6 +6,11 @@ component extends="quick.models.BaseEntity" accessors="true" { property name="createdDate" column="created_date"; property name="modifiedDate" column="modified_date"; + variables._dispatchesEvents = { + "postInsert" : "onSongCreated", + "postSave" : [ "onSongSaved", "onMediaSaved" ] + }; + function instanceReady( eventData ) { request.instanceReadyCalled = eventData; } diff --git a/tests/specs/integration/BaseEntity/Events/CustomEventsSpec.cfc b/tests/specs/integration/BaseEntity/Events/CustomEventsSpec.cfc new file mode 100644 index 00000000..8674af3c --- /dev/null +++ b/tests/specs/integration/BaseEntity/Events/CustomEventsSpec.cfc @@ -0,0 +1,60 @@ +component extends="tests.resources.ModuleIntegrationSpec" { + + function beforeAll() { + super.beforeAll(); + controller + .getInterceptorService() + .registerInterceptor( + interceptorObject = this, + interceptorName = "CustomEventsSpec", + customPoints = [ + "onSongCreated", + "onSongSaved", + "onMediaSaved" + ] + ); + } + + function afterAll() { + controller.getInterceptorService().unregister( "CustomEventsSpec" ); + super.afterAll(); + } + + function run() { + describe( "custom entity events", function() { + beforeEach( function() { + variables.customEvents = []; + } ); + + it( "dispatches string and array interception points for lifecycle events", function() { + var song = getInstance( "Song" ).create( { + title : "Rainbow Connection", + download_url : "https://open.spotify.com/track/1SJ4ycWow4yz6z4oFz8NAG" + } ); + + expect( variables.customEvents ).toBe( [ + "onSongCreated", + "onSongSaved", + "onMediaSaved" + ] ); + expect( variables.customEventEntity.getId() ).toBe( song.getId() ); + } ); + } ); + } + + function onSongCreated( event, interceptData ) { + variables.customEvents.append( "onSongCreated" ); + variables.customEventEntity = arguments.interceptData.entity; + } + + function onSongSaved( event, interceptData ) { + variables.customEvents.append( "onSongSaved" ); + variables.customEventEntity = arguments.interceptData.entity; + } + + function onMediaSaved( event, interceptData ) { + variables.customEvents.append( "onMediaSaved" ); + variables.customEventEntity = arguments.interceptData.entity; + } + +}