On my page I am making an invoice that is fully compatible with Livewire. I use this package: https://github.com/LaravelDaily/laravel-invoices to generate my invoice and everything works fine. But their is one problem I ran into. I can't download my PDF with Livewire.
Here is a basic example to generate a PDF and download it:
public function invoice()
{
$customer = new Buyer([
'name' => 'John Doe',
'custom_fields' => [
'email' => 'test#example.com',
],
]);
$item = (new InvoiceItem())->title('Service 1')->pricePerUnit(2);
$invoice = Invoice::make()
->buyer($customer)
->discountByPercent(10)
->taxRate(15)
->shipping(1.99)
->addItem($item);
return $invoice->download();
}
Whenever I click on a button
<a role="button" class="pdf-download cursor-pointer" wire:click="invoice">download</a>
Nothing happens. So the problem is that Livewire doesn't support this download method. And this download method looks like this:
public function download()
{
$this->render();
return new Response($this->output, Response::HTTP_OK, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $this->filename . '"',
'Content-Length' => strlen($this->output),
]);
}
$this->render(); Renders a template in a specific folder
Is their a work around for this? Where I can download my pdf with a template or maybe a different strategy. I allready tried one thing. I stored the invoice into a session, like so:
Session::put('invoice', $invoice);
Session::save();
And in a different controller I have.
if ($invoice = Session::get('invoice')) {
$invoice->download();
}
But that gives me this error:
serialization of 'closure' is not allowed
And I tried some stuff I found here: https://github.com/livewire/livewire/issues/483
But nothing works. Can someone give me a direction on where to look or how to fix this? Thanks!
return response()->streamDownload(function () use($invoice) {
echo $invoice->stream();
}, 'invoice.pdf');
Seems to do the trick.
Related
I want to load pdf file in html but i got an error.
here is my function
public function getDocument($file){
$filePath = 'app/final/attachments/AA-19-4-2019-18123/'.$file;
$type = Storage::mimeType($filePath);
$pdfContent = Storage::get($filePath);
return Response::make($pdfContent, 200, [
'Content-Type' => $type,
'Content-Disposition' => 'inline; filename="'.$file.'"'
]);
}
here is my route
Route::get('/documents/pdf-document/{file}', 'inboxController#getDocument');
and here is my code in blade
<embed src="{{ action('inboxController#getDocument', ['file'=> basename($attach)]) }}" style="width:100%;height:auto;overflow: hidden;" frameborder="0" allowfullscreen>
it seems like, the error is because of the filename of the file. When i changed it to asdf.pdf, it loaded the file, but when i change its filename i wont loaded anymore. Images doesnt have really a problem. only pdf files. Please help me
edit
when i tried to use this static code, then remove {file} from route and also in blade, then pdf will loaded. i cant figure it out why.
public function getDocument(){
$filePath = 'app/final/attachments/AA-19-4-2019-18123/my.pdf';
$type = Storage::mimeType($filePath);
$pdfContent = Storage::get($filePath);
return Response::make($pdfContent, 200, [
'Content-Type' => $type,
'Content-Disposition' => 'inline; filename="'.$file.'"'
]);
}
You can do it this way :
php artisan storage:link
Next Go to the storage folder under 'public', and create a Folder 'FOLDER_NAME'
Your function :
public function getDocument($filename){
return response()->file('storage/FOLDER_NAME/'.$filename);
}
In your routes, web.php :
Route::get('/pdf/{filename}', ['as' => 'filename', 'uses' => 'ControllerName#getDocument' ]);
Then you can call it from your blade :
See PDF File:
I have a controller method like so:
use Symfony\Component\HttpFoundation\StreamedResponse;
public function downloadTransactions($type)
{
$this->authorize('download', Invoice::class);
$filename = 'invoices-' . strtolower($type) . '.csv';
$response = new StreamedResponse(function() {
Invoice::generateTransactionsCsv($type);
}, 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
return $response;
}
and then in my Invoice model I am populating the file:
public static function generateTransactionsCsv($type = null)
{
// Open output stream
$handle = fopen('php://output', 'w');
// Add CSV headers
fputcsv($handle, [
'ID',
'REF',
'DESCRIPTION',
'DATE',
'AMOUNT',
]);
// Close the output stream
fclose($handle);
}
but I get an ERR_INVALID_RESPONSE in Chrome, although I would assume the browser doesn't matter. I've checked similar questions which suggest installing the zip extension but I already have it installed. Using PHP 7.1 locally. Also tried looking at the logs but there doesn't seem to be anything there (using Valet locally).
If I move the logic from the model to the controller then it works fine but my example above is simplified to just the header row of the csv, in reality, there's a bit more to it so I'd like to keep the logic in the model if possible.
I've also tried opening and closing the file handle in the controller and passing it the model but that didn't work either.
Looks like it was because the $type variable wasn't being passed correctly:
$response = new StreamedResponse(function() use ($type) {
....
}
Was able to figure it out thanks to Safari, it downloaded a csv with the Laravel error trace in it which was weird, I didn't think it would be any different from Chrome.
I built an API using dingo/api 0.10.0, Laravel 5.1 and lucadegasperi/oauth2-server-laravel": "^5.1".
All my routes work fine in Postman/Paw!
The problem appears when I try to test the API using PHPUnit.
This is part of my route-api.php file
<?php
$api = app('Dingo\Api\Routing\Router');
$api->version(['v1'], function ($api) {
$api->post('oauth/access_token', function () {
return response(
\LucaDegasperi\OAuth2Server\Facades\Authorizer::issueAccessToken()
)->header('Content-Type', 'application/json');
});
$api->group(['middleware' => ['oauth', 'api.auth']], function ($api) {
$api->post('/register', 'YPS\Http\Controllers\Api\UserController#register');
});
And this is my test file UserRegistrationTest.php
class UserRegistrationTest extends ApiTestCase
{
public function setUp()
{
parent::setUp();
parent::afterApplicationCreated();
}
public function testRegisterSuccess()
{
$data = factory(YPS\User::class)->make()->toArray();
$data['password'] = 'password123';
$this->post('api/register', $data, $this->headers)
->seeStatusCode(201)
->seeJson([
'email' => $data['email'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
]);
}
public function testRegisterMissingParams()
{
$this->post('api/register', [], $this->headers, $this->headers, $this->headers)->seeStatusCode(422);
}
}
The ApiTestCase simply retrieves a token and sets the headers.
private function setHeaders()
{
$this->headers = [
'Accept' => 'application/vnd.yps.v1+json',
'Authorization' => 'Bearer ' . $this->OAuthAccessToken,
];
}
Now, the weird part is that the first test testRegisterSuccess runs perfectly and returns the response I expect. But the second one testRegisterMissingParams, even though it's the same route, returns this,
array:2 [
"message" => "The version given was unknown or has no registered routes."
"status_code" => 400
]
I tracked the error and it is in the Laravel adapter here:
public function dispatch(Request $request, $version)
{
// it seems that the second time around can't find any routes with the key 'v1'
if (! isset($this->routes[$version])) {
throw new UnknownVersionException;
}
$routes = $this->mergeExistingRoutes($this->routes[$version]);
$this->router->setRoutes($routes);
return $this->router->dispatch($request);
}
And further more, if i run one test at a time (eg comment one out, run test and then comment the other and run test) i see the result expected in both tests. The problem is when i run multiple tests.
Any thoughts on that?
Thank you!
Run php artisan api:routes to see full path you may have missed something for the URL, also if this working if you request your URL manually?
I had same problem with testing using Dingo & Lumen. This worked for me - remove bootstrap="bootstrap/app.php" from phpunit.xml file and change line processIsolation="false" to processIsolation="true".
I'm getting a bit muddled with a CSV download. I'm very happy to save it to a file and supply a link to the user, but this seems like the wrong way to go judging from things like these.
Going from this answer Use Laravel to Download table as CSV I think I've found that the stream() method no longer exists.
public function download()
{
$headers = [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0'
, 'Content-type' => 'text/csv'
, 'Content-Disposition' => 'attachment; filename=galleries.csv'
, 'Expires' => '0'
, 'Pragma' => 'public'
];
$list = $this->users->getAllUsers()->toArray();
# add headers for each column in the CSV download
array_unshift($list, array_keys($list[0]));
$callback = function() use ($list)
{
$FH = fopen('php://output', 'w');
foreach ($list as $row) {
fputcsv($FH, $row);
}
fclose($FH);
};
// return Response::stream($callback, 200, $headers); // Old version
return response()->download($callback, 'Users-' . date('d-m-Y'), $headers);
}
I've tried to use the Laravel 5.2 response() function, however I'm just getting a bit lost as to what I'm responding with – download() seems the logical option, but that gives me the following error:
Object of class Closure could not be converted to string
Which makes sense. What is the right way of going about this? Or should I save the file and then just use the filepath as the first argument of my download() function – something that seems to be bad practise?
It was simple enough and worked great once I replaced the class & static call Response:: With the helper function, response()->:
return response()->stream($callback, 200, $headers);
I believe this uses the StreamedResponse class.
I am using this Bundle to convert HTML to PDF files.
The actual conversion works, but I have a problem understanding the routing.
Here is my code:
/**
* #Route("/formulare/selbstauskunft/{keycode}", name="saPrint")
*/
public function saPrintAction(Request $request, $keycode)
{
$em = $this->getDoctrine()->getManager();
$sa = $em->getRepository('AppBundle:Selfinfo')->findOneBy(array(
'keycode' => $keycode,
));
if(count($sa) > 0){
$response = new Response(
$this->get('padam87_rasterize.rasterizer')->rasterize(
$this->renderView('default/formSAPrint.html.twig', array(
'selfinfo' => $sa,
))
),
200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="my.pdf"'
]
);
return $response;
}else{
return new Response("fail");
}
}
The bundle creates 2 files, rasterize-UNIQUEID.html and rasterize-UNIQUEID.pdf. The html file contains the correct output.
After the creation of the html file in /bundles/padam87rasterize/temp/ the second part of the script opens this file via an url call here.
Unfortunately the actual rendered page is a symfony error page, saying:
No route found for GET /bundles/padam87rasterize/temp/rasterize-UNIQUEID.html
What do I have to set in order to render the html file?
I think you actually have to create a separare route to render the html. As far as I can tell the rasterize function generates a pdf from the temporary html file (The key word being temporary).