Can I change a Laravel error message globally? - php

I can do stuff like this in the request.
public function messages()
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
But I still feel like I will repeat a lot of my code, cause in my case, I will also repeat many of the same error messages for different errors and fields. So is there a way to modify the required error, for example, for the scope of the whole project?

Related

Laravel test if the response contains errors?

I'm working on a legacy code and trying to use tests to cover the code for later refactoring. In one controller there's a piece of code like this:
return redirect()->route('login')->withErrors(['invalid credentials']);
Here are my assertions for the test:
$response->assertRedirect(route('login'));
$response->assertSessionHasErrors([
0 => 'invalid credentials'
]);
But the problem is I get the following output:
Session missing error: 'invalid credentials'
Failed asserting that false is true.
Any idea how can I get this done?
Looking at the source code of assertSessionHasErrors() I think it cannot be done with your use case. The problem is the unnamed array in your withErrors(...) method. I see two options for you:
Change your legacy application into:
return redirect()->route('login')->withErrors(['error' => 'invalid credentials']);
Afterwards you can run your test like so:
$response->assertRedirect(route('login'));
$response->assertSessionHasErrors([
'error' => 'invalid credentials'
]);
If you cannot change your legacy application you could use this:
$response->assertRedirect(route('login'));
$this->assertEquals(session('errors')->getBag('default')->first(),'invalid credentials');

PhpSpec test if log written with same data

I need to test if my application logs written with correct data (I know in most cases it's not very important to check logs, but it's very important in this specific case).
So log looks like this:
$this->logger->error(
'Invalid survey provided',
[
'exception' => $e,
'survey' => $survey
]
);
and in the spec I have a code:
$exception = new ValidationException(
sprintf(
'Provided survey "%s" does not have all required fields %s',
json_encode($surveysResponse['result'][0]),
json_encode(Survey::$requiredFields)
)
);
$logger->error(
'Invalid survey provided',
[
'exception' => $exception,
'survey' => $surveysResponse['result'][0]
]
)->shouldBeCalled();
and spec failing b-z mock not matching, but I'm sure that same error message with same survey and exception with same error message actually logged. I'm not able to tell you exact issue as error output is huge and trimmed. But I'm 90% sure it's failing while comparing exception object because exceptions are not exact the same objects.
This might be the wrong approach, because the log entry will not be the same due to different timestamps on the log entry. Just preg_match() the log file, spanning multiple lines, obviously with a wildcarded timestamp. Then it should be save to assume that they're "the same", when the count of returned matches equals two (assuming a truncated log file, to begin with). Check out \PHPSpec\Matcher .beTrue() in combination with said condition.

Show error page in Laravel?

Before I get into the question, I'll give you a brief introduction into what I want to do. I want to be able to show a friend;y view to users when a error happens in my Laravel project but unfortunately I don't know how to do this and was hoping some of you may be able to help me?
Hello. Today I am asking a question about Laravel. For a long time I have wanted to log EVERY single error in my laravel project. Now some of you may say that its easy, just overwrite the handle() method in the App\Exceptions\Handler class.
While that's relatively easy to do, it doesn't handle EVERY single error. I have noticed it doesn't handle Query exceptions.
What I am asking is how can I handle EVERY exception. What I mainly want to do is log the error in a database table, and disable a nice view to the end user. Then if I am the one, or another member of my team that receives the error, they can easily check in the database without having to show any critical details to the end user.
I followed this tutorial but it's the same, it doesn't log every single exception.
http://blog.sarav.co/registering-custom-exception-handler-laravel-5/
You can simply add some code in the App\Exceptions\Handler::render method, for example:
public function render($request, Exception $exception)
{
if($exception instanceof \Illuminate\Database\QueryException) {
// Do something with the $exception
// dd($exception); // analyze it
// return a response/redirect
}
return parent::render($request, $exception);
}
In this $exception instance, you can find many useful information using following methods (Omit magic methods, it's a dump of get_class_methods):
array:12 [▼
0 => "__construct"
1 => "getSql"
2 => "getBindings"
3 => "__wakeup"
4 => "getMessage"
5 => "getCode"
6 => "getFile"
7 => "getLine"
8 => "getTrace"
9 => "getPrevious"
10 => "getTraceAsString"
11 => "__toString"
]
Also, the property $exception->errorInfo will give you some information as well, for example (One particular errorInfo):
errorInfo: array:3 [▼
0 => "42S22"
1 => 1054
2 => "Unknown column 'ids' in 'field list'"
]
Note: FYI, error and exception are two different things so the set_error_handler and the set_exception_handler both are for different reasons, an error handler will not catch an exception.
Use set_error_handler to set custom exception. Or you could use log4php they have a package for laravel I believe.

Testing Exceptions in PHPUnit

I am new to unit testing and now trying to write some test cases using PHPUnit for a Laravel application. I have done one basic test which is like the following :
public function testGetPointsByApp()
{
$this
->json(
'GET',
self::URL.'/'.$value
)
->assertResponseStatus(200)
->seeJson([
'status' => 'success',
])
->seeJsonStructure([
'status',
'message',
'data' => []
]);
}
Now this is working. But I would like to know how can I test for invalid inputs and for the cases like there is not data at all with the given parameters. I am throwing corresponding exceptions in each of these cases and it will add particular messages. How can I test whether it is thrown ?
I don't want to include it to this method and would like to write some other methods to test different scenarios in the API like invalid UUID, no data etc. So for each time, I need to call the API url or this call can be done from any kind of set up function ?
I don't know laravel but in PHPUNIT you can test if exception is thrown with expectException function. For example for InvalidArgumentException
$this->expectException(InvalidArgumentException::class);
You can also use annotation #expectedException and there are also a lot of things that can be tested in exception like expectExceptionCode() etc.
More you can find here
Since you're not doing an Unit test (this kind of test you're doing is an acceptance test), you cannot check for the exception it self, you will look for a bad response:
$this
->json(
'GET',
self::URL.'/'.$BAD_VALUE
)
->assertResponseStatus(422)
->seeJson([
/* Whatever you want to receive at invalid request */
])
->seeJsonStructure([
/* Whatever you want to receive at invalid request */
]);
Laravel validation errors returns 422 - unprocessable entity HTTP code.
You can check the response also for your expected error messages or something else.

