Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

elemkeh's avatar

Command to generate standardized controllers, models, views?

I was reading through the Laravel docs on creating new Artisan commands and some uses cases immediately sprang to mind. There are components I build that have extremely similar functionality from app to app, and which it seems like could be streamlined by extending existing commands, but the documentation wasn't enough for me to understand how I might do this. Let me give you an example.

One of the most common components is a blogging function. Almost invariably, I use Artisan to create a Post model with a migration, then I build a --resource type PostController for the back-end and a standard type ArticleController for the front-end, and each consistently features the same functionality--the PostController's index method always looks like this:

public function index() { $posts = Post::orderBy('id', 'desc')->paginate(5); return view('posts/index')->withPosts($posts); }

And the PostController also always has the auth middleware in its constructor since the CRUD views are only available to the logged-in user. The CRUD views themselves also have repetitive features such as the Create view always having a form that has inputs for a title, a slugline, a category, tags, and body-text. The migrations, too, always feature definitions for these same properties to go into the database.

Currently, I just copy this code over from a standing boilerplate directory, but what I'd like to do is have a command that writes this code into the appropriate files after calling the built-in artisan commands that generate the files in the first place. So, a hypothetical php artisan make:PostModule would not just create a Post model with a migration, the two associated controllers, and the four CRUD views, but would write the code I want to them automatically. How would I go about doing this?

0 likes
1 reply
kubaszymanowski's avatar

First, you should take a look at how it's currently done for models or controllers. Most of these make commands are in Illuminate\Foundation\Console namespace and are called *MakeCommand.

If you wan't, you can learn about Symfony Console component, I think Jeffrey has a video about it. It might help you understand the commands better.

It would be best if you could utilize existing Laravel commands, but I don't think that would work for you, because apart from creating a class you'd need to fill some methods with code.

The best option, I think, is to extend the GeneratorCommand class(like eg. ModelMakeCommand do) for each task of the process you mentioned and then call all of them from one wrapper command.

You'll need stubs Here's an example controller.plain.stub:

<?php

namespace DummyNamespace;

use Illuminate\Http\Request;
use DummyRootNamespaceHttp\Controllers\Controller;

class DummyClass extends Controller
{
    //
}

Notice the Dummy* keywords. These are replaced with the relevant content by the generator command. Let's assume you want to create a controller with the index method filled. Here's how the stub would look like:

<?php

namespace DummyNamespace;

use DummyModelNamespace\DummyModel;
use Illuminate\Http\Request;
use DummyRootNamespaceHttp\Controllers\Controller;

class DummyClass extends Controller
{
    public function index()
    {
        $DummyTableName = DummyModel::orderBy('id', 'desc')->paginate(5);
        
        return view('DummyTableName/index', compact('DummyTableName'));
    }
}

Then, you'll need to redefine the buildClass method inherited from GeneratorCommand:

protected function buildClass($name)
{
    $controllerNamespace = $this->getNamespace($name);

    $replace = [
        'DummyModelNamespace' => $this->modelNamespace,
        'DummyModel' => $this->modelName,
        'DummyTableName' => $this->tableName,
        "use {$controllerNamespace}\Controller;\n" => '',
    ];

    return str_replace(
        array_keys($replace), array_values($replace), parent::buildClass($name)
    );
}
  1. DummyModelNamespace. If the model you created is eg. App\Forum\Post, it would be App\Forum
  2. DummyModel would be then just Post
  3. DummyTableName will serve as view directory name and the variable name. If model is called Post, it would be posts. For this you can utilize the Model::getTable() method.

Last replacement is a cosmetic procedure to remove the use App\Http\Controllers\Controller; statement if the new controller is in the App\Http\Controllers namespace.

This method first calls the parent::buildClass() which refers to GeneratorCommand::buildClass and replaces DummyClass, DummyNamespace and DummyRootNamespace and then replaces the rest of Dummy keywords in the output of that call.

You'll probably follow similar procedure for all other commands and then join them in one wrapping command like this:

$this->call('make:foo', $fooArguments);
$this->call('make:bar', $barArguments);
$this->call('make:baz', $bazArguments);

Please or to participate in this conversation.