Carbon (laravel) deal with invalid date - php

I have a quite simple problem.. I use the Carbon::parse($date) function with $date = '15.15.2015'. Of course it can not return a valid string because there is no 15th month. But how can i "ignore" the error message?
Great would be something like
if (Carbon::parse($date) != error) Carbon::parse($date);
else echo 'invalid date, enduser understands the error message';

You can catch the exception raised by Carbon like this:
try {
Carbon::parse($date);
} catch (\Exception $e) {
echo 'invalid date, enduser understands the error message';
}
Later edit: Starting with Carbon version 2.34.0, which was released on May 13, 2020, a new type of exception is being thrown: Carbon\Exceptions\InvalidFormatException
So if you're using a newer version of Carbon, you can actually do this more elegantly
try {
Carbon::parse($date);
} catch (\Carbon\Exceptions\InvalidFormatException $e) {
echo 'invalid date, enduser understands the error message';
}
Thank you Christhofer Natalius for pointing this out!

Pass Laravel's validation before use it. Create a validator like this:
protected function validator(array $data)
{
//$data would be an associative array like ['date_value' => '15.15.2015']
$message = [
'date_value.date' => 'invalid date, enduser understands the error message'
];
return Validator::make($data, [
'date_value' => 'date',
],$message);
}
And call him right before use your date:
$this->validator(['date_value' => $date])->validate();
// $this->validator(request()->all())->validate(); you can pass the whole request if fields names are the same
Carbon::parse($date);
You can add all your desired fields to validator and apply multiple validations handling every message or using the default message. This would be the way if you are validating User's input

Try this
$birth_date = Carbon::createFromFormat('dmy', $birth_date_mark)->startOfDay();
if ($birth_date->format('dmy') !== $birth_date_mark) {
throw new OperationException(trans('exception.invalid_birth_date'));
}

another solution would be to handle the exception globally.
in app/Exceptions/Handler.php
use Carbon\Exceptions\InvalidFormatException;
then in the render method check if an exception is thrown by Carbon
if ($exception instanceof InvalidFormatException) {
return response()->json([
'status' => 'fail',
'data' => [
'message' => 'Invalid date formate!'
]
], 400);
}

Both try...catch... and validator is good. Sam's answer is good too.
In Laravel 8, I use following code:
// app/Exceptions/Handler.php
use Carbon\Exceptions\InvalidFormatException;
public function register()
{
$this->renderable(function (InvalidFormatException $e, $request) {
return response()->json([
'message' => 'Invalid date format!.'
], 400);
});
}
When InvalidFormatException thrown, Laravel will return http status 400 and json with message.
If you don't want to use try...catch... at every Carbon::parse() section, this is a good way to handle exception.

Related

Laravel custom exception

