I have a custom entity (contract) created in a custom module (amap) by a bunch of BaseFieldDefinition, one of which being

$fields['file1'] = BaseFieldDefinition::create('file')
  ->setLabel(t('Source file'))
  ->setDescription(t('Source file (may be modified)'))
    'target_type' => 'file',
    'file_extensions' => 'doc docx odt pages',
    'uri_scheme' => 'private',
    'file_directory' => 'contracts',

I have a View about the custom entity that displays some fields in table mode:
enter image description here The download action (the yellow arrow) is defined using Custom text with rewrite results, link path being {{ file1__target_id }}:
The link is something like mysite/system/files?file=contracts/Contract-4-20200408.doc (for example).
And following the link gives different results depending on the browser. None of them being what I want: the default filename proposed is not correct 'files' or 'file.dot' instead of 'Contract-4-20200408.doc' (in my example).

So I tried to implement hook_file_download. My code is

function amap_file_download($uri) {
  $sFileName =  \Drupal::service('file_system')->basename($uri);
  $sFileNameWithPath = 'sites/default/files/_private/contracts/' . $sFileName;
  $response = new BinaryFileResponse($sFileNameWithPath);
  $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sFileName);
  return $response;

and there I get this error!

Notice: Object of class Symfony\Component\HttpFoundation\BinaryFileResponse could not be converted to int in Drupal\system\FileDownloadController->download() (line 51 of core/modules/system/src/FileDownloadController.php).
Drupal\system\FileDownloadController->download(Object, 'private')
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

What am I doing wrong?

  • 1
    You have an error on the first line in hook file download,take the dollar sign off of the variable assignment for sFileName. Other than that this is not the right hook to use. See the docs: api.drupal.org/api/drupal/…. You are using private file storage, why rewrite the path to it instead of just let Drupal handle the request? – Kevin Apr 9 at 15:16
  • The actual code (giving the error) has not the dollar sign (wrong copy and paste when I wrote my question. I edited my question). I don't understand why you say this is not the right hook to use and then you point to 'hook_file_download'. My function is 'amap_file_download', amap being the name of my module. – gbmapo Apr 9 at 16:11
  • OK! I got it: Return value : If the user does not have permission to access the file, return -1. If the user has permission, return an array with the appropriate headers. If the file is not controlled by the current module, the return value should be NULL. – gbmapo Apr 9 at 16:17

Thanks to @Kevin, I updated my code to

function amap_file_download($uri) {

  $sFileName =  \Drupal::service('file_system')->basename($uri);
  return array(
      'Content-disposition' => 'attachment; filename="' . $sFileName . '"',


And it works!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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