4

I'm in the process of writing a module. The module works very well. In the module, I generate a form which consists of one submit button, and in the .module file, I'm calling that form and the submitForm works too. I was asked to move that button into a block, so I did. submitForm still works, but the main functionality doesn't. How come?

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

/**
* Generate button.
*/
class myModuleForm extends FormBase {

  /**
  * {@inheritdoc}.
  */
  public function getFormId() {
    return 'my_module_form';
  }

  /**
  * {@inheritdoc}.
  */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['my_module_btn'] = [
      '#type' => 'submit',
      '#value' => 'Do something'        ];
    return $form;
  }

  /**
  * {@inheritdoc}.
  */
  public function validateForm(array &$form, FormStateInterface $form_state) {
  }

  /**
  * {@inheritdoc}.
  */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $mpdf = new \Mpdf\Mpdf(['tempDir' => 'sites/default/files/tmp', 'default_font' => 'roboto', 'margin_left' => 6, 'margin_top' => 6, 'margin_right' => 6, 'margin_bottom' => 11]);
    ...
    ...
    ...
    $mpdf->Output($title."-".date("Ymd-His").".pdf", 'D');
  }
}

4 Answers 4

4

Though 4k4 says its not usually advisable, you can add an exit; at the end of submitForm in your particular case since you are generating a PDF and immediately serving it to the client. This will stop any further code from executing and solve the immediate problem (though it sounds like more scalable ones exist).

9

I googled the Mpdf library and it supports a string output. So you can use the string output to build a response and return it via $form_state:

use Symfony\Component\HttpFoundation\Response;

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $content = '%PDF-1.3...';
    $headers = [
      'Content-Type' => 'application/pdf',
    ];
    $response = new Response($content, 200, $headers);
    $form_state->setResponse($response);
  }
1
  • Even better. This is likely what you want.
    – Kevin
    Jun 22, 2018 at 18:16
1

I think it will be because the form functionality will be attempting to reload/redirect back to the page the form is on and you can't interrupt that mid flow with your own output.

You should probably add a redirect in your form submit to go to a custom controller page that will output your PDF

4
  • What if you add an exit; at the end of submit form? Is that code just dumping a generated PDF?
    – Kevin
    Jun 22, 2018 at 13:05
  • Yeah it might work but could potentially stop any other form submit hooks from firing. Not hat it will probably matter in this case but not a good habit to get into
    – Leigh
    Jun 22, 2018 at 13:40
  • A D8 version of an exit; would be to throw a custom exception and then catch this in an exception event subscriber to set a response for the pdf. This is not exactly how you are supposed to control your code flow, but core does the same to return an ajax response, see FormAjaxSubscriber::onException
    – 4uk4
    Jun 22, 2018 at 13:45
  • @Kevin please make that an answer, because adding exit; worked :)
    – Kartagis
    Jun 22, 2018 at 15:14
0

You can update the code as follows-

public function submitForm(array &$form, FormStateInterface $form_state) {
    $mpdf = new \Mpdf\Mpdf(['tempDir' => 'sites/default/files/tmp', 'default_font' => 'roboto', 'margin_left' => 6, 'margin_top' => 6, 'margin_right' => 6, 'margin_bottom' => 11]);
    ...
    ...
    ...
    $mpdf->Output($title."-".date("Ymd-His").".pdf", 'D');

  // Add the line for custom redirect

  $form_state->setRedirect('NEW PATH');

  exit;

  }
3
  • Problem is poster doesn’t want a redirect they want to serve the PDF.
    – Kevin
    Jun 22, 2018 at 16:20
  • You can use exit; or die($mpdf); in that case. Jun 22, 2018 at 16:27
  • Right.. that’s in the accepted answer.
    – Kevin
    Jun 22, 2018 at 16:28

Your Answer

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

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