Before posting this question I have searched internet for appropriate answers but got none.These are my following questions:
1) How to throw exception without try catch in laravel controller and get exception in the view of the called controller.
Example : TestController.php
function index(){
throw new CustomException('Data not found');
return view('dashboard');
}
How to get exception message in dashboard view
2) How to set format for exception message, suppose I want to return format as
$response['code'] = 0;
$response['status'] = 'error';
$response['message'] = 'message';
$response['data'] = '';
I have created a custom exception but don't know how to use it to fully
<?php
namespace App\Exceptions;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Mockery\Exception;
class CustomException extends Exception{
public $response;
/**
* Report the exception.
*
* #return void
*/
public function report()
{
}
/**
* Render the exception into an HTTP response.
*
* #param \Illuminate\Http\Request
* #return \Illuminate\Http\Response
*/
public function render($request,$exception){
ob_clean();
$response['code'] = 0;
$response['status'] = 'error';
$response['message'] = 'Message';
$response['data'] = '';
if(!$request->ajax()){
// non ajax response
}else{
return response()->json($response);
}
}
}
Answering your questions:
To pass this exception to view, you can implement render method what you already started to do. You can just do:
if(!$request->ajax()){
view('error_handler', compact('exception'))
} else {
return response()->json($response);
}
so now you can just create error_handler.blade.php view and you will have access in there to $exception variable, so you can use in there {{ $exception->getMessage}} and so on
You didn't define what exactly you want to achieve, however it should work without any problem:
public function render($request,$exception) {
if(!$request->ajax()){
view('error_handler', compact('exception'))
}
return response()->json([
'code' => $exception->getCode(),
'status' => 'error',
'message' => $exception->getMessage(),
'data' => 'sample data'
]);
}
Of course instead of using $exception->getCode() for code you can put anything you want, this is just an example that you can also use code and message that you have in your exception assuming you set some custom when you throw exception for example:
throw new CustomException('This is custom message', 123);
There isn't realy reason to thrown an exception if your purpose is to show the message of that exception within the view which is rendered by the controller. And It isn't a best way to manage exception, because by default all exception which are throw are handle and catch within the App\Exceptions\Handler class.
I think you know exactly when that type of CustomExption you have create will be thrown, but instead of throwing that error just traite that error which need an exception in different way without exception. For that you can create an Array in which old code, status, message, data and pass it to the view method;
class CustomController extends Controller
{
public function samemethod(){
// some code that can generate an error
// construct the error data
$customErrorData = [
'code' => 0000,
'status' => "some status",
'message' => "Some error message",
'data' => [...]
];
// After error data creation you can pass it to the view
return View::make('customview', compact('customErrorData'));
}
}
You have you error data in your view
All uncaught exceptions are intercepted by default exceptions handler. If you want this to behave differently, you just need to modify it: https://laravel.com/docs/5.7/errors#the-exception-handler

Customize Laravel API validation responses

I'm building a REST API with Laravel and wondering if there is a way to customize the API responses when validating.
For example, I have a validation rule in a Laravel request, saying a specific field is required.
public function rules() {
return [
'title'=>'required|min:4|max:100',
];
}
So, for this validation I get the error message in Postman like this
{
"title": [
"Please enter Ad Title"
]
}
What I want is to customize that response like this..
{
"success": false,
"message": "Validation Error"
"title": [
"Please enter Ad Title"
]
}
So, that the error is more specific and clear.
So, how to achieve this ?
Thanks!
I got a solution for your REST-API Validation Laravel FormRequest Validation Response are change by just write a few lines of code.
enter code here
Please add this two-line into your App\Http\Requests\PostRequest.php
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
after that add this function in your file.
you can change $response variable into your specific manner.
protected function failedValidation(Validator $validator) {
$response = [
'status' => false,
'message' => $validator->errors()->first(),
'data' => $validator->errors()
];
throw new HttpResponseException(response()->json($response, 200));
}
Provide a custom function to the FormRequest class called messages and return an array of validation messages mapped using dot notation for specific messages on specific rules:
public function messages()
{
return [
'title.required' => 'Please enter an Ad title',
'title.min' => 'Your title must be at least 4 character'
]
}
Returning a success message is futile as if it fails a 422 error code will be thrown when performing an ajax request anyway.
As for the message property, you will receive that as part of the payload, wherein the actual validation errors will be contained in the object.
You can customize errors, check the documentation. also you can validate in this way
$validator = Validator::make($request->all(), [
'title'=>'required|min:4|max:100'
]);
if ($validator->fails()) {
// get first error message
$error = $validator->errors()->first();
// get all errors
$errors = $validator->errors()->all();
}
then add them to your response, for example
return response()->json([
"success" => false,
"message" => "Validation Error"
"title" => $error // or $errors
]);

Slim3/DRY - How to handle errors/exceptions correctly without duplicating code?