Laravel 4 always returns HTTP status code 200

I have below code in error.php, which is triggered using App::abort(404, $error) in my controller. Still my response status code is 200(ok). I tried with various error codes like 400, 403
// NotFoundException handler
App::error(function(NotFoundException $e)
{
$default_message = 'The requested resource was not found';
return Response::json(array(
'error' => $e->getMessage() ?: $default_message,
), 404);
});
For anyone still googling this problem:
I was struggling with this problem for hours. For me the problem was caused by an issue with one of my controllers.
Check all of your controllers and make sure there are no spaces in front of the <?php tag. The <?php tag should be the very first thing in the file. A single space in front of the <?php tag in any of your controllers that are routed as such:
Route::controller('example', 'ExampleController');
Will cause all status codes to be 200.
I believe, regardless, you should receive a 404 response, so there might be something else happening that's the result of code not included in your question.
That being said, the Exception class that is thrown for 404 is NotFoundHttpException rather than NotFoundException.
Since Laravel 4 uses Symfony's HttpKernal, that Exception is here.
You can see here where App::abort() throws NotFoundHttpException when a 404 is triggered.
Therefore, your code should look like:
// NotFoundHttpException handler
App::error(function(\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e)
{
$default_message = 'The requested resource was not found';
return Response::json(array(
'error' => $e->getMessage() ?: $default_message,
), 404);
});
Important: This will only fire for a 404 status, as that's the corresponding code to NotFoundHttpException. Other status codes return other Exception classes. To capture all HTTP status error codes exceptions, type hint for HttpException like so:
// HttpException handler
App::error(function(\Symfony\Component\HttpKernel\Exception\HttpException $e)
{
return Response::json(array(
'error' => $e->getMessage(),
), $e-> getStatusCode());
});
Lastly, consider using a bit of Content Negotiation when deciding to return JSON or HTML.
The solution didn't worked for me, so in case anyone is still looking for an answer, I thought it be best to put it here instead of creating another question.
After some time I had this problem too, in my app/Exceptions/Handler.php I had:
if ($e instanceof ModelNotFoundException) {
if ($request->ajax()) {
return response()
->json(['error' => ['No results']])
->header('status', 422);
}
}
This worked in my local environment, however, in the homolog environment (which reproduces the production environment, just to be clear) it didn't returned the correct status code.
After another look I started looking at Laravel's docs, and I changed the call to the following:
return response()
->json(['error' => ['No results.']], 422);
And that did the trick. Hope this can help.
In my case I found some space in front of <?php
Remove dump & other print functions
I was actively debugging when I noticed this issue. It was caused because I had dump(...) calls in the code at that time.
When I removed all my debug dump calls, the status code was correctly 404 again (using abort(404).

Categories