Alternate templates and formats

For anyone who is interested, now or in the future.

I had a page with data, a lot like this: SilverStripe Lessons » Controller Actions / DataObjects as Pages » Silverstripe CMS
I wanted to create a link to itself that would supply a different file format. I wanted to be able to click a link and generate a vcard response.

This is how I did it. I’m sure there are errors. I’m sure I’m doing it wrong. I’m sure people will respond to show you the better way. Good on them. Go for gold, you good thing, knowledge sharing has to start somewhere.

In the page type:

   public function createVLink(){
   	return $this->Link('vcard/'.$this->ID);
   }

This creates a link to that specific data object. I was concerned that there may be unexpected issues down the track if I over rode the Link() method. So I created a new method instead.

In the template.ss the function is called like so: Download $Company’s contact details as vCard

In the controller of the page type:

    private static $allowed_actions = [
		'vcard',
    ];

    public function vcard()
    {
	
	$body = $this->renderWith('vcard');
	
	$this->setResponse(new HTTPResponse());
    
	
	
	$this->getResponse()->addHeader("Content-type", "text/x-vcard");
	
	$this->getResponse()->addHeader("charset", "utf-8");
    $this->getResponse()->setBody($body);
	
	$this->getResponse()->setStatusCode(200);
	
	return $this->getResponse();
	

    }

I created a template: vcard.ss where the data is formatted out into vcard format. Once the link is clicked, the vcard function renders the data to the vcard template, creates a new response, adds some headers .eg. content type, sets the body, sets a status code, and returns.

NB. Remember all the namespaces at the top.

This took me far too long to figure out. Hopefully I’ve saved someone some time somewhere.

Plenty of knowledge-sharing on the forum here.

There’s nothing fundamentally wrong with your approach, but you can save a little code by using the send_file() method of the http request class which will take care of a lot of the mechanics for you:

  $body = $this->renderWith('vcard');
  $this->setResponse(HTTPRequest::send_file($body,  'vcard.vcf', 'text/vcard'));
  return $this->getResponse();