Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new handler metadata property cacheIncludeRcKeys #503

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions system/cache/util/EventURLFacade.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,22 @@ component accessors="true" {

/**
* Build a unique hash from an incoming request context
* Note: the 'event' key is always ignored from the request collection
*
* @event A request context object
* @cacheIncludeRcKeys A list of keys to include ( '*'=all keys )
*/
string function getUniqueHash( required event ){
string function getUniqueHash( required event, string cacheIncludeRcKeys = "*" ){
var rcTarget = arguments.event
.getCollection()
.filter( function( key, value ){
// Remove event, not needed for hashing purposes
return ( key != "event" );
return (
key != "event" && // Remove event, not needed for hashing purposes
(
cacheIncludeRcKeys == "*" || // include all keys if *
listFindNoCase( cacheIncludeRcKeys, key ) // or if the key is specified
)
);
} );

// systemOutput( "=====> uniquehash-rcTarget: #variables.jTreeMap.init( rcTarget ).toString()#", true );
Expand Down Expand Up @@ -108,9 +115,13 @@ component accessors="true" {
string function buildEventKey(
required keySuffix,
required targetEvent,
required targetContext
required targetContext,
string cacheIncludeRcKeys = "*"
){
return buildBasicCacheKey( argumentCollection = arguments ) & getUniqueHash( arguments.targetContext );
return buildBasicCacheKey( argumentCollection = arguments ) & getUniqueHash(
arguments.targetContext,
arguments.cacheIncludeRcKeys
);
}

/**
Expand Down
26 changes: 16 additions & 10 deletions system/web/services/HandlerService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,10 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {

// Create the Cache Key to save
eventCachingData.cacheKey = oEventURLFacade.buildEventKey(
keySuffix = eventDictionaryEntry.suffix,
targetEvent = arguments.ehBean.getFullEvent(),
targetContext = oRequestContext
keySuffix = eventDictionaryEntry.suffix,
targetEvent = arguments.ehBean.getFullEvent(),
targetContext = oRequestContext,
cacheIncludeRcKeys = eventDictionaryEntry.cacheIncludeRcKeys
);

// Event is cacheable and we need to flag it so the Renderer caches it
Expand Down Expand Up @@ -629,12 +630,13 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
*/
private struct function getNewMDEntry(){
return {
"cacheable" : false,
"timeout" : "",
"lastAccessTimeout" : "",
"cacheKey" : "",
"suffix" : "",
"provider" : "template"
"cacheable" : false,
"timeout" : "",
"lastAccessTimeout" : "",
"cacheKey" : "",
"suffix" : "",
"provider" : "template",
"cacheIncludeRcKeys" : "*"
};
}

Expand Down Expand Up @@ -668,7 +670,11 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
"cacheLastAccessTimeout",
""
);
mdEntry.provider = arguments.ehBean.getActionMetadata( "cacheProvider", "template" );
mdEntry.provider = arguments.ehBean.getActionMetadata( "cacheProvider", "template" );
mdEntry.cacheIncludeRcKeys = arguments.ehBean.getActionMetadata(
"cacheIncludeRcKeys",
"*"
);

// Handler Event Cache Key Suffix, this is global to the event
if (
Expand Down
7 changes: 4 additions & 3 deletions system/web/services/RequestService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ component extends="coldbox.system.web.services.BaseService" {
eventCache.append( eventDictionary, true );
// Build the event cache key according to incoming request
eventCache[ "cacheKey" ] = oEventURLFacade.buildEventKey(
keySuffix = eventDictionary.suffix,
targetEvent = currentEvent,
targetContext = arguments.context
keySuffix = eventDictionary.suffix,
targetEvent = currentEvent,
targetContext = arguments.context,
cacheIncludeRcKeys = eventDictionary.cacheIncludeRcKeys
);

// Check for Event Cache Purge
Expand Down
69 changes: 69 additions & 0 deletions test-harness/handlers/eventcaching.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,75 @@
return prc.data;
}

// cacheIncludeRcKeys (all keys)
function withIncludeAllRcKeys( event, rc, prc )
cache ="true"
cacheTimeout ="10"
cacheIncludeRcKeys="*"
{

prc.data = [
{ id : createUUID(), name : "luis" },
{ id : createUUID(), name : "lucas" },
{ id : createUUID(), name : "fernando" }
];

return prc.data;
}

// cacheIncludeRcKeys (no keys)
function withIncludeNoRcKeys( event, rc, prc )
cache ="true"
cacheTimeout ="10"
cacheIncludeRcKeys=""
{

prc.data = [
{ id : createUUID(), name : "luis" },
{ id : createUUID(), name : "lucas" },
{ id : createUUID(), name : "fernando" }
];

return prc.data;
}

// cacheIncludeRcKeys (1 RC key)
function withIncludeOneRcKey( event, rc, prc )
cache ="true"
cacheTimeout ="10"
cacheIncludeRcKeys="slug"
{

param rc.slug = "";

prc.data = [
{ id : createUUID(), name : "luis" },
{ id : createUUID(), name : "lucas" },
{ id : createUUID(), name : "fernando" }
];

return prc.data;
}

// cacheIncludeRcKeys (RC 2 keys)
function withIncludeRcKeyList( event, rc, prc )
cache ="true"
cacheTimeout ="10"
cacheIncludeRcKeys="slug,id"
{

param rc.slug = "";
param rc.id = "";

prc.data = [
{ id : createUUID(), name : "luis" },
{ id : createUUID(), name : "lucas" },
{ id : createUUID(), name : "fernando" }
];

return prc.data;
}

function cacheKeys( event, rc, prc ){
var keys = {
"template" : getCache( "template" ).getKeys(),
Expand Down
4 changes: 2 additions & 2 deletions tests/specs/cache/providers/CacheBoxProviderTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@
var results = cache.getMulti( "test,test2" );
// debug(results);

expect( isNull( results.test ) ).toBeFalse();
expect( isNull( results.test2 ) ).toBeTrue();
expect( isNull( results.test ) ).toBeFalse();
expect( isNull( results.test2 ) ).toBeTrue();
}

function testgetCachedObjectMetadata(){
Expand Down
135 changes: 134 additions & 1 deletion tests/specs/integration/EventCaching.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

expect( prc.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "provider" );
expect( prc.cbox_eventCacheableEntry.provider ).toBe( "template" );
// debug( prc.cbox_eventCacheableEntry );
debug( prc.cbox_eventCacheableEntry );
} );


Expand All @@ -31,6 +31,139 @@
expect( prc.cbox_eventCacheableEntry.provider ).toBe( "default" );
} );

it( "can handle different RC collections", function(){
// execute an event and specify a queryString variable
var event1 = execute(
event = "eventcaching",
renderResults = true,
queryString = "id=1"
);
var prc1 = event1.getPrivateCollection();

expect( prc1.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc1.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "*" );

// reset to simulate another request with a different rc scope
setup();

var event2 = execute(
event = "eventcaching",
renderResults = true,
queryString = "id=2"
);

var prc2 = event2.getPrivateCollection();

expect( prc2.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc2.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "*" );

// because the default cache considers the rc scope, the cache keys should be different
expect( prc1.cbox_eventCacheableEntry.cacheKey ).notToBe( prc2.cbox_eventCacheableEntry.cacheKey );
} );

it( "can handle the cacheIncludeRcKeys metadata", function(){
// execute an event and specify a queryString variable
var event1 = execute(
event = "eventcaching.withIncludeAllRcKeys",
renderResults = true,
queryString = "id=1"
);
var prc1 = event1.getPrivateCollection();

expect( prc1.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc1.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "*" );
} );

it( "can ignore the rc scope", function(){
// execute an event and specify a queryString variable
var event1 = execute(
event = "eventcaching.withIncludeNoRcKeys",
renderResults = true,
queryString = "id=1"
);
var prc1 = event1.getPrivateCollection();

expect( prc1.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc1.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "" );

// reset to simulate another request
setup();

var event2 = execute(
event = "eventcaching.withIncludeNoRcKeys",
renderResults = true,
queryString = "id=2"
);

var prc2 = event2.getPrivateCollection();

expect( prc2.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc2.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "" );

// because we ignore the RC, the cache key should match
expect( prc1.cbox_eventCacheableEntry.cacheKey ).toBe( prc2.cbox_eventCacheableEntry.cacheKey );
} );

it( "can isolate specific RC scope keys and ignore the rest", function(){
// execute an event and specify a queryString variable
var event1 = execute(
event = "eventcaching.withIncludeOneRcKey",
renderResults = true,
queryString = "id=1&slug=foo"
);
var prc1 = event1.getPrivateCollection();

expect( prc1.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc1.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "slug" );

// reset to simulate another request
setup();

var event2 = execute(
event = "eventcaching.withIncludeOneRcKey",
renderResults = true,
queryString = "id=2&slug=foo"
);

var prc2 = event2.getPrivateCollection();

expect( prc2.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc2.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "slug" );

// because we ignore the RC, the cache key should match
expect( prc1.cbox_eventCacheableEntry.cacheKey ).toBe( prc2.cbox_eventCacheableEntry.cacheKey );
} );

it( "can handle a list of specific RC scope keys and ignore the rest", function(){
// execute an event and specify a queryString variable
var event1 = execute(
event = "eventcaching.withIncludeRcKeyList",
renderResults = true,
queryString = "id=1&slug=foo&source=google"
);
var prc1 = event1.getPrivateCollection();

expect( prc1.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc1.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "slug,id" );

// reset to simulate another request
setup();

var event2 = execute(
event = "eventcaching.withIncludeRcKeyList",
renderResults = true,
queryString = "id=1&slug=foo&source=bing"
);

var prc2 = event2.getPrivateCollection();

expect( prc2.cbox_eventCacheableEntry ).toBeStruct().toHaveKey( "cacheIncludeRcKeys" );
expect( prc2.cbox_eventCacheableEntry.cacheIncludeRcKeys ).toBe( "slug,id" );

// because we ignore the RC, the cache key should match
expect( prc1.cbox_eventCacheableEntry.cacheKey ).toBe( prc2.cbox_eventCacheableEntry.cacheKey );
} );

var formats = [ "json", "xml", "pdf" ];
for ( var thisFormat in formats ) {
it(
Expand Down
2 changes: 1 addition & 1 deletion tests/specs/ioc/InjectorCreationTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
function testWebService() skip="isAdobe"{
ws = injector.getInstance( "coldboxWS" );

//
//
if ( listFindNoCase( "Lucee", server.coldfusion.productname ) ) {
expect( getMetadata( ws ).name ).toMatch( "rpc" );
}
Expand Down
2 changes: 1 addition & 1 deletion tests/specs/ioc/config/samples/NoScopeBinder.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* The default ColdBox WireBox Injector configuration object that is used when the
* WireBox injector is created
**/
component extends="coldbox.system.ioc.config.Binder" {
component extends="coldbox.system.ioc.config.Binder" {

/**
* Configure WireBox, that's it!
Expand Down
4 changes: 2 additions & 2 deletions tests/specs/web/flash/AbstractFlashScopeTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
mockController.getConfigSettings().identifierProvider = function(){
return createUUID();
};
mockRService = createMock( className = "coldbox.system.web.services.RequestService", clearMethods = true );
mockEvent = createMock( className = "coldbox.system.web.context.RequestContext", clearMethods = true );
mockRService = createMock( className = "coldbox.system.web.services.RequestService", clearMethods = true );
mockEvent = createMock( className = "coldbox.system.web.context.RequestContext", clearMethods = true );

mockController
.$( "getRequestService", mockRService )
Expand Down
4 changes: 2 additions & 2 deletions tests/specs/web/flash/ColdboxCacheFlashTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

// mocks
session.sessionid = createUUID();
mockController = createMock( "coldbox.system.web.Controller" ).init( expandPath( "/root" ) );
mockController = createMock( "coldbox.system.web.Controller" ).init( expandPath( "/root" ) );
mockController.getConfigSettings().identifierProvider = function(){
return createUUID();
};
mockCache = createMock(
mockCache = createMock(
className = "coldbox.system.cache.providers.CacheBoxProvider",
clearMethods = true
);
Expand Down