Testing Laravel-Excel download - laravel

I'm using following package: https://github.com/Maatwebsite/Laravel-Excel at version 2 with Laravel version 5.1
I've have got controller method with following code:
....
return Excel::create('List', function($excel) use ($list)
{
$excel->sheet('List', function($sheet) use ($list)
{
$sheet->fromModel($list);
});
})
->download('csv');
and simple test like this:
$this->call('GET', 'route/to/csv', [
'param' => 'value',
]);
$this->dump();
Above test outputs [ERROR]: Headers already sent from this line of the package.
Controller method works fine, but can't test it.
I've tried to run phpunit with --stderr param. In that case, no error is thrown, but it just dumps output of CSV file to console and exits.
I've also tried to run test with #runInSeparateProcess annotation and got errors like:
PHPUnit_Framework_Exception: PHP Notice: Constant LARAVEL_START already defined in bootstrap/autoload.php on line 3
....
PHP Fatal error: Uncaught exception 'ReflectionException' with message 'Class env does not exist' in vendor/laravel/framework/src/Illuminate/Container/Container.php:736
Could this be a bug in Laravel-Excel package or I'm testing it wrong?

Thats because the way the download method works in laravel-excel is by setting headers. You want to avoid that, and instead do all the work your self by returning laravel Responses.
Try this instead:
$file = Excel::create('List', function($excel) use ($list) {
$excel->sheet('List', function($sheet) use ($list)
{
$sheet->fromModel($list);
});
})->string('xls');
return new Response($file, 200, [
'Content-Type' => 'application/vnd.ms-excel; charset=UTF-8',
'Content-Disposition' => 'attachment; filename="' . $file->filename . '.' . $file->ext . '"',
'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', // Date in the past
'Last-Modified' => Carbon::now()->format('D, d M Y H:i:s'),
'Cache-Control' => 'cache, must-revalidate',
'Pragma' => 'public',
]);
The key difference is to use the string() method which will return the binary data for the excel file and allows you to pass it as the data for a response.

Related

How to do an actual file upload with phpunit and Laravel that's not fake

Phpunit, Laravel 5.5
How do I emulate, not fake, an actual file upload with phpunit and Laravel. My latest stab at it is like this. From the unit test:
$handle = fopen($path,'r');
$content = fread($handle,2048);
fclose($handle);
$fdata = [
'delimiter' => '3',
'id' => 1,
'allow_shared_roles' => 'on',
'file'=>$name
];
$this->call('POST','/event/add-wizard/2',$fdata,[],[],[
'Content-Length'=>strlen($content),
'Content-Type'=>'multipart/form-data;boundary='.$content,
'Content-Disposition'=>'form-data;name="file";filename="'.$name.'"'
],$content);
Then on the server side, this is where I get hung up.
if ($request->hasFile('file')) {
$input['extension'] = strtolower($request->file('file')->getClientOriginalExtension());
}
$validator = \Validator::make($input, ['file' => 'required', 'extension' => 'in:csv', 'delimiter' => 'required'], ['extension.in' => 'The file must be a .csv file.']);
if ($validator->fails()) {
return \Redirect::back()->withInput()->withErrors($validator);
}
if (!file_exists(storage_path('temp-files'))) {
\File::makeDirectory(storage_path('temp-files'));
}
$date = \Carbon\Carbon::now();
$tmpFile = $request->file('file')->move(storage_path('temp-files'), $date->format('YmdHis') . '_' . $request->file('file')->getClientOriginalName());
Then I get move on null error on the last line shown.
Having never done this kind of thing before I admit I'm stabbing in the dark. Any help would be greatly appreciated.
After confirming in the comments that you want to check if the upload routine is being followed instead really uploading a file you can mock the facade File to see if the methods are called and with the right parameters (optional).
To mock a Facade in Laravel you can use the build in shouldReceive('method_name') method. In your situation you can add this before the call:
// should create new directory
File::shouldReceive('makeDirectory')
->once();
// should move the uploaded file to the dir
File::shouldReceive('move')
->once()
->andReturn( $fake_file );
You can read more about mocking facades here.

php aws sdk cant invoke lambda function

Using the below PHP code to invoke lambda function but i am getting the below error. Looked at the PHP AWS api docuumentation not able to find whats causing issue.
Receiving the below error from aws php sdk
PHP Warning: Illegal string offset 'StatusCode' in /var/www/html/Guzzle/Service/Command/LocationVisitor/Response/StatusCodeVisitor.php on line 21
PHP Warning: Illegal string offset 'FunctionError' in /var/www/html/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php on line 24
PHP Warning: Illegal string offset 'LogResult' in /var/www/html/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php on line 24
PHP Catchable fatal error: Argument 1 passed to Guzzle\Service\Resource\Model::__construct() must be of the type array, string given, called in /var/www/html/Guzzle/Service/Command/OperationResponseParser.php on line 86 and defined in /var/www/html/Guzzle/Service/Resource/Model.php on line 20
use Aws\Lambda\LambdaClient;
$client = LambdaClient::factory(array(
'credentials' => array(
'key' => $f_key,
'secret' => $f_secret,
),
'region' => 'ap-southeast-2'
));
try {
echo "new invoke" . "\n";
$result = $client->invoke(array(
// FunctionName is required
'FunctionName' => 'hello_wo’,
));
}catch(Exception $e) {
echo 'Error retrieving lambd error message code-' . $e->getCode . '-error message-' . $e->getMessage() ;
}
Try this:
$client = LambdaClient::factory([
'key' => $f_key,
'secret' => $f_secret,
'region' => 'ap-southeast-2'
]);

