Carlos
Carlos

Reputation: 1331

Laravel 5.3 Exception handling in nested methods

I just ran into a problem where i can't seem to find a proper way of handling. I know this is a stupid example, but its the fastest i could think of.

UserController

trait SaveUser;

public function example(Request $request){
    $user = $this->saveUser($request->name);
    return $user;
}

Trait SaveUser;

public function saveUser($name){

    $is_valid = $this->validateUser;
    if(!is_valid) return response()->json(['data' => null,'message' => "please enter a name for the user",],500);
    try{
        $user = new User();
        $user->name = $name;
        $user->save()

        return $user;

    }catch(\Exception $e){
        return response()->json(['data' => null,'message' => "error saving the user.",],500);
    }
}

private function validateUser($name){
    if($name == null)
        return false;

    return true;

}

Lets say i am saving a user, requesting the name from the api request. I send it to a trait because its going to be used in many places, if the user name is not valid, it returns a json response saying it needs to be set, else if an error occurs while saving the user, return a code 500 response. Now this is a simple example, on my case, i have the validate method validate many other things and each have a unique message for a response, same for attributes of the user, etc..

So pretty much my problem is, that when the try catch catches an execption or something is not valid, it returns return response()->json(['data' => null,'message' => "error saving the user.",],500); to the $user in the UserController variable. What i would like it to do is, end my code in the exception or in the return response()-> and return the response. Is there anyway i can just end the code anywhere that i have return response()->...?

I am using this in an API, this is just a quick example. Any help would be appreciated. Thanks

Upvotes: 0

Views: 1430

Answers (2)

user1669496
user1669496

Reputation: 33148

I really don't mean any offense by this but this seems to be a case where you are trying to cover up bad practices with more bad practices.

Your first problem is trying to return responses from methods which aren't in your routes file. You can do this and it should work just fine because in your example, your just returning that response anyway which is being stored in the $user variable.

The cover-up for this which you are asking for is how to now handle functions returning either Response objects or User objects. So you would essentially have to use instanceof to determine if this object is a Response or User. if it's a response, return it, otherwise, keep doing more work.

This isn't terrible because you only have to add a few more conditions but I don't think it's a road you want to start going down because it has potential to snowball from there and create very un-maintainable code.

I'd suggest you start thinking about it this way. Why is the saveUser function worried about validating the user when we already have a validateUser function. Let the function which is being called by the routes do all the "controlling" and let your other functions do just what they were intended to do and nothing else. They should basically just act as helper functions to separate out different parts of your logic.

There are many ways to handle this but I'd suggest something like the following.

public function example(Request $request)
{
    //  Do all the "controlling" in this function, other functions should just be handling all the business logic.
    if (! $this->validateUser($request->name)) {
        return response()->json(['data' => null,'message' => "please enter a name for the user",],500);
    }

    try {
        $user = $this->saveUser($request->name);
    } catch (Exception $e) {
        return response()->json(['data' => null,'message' => "error saving the user.",],500);
    }

    // Here we know this will always be a User object.
    return $user;
}

public function saveUser($name)
{
    $user = new User();
    $user->name = $name;
    $user->save();

    return $user;
}

private function validateUser($name)
{
    if($name == null) {
        return false;
    }

    return true;
}

Upvotes: 2

rtgnx
rtgnx

Reputation: 46

I am pretty sure the only way to return response to the user is by returning it from function/method called by Router.

So the "cleanest" way would be to have another variable with error response either passed by reference or from returned array and if there's error return it instead of user object

UserController

public function example(Request $request){
$err = NULL;
$user = $this->saveUser($request->name, $err);

return ($err != NULL) ? $err : $user;
}

SaveUser

 public function saveUser($name, &$err){

$is_valid = $this->validateUser;
if(!is_valid)
    $err = response()->json(['data' => null,'message' => "please enter a name for the user",],500);
try{
    $user = new User();
    $user->name = $name;
    $user->save()

    return $user;

    }catch(\Exception $e){
    $err =  response()->json(['data' => null,'message' => "error  saving the user.",],500);
    }
}

private function validateUser($name){
   if($name == null)
       return false;

   return true;

}

Upvotes: 1

Related Questions