Laravel polymorphic route model binding

ou can use a shared controller for this with some explicit model binding. The following is untested code, it provides the general idea rather than copy and pasteable. Let me know if you run into any issues.

  1. Create a new CommentableModel that extends Model

  2. Extend Photo and Video from CommentableModel instead of Model

  3. Create a controller, and in your create method typehint CommentableModel $commentable — so within the method you do $commentable->comments->create()

  4. Create a new global routing constraint which is a regular expression for your commentable types, e.g: Route::pattern('commentableType', 'photo|video')

  5. Create your route for your controller, using your global constraint, e.g: Route::get('comments/{commentableType}/{commentable}/create', 'CommentableController@create');

  6. Create your explicit route model binding which uses the commentable parameter to determine the model type, e.g:

    Route::bind('commentable', function ($id) {
        $type = app()->request->route('commentableType');
        $models = ['video' => Video::class, 'photo' => Photo::class];
        $model = $models[$type];
        return (new $model)->where('id', $id)->firstOrFail(); // you could use findOrFail here if you're using IDs instead of slugs but I used where just as an example
    });

Then when a user visits https://www.example.com/comments/photo/1/create your create method on CommentableController will be called, with the Photo of ID 1 injected as the CommentableModel.

Note: you could improve this code by creating a configuration that contains your commentable models and their keys, and from there you could pull that in to both your route constraint and model binding, that would produce more maintainable code. Stick both the route binding and constraints in a service provider just for the commentable code.