Cannot throw objects that do not implement Throwable - laravel

I am using Laravel 5.5. There is following class
vendor\laravel\framework\src\Illuminate\Routing\Middleware\ThrottleRequests.php
with Method Name: buildException
In, Laravel 5.4, I was able to return JSON in this method like below.
protected function buildException($key, $maxAttempts)
{
$retryAfter = $this->getTimeUntilNextRetry($key);
$headers = $this->getHeaders(
$maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
$retryAfter
);
return response()->json('429 Too many requests');
}
When I try to return JSON in above method using Laravel 5.5, it says
Cannot throw objects that do not implement Throwable
Now sure , how could I return JSON in Laravel 5.5 for above method

Well, you cannot do it like this now any more. You need to return exception class. But what you can do is returning some custom exception class and then in app/Exceptions/Handler.php in `render method you can add:
if ($e instanceof YourCustomException) {
return response()->json('429 Too many requests');
}
Of course if you really need, you can add your own implementation of handle method and instead of throwing exception you can return response directly in there but probably throwing custom exception and handling it in Handler class is better choice.

Related

How to call Service class function?

use App\Http\Controllers\ATransaction;
use App\Service\ATransactionServices;
class TransactionController extends Controller {
public function ATransaction(Request $request, ATransactionServices $ATransaction){
try {
$validated_request = $this->validateRequest($request);
} catch (ValidationException $exception) {
return redirect()->back()->withInput()->withErrors($exception->errors());
}
How to call my service class function to replace into
$validated_request = $this->validateRequest($request);
Can someone show me the right way?
You can traits concepts or can directly use DI ( dependency Injection ) to implement service into this class.
For traits, you can check How to create traits in Laravel
And if you want to use Dependency Injection then do something like:
public function __construct(ATransactionServices $aTransactionServices)
{
$this->aTransactionServices = $aTransactionServices;
}
Then inside the method you can directly use the service methods:
$this->aTransactionServices->methodName();
If you want to use method inside the try and catch than simplest way is to add them in controller.
class TransactionController extends Controller {
//This will help in directly injecting the service into the container
public function __construct(ATransactionServices $aTransactionServices)
{
$this->aTransactionServices = $aTransactionServices;
}
//Otherwise you can create a custom request to handle validations on the request level
public function ATransaction(Request $request){
try {
$validated_request = $this->aTransactionServices->validateRequest($request);
//Here you can setup the validation mechanism like custom status based validation e.g. $validated_request['status'] which can be true or false otherwise use validator instance to use $validated_request->fails() to check
if($validated_request->fails()) {
//Here pass the data and you can handle on catch how you want to send response
throw new Exception('Exception details or validator instance');
}
} catch (Exception $exception) {
return redirect()->back()->withInput()->withErrors($exception->errors());
}
}
But if your only purpose is to handle the validations than you can use custom request in laravel for validations handling: Custom Request
Hope this works for you and resolves your issue.
have a great day.
$validated_request = $ATransaction->validateRequest($request);

Laravel not calling report method in custom exception

Trying to use custom exception:
namespace App\Exceptions\Cloud;
use Exception;
class CantConfirmOrder extends Exception
{
public function report()
{
info('test exception');
}
}
But when I throwing it in tinker - nothing writes to log:
>>> throw new CantConfirmOrder('test');
[!] Aliasing 'CantConfirmOrder' to 'App\Exceptions\Cloud\CantConfirmOrder' for this Tinker session.
App\Exceptions\Cloud\CantConfirmOrder with message 'test'
Handler.php:
public function report(Throwable $exception)
{
parent::report($exception);
}
Does I need to call report() manually with try catch? I thinked it will be called automatically when I throwing.
In the context of an HTTP-request, the routing will pick this up and call the report method. So if you throw the error in a Controller method or another route action it should be called. You can try it in a test like this :
Route::get('x', fn() => throw new CantConfirmOrder('test)); $this->get('x');
The Route class/method that invokes the method is
https://laravel.com/api/9.x/Illuminate/Routing/Pipeline.html#method_handleException

Method render() is not being called when custom Laravel exception is thrown from view composer

Edited:
I have a custom exception with render method which is being called when I throw it e.g. from controller, but not being called when I throw it in View composer.
So when I do something like that
public function compose(View $view)
{
throw new CustomException();
}
and put dd() to exception render method
public function render()
{
dd('render is called');
}
I get no result.
If I log my exception directly, finds out that first the CustomException being thrown, then as the result I see ErrorException.
I found a place where it being thrown.
\Illuminate\View\Engines\CompilerEngine::handleViewException
protected function handleViewException(Exception $e, $obLevel)
{
$e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e);
parent::handleViewException($e, $obLevel);
}
I didn't found any mentions in Laravel docs about that case.
I found a tread on github with the same issue: https://github.com/laravel/framework/issues/24658
So the question is, is this expected? Is there any adequate way to avoid this behaviour?
Edit
So, as you know, any exception during view compilation is intercepted and rethrown as ErrorException or as FatalThrowableError.
What you can do is intercept ErrorException and check if ($e->getPrevious() instanceof \CustomException) if so, you do your code, else, let the handler continue.
So I've found working solution for myself.
I've extended CompilerEngine and added additional processing in order to not throw ErrorException when I don't want to.
The important thing is - your resulting Exception must be inherited from ErrorException. Otherwise you will face multiple calls to \App\View\Engines\CompilerEngine::handleViewException which can break your logic and write multiple log entities to your log file.

laravel: Argument 1 passed to App\Exceptions\CustomException::report() must be an instance of Exception,

I have created a custom exception class in Laravel 5.2. It works well till laravel 5.4.
When Im trying to use the same custom exception class with laravel 5.5 it is throwing following error.
Type error: Argument 1 passed to App\Utility\Exceptions\CustomException::report() must be an instance of Exception, none given, called in /var/www/html/bubbles/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php on line 102 {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Type error: Argument 1 passed to App\\Utility\\Exceptions\\CustomException::report() must be an instance of Exception, none given, called in /var/www/html/bubbles/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php on line 102 at /var/www/html/bubbles/app/Utility/Exceptions/CustomException.php:39)
Here is the custom exception class I've been using
<?php
namespace App\Utility\Exceptions;
use Illuminate\Support\Facades\Lang;
use Exception;
class CustomException extends Exception
{
private $error_code = NULL;
private $error_info = NULL;
function __construct($type = NULL, $errors = NULL)
{
$this->error_code = $type['error_code'];
$this->error_info = $errors;
$message = Lang::get('exceptions.'.$this->error_code);
parent::__construct($message, $type['code'], NULL);
}
public function report(Exception $exception)
{
parent::report($exception);
}
public function getErrorCode()
{
return $this->error_code;
}
public function getErrorInfo()
{
return $this->error_info;
}
}
// end of class CustomException
// end of file CustomException.php
Could anybody will explain me why it is throwing argument must be instance of exception ? Any help would be greatly appreciated.
My programming environment
PHP 7.0.1
Laravel 5.5
The exception handler in Laravel 5.5 checks if the exception has a report method, and if so, let the exception handle the reporting itself. This means that the handler will see your report method, and call $e->report();, but your report method requires a parameter.
This is done in Handler::report.
You either need to remove the parameter in your report method (it should be reporting itself; $this) if you want to use this functionality, or rename the method if you don't want Laravel to call it (and fail).
Relevant: Laravel 5.5 Adds Support for Custom Exception Reporting

Laravel 5 Invalid Custom Request - do not redirect

I have a custom Request Class on Laravel 5 which handles form inputs (POST). the thing is, I want to use the same request class for a GET method but instead of redirecting the user back to the original request URL (which causes an infinite) loop I want to throw an exception (if the request is not valid), how is that possible?
In your custom Request class, you can override the failedValidation method that is defined in the FormRequest class.
I.e. place this method in your Request class:
protected function failedValidation(\Illuminate\Validation\Validator $validator) {
throw new \Exception('Error processing request');
}
Overriding the response() method can also be used to return a preferred response, personally I have used this to return the errors in JSON form, all that was required to do this was to return a JsonResponse with the errors and response code:
public function response(array $errors)
{
return new JsonResponse($errors, 422);
}
You can add something like this in your request method:
if (Request::isMethod('get'))
{
//Here you can add your custom exception.
}
You can see the documentation for more info about this: http://laravel.com/docs/5.0/requests#other-request-information

Resources