Use auto generated UUID slugs to identify and retrieve your Eloquent models.

Overview

Laravel Eloquent UUID slug

Summary

About

By default, when getting a model from a controller using Route Model Binding, Laravel will try to find a model using the parameter in your route, and associate it to the default identifier of the related table (most of the time, this is the "id" key).

// routes/web.php

use App\Models\Cart;
use Illuminate\Support\Facades\Route;

// --> What you see
Route::get("/cart/{cart}", function(Cart $cart) {
  // $cart ready to be used
});

// --> What happens behind the scene
Route::get("/cart/{cart}", function(string $identifier) {
  $cart = Cart::findOrFail($identifier);

  // $cart ready to be used
});

This means if you offer the possibility to view your cart, you will expose the route /cart/12 for example. This is not ideal in terms of security because you now expose your cart database identifier, and if you forgot or made a mistake into your cart's policy, a malicious user can access the cart of other users (/cart/41).

In this context UUID are very useful because:

  • They offer a good way to create random, hard to predict identifiers
  • Can be manually generated from the code
  • Are not likely to collide

The best scenarios would be to expose this uuid instead of your database auto incremented identifier, like /cart/e22b86bcb8e24cfea13856a0766bfef2.

The goal of this package is to simplify at best this task for you.

Features

  • Provide a trait to configure your Route Model Binding to use a slug column
  • Provide an helper to create the slug column on your migration, according to your configuration
  • Provide a scope to find your model by the slug column
  • Allow you to customize the name of the slug column

Requirements

Installation

1. Install the package

composer require khalyomede/laravel-eloquent-uuid-slug

2. Setup your model

On the model of your choice, use the Sluggable trait.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Khalyomede\EloquentUuidSlug\Sluggable;

class Cart extends Model
{
  use Sluggable;
}

3. Add the slug column in your migration

The Sluggable trait offers the method Sluggable::addSlugColumn() to make this step a breeze for you.

use App\Models\Cart;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

final class CreateCartsTable extends Migration
{
  public function up(): void
  {
    Schema::create('carts', function (Blueprint $table): void {
      $table->id();
      $table->string('name');

      Cart::addSlugColumn($table);

      $table->timestamps();
    });
  }

  public function down(): void
  {
    Schema::drop('carts');
  }
}

Examples

1. Configure the slug column name

By default the Sluggable trait will assume the name of the slug column is slug. Here is how to provide one that you prefer.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Khalyomede\EloquentUuidSlug\Sluggable;

class Cart extends Model
{
  use Sluggable;

  public function slugColumn(): string
  {
    return 'code';
  }
}

2. Use dashes for the generated UUID

By default, the Sluggable trait will configure the UUID generator to remove dashes, to help make shorter URLs. If you prefer to keep them, here is how you can do it.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Khalyomede\EloquentUuidSlug\Sluggable;

class Cart extends Model
{
  use Sluggable;

  public function slugWithDashes(): bool
  {
    return true;
  }
}

3. Custom route model binding for specific routes

By default, all your models that use the Sluggable trait will retreive their model using the slug column when performing Route Model Binding.

If you would like to bypass it for specific routes, you can customize the column used to retreive your model occasionally.

For example, this is how to retreive your Cart model using its id for a specific route.

// routes/web.php

use App\Models\Cart;
use Illuminate\Support\Facades\Route;

// --> What you see
Route::get("/cart/{cart:id}", function(Cart $cart) {
  // $cart ready to be used
});

As a final resort, if this method does not work, you can always fallback to get the raw data from your route, and perform fetching your model yourself:

// routes/web.php

use App\Models\Cart;
use Illuminate\Support\Facades\Route;

// --> What you see
Route::get("/cart/{cart}", function(string $identifier) {
  $cart = Cart::findOrFail($identifier);

  // $cart ready to be used
});

4. Customize the slug column in your migration

You can use all the available column modifiers right after calling the method Sluggable::addSlugColumn(), to re-order the column or add some comments for example.

use App\Models\Cart;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

final class CreateCartsTable extends Migration
{
  public function up(): void
  {
    Schema::create('carts', function (Blueprint $table): void {
      $table->id();
      $table->string('name');

      Cart::addSlugColumn($table)
        ->after('name')
        ->comment('Auto-generated by a package.');

      $table->timestamps();
    });
  }

