Laravel HTTP Test : How to use sequence in fake call back - php

I wonder how to use sequence in HTTP::fake call back.
What I want is to get a sequence of responses when the body of my request contains ListSupplierRoutes.
here is my code:
Http::fake(function (Request $request) {
$body = $request->body();
$xmlFileName = 'login';
if (Str::contains($body, 'Login')) {
$xmlFileName = 'login';
}
if (Str::contains($body, 'ListSupplierRoutes')) {
return Http::sequence()
->push($this->loadXMLResponse('list-supplier-routes-ryanair'))
->push($this->loadXMLResponse('list-supplier-routes-ezy'));
}
// Some other conditions
return Http::response($this->loadXMLResponse($xmlFileName));
});
With this approach I get the below exception:
BadMethodCallException : Method Illuminate\Http\Client\ResponseSequence::then does not exist.
/..../vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:103
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:730
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:707
.../vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php:64
.../vendor/guzzlehttp/guzzle/src/Middleware.php:37
.../vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php:71
.../vendor/guzzlehttp/guzzle/src/Middleware.php:61
.../vendor/guzzlehttp/guzzle/src/HandlerStack.php:75
.../vendor/guzzlehttp/guzzle/src/Client.php:331
.../vendor/guzzlehttp/guzzle/src/Client.php:168
.../vendor/guzzlehttp/guzzle/src/Client.php:187
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:609
.../vendor/laravel/framework/src/Illuminate/Support/helpers.php:234
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:624
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:528

Make sure your $this->loadXMLResponse() is returning either a string or an array. Also, the Http::fake() requires that you pass an associative array of url mapping to Http::resonse() type or Http::sequence().
For instance
Http::fake(['http://stackoverflow.com' => Http::sequence()->push('OK', 200)->push('Bad Request', 400)])

Related

Is it appropriate to use a method within same object context ($this) that normally returns JSON response for client?

