How can I create a link, within a form, for a user to download a file? I'm new to Drupal.

I have a custom form, within a custom module, using Drupal 8.

I would like to provide a simple link (or button, whatever the correct terminology would be), that when a user clicks will download a file that I specify.


How do I create the clickable part in the first place? Is there something like '#type' =&gt; 'download', similar to the way '#type' =&gt; 'managed_file' is used for uploads? Or is using the 'type' =&gt; '#submit' route the best way to go?
Where do I place the file, and how do I make the clickable part grab that file?


The file will be a .xlsx in my case, but I've seen similar questions asking how to do this for a .pdf file, .doc file, etc., but none of them have a concrete answer.

I don't care what the user does with the file once they've downloaded it. It doesn't need to be protected or "read-only" or anything fancy. I just want someone to be able to download the file and save it to their computer.

Code examples would be extremely helpful. So far my best guess is something like this:

// Taxonomy Download
    $form['taxonomy_download'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; t('Download Default Taxonomy Terms'),
      '#submit' =&gt; array('::downloadFile'),
    ];

(...)

public function downloadFile() {
     //Get file from /file/path/
     //return $file
}
Okay, so I found a solution that works pretty well, though I'm sure there are better ways to do this.

I resolved on the submit button approach, as it seems all buttons in Drupal 8 turn into submit buttons anyway. Here's the code for the button itself.

$form['taxonomy_download'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; t('Download Default Taxonomy Terms'),
      '#limit_validation_errors' =&gt; array(),  //don't run form validation when this button is pressed
      '#submit' =&gt; array('::downloadFile'),  //call this function when the button is pressed
];


Then, for the downloadFile function:

public function downloadFile(array &amp;$form, FormStateInterface $form_state) {

    // Creates a string of the file location. SERVER_NAME returns the
    // name of the host site, e.g. 'www.example.com' or '50.0.0.1'
    $buildUrl = 'http://' . $_SERVER['SERVER_NAME'] . '/sites/default/files/Example.xlsx';

    //drupal_set_message($buildUrl);    //uncomment this line to see what is getting passed

    $url = Url::fromUri($buildUrl);     //Creates a url from the file location

    $form_state-&gt;setRedirectUrl($url);  //Redirects the user to the file location
}


You will need to place the file that you're trying to download into the public files folder, found in your Drupal installation's sites/default/files/ folder. You can test that you have the file in the correct location by typing the full path (e.g. http://www.yoursite.com/drupal/sites/default/files/ExampleFile.ext) into your browser's address bar. The file should download when you go to that address.

Finally, you will need to include use Drupal\Core\Url; at the top of your code to make the fromUri() and setRedirectUrl() functions work.