I'm working on a fairly large JSON API using Slim3. My controllers/actions are currently littered with the following:
return $response->withJson([
'status' => 'error',
'data' => null,
'message' => 'Username or password was incorrect'
]);
At certain points in the application anything can go wrong and the response needs to be appropriate. But one thing that is common is the error responses are always the same. The status is always error, the data is optional (in the case of form validation errors data will contain those) and message is set to indicate to the user or consumer of the API what went wrong.
I smell code duplication. How can I reduce the code duplication?
From the top of my head all I could think of doing was creating a custom exception, something like App\Exceptions\AppException that takes option data and the message will be obtained form $e->getMessage().
<?php
namespace App\Exceptions;
class AppException extends Exception
{
private $data;
public function __construct($message, $data = null, $code = 0, $previous = null)
{
$this->data = $data;
parent::__construct($message, $code, $previous);
}
public function getData()
{
return $this->data;
}
}
Following that create middleware that calls $next wrapped in a try/catch:
$app->add(function($request, $response, $next) {
try {
return $next($request, $response);
}
catch(\App\Exceptions\AppException $e)
{
$container->Logger->addCritical('Application Error: ' . $e->getMessage());
return $response->withJson([
'status' => 'error',
'data' => $e->getData(),
'message' => $e->getMessage()
]);
}
catch(\Exception $e)
{
$container->Logger->addCritical('Unhandled Exception: ' . $e->getMessage());
$container->SMSService->send(getenv('ADMIN_MOBILE'), "Shit has hit the fan! Run to your computer and check the error logs. Beep. Boop.");
return $response->withJson([
'status' => 'error',
'data' => null,
'message' => 'It is not possible to perform this action right now'
]);
}
});
Now all I have to do at points in the code is to throw new \App\Exceptions\AppException("Username or password incorrect", null).
My only issue with this is it feels like I'm using exceptions for the wrong reasons and it may make debugging a little more difficult.
Any suggestions on reducing the duplicates and cleaning up error responses?
You can achieve similar similar results by creating an error handler which outputs JSON.
namespace Slim\Handlers;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
final class ApiError extends \Slim\Handlers\Error
{
public function __invoke(Request $request, Response $response, \Exception $exception)
{
$status = $exception->getCode() ?: 500;
$data = [
"status" => "error",
"message" => $exception->getMessage(),
];
$body = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
return $response
->withStatus($status)
->withHeader("Content-type", "application/json")
->write($body);
}
}
You must also configure Slim to use your custom error handler.
$container = $app->getContainer();
$container["errorHandler"] = function ($container) {
return new Slim\Handlers\ApiError;
};
Check Slim API Skeleton for example implemention.

Catch not found error by certain route prefix [Laravel]

I'm building web api along side with website in laravel 5.2, when user visit unavailable url on my web like http://stage.dev/unavailable/link then it will throw on 404 page on errors view resource, then i want to catch with different way if user try to access my API with unavailable url like http//stage.dev/api/v1/unavailable/link, then i want to return json/xml response
{
'status' : 'not found',
'code' : 404,
'data' : []
}
not the view, is there a way to detect it by url prefix 'api/*' or how.., maybe another approach with similar result, so the device/client which access it could proceed by standard format (i have simple format in all json response)
{
'status' : 'success|failed|restrict|...',
'api_id' : '...',
'token' : '...',
'data' : [
{'...' : '...'},
{'...' : '...'},
...
]
}
SOLVED
I figure out something after read answer from Chris and Alexey this approach works for me i add couples of lines in handler.php at render() method,
if($e instanceof ModelNotFoundException || $this->isHttpException($e)) {
if($request->segment(1) == 'api' || $request->ajax()){
$e = new NotFoundHttpException($e->getMessage(), $e);
$result = collect([
'request_id' => uniqid(),
'status' => $e->getStatusCode(),
'timestamp' => Carbon::now(),
]);
return response($result, $e->getStatusCode());
}
}
my header request respond 404 error code and return json data like i want..
Maybe there's a better way to do that, but you could create custom error 404 handler. Follow this tutorial, but change case 404 part to something like this:
if(str_contains(Request::url(), 'api/v1/')){
return response()->json(your_json_data_here);
}else{
return \Response::view('custom.404',array(),404);
}
Inside App\Exception\Handler.php you have a render method which can be handy for general purpose error catching and handling.
In this case you can also use the request()->ajax() method to determine if it's ajax. It does this by checking that certain headers are present, in particular:
'XMLHttpRequest' == $this->headers->get('X-Requested-With')
Anyway, back to the render method in Handler.php.
You can do something like:
public function render($request, Exception $e)
{
if($e instanceof HttpException && $e->getStatusCode() == 404) {
if (request()->ajax()) {
return response()->json(['bla' => 'foo']);
} else {
return response()->view('le-404');
}
}
return parent::render($request, $e);
}
I figure out something after read answer from Chris and Alexey this approach works for me i add couples of lines in handler.php at render() method,,
if($e instanceof ModelNotFoundException || $this->isHttpException($e)) {
if($request->segment(1) == 'api' || $request->ajax()){
$e = new NotFoundHttpException($e->getMessage(), $e);
$result = collect([
'request_id' => uniqid(),
'status' => $e->getStatusCode(),
'timestamp' => Carbon::now(),
]);
return response($result, $e->getStatusCode());
}
}