  public function down(): void
  {
    Schema::drop('carts');
  }
}

5. Retreive a model by its slug

To help you manually fetching a model by its slug, you can use the Sluggable::scopeWithSlug() scope to do it. It follows your configuration, so no matter how you named your slug column it will still work.

// routes/web.php

use App\Models\Cart;
use Illuminate\Support\Facades\Route;

Route::get("/cart/{cart}", function(string $identifier) {
  $cart = Cart::withSlug($identifier)->firstOrFail();

  // $cart ready to be used
});

Compatibility table

The table below shows the compatibility across Laravel, PHP and this package current version. For the compatibility regarding this package previous version, please browse another tag.

Laravel version PHP version Compatible
8.* 8.0.*
8.* 7.4.*
8.* 7.3.*
7.x *

To counter-check these results, you can use the Docker containers (see docker-compose.yml file) to run the tests described in the Tests section.

Alternatives

I created this package mostly to practice creating a tested laravel package, and toying with my first Github Workflow. There is some others high quality packages out there so make sure to take a look at them!

Tests

composer run install-checker
composer run test
composer run analyse
composer run check
composer run lint
composer outdated --direct
Comments
  • 15-calling-model-replicate-save-raise-an-exception

    15-calling-model-replicate-save-raise-an-exception

    Added

    • laravel/framework version upgrade

    Fixed

    • Calling $model->replicate()->save() will now work as expected (without raising a database duplicate error)

    Breaked

    N/A

    bug 
    opened by khalyomede 0
  • add ExistsBySlug form request

    add ExistsBySlug form request

    Use case:

    namespace App\Http\Requests;
    
    use App\Models\Posts;
    use Illuminate\Foundation\Http\FormRequest;
    use Khalyomede\EloquentUuidSlug\ExistsBySlug;
    
    class MyRequest extends FormRequest
    {
      public function rules()
      {
        return [
          "post" => "required|exists:slug", // before
          "post" => ["required", new ExistsBySlug(Post::class), // after (will dynamically get the "slug" column name for you)
        ];
      }
    }
    
    enhancement 
    opened by khalyomede 0
  • #2 add dropping slug column

    #2 add dropping slug column

    Added

    • New Sluggable::dropSlugColumn(Blueprint) to drop the slug column within a migration
    • New Sluggable::addUnconstrainedSlugColumn(Blueprint) to add the slug column without not null and unique SQL constraints within a migration
    • New Sluggable::fillEmptySlugs() to fill the slug column with slugs when this column has a null value

    Fixed

    N/A

    Breaking

    N/A

    enhancement 
    opened by khalyomede 0
  • 10-find-eloquent-model-by-slug

    10-find-eloquent-model-by-slug

    Added

    • New Sluggable::findBySlug(string) method, similar to Model::find(mixed)
    • New Sluggable::findBySlugOrFail(string) method, similar to Model::findOrFail(mixed)

    Fixed

    N/A

    Breaking

    N/A

    enhancement 
    opened by khalyomede 0
  • New ExistsBySlug validation rule

    New ExistsBySlug validation rule

    Instead of

    return [
      "post" => [
        "required", 
        new Exists(Post::class, "slug"),
      ],
    ];
    

    We have this rule which automatically finds the correct slug column name

    return [
      "post" => [
        "required", 
        new ExistsBySlug(Post::class),
      ],
    ];
    
    enhancement 
    opened by khalyomede 0
  • New firstBySlug and firstBySlugOrFail methods

    New firstBySlug and firstBySlugOrFail methods

    Current alternative, which forces the developer to hard code the slug column name, since Sluggable::getSlugColumn() is private:

    $slug = "...";
    $post = Post::withTrashed()->where("slug", $slug)->first();
    

    Expected:

    $slug = "...";
    $post = Post::withTrashed()->firstBySlug($slug);
    
    enhancement 
    opened by khalyomede 0
An opinionated package to create slugs for Eloquent models

Generate slugs when saving Eloquent models This package provides a trait that will generate a unique slug when saving any Eloquent model. $model = new

Spatie 1.1k Jan 4, 2023
Laravel package to generate and to validate a UUID according to the RFC 4122 standard. Only support for version 1, 3, 4 and 5 UUID are built-in.

Laravel Uuid Laravel package to generate and to validate a universally unique identifier (UUID) according to the RFC 4122 standard. Support for versio

Christoph Kempen 1.7k Dec 28, 2022
A simple drop-in solution for providing UUID support for the IDs of your Eloquent models.

Introduction A simple drop-in solution for providing UUID support for the IDs of your Eloquent models. Both v1 and v4 IDs are supported out of the box

GoldSpec Digital 501 Jan 4, 2023
Simple slugs for your Laravel models.

Simple slugs for your Laravel models. This packages provides an opinionated, attribute-driven trait for automatically generating slugs when creating L

Ryan Chandler 20 Aug 15, 2022
Auto-generated Interface and Repository file via Repository pattern in Laravel

Auto-generated Repository Pattern in Laravel A repository is a separation between a domain and a persistent layer. The repository provides a collectio

Ngo Dinh Cuong 11 Aug 15, 2022
This package provides a trait that will generate a unique uuid when saving any Eloquent model.

Generate slugs when saving Eloquent models This package provides a trait that will generate a unique uuid when saving any Eloquent model. $model = new

Abdul Kudus 2 Oct 14, 2021
Generate UUID for a Laravel Eloquent model attribute

Generate a UUIDv4 for the primary key or any other attribute on an Eloquent model.

Alex Bouma 4 Mar 1, 2022
Quickly identify controller methods with no route in your Laravel applications.

Orphan Controller Quickly identify controller methods with no route in your Laravel applications. Installation You can install the package via Compose

Ryan Chandler 16 Feb 18, 2022
Use UUID or Ulid as optional or primary key in Laravel.

Laravel OptiKey Use UUID or Ulid as optional or primary key in Laravel. composer require riipandi/laravel-optikey This package adds a very simple trai

Aris Ripandi 33 Nov 4, 2022
Retrieve the EC2 Metadata using Laravel's eloquent syntax.

Laravel EC2 Metadata Retrieve the EC2 Metadata using Laravel's eloquent syntax. ?? Supporting If you are using one or more Renoki Co. open-source pack

Renoki Co. 4 Dec 27, 2021
This package lets you add uuid as primary key in your laravel applications

laravel-model-uuid A Laravel package to add uuid to models Table of contents Installation Configuration Model Uuid Publishing files / configurations I

salman zafar 10 May 17, 2022
A system for auto-decorating models with presenters

Laravel Auto Presenter 7 This package automatically decorates objects bound to views during the view render process. Features Automatically decorate o

Laravel Auto Presenter 754 Dec 21, 2022
A laravel package to attach uuid to model classes

Laravel Model UUID A simple package to generate model uuid for laravel models Installation Require the package using composer: composer require touhid

null 10 Jan 20, 2022
Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes and constraints by adding them as a subquery.

Laravel Eloquent Scope as Select Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes an

Protone Media 75 Dec 7, 2022
Laravel 5.6 based quiz system - generated with QuickAdmin

LaraQuiz: Laravel 5.6 based quiz system It is a demo project for demonstrating what can be generated with QuickAdminPanel tool. LaraQuiz was mostly ge

Laravel Daily 216 Dec 12, 2022
An Eloquent Way To Filter Laravel Models And Their Relationships

Eloquent Filter An Eloquent way to filter Eloquent Models and their relationships Introduction Lets say we want to return a list of users filtered by

Eric Tucker 1.5k Jan 7, 2023
Laravel Ban simplify blocking and banning Eloquent models.

Laravel Ban Introduction Laravel Ban simplify management of Eloquent model's ban. Make any model bannable in a minutes! Use case is not limited to Use

cybercog 879 Dec 30, 2022
cybercog 996 Dec 28, 2022
Record created by, updated by and deleted by on Eloquent models automatically.

quarks/laravel-auditors Record created by, updated by and deleted by (if SoftDeletes added) on Eloquent models automatically. Installation composer re

Quarks 3 Jun 13, 2022