This May sound like a silly question but, I have a method that normally returns a JSON response to the client side. But now I need the same method within the class to prevent DRY. Something like:
public function deleteChild($id){
// delete the element with given id ...
if($success){
return response()->json(['success'=>'successfully deleted'], 200);
}else{
return response()->json(['error'=>'could not be deleted'], 422);
}
}
This method is already used by the client side. But now I have another one that needs this method as well. Something like:
public function deleteMaster($id){
$master = Master::find($id);
foreach($child as $master->children){
$child_json_response = $this->deleteChild($child->id);
$response_data = $child_json_response->getData();
if($response_data->error){
// handle child error response
// ...
}
// delete master itself
}
}
Here I can extract the response data with getData() and process it.
Is this the right way to use a sibling function that returns a JSON response (actually made for client-side) or should I create another method that returns direct results serving server-side only?
You should use a Response macro
Into a service provider's boot, add this:
\Illuminate\Http\Response::macro('deleteJson', function ($success) {
return $success
? $this->json(['success'=>'successfully deleted'], 200)
: $this->json(['error'=>'could not be deleted'], 422);
}
public function deleteChild($id){
// delete element with given id ...
return response()->deleteJson($success);
}

Laravel -- Route Name Replaced with Full URI?

I'm working on a developer tool (closed source at the moment, unfortunately) that reports on Laravel route names. It does so with code that works mostly like this (this is simplified to make asking this question easier).
function identifyRoute() {
$router = app('router');
$route = $router->current();
$name = $route->name;
if($name) {
return $name;
}
$action = $route->getAction();
if(isset($action["controller"]) && $action["controller"]) {
return $action["controller"];
}
if($name = $route->uri())
{
return $name;
}
return 'Could Not Identify Name';
}
So, for a route like
Route::get('foo/{id}/bar', function($id ) {
//...
});
Our function returns the string foo/{id}/bar. Or, it usually returns the string foo/{id}/bar. We've had reports from users that sometimes this method of identifying routes returns results like
foo/1234/bar
foo/1235/bar
foo/1236/bar
foo/1237/bar
That is, it's returning the entire URI for the request.
Is there some Laravel setting (or popular extension/plugin) that could replace the results of calls to getName, uri, or the controller name, with the full URI of the request?
A bit of a guess, but an OPTIONS HTTP request will return a 200 response with the proper allowable verbs, using the requested path as-is instead of a pattern.
Current source code in 5.7
Method is almost the same in 5.4.9

Can't "get" data in get ajax request using laravel

I just can't retrieve the data in my query string section.
I've used AJAX request throughout my website to implement a wide variety of tasks asynchronously and didn't had an issue of this kind.
Route
Route::get('/mensagem/enviar_mensagem', [ 'as' => 'mensagem.enviar_mensagem', 'uses' => 'MensagemController#enviar_mensagem']);
the testing url:
http://mydomain.com.br/mensagem/enviar_mensagem?para=email#bol.com.br
my action method:
public function enviar_mensagem(Request $request)
{
$para = $request->get('para');
//$para = $_GET['para']; I get an undefined index error
echo $para; //always empty string!
}
You need to use input. Like so:
Also, for testing, return versus echo.
public function enviar_mensagem(Request $request)
{
$para = $request->input('para');
return $para;
}
And to spark my curiosity, what does return $request->all() return?
Well, the provided code seems to be correct. Make sure you use \Illuminate\Http\Request. This code
Route::get('/mensagem/enviar_mensagem', function(\Illuminate\Http\Request $request) {
return $request->para;
// return $request->get('para'); // also works
});
returns email#bol.com.br by request http://your-site.app/mensagem/enviar_mensagem?para=email#bol.com.br
I copy pasted your code and both works:
$para = $request->get('para');
$para = $_GET['para'];
//$para = $_GET['para']; I get an undefined index error
Did you make sure the webserver is properly handling the HTTP request?
https://laravel.com/docs/5.4#web-server-configuration
You can try with below code :
use Request;
class xyzController {
public function enviar_mensagem()
{
$para = Request::all();
echo $para['para'];
}
}
First you will need to change the route to add also this
Route::get('/mensagem/enviar_mensagem/{para}',
[ 'as' => 'mensagem.enviar_mensagem', 'uses' =>
'MensagemController#enviar_mensagem']);
And after that in controller
public function enviar_mensagem($para){
return var_dump($para);
}
Use the route method on the request object to access GET parameters
public function enviar_mensagem(Request $request)
{
$para = $request->route('para');
echo $para;
}

Validating HTTP Response Codes in PHPUnit

I am writing unit tests for several methods which return HTTP response codes. I cannot find a way to assert an HTTP response code. Perhaps I am missing something obvious, or I am misunderstanding something about PHPUnit.
I am using PHPUnit 4.5 stable.
Relevant part of class Message:
public function validate() {
// Decode JSON to array.
if (!$json = json_decode($this->read(), TRUE)) {
return http_response_code(415);
}
return $json;
}
// Abstracted file_get_contents a bit to facilitate unit testing.
public $_file_input = 'php://input';
public function read() {
return file_get_contents($this->_file_input);
}
Unit test:
// Load invalid JSON file and verify that validate() fails.
public function testValidateWhenInvalid() {
$stub1 = $this->getMockForAbstractClass('Message');
$path = __DIR__ . '/testDataMalformed.json';
$stub1->_file_input = $path;
$result = $stub1->validate();
// At this point, we have decoded the JSON file inside validate() and have expected it to fail.
// Validate that the return value from HTTP 415.
$this->assertEquals('415', $result);
}
PHPUnit returns:
1) MessageTest::testValidateWhenInvalid
Failed asserting that 'true' matches expected '415'.
I'm unsure why $result is returning 'true' . . . especially as a string value. Also unsure what my 'expected' argument ought to be.
According to the docs you can call the http_response_code() method with no parameters to receive the current response code.
<?php
http_response_code(401);
echo http_response_code(); //Output: 401
?>
Therefore your test should look like:
public function testValidateWhenInvalid() {
$stub1 = $this->getMockForAbstractClass('Message');
$path = __DIR__ . '/testDataMalformed.json';
$stub1->_file_input = $path;
$result = $stub1->validate();
// At this point, we have decoded the JSON file inside validate() and have expected it to fail.
// Validate that the return value from HTTP 415.
$this->assertEquals(415, http_response_code()); //Note you will get an int for the return value, not a string
}

Getting GET "?" Variable in Laravel

