2

Let's say I have an URL like this:

/city/nyc   (display info about new york city)

and another like this:

/city/nyc/streets   (display a list of Street of nyc)

I can bind them to a method like this:

Route::get('city/{city}', 'CityController@showCity');
Route::get('city/{city}/streets', 'CityController@showCityStreet');

The problem is that I need to execute some checks on the city (for example if {city} is present in the database) on both methods. I could create a method and call them in both like this:

class CityController {

    private function cityCommonCheck($city) {
       // check
    }

    public function showCity($city) {
      $this->cityCommonCheck($city);

      // other logic
    }

    public function showCityStreet($city) {
      $this->cityCommonCheck($city);

      // other logic
    }
}

Is there any better way?

5
  • You could write a middleware for it Commented Mar 30, 2015 at 9:56
  • I don't think a middleware is the best option for this, I was thinking to put the check inside the constructor of the controller, but how can I access {city} from constructor? Commented Mar 30, 2015 at 10:01
  • 1
    Why do you think that? You can access {city} using the route facade Route::input('city') or by injecting the Router class $router->input('city') Commented Mar 30, 2015 at 10:04
  • Yes, in the __constructor i could use Route::input('city'); but maybe it'is better if we leave it off in a separate method (cityCommonCheck) so we can call it only on the route that we need Commented Mar 30, 2015 at 10:32
  • 1
    I don't get why you think this is not an appropriate use for middleware. It is exactly what middleware should be used for. Commented Mar 30, 2015 at 11:09

2 Answers 2

3

Even though you think differently, I believe a middleware is the best solution for this.

First, use php artisan make:middleware CityCheckMiddleware to create a class in App/Http/Middleware. Then edit the method to do what your check is supposed to do and add a constructor to inject the Router

public function __construct(\Illuminate\Http\Routing\Router $router){
    $this->route = $router;
}

public function handle($request, Closure $next)
{
    $city = $this->route->input('city');

    // do checking

    return $next($request);
}

Define a shorthand key in App/Http/Kernel.php:

protected $routeMiddleware = [
    'auth' => 'App\Http\Middleware\Authenticate',
    // ...
    'city_checker' => 'App\Http\Middleware\CityCheckerMiddleware',
];

Then, in your controller:

public function __construct()
{
    $this->middleware('city_checker', ['only' => ['showCity', 'showCityStreet']]);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Very interesting, but other than checks, my method return some data (the row of the city). I don't think I can tell to a middleware to pass that data to a controller, or can I?
Well you could work around this and pass it using the session or some kind of other global storage but that's not really the purpose of middleware. If you call your function to get some data then you should leave it in the controller or better move it to the model or a repository/helper class.
2

I think best way to do this, you can move common logic into a Model.So your code would like below.

class CityController {

  public function showCity($city) {
      City::cityCommonCheck($city);  
  }

  public function showCityStreet($city) {
    City::cityCommonCheck($city);
  }
}

model class

class City{
    public static function cityCommonCheck($city) {
      //put here your logic
    }
}

In this way you could invoke cityCommonCheck function from any controller.

1 Comment

Interesting, altho that's not much different from my solution, I can declare my method static too and call from anywhere

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.