Back to Course |
How to Create Laravel Package: Step-by-Step Example

Models, Migrations, Artisan Commands

In our specific package case, we didn't need some features, but I do want to mention them and show you how to use them, in case your packages need them.


Eloquent Models

This one is pretty easy, you just create a Model class in the /src/Models of the package and namespace it correctly.

Then, your Controllers (or the Controllers outside the package) may just use the Model by loading it from the correct namespace.

packages/laraveldaily/laravel-permission-editor/src/Models/Task.php:

namespace Laraveldaily\LaravelPermissionEditor\Models;
 
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
 
class Task extends Model
{
use HasFactory;
}

And that's it, anyone can use this model in or outside the package:

app/Http/Controllers/TaskController.php:

use Laraveldaily\LaravelPermissionEditor\Models\Task;
 
class TaskController extends Controller
{
public function index()
{
return Task::all();
}
}

Database Migrations

DB Migrations are "publishable" assets, but you may use them in two ways: publish or load directly from the package.

First, you put the migration file into the database/migrations folder of the package:

packages/laraveldaily/laravel-permission-editor/database/migrations/2023_01_01_100000_create_tasks_table.php:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
return new class extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
 
public function down()
{
Schema::dropIfExists('tasks');
}
};

Then, the easiest way to use that migration is to have this in the Service Provider:

packages/laraveldaily/laravel-permission-editor/src/PermissionEditorServiceProvider.php:

class PermissionEditorServiceProvider extends ServiceProvider
{
public function boot()
{
if ($this->app->runningInConsole()) {
$this->publishes(...); // assets and config
 
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
}
}
}

Then, whenever someone runs php artisan migrate, the migrations from the package would be executed.

But, in some cases you do want to publish the migrations, so users of the package may edit them.

Then, in your Service Provider, do this:

packages/laraveldaily/laravel-permission-editor/src/PermissionEditorServiceProvider.php:

class PermissionEditorServiceProvider extends ServiceProvider
{
public function boot()
{
if ($this->app->runningInConsole()) {
$this->publishes(...); // assets and config
 
$this->publishes([
__DIR__ . '/../database/migrations/2023_01_01_100000_create_tasks_table.php' =>
database_path('migrations/' . date('Y_m_d_His', time()) . '_create_tasks_table.php'),
 
// More migration files here
], 'migrations');
}
}
}

As you can see, you need to publish migration files one by one, generating their filenames. Also, you need to be careful here and take care of the naming of the migration classes, so they would be in the correct sequence with timestamps.


Artisan Commands

What if you want to include a command like php artisan make:task in your package? If you've been following the course so far, it should be quite easy for you, as you noticed the patterns.

We create our Artisan command:

packages/laraveldaily/laravel-permission-editor/src/Commands/MakeTaskCommand.php:

namespace Laraveldaily\LaravelPermissionEditor\Commands;
 
use Illuminate\Console\Command;
 
class MakeTaskCommand extends Command
{
protected $signature = 'make:task';
 
protected $description = 'Make a new task';
 
public function handle()
{
// ... code to create the new task
 
return Command::SUCCESS;
}
}

Then, in the Service Provider, we register the command(s) with this method:

packages/laraveldaily/laravel-permission-editor/src/PermissionEditorServiceProvider.php:

use Laraveldaily\LaravelPermissionEditor\Commands\MakeTaskCommand;
 
class PermissionEditorServiceProvider extends ServiceProvider
{
public function boot()
{
if ($this->app->runningInConsole()) {
$this->publishes(...); // assets, config, migrations
 
$this->commands([
MakeTaskCommand::class,
]);
}
}
}

That's it, I think I've covered the main things you may need to create your package!

Of course, my examples are pretty simple, and in some cases, you may need a more complex structure with Interfaces, reusable Traits, and other elements, but those are more the topics of PHP OOP and not that much about package creation specifically.

That said, please feel free to ask any questions in the comments, and I may update the tutorial with more sections or lessons in the future.

Now, wait a minute...

So, the package is in our local Laravel project for now, how do we actually publish it globally, so others would be able to run composer require laraveldaily/laravel-permission-editor?

Let's do this in the next chapter.