-1

In the submitForm of a custom form, I have this:

switch ($form_state->getValue('suscribe')) {
  case 0:
    $iStatus = 1;
    break;
  case 1:
    $iStatus = 3;
    $sFileName = 'sites/default/files/_private/bulletins/' . $form_state->getValue('adherent')[1] . ".pdf";
    $response = new BinaryFileResponse($sFileName);
    $response->setContentDisposition(
      ResponseHeaderBag::DISPOSITION_ATTACHMENT,
      'bulletin.pdf'
    );
    $form_state->setResponse($response);
    break;
}

$storage = \Drupal::entityTypeManager()->getStorage('member');
$id = $form_state->getValue('adherent')[0];
$entity = $storage->load($id);
$entity->status = $iStatus;
$entity->save();

\Drupal::messenger()->addMessage($this->t('Your wish has been recorded.'));

suscribe is a Yes/No radio button.
$form_state->setResponse($response); triggers the automatic download of a pdf document.

The message (Your wish...) is correctly displayed in case 0.
In case 1, the message shows only if I refresh the page (or go to another page).
How can I have the message displayed without doing another action after submitting the form in case 1?

By the way, database is correctly updated in both cases.
I'm using Drupal 8.6.10.

1

How can I have the message displayed without doing another action after submitting the form in case 1?

You can't - when you force download a file the page you see behind it is the original form request, and always will be. It's just how browsers work.

You'll need to refresh the page (or visit a new page) to see the messages, which haven't been rendered as part of the force-download request, and so are still sitting in the session waiting to be rendered.

You might be able to hack something together with JS to make this work, but in my experience it's not worth the hassle. The browser doesn't even report back to you when the file is downloaded (what if it isn't? What if the user cancels or there are network problems?), so it's a real pain to implement.

  • What do you think about replacing the automatic download (with setResponse) by a link to the file in the form that the user could click on and, then, submit the form? Would addMessage work in this case? – gbmapo Mar 15 at 10:06
  • 3
    addMessage will only work when you invoke a new request. You won't be able to do it in response to the file finishing its download, the browser doesn't tell you when that happens, but you could save the file in the temp folder on submission of the form, create a route to serve it, and put the link to download it in the message area after the form submits. You can delete the file once served. Think something along the lines of the message being "Your file has been prepared, here's a link to it: link". A cron job to clear up any generated but not downloaded files would also be wise. – Clive Mar 15 at 10:27
0

Finally and using advice from @Clive, I made it this way:

  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    switch ($form_state->getValue('suscribe')) {
      case 0:
        $iStatus = 1;
        $sMessage = $this->t('Your wish has been recorded.');
        break;
      case 1:
        $iStatus = 3;
        $Url = Url::fromUri('base:/association/membership/download/' . $form_state->getValue('adherent')[0]);
        $sLink = \Drupal\Core\Link::fromTextAndUrl($this->t('here'), $Url)->toString();
        $sMessage = $this->t('Your wish has been recorded.<BR>To download your membership form, please click %link.', ['%link' => $sLink]);
        break;
    }
    $storage = \Drupal::entityTypeManager()->getStorage('member');
    $id = $form_state->getValue('adherent')[0];
    $entity = $storage->load($id);
    $entity->status = $iStatus;
    $entity->save();
    \Drupal::messenger()->addMessage($sMessage);
  }

which gives

Case 0: a simple message saying that wish has been recorded.
enter image description here

Case 1: the same message plus a link to download the document enter image description here

In association.routing.yml:

association.membership_download:
  path: '/association/membership/download/{member}'
  defaults:
    _controller: '\Drupal\association\Controller\MembershipController::download'
  requirements:
    _permission: 'renew membership'  

In MembershipController.php:

  public function download($member)
  {

    $storage = \Drupal::entityTypeManager()->getStorage('member');
    $entity = $storage->load($member);
    $sFileName = 'sites/default/files/_private/bulletins/' . $entity->designation->value . '.pdf';
    $response = new BinaryFileResponse($sFileName);
    $response->setContentDisposition(
      ResponseHeaderBag::DISPOSITION_ATTACHMENT,
      'bulletin.pdf'
    );
    return $response;
  }

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.