“How to fix ‘Trying to get property 'headers' of non-object” VerifyCsrfToken - php

I run my project and i get this error:
Trying to get property 'headers' of non-object in
"\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php"
in this function
protected function addCookieToResponse($request, $response)
{
$config = config('session');
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}

What are you actually passing as $response argument in this case?
I believe one needs more details to come up with the concrete cause of why you are getting the error, however I can try to give a hint:
For some reason what you pass in place of $response is not being recognized as an instance of an object in your case.
You could try instantiating it like so:
$response = Response::make($contents, $statusCode);
$response->header('Content-Type', $value);
and then pass it to your function.
Maybe you can try and trace back based on this assumption, where exactly in your Project the chain is broken?
I mean, in your case it is a parameter in your function, but how would it know that it inherits from the Symfony\Component\HttpFoundation\Response class?
Maybe you should "typehint" it -> like say Response $response in the brackets.
I found this link here to be useful explanation also. In the post they talk about Request and not Response, but I think the principle of the issue is is related:
https://www.quora.com/What-does-Request-request-mean-in-Laravel
You can check out the documentation:
https://laravel.com/docs/4.2/responses

Related

Laravel Mock Request function only and header

I test code with PHPUnit 9.0.
I use Laravel framework 8.* and PHP 7.4
I struggle to test a function that uses request()
Here is a very short version of the code I have to test:
trait SomeTrait
{
function someFunction()
{
//1. retrieve only the documents
$documents = request()->only('documents');
....
//set an array called $header
$header = [ 'Accept-Encoding' => 'application/json'];
//2. add to Array $header if someKey is available in headers
if (request()->headers->has('someKey'))
{
$header = Arr::add($header, 'someKey', request()->header('someKey'));
}
}
}
At first (1.) it has to get the documents from a request. I solved this with an mock of the request and it works:
$requestMock = Mockery::mock(Request::class)
->makePartial()
->shouldReceive('only')
->with('documents')
->andReturn($document_data);
app()->instance('request', $requestMock->getMock());
$this->someFunction();
I create a mock of request class, that returns $document_data when request()->only('documents'); is called in someFunction().
But then the code request()->headers->has('someKey') returns the error:
Call to a member function has() on null
Can anybody help and explain how I can test the code?
Thanks for the help! I found a solution without mocking the request - sometimes it's easier than you think :D
//create a request
$request = new Request();
//replace the empty request with an array
$request->replace(['documents' => $all_documents]);
//replace the empty request header with an array
$request->headers->replace(['someKey' => 'someValue']);
//bind the request
app()->instance('request', $request);

Can't Use on_stats Option Using Laravel HTTP Client

Currently, I'm using Laravel HTTP client to make a request to an external URL. Mostly, the package working fine until I try to implement on_stats option from Guzzle.
From the doc, it says we can use Guzzle options using withMethod() method.
Here is my sample code to implement on_stats option using HTTP client.
$response = Http::withOptions([
'debug' => true,
'on_stats' => function(\GuzzleHttp\TransferStats $stats) {
Log::debug($stats->getTransferTime());
}
])
->get('https://laravel.com');
dd($response->status());
The code above will produce an error with the message:
Second array member is not a valid method
However, when I'm using the option within the Guzzle package directly, it works fine.
$client = new \GuzzleHttp\Client;
$response = $client->get('https://laravel.com', [
'on_stats' => function(\GuzzleHttp\TransferStats $stats) {
Log::debug($stats->getTransferTime());
}
]);
dd((string) $response->getStatusCode());
Any idea why this is happening? Is it a bug from the HTTP client wrapper from Laravel?
FYI, I'm using Laravel 8.x.
Thanks.
withOptions uses this code:
return tap($this, function ($request) use ($options) {
return $this->options = array_merge_recursive($this->options, $options);
});
So I'm guessing passing a closure in may not work, since it's not actually an array. From https://laracasts.com/discuss/channels/requests/httpwithtoken-get-total-time-of-request , you can get it from the response instead, so try this:
$client = new \GuzzleHttp\Client;
$response = $client->get('https://laravel.com');
Log::debug($response->transferStats->getTransferTime());

How To Use Mockery For Mocking Nested Object Like GuzzleHttp Request

