Bene
Bene

Reputation: 56

Laravel: One Controller for multiple Models

I'm currently rebuilding my vanilla-PHP-App with Laravel and I have the following problem. I have multiple database-tables, that represent word categories (noun, verb, adverb, ...). For each table I created a separate Model, a route::resource and a separate resource-Controller. For example:

NomenController.php

public function show($id)
{
    $vocab = Nomen::find($id);
    return view('glossarium.vocab_update', compact('vocab'));
}

and

VerbController.php

public function show($id)
{
    $vocab = Verb::find($id);
    return view('glossarium.vocab_update', compact('vocab'));
}

...which are essentially the same except the Model class.

I don't want to create a separate Controller for each model, that does exactly the same. What would be the most simple and elegant way to solve this? Should I just create a VocabController.php and add a parameter for the Model-name like:

Route::resource('/vocab/{category}', 'VocabController');

and then add a constructor method in this controller like

public function __construct ($category) {
    if ($category == 'nomen') {
        $this->vocab = App\Nomen;
    }
    else if ($category == 'verb') {
         $this->vocab = App\Verb;
    }
}

I wonder if there is a simpler method to do that. Can I somehow do this with Route Model Binding?

Thanks in advance

Upvotes: 4

Views: 10167

Answers (2)

prateekkathal
prateekkathal

Reputation: 3572

Simply create a trait like this in App\Traits, (you can name it anything... Don't go with mine though... I feel its pretty lame... :P)

namespace App\Traits;

trait CommonControllerFunctions {

    public function show($id) {
        $modelObject = $this->model;

        $model = $modelObject::find($id);

        return view('glossarium.vocab_update', compact('model'));
    }

}

and in your NomenController and VerbController, do this:

use App\Traits\CommonControllerFunctions;

class NomenController {

    use CommonControllerFunctions;

    protected $model = Nomen::class;

}

and

use App\Traits\CommonControllerFunctions;

class VerbController {

    use CommonControllerFunctions;

    protected $model = Verb::class;

}

Note: Please note that this example is just a work-around for your particular situation only... Everyone practices code differently, so this method might not be approved by all...

Upvotes: 7

piotr
piotr

Reputation: 1282

I think the simpliest way it to create only one controller, eg VocabController with methods nomen, verb and whatever you want.

Routes:

Route::get('/vocab/nomen/{nomen}', 'VocabController@item');
Route::get('/vocab/verb/{verb}', 'VocabController@item');

And the model binding:

Route::model('nomen', 'App\Nomen');
Route::model('verb', 'App\Varb');

Then your method shoud look like that:

public function item($item)
{
    return view('glossarium.vocab_update', $item);
}

Keep in mind, that $item is already fetched model from the database.

Upvotes: 2

Related Questions