@@ -528,12 +528,19 @@ component {
528528 * Supports comma-delimited variable names to constrain multiple variables at once.
529529 */
530530 public struct function $applyConstraintToLastRoute (required string variableName , required string pattern ) {
531- // Work exclusively with variables.routes (the Mapper's internal copy) to
532- // avoid Adobe CF runtime errors. Adobe CF returns application-scoped array
533- // elements by value, and chained expressions like
534- // application[key].routes[i].member cause "dereference scalar as struct"
535- // errors. After modifying routes here, we sync back to application scope.
536- local .routeCount = ArrayLen (variables .routes );
531+ // Resolve the application key for the Wheels scope.
532+ local .appKey = " wheels" ;
533+ if (StructKeyExists (application , " $wheels" )) {
534+ local .appKey = " $wheels" ;
535+ }
536+
537+ // Deep-copy the routes array into a fully independent local variable.
538+ // On Adobe CF, accessing application-scoped array elements by chained
539+ // bracket/dot notation (e.g., application[key].routes[i].member) causes
540+ // "dereference scalar as struct" errors. Duplicate() creates a plain local
541+ // copy that is safe to traverse on all CFML engines.
542+ local .routes = Duplicate (application [local .appKey ].routes );
543+ local .routeCount = ArrayLen (local .routes );
537544 if (local .routeCount == 0 ) {
538545 Throw (
539546 type = " Wheels.NoRouteToConstrain" ,
@@ -544,7 +551,7 @@ component {
544551 // Apply constraint to the last route (and its optional-segment variants).
545552 // When optional segments are used, $match adds multiple routes. We apply the
546553 // constraint to all routes that share the same name as the last one.
547- local .lastRoute = variables .routes [local .routeCount ];
554+ local .lastRoute = local .routes [local .routeCount ];
548555 local .lastRouteName = StructKeyExists (local .lastRoute , " name" ) ? local .lastRoute .name : " " ;
549556
550557 local .variables = ListToArray (arguments .variableName );
@@ -553,7 +560,7 @@ component {
553560
554561 // Walk backward through routes to find all variants of the same named route.
555562 for (local .i = local .routeCount ; local .i >= 1 ; local .i -- ) {
556- local .route = variables .routes [local .i ];
563+ local .route = local .routes [local .i ];
557564 local .routeName = StructKeyExists (local .route , " name" ) ? local .route .name : " " ;
558565
559566 // Stop if we've gone past the related routes.
@@ -571,9 +578,8 @@ component {
571578 // Recompile the regex with the new constraint.
572579 local .route .regex = $patternToRegex (local .route .pattern , local .route .constraints );
573580
574- // Write back to the internal array (Adobe CF returns array
575- // elements by value, so the local copy must be written back).
576- variables .routes [local .i ] = local .route ;
581+ // Write back to the local array copy.
582+ local .routes [local .i ] = local .route ;
577583 }
578584
579585 // If no name, only update the very last route.
@@ -583,14 +589,11 @@ component {
583589 }
584590 }
585591
586- // Sync modified routes back to application scope. We replace the entire
587- // array to avoid per-element access on application-scoped arrays, which
588- // triggers Adobe CF's "dereference scalar as struct" errors.
589- local .appKey = " wheels" ;
590- if (StructKeyExists (application , " $wheels" )) {
591- local .appKey = " $wheels" ;
592- }
593- application [local .appKey ].routes = variables .routes ;
592+ // Replace both the application-scoped and internal routes arrays with
593+ // the modified copy. A single array assignment avoids per-element
594+ // application-scope access that triggers Adobe CF runtime errors.
595+ application [local .appKey ].routes = local .routes ;
596+ variables .routes = local .routes ;
594597
595598 return this ;
596599 }
0 commit comments