I have the following code in PHP:
$response = $this->client->request('GET', $path, $requestBody, $headers);
$isRequestSuccess = $response->getStatusCode() === "200";
if ($isRequestSuccess) {
return $response->getBody()->getContents();
}
It seems like I was successful in creating a mock for the request:
$mockResponse = \Mockery::mock('GuzzleHttp\Psr7\Response');
$clientMock
->shouldReceive('request')
->once()
->withAnyArgs()
->andReturn($mockResponse);
$clientMock->shouldReceive('getStatusCode')->andReturn(200);
But, how should I use Mockery to mock getStatusCode?
It should return a Psr7\Response object of GuzzleHttp.
I know that the $clientMock return value should be assigned to a parameter, but how should I mock the
$response->getStatusCode();
and
$response->getBody()->getContents()
If I'm going to mock the getStatusCode and return 200, I get the following error:
Method Mockery_4_GuzzleHttp_Psr7_Response::getStatusCode() does not exist on this mock object
It is not a $request, it is a $response, you better name it so. It Is very confusing that $request variable contains a response object.
Anyway,
Mockery::mock(ResponseInterface::class)->shouldReceive('getStatusCode')->andReturn(200);
Looking at it deeper, you probably dont have to care, that response Is mocked and useless to test, you would be testing if you set up the mock right, rather then testing your code.

Slim3 Cannot use object of type Slim\Http\Response as array

I am having trouble with adding error output to the JWT middleware set up.
I am getting this error: Cannot use object of type Slim\Http\Response as array
I am using Slim 3 and the slim-jwt-auth package, I am using the sample code in the docs found at https://github.com/tuupola/slim-jwt-auth#error
The difference being I'm calling \Slim\Middleware\JwtAuthentication instead of Tuupola\Middleware\JwtAuthentication. If I use that the class cannot be found. Everything was working fine until I wanted to add the error output to the middleware set up, here is my code:
$app->add(new \Slim\Middleware\JwtAuthentication([
"path" => "/mypath",
"passthrough" => "/mypath/get-auth",
"secret" => getenv("SKEY"),
"secure" => false,
"error" => function ($response, $args) {
$data = array();
$data["status"] = "error";
$data["message"] = $args["message"];
return $response
->withHeader("Content-Type", "application/json")
->getBody()->write(
json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
]));
The error output says it's coming from the line $data["message"] = $args["message"];.
Am I looking right at the problem and not seeing it?
The function signature for the "error" closure is:
function ($request, $response, $args): Response
You're missing the first parameter in your code, so when you use $args, you're getting the Response object.

Using value from previous test case in PHPUnit

I am trying to assign a value to a variable inside the first testing function and then use it in other testing functions inside the class.
right now in my code the second function fails due to this error:
1) ApiAdTest::testApiAd_postedAdCreated
GuzzleHttp\Exception\ClientException: Client error: 404
and i dont know why. this is how the code looks like:
class ApiAdTest extends PHPUnit_Framework_TestCase
{
protected $adId;
private static $base_url = 'http://10.0.0.38/adserver/src/public/';
private static $path = 'api/ad/';
//start of expected flow
public function testApiAd_postAd()
{
$client = new Client(['base_uri' => self::$base_url]);
$response = $client->post(self::$path, ['form_params' => [
'name' => 'bellow content - guzzle testing'
]]);
$data = json_decode($response->getBody());
$this->adId = $data->id;
$code = $response->getStatusCode();
$this->assertEquals($code, 200);
}
public function testApiAd_postedAdCreated()
{
$client = new Client(['base_uri' => self::$base_url]);
$response = $client->get(self::$path.$this->adId);
$code = $response->getStatusCode();
$data = json_decode($response->getBody());
$this->assertEquals($code, 200);
$this->assertEquals($data->id, $this->adId);
$this->assertEquals($data->name, 'bellow content - guzzle testing');
}
in the phpunit doumintation https://phpunit.de/manual/current/en/fixtures.html i see i can define a
a variable inside the setUp method and then use it as i want but in my case i only know the value after the first post executes. any idea how can i use $this->adId in the second function??
Unit tests by definition should not rely on one another. You will end up with unstable and fragile tests which are then hard to debug the moment they start failing, since the cause is in another test case.
There is no guarantee in which order the tests execute in PHPUnit by default.
PHPUnit supports the #depends annotation to achieve what you want, the docs have the same warning though.

Categories