├── LICENSE.md ├── README.md ├── composer.json └── src ├── Hashid.php └── HashidRouting.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Matt Daneshvar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eloquent Hashids for Laravel 2 | [![Build Status](https://travis-ci.org/matt-daneshvar/eloquent-hashids.svg?branch=master)](https://travis-ci.org/matt-daneshvar/eloquent-hashids) 3 | ![GitHub](https://img.shields.io/github/license/matt-daneshvar/eloquent-hashids.svg) 4 | 5 | Automatically persist Hashids on your newly created Eloquent models 6 | using Ivan Akimov's [Hashids library](https://github.com/ivanakimov/hashids.php). 7 | 8 | This can be useful when you need to generate unique alphanumeric (or any other character) combinations 9 | to represent your models. 10 | 11 | ## Installation 12 | 13 | Require the package using composer. 14 | 15 | ```bash 16 | composer require matt-daneshvar/eloquent-hashids 17 | ``` 18 | 19 | ## Usage 20 | Add a *nullable* `hashid` column to your database table in your migrations. 21 | ```php 22 | $table->string('hashid')->nullable(); 23 | ``` 24 | 25 | Use the `Hashid` trait to automatically generate and persist Hashids for your new models. 26 | Optionally use `HashidRouting` to set your model to use the `hashid` column for 27 | Laravel's [Route Model Binding](https://laravel.com/docs/routing#route-model-binding). 28 | 29 | ```php 30 | use Illuminate\Database\Eloquent\Model; 31 | use MattDaneshvar\EloquentHashids\Hashid; 32 | use MattDaneshvar\EloquentHashids\HashidRouting; 33 | 34 | class Receipt extends Model 35 | { 36 | use Hashid, HashidRouting; 37 | } 38 | ``` 39 | 40 | ### Customizing Hashid generation 41 | While the package attempts to use sensible defaults to minimize configuration out of the box, 42 | you're free to adjust the Hashid generation behaviour using static properties on your model definition. 43 | ```php 44 | class Receipt extends Model 45 | { 46 | use Hashid; 47 | 48 | /** 49 | * The column used to store Hashid. 50 | * 51 | * @var array 52 | */ 53 | protected static $hashidColumn = 'hashid'; 54 | 55 | /** 56 | * The minimum length of the generated Hashids. 57 | * 58 | * @var array 59 | */ 60 | protected static $hashidMinLength = 8; 61 | 62 | /** 63 | * The whitelist of characters used inside the generated Hashids. 64 | * 65 | * @var array 66 | */ 67 | protected static $hashidChars = 'abcdefghijklmnopqrstuvwxyz1234567890'; 68 | 69 | /** 70 | * The salt for generating Hashids. 71 | * 72 | * @var array 73 | */ 74 | protected static $hashidSalt = 'your unique salt'; 75 | 76 | /** 77 | * The attribute encoded to generate the Hashid. 78 | * 79 | * @var array 80 | */ 81 | protected static $hashidKey = 'id'; 82 | } 83 | ``` 84 | 85 | ### Changing the Hashid column 86 | To customize the hashid column, set your own custom `$hashidColumn` value on your model. 87 | ```php 88 | class Receipt extends Model 89 | { 90 | use Hashid; 91 | 92 | protected static $hashidColumn = 'uid'; 93 | } 94 | ``` 95 | 96 | ### Changing the salt 97 | Each model's table name is by default used as the salt for generating Hashids. 98 | With that, models of separate classes that share the same IDs 99 | (e.g. a `Task` model with ID of 1 and a `Receipt` model also with ID of 1) would each have different Hashids. 100 | You may change this behaviour and override the salt by specifying the `$hashidSlat` on your model. 101 | ```php 102 | class Receipt extends Model 103 | { 104 | use Hashid; 105 | 106 | protected static $hashidSalt = 'salt and pepper'; 107 | } 108 | ``` 109 | 110 | ### Creating your own Hashids instance 111 | To fully customize the behaviour of the underlying Hashids library, 112 | you may also define your own `Hashids` instance in your model's boot method. 113 | Note that your Hashids instance would take precedence over 114 | all other customizations, and therefore all the rest of the static Hashid properties on your model 115 | (i.e. `$hashidMinLength`, `$hashidChars`, etc.) 116 | would be ignored once you specify your own `Hashids` instance. 117 | ```php 118 | class Receipt extends Model 119 | { 120 | public static function boot() 121 | { 122 | parent::boot(); 123 | 124 | static::$hashidsInstance = new Hashids('salt and pepper', 5); 125 | } 126 | } 127 | ``` 128 | 129 | ### Using the HashidRouting trait 130 | A common use case of Hashids with Eloquent models 131 | is to use short URLs using the generated Hashids as identifiers. 132 | 133 | For example you may wish to represent your app's receipts using their Hashid values: 134 | ``` 135 | https://example.com/receipts/2ov7j3o3 136 | ``` 137 | instead of their IDs: 138 | ``` 139 | https://example.com/receipts/4 140 | ``` 141 | 142 | For more convenience this package comes with a `HashidRouting` trait out of the box; once added to your model, 143 | this trait will change the model's route key name to its corresponding Hashid column, 144 | which would allow you to take advantage of 145 | Laravel's [Route Model Binding](https://laravel.com/docs/routing#route-model-binding) 146 | and use the Hashid URLs: 147 | ```php 148 | Route::get('api/receipts/{receipt}', function (App\Receipt $receipt) { 149 | return $receipt->total; 150 | }); 151 | ``` 152 | 153 | ## License 154 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 155 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matt-daneshvar/eloquent-hashids", 3 | "description": "Automatically generate and persist Hashids for newly created Eloquent models.", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Matt Daneshvar", 9 | "email": "matt.daneshvar@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^7.3|^7.4|^8.0", 14 | "hashids/hashids": "^4.0" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "MattDaneshvar\\EloquentHashids\\": "src/" 19 | } 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "^9.0", 23 | "orchestra/testbench": "^4.0|^5.0|^6.0", 24 | "illuminate/database": "^6.0|^7.0|^8.0", 25 | "mockery/mockery": "^1.3.2|^1.4" 26 | }, 27 | "autoload-dev": { 28 | "psr-4": { 29 | "MattDaneshvar\\EloquentHashids\\Tests\\": "tests/" 30 | }, 31 | "files": [ 32 | "tests/utilities/TestModel.php" 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Hashid.php: -------------------------------------------------------------------------------- 1 | generateHashId(); 52 | }); 53 | } 54 | 55 | /** 56 | * Generate and persist hashid. 57 | * 58 | * @return void 59 | */ 60 | public function generateHashId() 61 | { 62 | $key = isset(static::$hashidKey) ? $this->{static::$hashidKey} : $this->id; 63 | $this->{static::$hashidColumn ?? static::$defaultHashidColumn} = static::getHashIdInstance()->encode($key); 64 | $this->save(); 65 | } 66 | 67 | /** 68 | * Get Hashids instance. 69 | * 70 | * @return \Hashids\Hashids 71 | */ 72 | protected static function getHashIdInstance() 73 | { 74 | if (isset(static::$hashidsInstance)) { 75 | return static::$hashidsInstance; 76 | } 77 | 78 | return static::$defaultHashidsInstance = new Hashids( 79 | static::$hashidSalt ?? (new self)->getTable(), 80 | static::$hashidMinLength ?? 8, 81 | static::$hashidChars ?? 'abcdefghijklmnopqrstuvwxyz1234567890' 82 | ); 83 | } 84 | 85 | /** 86 | * Find model by hashid. 87 | * 88 | * @param $hashid 89 | * @return mixed 90 | */ 91 | public static function findByHashId($hashid) 92 | { 93 | return static::where(static::$hashidColumn ?? static::$defaultHashidColumn, $hashid)->first(); 94 | } 95 | 96 | /** 97 | * Find model by hashid; otherwise throw an exception. 98 | * 99 | * @param $hashid 100 | * @return mixed 101 | * @throws \Illuminate\Database\Eloquent\ModelNotFoundException 102 | */ 103 | public static function findByHashIdOrFail($hashid) 104 | { 105 | return static::where(static::$hashidColumn ?? static::$defaultHashidColumn, $hashid)->firstOrFail(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/HashidRouting.php: -------------------------------------------------------------------------------- 1 |