I am running Laravel 5 project and I created a controller in App->Mail->SendEmail to send emails with an attached system-generated invoice through mpdf, with the below code the invoice is generated but downloaded in my browser before being sent, and when changing the output to be s I get the error "Call to a member function output() on null"
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Order $order, $data, $mpdf)
{
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML(view('invoices.paid_invoice', compact('order', 'data')));
$fileName = 'Invoice-'.$order->id.'.pdf';
$mpdf->Output($fileName,"D");
$this->order = $order;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.send_order')
->subject(('my subject'))
->attachData($this->mpdf->output(), 'invoice.pdf', [
'mime' => 'application/pdf',])
;
}}
CodePudding user response:
In your code $this->mpdf
references nothing.
You dont need to use MDF anymore once you created the file so just save the filename and reuse that in the build function
private $filename;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Order $order, $data, $mpdf)
{
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML(view('invoices.paid_invoice', compact('order', 'data')));
$this->filename = 'Invoice-'.$order->id.'.pdf';
$mpdf->Output($this->filename,"D");
$this->order = $order;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.send_order')
->subject(('my subject'))
->attach($this->filename, [
'as' => 'invoice.pdf',
'mime' => 'application/pdf',
]);
}
CodePudding user response:
As @N69S already mentioned in their answer, the mPDF object is not assigned to the class property. The best would be to avoid any "heavy lifting" in the constructor of the class. You need to call the Output method of mPDF exactly once. You can also create the mPDF object in the build method directly (or use a wrapper for Laravel providing a Facade, if that is your poison).
The main issue with provided examples is that with used second parameter 'D'
, the Output method echoes the PDF content directly (see $dest in Output method documentation) and does not return/save anything. You need either:
To save the output to the $this->filename
property (which can also be a local variable only in your example). This is done with $mpdf->Output($this->filename, 'F');
,
Or output the binary data of the PDF as a string with $mpdf->Output(null, 'S');
. If you don't need to save the PDF on your server while generating the invoice, this is the cleanest option.
Based on the variant chosen, the constructor will look like this:
public function __construct(Order $order, $data)
{
$this->data = $data; // define properties for the class
$this->fileName = 'Invoice-'.$order->id.'.pdf';
$this->order = $order;
}
and the build method will look like this:
public function build()
{
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML(view('invoices.paid_invoice', [
'order' => $this->order,
'data' => $this->data
]));
$mpdf->Output($this->filename, 'F');
return $this->markdown('emails.send_order')
->subject(('my subject'))
->attach($this->filename, [
'as' => 'invoice.pdf',
'mime' => 'application/pdf',
]);
}
or this:
public function build()
{
$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML(/* omitted for readability */);
return $this->markdown('emails.send_order')
->subject(('my subject'))
->attachData($mpdf->Output(null, 'S'), invoice.pdf, [
'as' => 'invoice.pdf',
'mime' => 'application/pdf',
]);
}