Permalink
Database routing just like WordPress permalinks for Laravel
Install / Use
/learn @IsraelOrtuno/PermalinkREADME
Advanced Laravel Permalinks and SEO Management from Database
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
- [ ] Resources for visual SEO management (in progress)
Documentation
- Installation
- Getting Started
- Replacing the Default Router
- Creating a Permalink
- Updating a Permalink
- Binding Models to Permalinks
- Automatically Handling Permalinks
- Nesting Permalinks
- Deleting Permalinks
- Caching Permalinks
- Handling SEO Attributes
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
feishu-drive
353.3k|
things-mac
353.3kManage Things 3 via the `things` CLI on macOS (add/update projects+todos via URL scheme; read/search/list from the local Things database)
clawhub
353.3kUse the ClawHub CLI to search, install, update, and publish agent skills from clawhub.com
postkit
PostgreSQL-native identity, configuration, metering, and job queues. SQL functions that work with any language or driver
