search
top

Force download a custom view using MediaView

Just some quick hint: Let’s assume you generate a non-html file using a view, layout and custom extension (sql, xml, json, etc..) and you want to offer the displayed result as a download. – Generally you would need to force-download the file, probably using MediaView. Problem is that it isn’t actually a real file for MediaView to work with.

Here’s a quick workaround to that, using two calls to render() in a single action (comments welcome):

public function export() {
  $data = $this->{$this->modelClass}->find('all');
  $this->set(compact('data'));
  $rendered = $this->render();
  $fileext = 'xml'; // optional: $this->params['url']['ext'];
  $filepath = TMP.'rendered'.DS;
  $filename = md5(String::uuid()).'.'.$fileext;
  file_put_contents($filepath.$filename, $rendered); // php5 func
  $this->view = 'Media';
  $params = array(
    'id' => $filename,
    'path' => $filepath,
    'extension' => $fileext,
    'download' => true, // force download
    'name' => low($this->name).'-export' // fancy name
  );
  $this->set($params);
  $this->render(); // init download
}

That’s it. First you render the .ctp using all the fancy helpers, temporarly save the result on your (ram)disk, change the view to Media, reuse almost same variables for the params array and simply call render again. Since we change $this->view in between renders, we can use both view renderer in a row.

DRY: For the extension you could grab the current extension from $this->params['url']['ext'] if you used array('ext' => '...') in the HtmlHelper::link() url param. This makes the action even more generic.

Leave a Reply

top