SkillAgentSearch skills...

Permalink

Database routing just like WordPress permalinks for Laravel

Install / Use

/learn @IsraelOrtuno/Permalink
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Advanced Laravel Permalinks and SEO Management from Database

Build Status Latest Stable Version

2021-08-25: Looking for maintainer

Despite it's pretty stable, I do not have time to keep maintaining this package for future Laravel releases and add more features so I am looking for anyone who found this useful and would like to maintain it. Feel free to contact! israel@devio.es


This package allows to create dynamic routes right from database, just like WordPress and other CMS do.

IMPORTANT Despite the functionality of this package is not complex at all, there are a few things and good practices to consider. I really recommend to carefully read the entire documentation to deeply understand how this package works as you will be replacing the default Laravel Routing System and do not want to mess up with your URLs and SEO!

Roadmap

Documentation

Installation

Install the package

composer require devio/permalink

Run the migrations

php artisan migrate

Getting started (PLEASE READ)

This package handles dynamic routing directly from our database. Nested routes are also supported, so we can easily create routes like this /jobs/frontend-web-developer.

Most of the solutions out there are totally bound to models with polymorphic relationships, however that's not flexible at all when dealing with routes without models. This package supports both, routes with bound models and regular routes.

Basically, the package stores routes in a permalinks table which contains information about every route:

  • Slug
  • Parent (parent route for nesting)
  • Model (if any)
  • Action (controller action or model default action)
  • SEO options (title, metas...)

By default, this package will try to find if there's a a permalink in the permalinks table matching the current request path in a single SQL query. This is ok for most of the use cases. If for some reason you want to cache your permalinks information into the Laravel Routing Cache, please refer to the Caching Permalinks section.

Example

Let check out a very basic example to understand how it internally works:

| id | slug | parent_id | parent_for | entity_type | entity_id | action | final_path | | -- | ------------- | --------- | ---------- | ------------------ | ---------------- | -------------------- | --------------------- | | 1 | users | NULL | App\User | NULL | NULL | UserController@index | users | 2 | israel-ortuno | 1 | NULL | App\User | 1 | UserController@show | users/israel-ortuno

It will run the following (this example tries to be as explicit as possible, internally it uses eager loading and some other performance optimizations):

$router->get('users', 'UserController@index');
$router->get('users/israel-ortuno', 'UserController@show');

// Which will produce:
//    /users                UserController@index
//    /users/israel-ortuno  

NOTE: The show method will receive the user as parameter App\User::find(1) the route is bound to that model.

Replacing the Default Router

This package has it's own router which extends the default Laravel router. To replace the default router for the one included in this package you have two options:

php artisan permalink:install {--default}

The console will propmpt you with 2 options:

  [0] Http/Kernel.php (Default & Recommended)
  [1] bootstrap/app.php (Advanced)

Select the one that fits your needs. For most cases I recommend going through Http\Kernel.php. Use the --default option to avoid blocking prompts (could also use the default Laravel command's flag --no-interaction).

Both of these methods will replace the default Laravel Router by an extended version provided by this package which contains the Permalink management logic.

IMPORTANT: Use either Http\Kernel.php or bootstrap/app.php. Do not use both as it may cause unexpected behaviour.

Creating Permalinks

That's pretty much it for setting up the dynamic routing system. Let's create a Permalink record and test it out!

Permalink::create([
    'slug' => 'home',
    'action' => 'App\Http\Controllers\HomeController@index'
]);
// Then visit /home

If your permalink is bound to a model (read next section), you may create your permalink record as follows:

// Note: when using the User::create method, even if permalinkHandling (read more about it below)
// is disabled, it will create the permalink record.
$user = User::create([
    'name' => 'israel',
    'permalink' => [
        'slug' => 'israel-ortuno',
        'action' => 'user.show',
        'seo' => [...] // omit this attribute until you read more about it
    ]
]);

// Or

$user->createPermalink([...);

If you do not provide any data to the permalink key when using User::create or createPermalink, it will automatcally use the default data. Any existing key in the data array will override its default value when creating the permalink.

NOTE: This will only work if permalinkHandling has not been disabled, read more about it below.

Updating Peramlinks

You can easily update a permalink just like any other Eloquent model. BE CAREFUL when updating a permalink slug as the previous URL won't be available anymore and this package does not handle 301/302 redirections.

Rebuilding Final Path (PLEASE READ)

When updating a slug, the package will recursively update its nested permalinks final_url attribute reemplacing the previous slug semgment with the new one. You can control this behaviour from the rebuild_children_on_update option in your config/permalink.php config file. Disable this option if you wish to handle this task manually (NOT RECOMMENDED).

Check out Devio\Permalink\Services\PathBuilder class to discover the methods available for performing the manual update.

NOTE: Make sure to rebuild childen's final path in the current request lifecycle.

Binding Models to Permalinks

You may want to bind a permalink to a model resource, so you can create a unique URL to access that particular resource. If you want to do so, you just have to use the tait HasPermalinks and implement the contract Permalinkable to your model.

class User extends Model implements \Devio\Permalink\Contracts\Permalinkable;
{
    use \Devio\Permalink\HasPermalinks;
    
    public function permalinkAction()
    {
        return UserController::class . '@show';
    }

    public function permalinkSlug(): array 
    {
        return ['entity.name'];
    }
}

Once you have this setup, this package will generate a permalink for every new record of this model automatically.

Also, the Permalinkable interface will force you to define two simple methods:

permalinkAction()

This method will return the default controller action responsible for handling the request for this particular model. The model itself will be injected into the action (as Laravel usually does for route model binding).

public function show($user)
{
    return view('users.show', $user);
}

NOTE: This action will be overwritten by any existing value on the action column in your permalink record, so you could have multiple actions for the same model in case you need them.

permalinkSlug()

This method is a bit more tricky. Since all the slugging task is being handled by the brilliant Sluggable package, we do have to provide the info this package requires on its sluggable method.

The permalink model will expose an entity polymorphic relationship to this model. Since the slugging occurs in the Permalink model class, we do have to specify which is going to be the source for our slug. You can consider entity as $this, so in this case entity.name would be equivalent to $this->name. Return multiple items if you would like to concatenate multiple properties:

['entity.name', 'entity.city']

NOTE: This method should return an array compatible with the Sluggable package, please check the package documentation if you want to go deeper.

Automatically Handling Permalinks

By default, this package takes care of creating/updating/deleting your permalinks based on the actions performed in the bound model. If you do not want this to happen and want to decide when decide the precise moment the permalink has to be created/updated/deleted for this particular model. You can disable the permalink handling in two ways:


// Temporally disable/enable:
$model->disablePermalinkHandling();
$model->enablePermalinkHandling();

// Permanent disable or return a condition.
// Create this method in you mode

Related Skills

View on GitHub
GitHub Stars65
CategoryData
Updated5mo ago
Forks13

Languages

PHP

Security Score

92/100

Audited on Oct 28, 2025

No findings