Hello I'm creating an API using REST and Laravel following this article.
Everything works well as expected.
Now, I want to map a GET request to recognise a variable using "?".
For example: domain/api/v1/todos?start=1&limit=2.
Below is the contents of my routes.php :
Route::any('api/v1/todos/(:num?)', array(
'as' => 'api.todos',
'uses' => 'api.todos#index'
));
My controllers/api/todos.php :
class Api_Todos_Controller extends Base_Controller {
public $restful = true;
public function get_index($id = null) {
if(is_null($id)) {
return Response::eloquent(Todo::all(1));
} else {
$todo = Todo::find($id);
if (is_null($todo)) {
return Response::json('Todo not found', 404);
} else {
return Response::eloquent($todo);
}
}
}
}
How do I GET a parameter using "?" ?
Take a look at the $_GET and $_REQUEST superglobals. Something like the following would work for your example:
$start = $_GET['start'];
$limit = $_GET['limit'];
EDIT
According to this post in the laravel forums, you need to use Input::get(), e.g.,
$start = Input::get('start');
$limit = Input::get('limit');
See also: http://laravel.com/docs/input#input
On 5.3-8.0 you reference the query parameter as if it were a member of the Request class.
1. Url
http://example.com/path?page=2
2. In a route callback or controller action using magic method Request::__get()
Route::get('/path', function(Request $request){
dd($request->page);
});
//or in your controller
public function foo(Request $request){
dd($request->page);
}
//NOTE: If you are wondering where the request instance is coming from, Laravel automatically injects the request instance from the IOC container
//output
"2"
###3. Default values
We can also pass in a default value which is returned if a parameter doesn't exist. It's much cleaner than a ternary expression that you'd normally use with the request globals
//wrong way to do it in Laravel
$page = isset($_POST['page']) ? $_POST['page'] : 1;
//do this instead
$request->get('page', 1);
//returns page 1 if there is no page
//NOTE: This behaves like $_REQUEST array. It looks in both the
//request body and the query string
$request->input('page', 1);
###4. Using request function
$page = request('page', 1);
//returns page 1 if there is no page parameter in the query string
//it is the equivalent of
$page = 1;
if(!empty($_GET['page'])
$page = $_GET['page'];
The default parameter is optional therefore one can omit it
###5. Using Request::query()
While the input method retrieves values from entire request payload (including the query string), the query method will only retrieve values from the query string
//this is the equivalent of retrieving the parameter
//from the $_GET global array
$page = $request->query('page');
//with a default
$page = $request->query('page', 1);
###6. Using the Request facade
$page = Request::get('page');
//with a default value
$page = Request::get('page', 1);
You can read more in the official documentation https://laravel.com/docs/5.8/requests
We have similar situation right now and as of this answer, I am using laravel 5.6 release.
I will not use your example in the question but mine, because it's related though.
I have route like this:
Route::name('your.name.here')->get('/your/uri', 'YourController#someMethod');
Then in your controller method, make sure you include
use Illuminate\Http\Request;
and this should be above your controller, most likely a default, if generated using php artisan, now to get variable from the url it should look like this:
public function someMethod(Request $request)
{
$foo = $request->input("start");
$bar = $request->input("limit");
// some codes here
}
Regardless of the HTTP verb, the input() method may be used to retrieve user input.
https://laravel.com/docs/5.6/requests#retrieving-input
Hope this help.
This is the best practice. This way you will get the variables from
GET method as well as POST method
public function index(Request $request) {
$data=$request->all();
dd($data);
}
//OR if you want few of them then
public function index(Request $request) {
$data=$request->only('id','name','etc');
dd($data);
}
//OR if you want all except few then
public function index(Request $request) {
$data=$request->except('__token');
dd($data);
}
Query params are used like this:
use Illuminate\Http\Request;
class MyController extends BaseController{
public function index(Request $request){
$param = $request->query('param');
}
In laravel 5.3 $start = Input::get('start'); returns NULL
To solve this
use Illuminate\Support\Facades\Input;
//then inside you controller function use
$input = Input::all(); // $input will have all your variables,
$start = $input['start'];
$limit = $input['limit'];
In laravel 5.3
I want to show the get param in my view
Step 1 : my route
Route::get('my_route/{myvalue}', 'myController#myfunction');
Step 2 : Write a function inside your controller
public function myfunction($myvalue)
{
return view('get')->with('myvalue', $myvalue);
}
Now you're returning the parameter that you passed to the view
Step 3 : Showing it in my View
Inside my view you i can simply echo it by using
{{ $myvalue }}
So If you have this in your url
http://127.0.0.1/yourproject/refral/this#that.com
Then it will print this#that.com in you view file
hope this helps someone.
It is not very nice to use native php resources like $_GET as Laravel gives us easy ways to get the variables. As a matter of standard, whenever possible use the resources of the laravel itself instead of pure PHP.
There is at least two modes to get variables by GET in Laravel (
Laravel 5.x or greater):
Mode 1
Route:
Route::get('computers={id}', 'ComputersController#index');
Request (POSTMAN or client...):
http://localhost/api/computers=500
Controler - You can access the {id} paramter in the Controlller by:
public function index(Request $request, $id){
return $id;
}
Mode 2
Route:
Route::get('computers', 'ComputersController#index');
Request (POSTMAN or client...):
http://localhost/api/computers?id=500
Controler - You can access the ?id paramter in the Controlller by:
public function index(Request $request){
return $request->input('id');
}

Categories