Laravel Model Error Handling when Creating

I want to use Eloquent to create a DB entry like this:
MFUser::create(array(
'user_reference' => $this->userReference,
'first_name' => $this->firstName,
'last_name' => $this->lastName,
'user_type_id' => $this->userTypeId,
'email' => $this->email,
'password' => $this->password
));
It works well, except for the case, when exactly the same data is put into the fields, which is expected, as there should be no duplicate. I get the QueryExecption then.
But how do I properly perform error handling here to check if this query exception occurs so I can return a response from my server to the client via json then?
Just wrap that code in a try-catch block. Something like this:
try {
MFUser::create(array(
'user_reference' => $this->userReference,
'first_name' => $this->firstName,
'last_name' => $this->lastName,
'user_type_id' => $this->userTypeId,
'email' => $this->email,
'password' => $this->password
));
} catch (\Illuminate\Database\QueryException $exception) {
// You can check get the details of the error using `errorInfo`:
$errorInfo = $exception->errorInfo;
// Return the response to the client..
}
I prefer to reserve try/catch's for unexpected events that can't be handled elsewhere. In this case, you can utilise validation as a first measure, and the exception handler as a backup measure.
If the form request fails, the error messages are flashed and the user is returned to the previous page (where the form was submitted) and you can handle the messages gracefully. Validation requests
// First line of defence - gracefully handle
// Controller
public function store(MFUserRequest $request)
{
// The incoming request is valid...
MFUser::create(array(...));
}
// Form Request
class MFUserRequest extends Request
{
public function rules()
{
return [
'email' => 'required|email|unique:users,email',
];
}
}
Elsewhere, in your App\Exceptions directory you have the exception handler class that can be a catch all for various errors. Use this, when you haven't been able to gracefully handle it further down.
// Second line of defence - something was missed, and a model was
// created without going via the above form request
namespace App\Exceptions;
class Handler extends ExceptionHandler
{
public function render($request, Exception $e)
{
if($e instanceof QueryException) {
// log it or similar. then dump them back on the dashboard or general something bad
// has happened screen
return redirect()->route('/dashboard');
}
}
}
Simply make use of try / catch block.
use Illuminate\Database\QueryException;
// ...
try {
// DB query goes here.
} catch (QueryException $e) {
// Logics in case there are QueryException goes here
}
// ...
Try and Catch something might help u and imagine for create try catch for all of them, but have best practice to handle all of QueryException, my recommend is use Laravel Exceptions Handler because it's make u easy for make execption global!
let's try it!, open App\Exception\Handler.php and at render method u can write like this one
public function render($request, Throwable $exception)
{
if ($request->ajax() || $request->wantsJson()) {
if ($exception instanceof QueryException) {
// example algo for make response
return response()->json(['message' => 'xxx'], 403);
}
}
return parent::render($request, $exception);
}
after that, u can get xxx json for every error request triggered by Query

Categories