2

I am trying to create an XLS file and send it to the browser on a form submit but I cannot figure out how to do it. I am using XLS Serialization module but I'm open to all other suggestions. With this module I successfully created some views with XLS Export feature. But now I have a form and the excel file should be created on form submit depending on the submitted data.

I created the following code but if I send the form, I get no excel file to download:

class MyForm extends FormBase {
  private SerializerInterface $serializer;

  public static function create(ContainerInterface $container) {
    return new static($container->get('serializer'));
  }

  public function __construct(SerializerInterface $serializer) {
    $this->serializer = $serializer;
  }

  // Removed the buildForm() etc for simplicity

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $response = (new StreamedResponse(function () use ($selected_values) {
      $this->serializer->serialize([[1, 2, 3], [4, 5, 6]], 'xlsx');
    }))->send();

    $form_state->setResponse($response);
  }
}
2
  • 1
    "didn't work" ? Not sure what that means exactly ... The only weird thing I can see is the ->send(), but you left out some code and you don't say what the error or problem is.
    – anonymous
    Commented Nov 3, 2021 at 8:41
  • it means when I send the form, I don't get an excel file to download
    – Elin Y.
    Commented Nov 3, 2021 at 12:02

1 Answer 1

4
+350

First off, you need a serializer for xls(x), I used https://www.drupal.org/project/xls_serialization

The following example code should deliver what you need:

public function submitForm(array &$form, FormStateInterface $form_state) {
  $values = $form_state->getValues();
  $filename = "random_file_" . rand() . ".xlsx";

  $response = new StreamedResponse(function () use ($values) {
    echo $this->serializer->serialize([[1, 2, 3], [4, 5, 6]], 'xlsx');
  });
  $response->headers->set('Content-Type', 'application/vnd.ms-excel');
  $response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');

  $form_state->setResponse($response);
}

I tried that with the XLS encoder provided https://www.drupal.org/project/xls_serialization and it worked.

Good luck!

References:

5
  • Thank you, I worked out a working solution. But with a bit different and simpler callback function in StreamedResponse. Would you mind if I update your code?
    – Elin Y.
    Commented Nov 4, 2021 at 9:27
  • If it's the same approach, yes, please do. Otherwise, this question needs a different answer than mine. Curious in any case! The callback code I wrote in there was based off of your question, perhaps you can update the question and then I can update my answer. Commented Nov 4, 2021 at 9:30
  • Updated the code with the one worked for me. Please check my changes: drupal.stackexchange.com/posts/308007/revisions If you want you can still rollback to your version. Thanks.
    – Elin Y.
    Commented Nov 4, 2021 at 10:32
  • So, all you needed was the headers' part to get your code working, right? Commented Nov 4, 2021 at 11:50
  • Not only the headers. I also added echo to the StreamedResponse callback, and removed the send() method that I used at the beginning.
    – Elin Y.
    Commented Nov 4, 2021 at 12:51

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.