Custom exceptions in CodeIgniter - codeigniter

I want to extend the exception class that returns custom message when getMessage is called.
class MY_Exceptions extends CI_Exceptions{
function __construct(){
parent::__construct();
}
function getMessage(){
$msg = parent::getMessage();
return "ERROR - ".$msg;
}
}
MY_Exceptions is placed in core folder. And the exception throwing / handling is as follows:
try{
throw new Exception('a message');
}catch (Exception $e) {
echo $e->getMessage();
}
The intention is to get "ERROR - a message". But it always returns "a message". When I try debugging, the control never goes to MY_Exception class. Is there anything that I am missing?

Create file core/MY_Exceptions.php
<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Exceptions extends Exception {
public function __construct($message, $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
// custom string representation of object
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; //edit this to your need
}
}
class MyCustomExtension extends MY_Exceptions {} //define your exceptions

Related

Laravel handle error that only thrown by controller

I am creating a logic where a controller can call another controller depend on Auth::user() role, but not all of controller shared same method, so i want if controller calling a method that does not exist it will throw a 404 not found.
here is my controller
class LokalController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
Public $controller;
public function __construct()
{
//$this->middleware('adminakses');
$this->middleware(function ($request, $next) {
$this->setController();
return $next($request);
});
}
public function setController()
{
$role = Auth::user()->role;
switch ($role)
{
case 'admin':
$this->controller = new \SIA\Http\Controllers\Admin\LokalController;
break;
case 'guru':
$this->controller = new \SIA\Http\Controllers\Guru\LokalController;
break;
case 'siswa':
$this->controller = new \SIA\Http\Controllers\Guru\LokalController;
break;
}
}
public function index()
{
return $this->controller->index();
}
for example Admin\LokalController has method A(), but Guru\LokalController doesn't, and if user logged in as guru and trying to cal method A() it should returning not found exception or something user understandable message, but currently showing BadMethodCallException method A() does not exist
The approach you're trying to work is achievable but I think it will be overwhelming in time.
public function index()
{
try {
$action = $this->controller . '#' . __FUNCTION__;
action($action);
} catch (Exception $e) {
abort('401', "Your Message");
}
}
How I'd do it instead is, I'd create a redirect path for the User model.
public function getRedirectPathAttribute() {
switch ($this->role) {
case 'admin':
return '/admin';
case 'guru':
return '/guru';
case 'siswa':
return '/siswa';
}
}
And then create a middleware to make the check, and if redirect is needed, I'd redirect using auth()->user()->redirect_path.
What do you think?
One option is to have a controller all this controllers inherits from that implement all methods by calling App::abort(404), and in each of the child classes implement the methods they need, stopping the methods in the parent classes from being called
class BaseController extends Controller{
public function a() {
App::abort(404);
}
}
class AdminController extends BaseController{
public function a() {
// to stuff for admin
}
}
Controllers inheriting from BaseController that don't implement a() will get 404, admin controller will not

share variables between methods laravel

i need help, to understand , how i can share variables between methods in the same controller?
In this case,i have the method imprimirFecha() and i need get values of the variable 'servicio' that i use in the method mostrandoFecha()
class ControllerReport extends Controller
{
public $desde ;
public $hasta;
public $servicio;
public function mostrandoFecha(Request $request){
global $servicio;
try{
$desde=($request->input('desde'));
$hasta=($request->input('hasta'));
$servicio = DB::table('mivista')
->whereBetween('fechap',array($desde, $hasta))->get();
$this->servicio=$servicio;
return view ('report.buscar_pagosFecha',compact('servicio'));
} catch (Exception $e){
return ('Error - ' . $e);
}
}
public function imprimirFecha(){
$servicio=$this->servicio;
$pdf = \PDF::loadView('report.buscar_pagosFechaPrint',$servicio);
return $pdf->stream('buscar_pagosFechaPrint.pdf');
}
}

How to return AJAX errors from a Laravel controller?

