3

I'm trying to debug a route that should work like the one(s) used by the private: file scheme (i.e., a path like system/files/path/to/file, where path/to/file is an arbitrary string that may contain '/' characters). I more or less copied the the router definition. For private files:

system.private_file_download:
  path: '/system/files/{filepath}'
  defaults:
    _controller: 'Drupal\system\FileDownloadController::download'
  requirements:
    # Permissive regex to allow slashes in filepath see
    # http://symfony.com/doc/current/cookbook/routing/slash_in_parameter.html
    filepath: .+
    _access: 'TRUE'

For my "knock-off", which uses a custom scheme called 'session:':

file_example.files.session:
  path: '/example/file_example/files/{filepath}'
  defaults:
    _controller: '\Drupal\system\FileDownloadController::download'
    scheme: session
  requirements:
    # Permissive regex to allow slashes in filepath see
    # http://symfony.com/doc/current/cookbook/routing/slash_in_parameter.html
    filepath: .+
    _access: 'TRUE'

As near as I can tell, my route is never matched; yet the private: case works. What's different here? How can I debug how the router makes its decisions?

Part of what I need to know is just what route got picked when the private: scheme actually works. So it would be handy to get a link to the current route. This is a fairly obvious thing to do, but I can't find a reference in the docs. How can I determine what the "current route" is for current request?

1 Answer 1

4

This is a case where reading the routing file is a bit deceptive.

There are actually two similar routes defined in system.routing.yml:

system.files:
  path: '/system/files/{scheme}'
  defaults:
    _controller: 'Drupal\system\FileDownloadController::download'
    scheme: private
  requirements:
    _access: 'TRUE'

system.private_file_download:
  path: '/system/files/{filepath}'
  defaults:
    _controller: 'Drupal\system\FileDownloadController::download'
  requirements:
    # Permissive regex to allow slashes in filepath see
    # http://symfony.com/doc/current/cookbook/routing/slash_in_parameter.html
    filepath: .+
    _access: 'TRUE'

After watching in the debugger, it turns out that the matched route is actually system.files, and not system.private_file_download. But it will not match a tailed-URL at all without help.

The help needed is a "path processor", which is a routine that the router calls to let code do unusual things with route matching. Here's the one that's used for private: and temporary: files, among other users in Core:

In core/modules/system/src/PathProcessor/PathProcessorFiles.php:

class PathProcessorFiles implements InboundPathProcessorInterface {

  /**
   * {@inheritdoc}
   */
  public function processInbound($path, Request $request) {
    if (strpos($path, '/system/files/') === 0 && !$request->query->has('file')) {
      $file_path = preg_replace('|^\/system\/files\/|', '', $path);
      $request->query->set('file', $file_path);
      return '/system/files';
    }
    return $path;
  }

}

A path processor is a service, and needs a "tagged" service definition. Here's the one for Core's path processor for the /system/files subpath:

In system.services.yml:

  path_processor.files:
    class: Drupal\system\PathProcessor\PathProcessorFiles
    tags:
      - { name: path_processor_inbound, priority: 200 }

Once I'd added the correct route and service definitions, my custom URL scheme works the same way the Core file scheme URLs work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.