Laravel : Force the download of a string without having to create a file

I'm generating a CSV, and I want Laravel to force its download, but the documentation only mentions I can download files that already exist on the server, and I want to do it without saving the data as a file.
I managed to make this (which works), but I wanted to know if there was another, neater way.
$headers = [
'Content-type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="download.csv"',
];
return \Response::make($content, 200, $headers);
I also tried with a SplTempFileObject(), but I got the following error : The file "php://temp" does not exist
$tmpFile = new \SplTempFileObject();
$tmpFile->fwrite($content);
return response()->download($tmpFile);
Make a response macro for a cleaner content-disposition / laravel approach
Add the following to your App\Providers\AppServiceProvider boot method
\Response::macro('attachment', function ($content) {
$headers = [
'Content-type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="download.csv"',
];
return \Response::make($content, 200, $headers);
});
then in your controller or routes you can return the following
return response()->attachment($content);
A Laravel 7 approach would be (from the docs):
$contents = 'Get the contents from somewhere';
$filename = 'test.txt';
return response()->streamDownload(function () use ($contents) {
echo $contents;
}, $filename);
Try this:
// Directory file csv, You can use "public_path()" if the file is in the public folder
$file= public_path(). "/download.csv";
$headers = ['Content-Type: text/csv'];
//L4
return Response::download($file, 'filename.csv', $headers);
//L5 or Higher
return response()->download($file, 'filename.csv', $headers);

Connecting to shopify and returning products

I'm tring to return products from my shopify store and dump the expected returned json on to the page. No products return via the code but if I go directly to the url in the form below I get the expected json displayed on the page:
https://API_KEY:PASSWORD#your-store.myshopify.com/admin/products.json
Can anyone help me return the json using this package which I'm using to connect to shopify? I'm also using Laravel 5.
I've noticed that the Input calls return nothing:
Input::get('code');
Input::all();
I added this to app.php:
'Input' => Illuminate\Support\Facades\Input::class,
I'm getting this error:
ERROR #22: The requested URL returned error: 401
in api.php line 309 at API->call(array('METHOD' => 'GET', 'URL' => '/admin/products.json?page=1')) in routes.php line 87
This is my route:
Route::get('/show_products', function() {
$shopify = App::make('ShopifyAPI');
// This creates an instance of the Shopify API wrapper and
// authenticates our app.
$shopify = App::make('ShopifyAPI', [
'API_KEY' => 'api_key',
'API_SECRET' => 'api_secret',
'SHOP_DOMAIN' => 'shop_domain.myshopify.com',
'ACCESS_TOKEN' => 'access_token'
]);
$shopify->installURL(['permissions' => array('read_products', 'write_products'), 'redirect' => 'https://dev.shopify.com/public/']);
try {
$verify = $shopify->verifyRequest(Input::all(), true);
if ($verify)
{
$code = Input::get('code');
echo "code: ".$code; // no code returned
$accessToken = $shopify->getAccessToken($code);
echo "accessToken: ".$accessToken; // no access token
}
else
{
echo "issue with data";
// Issue with data
}
}
catch (Exception $e)
{
echo '<pre> Error: ' . $e->getMessage() . '</pre>';
}
// Gets a list of products
$result = $shopify->call([
'METHOD' => 'GET',
'URL' => '/admin/products.json?page=1'
]);
$products = $result->products;
print_r($products);
exit;
});
I ran into this issue on Android. The accessing the products by the url with key/secret worked fine if I was in a browser, but failed trying to do a basic GET against that URL from the device.
I couldn't figure out why, but I ended up setting the header on the request, and that worked well.
Where you had
https://API_KEY:PASSWORD#your-store.myshopify.com/admin/products.json
Instead, request
https://your-store.myshopify.com/admin/products.json
but set the header x-shopify-access-token to PASSWORD

guzzle client throws exception in laravel

I am trying to make a http post request in laravel as below
$client = new Client(['debug'=>true,'exceptions'=>false]);
$res = $client->request('POST', 'http://www.myservice.com/find_provider.php', [
'form_params' => [
'street'=> 'test',
'apt'=> '',
'zip'=> 'test',
'phone'=> 'test',
]
]);
It return empty response. On debugging ,following exception is occurring
curl_setopt_array(): cannot represent a stream of type Output as a STDIO FILE*
I am using latest version of guzzle.
Any idea how to solve it?.
The request() method is returning a GuzzleHttp\Psr7\Response object.
To get the actual data that is returned by your service you should use:
$data = $res->getBody()->getContents();
Now check what you have in $data and if it corresponds to the expected output.
More information on using Guzzle Reponse object here
I had to do this
$data = $res->getBody()->getContents();<br>
but also change<br>
$client = new \GuzzleHttp\Client(['verify' => false, 'debug' => true]);<br>
to<br>
$client = new \GuzzleHttp\Client(['verify' => false]);
Here is what i did for my SMS api
use Illuminate\Support\Facades\Http; // Use this on top
// Sample Code
$response = Http::asForm()
->withToken(env('SMS_AUTH_TOKEN'))
->withOptions([
'debug' => fopen('php://stderr', 'w') // Update This Line
])
->withHeaders([
'Cache-Control' => 'no-cache',
'Content-Type' => 'application/x-www-form-urlencoded',
])
->post($apiUrl,$request->except('_token'));

Resources