I am building a REST API with Laravel 5.
In Laravel 5, you can subclass App\Http\Requests\Request to define the validation rules that must be satisfied before a particular route will be processed. For example:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class BookStoreRequest extends Request {
public function authorize() {
return true;
}
public function rules() {
return [
'title' => 'required',
'author_id' => 'required'
];
}
}
If a client loads the corresponding route via an AJAX request, and BookStoreRequest finds that the request doesn't satisfy the rules, it will automagically return the error(s) as a JSON object. For example:
{
"title": [
"The title field is required."
]
}
However, the Request::rules() method can only validate input—and even if the input is valid, other kinds of errors could arise after the request has already been accepted and handed off to the controller. For example, let's say that the controller needs to write the new book information to a file for some reason—but the file can't be opened:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\BookCreateRequest;
class BookController extends Controller {
public function store( BookStoreRequest $request ) {
$file = fopen( '/path/to/some/file.txt', 'a' );
// test to make sure we got a good file handle
if ( false === $file ) {
// HOW CAN I RETURN AN ERROR FROM HERE?
}
fwrite( $file, 'book info goes here' );
fclose( $file );
// inform the browser of success
return response()->json( true );
}
}
Obviously, I could just die(), but that's super ugly. I would prefer to return my error message in the same format as the validation errors. Like this:
{
"myErrorKey": [
"A filesystem error occurred on the server. Please contact your administrator."
]
}
I could construct my own JSON object and return that—but surely Laravel supports this natively.
What's the best / cleanest way to do this? Or is there a better way to return runtime (as opposed to validate-time) errors from a Laravel REST API?
You can set the status code in your json response as below:
return Response::json(['error' => 'Error msg'], 404); // Status code here
Or just by using the helper function:
return response()->json(['error' => 'Error msg'], 404); // Status code here
You can do it in many ways.
First, you can use the simple response()->json() by providing a status code:
return response()->json( /** response **/, 401 );
Or, in a more complexe way to ensure that every error is a json response, you can set up an exception handler to catch a special exception and return json.
Open App\Exceptions\Handler and do the following:
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* #var array
*/
protected $dontReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
NotFoundHttpException::class,
// Don't report MyCustomException, it's only for returning son errors.
MyCustomException::class
];
public function render($request, Exception $e)
{
// This is a generic response. You can the check the logs for the exceptions
$code = 500;
$data = [
"error" => "We couldn't hadle this request. Please contact support."
];
if($e instanceof MyCustomException) {
$code = $e->getStatusCode();
$data = $e->getData();
}
return response()->json($data, $code);
}
}
This will return a json for any exception thrown in the application.
Now, we create MyCustomException, for example in app/Exceptions:
class MyCustomException extends Exception {
protected $data;
protected $code;
public static function error($data, $code = 500)
{
$e = new self;
$e->setData($data);
$e->setStatusCode($code);
throw $e;
}
public function setStatusCode($code)
{
$this->code = $code;
}
public function setData($data)
{
$this->data = $data;
}
public function getStatusCode()
{
return $this->code;
}
public function getData()
{
return $this->data;
}
}
We can now just use MyCustomException or any exception extending MyCustomException to return a json error.
public function store( BookStoreRequest $request ) {
$file = fopen( '/path/to/some/file.txt', 'a' );
// test to make sure we got a good file handle
if ( false === $file ) {
MyCustomException::error(['error' => 'could not open the file, check permissions.'], 403);
}
fwrite( $file, 'book info goes here' );
fclose( $file );
// inform the browser of success
return response()->json( true );
}
Now, not only exceptions thrown via MyCustomException will return a json error, but any other exception thrown in general.
A simple approach is to use the abort() method in the controller. This will return an error that will be picked up by ajax error:function(){}
Controller Example
public function boost_reputation(Request $request){
$page_owner = User::where('id', $request->page_owner_id)->first();
// user needs to login to boost reputation
if(!Auth::user()){
toast('Sorry, you need to login first.','info');
abort();
}
// page owner cannot boost his own reputation
if(Auth::user() == $page_owner){
toast("Sorry, you can't boost your own reputation.",'info');
abort();
}
}
Ajax Example
$('.reputation-btn').on('click',function(event){
var btn = this;
var route = "{{ route('boost_reputation') }}";
var csrf_token = '{{ csrf_token() }}';
var id = '{{ $page_owner->id }}';
$.ajax({
method: 'POST',
url: route,
data: {page_owner_id:id, _token:csrf_token},
success:function(data) {
...your success code
},
error: function () {
...your error code
}
});
});
More info: https://laravel.com/docs/7.x/errors

Codeigniter when calling library method I get HTTP 500 error

I'm trying to create a library (in application/libraries) but I'm having problems when I call it from the controller.
Below is the code in the controller
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Client extends CI_Controller {
function __construct() {
parent::__construct();
$this->load->library('security');
}
function index() {
try {
$activation_code = 'aa';
$this->security->Check_User_By_ValidationCode($activation_code);
} catch (Exception $e) {
log('error', $e->getMessage());
}
}
}
?>
And this is what I have in the library
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Security {
var $CI;
public function __construct()
{
$this->CI =& get_instance();
}
public function Check_User_By_ValidationCode($activation_code) {
return $activation_code ;
}
}
?>
But I'm getting a "HTTP Error 500 (Internal Server Error): An unexpected condition was encountered while the server was attempting to fulfil the request." in Chrome.
I'm not able to get anything from logs so I can't tell what I'm doing wrong here.
Any clues?
Thanks
You cannot use the class security because that class is defined by CodeIgniter. Just change the name to something else, like "Auth" or something more descriptive.
See: http://ellislab.com/codeigniter/user_guide/libraries/security.html

set_exception_handler in codeigniter - how to use?

I have a code similar to the following which is not working.
class Abc extends CI_Controller {
static function exception_handler(Exception $ex)
{
var_dump($ex);
echo $ex->getMessage();
exit;
}
function __construct()
{
parent::__construct();
set_exception_handler('exception_handler');
}
function Index()
{
throw new Exception('hehe');
}
}
I get
A PHP Error was encountered
Severity: Warning
Message: set_exception_handler() expects the argument
(exception_handler) to be a valid callback
How to use set_exception_handler in codeigniter
Since exception_handler is a function inside a class, it should be:
set_exception_handler(array('self','exception_handler'));
Or
set_exception_handler(array('Abc','exception_handler'));
Set_exception_handler always expects full name class, including the namespace and omits the "use instruction" for use others namespaces.
In your case the fullname is: 'CI_Controller:exception_handler'
Therefore the correct call is: set_exception_handler('CI_Controller:exception_handler');
If you had one namespace e.g. namespace App;
The correct call is: set_exception_handler('App\CI_Controller:exception_handler');
function Index()
{
function ExceptionHandler($e) use($this)
{
$this->load->view('error', $this->sharedData);
}
set_exception_handler('ExceptionHandler');
throw new Exception('hehe');
}
You should use method of the instantiated Object with access level is public.
final class MyException
{
/**
* Constructor
* trigger getErrorTypesFromDefinedConstant method
*/
public function __construct()
{
// Set global exception handler
set_exception_handler(array($this, 'globalException'));
}
public function globalException($e)
{
// Your code to handle exception
}
}

Resources