├── .releaserc.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── package-lock.json ├── package.json ├── pint.json ├── resources └── views │ └── .gitkeep └── src ├── Concerns ├── HasSqids.php ├── HasSqidsRouting.php ├── WithAlphabet.php ├── WithBlocklist.php ├── WithMinLength.php └── WithSalt.php ├── Facades └── Sqids.php ├── Sqids.php └── SqidsServiceProvider.php /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "@semantic-release/commit-analyzer", 5 | { 6 | "preset": "conventionalcommits", 7 | "releaseRules": [ 8 | { 9 | "type": "feat", 10 | "release": "minor" 11 | }, 12 | { 13 | "type": "fix", 14 | "release": "patch" 15 | }, 16 | { 17 | "type": "docs", 18 | "scope": "README", 19 | "release": "patch" 20 | }, 21 | { 22 | "type": "refactor", 23 | "release": "patch" 24 | }, 25 | { 26 | "type": "chore", 27 | "release": "patch" 28 | }, 29 | { 30 | "type": "style", 31 | "release": false 32 | }, 33 | { 34 | "type": "perf", 35 | "release": "patch" 36 | }, 37 | { 38 | "type": "test", 39 | "release": false 40 | }, 41 | { 42 | "scope": "no-release", 43 | "release": false 44 | } 45 | ] 46 | } 47 | ], 48 | [ 49 | "@semantic-release/release-notes-generator", 50 | { 51 | "preset": "conventionalcommits", 52 | "presetConfig": { 53 | "types": [ 54 | { 55 | "type": "feat", 56 | "section": "Features" 57 | }, 58 | { 59 | "type": "fix", 60 | "section": "Bug Fixes" 61 | }, 62 | { 63 | "type": "refactor", 64 | "section": "Refactor" 65 | }, 66 | { 67 | "type": "docs", 68 | "section": "Documentation" 69 | }, 70 | { 71 | "type": "chore", 72 | "section": "Chore" 73 | }, 74 | { 75 | "type": "style", 76 | "section": "Style" 77 | }, 78 | { 79 | "type": "perf", 80 | "section": "Performance" 81 | }, 82 | { 83 | "type": "test", 84 | "section": "Tests" 85 | } 86 | ] 87 | } 88 | } 89 | ], 90 | "@semantic-release/github" 91 | ], 92 | "branches": [ 93 | "+([0-9])?(.{+([0-9]),x}).x", 94 | "main", 95 | "master", 96 | { 97 | "name": "beta", 98 | "prerelease": true 99 | }, 100 | { 101 | "name": "alpha", 102 | "prerelease": true 103 | } 104 | ], 105 | "tagFormat": "${version}" 106 | } 107 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `sqids-for-laravel` will be documented in this file. 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Guava 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![sqids-for-laravel Banner](docs/images/banner.jpg) 2 | 3 | 4 | # Laravel wrapper for Sqids 5 | 6 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/guava/sqids-for-laravel.svg?style=flat-square)](https://packagist.org/packages/guava/sqids-for-laravel) 7 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/guavaCZ/sqids-for-laravel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/guavaCZ/sqids-for-laravel/actions?query=workflow%3Arun-tests+branch%3Amain) 8 | [![Total Downloads](https://img.shields.io/packagist/dt/guava/sqids-for-laravel.svg?style=flat-square)](https://packagist.org/packages/guava/sqids-for-laravel) 9 | 10 | Laravel Wrapper for [sqids.org](https://sqids.org) PHP library. 11 | 12 | ## Support us 13 | 14 | Your support is key to the continual advancement of our plugin. We appreciate every user who has contributed to our journey so far. 15 | 16 | While our plugin is available for all to use, if you are utilizing it for commercial purposes and believe it adds significant value to your business, we kindly ask you to consider supporting us through GitHub Sponsors. This sponsorship will assist us in continuous development and maintenance to keep our plugin robust and up-to-date. Any amount you contribute will greatly help towards reaching our goals. Join us in making this plugin even better and driving further innovation. 17 | 18 | ## Installation 19 | 20 | You can install the package via composer: 21 | 22 | ```bash 23 | composer require guava/sqids-for-laravel 24 | ``` 25 | 26 | ## Usage 27 | This package adds a slightly modified version of the Sqids class, which allows a fluent configuration of all options. It also adds a salting option. 28 | 29 | ### Generating Sqids 30 | There's multiple ways you can use this package to generate sqids: 31 | ```php 32 | // Via our Facade 33 | use Guava\Sqids\Facades\Sqids; 34 | 35 | Sqids::encode([1,2,3]); /// Outputs '86Rf07' 36 | 37 | 38 | 39 | // Via a classic instance 40 | use Guava\Sqids\Sqids; 41 | $sqids = new Sqids(); 42 | $sqids->encode([1,2,3]); /// Outputs '86Rf07' 43 | 44 | 45 | 46 | // Via the app container / dependency injection 47 | use Guava\Sqids\Sqids; 48 | app(Sqids::class)->encode([1,2,3]); /// Outputs '86Rf07' 49 | 50 | 51 | 52 | // Via our factory method, which simply returns an instance of Sqids 53 | // The factory method is also available on the facade class 54 | use Guava\Sqids\Sqids; 55 | Sqids::make()->encode([1,2,3]); 56 | ``` 57 | 58 | It's entirely up to you which way you prefer. In our examples, we will make use of the factory method. 59 | 60 | ### Using in Eloquent Models 61 | This package also comes with a trait that you can use in your Eloquent models. This trait will automatically add a sqid attribute which will be created from the model's primary key. 62 | ```php 63 | use \Illuminate\Database\Eloquent\Model; 64 | use \Guava\Sqids\Concerns\HasSqids; 65 | 66 | class YourModel extends Model { 67 | use HasSqids; 68 | 69 | // ... 70 | } 71 | ```` 72 | That's it! Now you can access the `sqid` attribute on your model. 73 | 74 | You can custimize how the sqid on your model is generated by overriding the `getSqids` method: 75 | ```php 76 | use \Illuminate\Database\Eloquent\Model; 77 | use \Guava\Sqids\Concerns\HasSqids; 78 | use \Guava\Sqids\Sqids; 79 | 80 | class YourModel extends Model { 81 | use HasSqids; 82 | 83 | // ... 84 | 85 | protected function getSqids(): Sqids 86 | { 87 | return Sqids::make() 88 | ->salt() // This will use the model's class name as the salt, so every model generates different IDs 89 | // ... add more options here 90 | ); 91 | } 92 | } 93 | ``` 94 | 95 | ### Route binding 96 | If you want to be able to use the `sqid` as the route key, simply add the `HasSqidsRouting` trait to your model: 97 | ```php 98 | use \Illuminate\Database\Eloquent\Model; 99 | use \Guava\Sqids\Concerns\HasSqids; 100 | use \Guava\Sqids\Concerns\HasSqidsRouting; 101 | 102 | class YourModel extends Model { 103 | use HasSqids, HasSqidsRouting; 104 | 105 | // ... 106 | } 107 | ``` 108 | 109 | ### Options 110 | 111 | #### Customizing the alphabet 112 | ```php 113 | use Guava\Sqids\Sqids; 114 | 115 | Sqids::make() 116 | ->alphabet('0123456789abcdef') 117 | ->encode([1,2,3]); /// Outputs 'c9bf67' 118 | ``` 119 | 120 | #### Customizing the minLength 121 | ```php 122 | use Guava\Sqids\Sqids; 123 | 124 | Sqids::make() 125 | ->minLength('8') 126 | ->encode([1,2,3]); /// Outputs '86Rf07xd' 127 | ``` 128 | 129 | #### Customizing the block list 130 | ```php 131 | use Guava\Sqids\Sqids; 132 | 133 | Sqids::make() 134 | ->blocklist(['86Rf07']) 135 | ->encode([1,2,3]); /// Outputs 'se8ojk' 136 | ``` 137 | 138 | #### Salting 139 | Salting can be used to generate different IDs based on the provided salt, which can be any string or integer. 140 | 141 | ```php 142 | use Guava\Sqids\Sqids; 143 | 144 | Sqids::make() 145 | ->salt('my-salt') 146 | ->encode([1,2,3]); /// Outputs 'rx035W' 147 | ``` 148 | 149 | Salting is especially useful when used on Models with the `HasSqids` trait and you want every model to return different, unique IDs. 150 | 151 | So for example a record of `Model1` with the ID 1 has a different sqid that a record of `Model2` with the ID 1. 152 | ```php 153 | use \Illuminate\Database\Eloquent\Model; 154 | use \Guava\Sqids\Concerns\HasSqids; 155 | use \Guava\Sqids\Sqids; 156 | 157 | class YourModel extends Model { 158 | use HasSqids; 159 | 160 | // ... 161 | 162 | protected function getSqids(): Sqids 163 | { 164 | return Sqids::make() 165 | ->salt() // This will use the model's class name as the salt, so every model generates different IDs 166 | ); 167 | } 168 | } 169 | ``` 170 | 171 | ## Changelog 172 | 173 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 174 | 175 | ## Contributing 176 | 177 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 178 | 179 | ## Security Vulnerabilities 180 | 181 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 182 | 183 | ## Credits 184 | 185 | - [Lukas Frey](https://github.com/lukas-frey) 186 | - [All Contributors](../../contributors) 187 | - Spatie - Our package skeleton is a modified version of [Spatie's Package Skeleton](https://github.com/spatie/package-skeleton-laravel) 188 | - https://github.com/mtvs/eloquent-hashids 189 | 190 | ## License 191 | 192 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 193 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guava/sqids-for-laravel", 3 | "description": "This is a laravel wrapper for sqids.", 4 | "keywords": [ 5 | "Guava", 6 | "laravel", 7 | "sqids-for-laravel" 8 | ], 9 | "homepage": "https://github.com/GuavaCZ/sqids-for-laravel", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Lukas Frey", 14 | "email": "mail@lukasfrey.cz", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.2", 20 | "illuminate/contracts": "^10.0|^11.0|^12.0", 21 | "spatie/laravel-package-tools": "^1.14.0", 22 | "sqids/sqids": "^0.5" 23 | }, 24 | "require-dev": { 25 | "laravel/pint": "^1.0", 26 | "nunomaduro/collision": "^7.8", 27 | "orchestra/testbench": "^8.8", 28 | "pestphp/pest": "^2.0", 29 | "pestphp/pest-plugin-arch": "^2.0", 30 | "pestphp/pest-plugin-laravel": "^2.0" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "Guava\\Sqids\\": "src/", 35 | "Guava\\Sqids\\Database\\Factories\\": "database/factories/" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Guava\\Sqids\\Tests\\": "tests/", 41 | "Workbench\\App\\": "workbench/app/" 42 | } 43 | }, 44 | "scripts": { 45 | "post-autoload-dump": "@composer run prepare", 46 | "clear": "@php vendor/bin/testbench package:purge-sqids-for-laravel --ansi", 47 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 48 | "build": [ 49 | "@composer run prepare", 50 | "@php vendor/bin/testbench workbench:build --ansi" 51 | ], 52 | "start": [ 53 | "Composer\\Config::disableProcessTimeout", 54 | "@composer run build", 55 | "@php vendor/bin/testbench serve" 56 | ], 57 | "analyse": "vendor/bin/phpstan analyse", 58 | "test": "vendor/bin/pest", 59 | "test-coverage": "vendor/bin/pest --coverage", 60 | "format": "vendor/bin/pint" 61 | }, 62 | "config": { 63 | "sort-packages": true, 64 | "allow-plugins": { 65 | "pestphp/pest-plugin": true, 66 | "phpstan/extension-installer": true 67 | } 68 | }, 69 | "extra": { 70 | "laravel": { 71 | "providers": [ 72 | "Guava\\Sqids\\SqidsServiceProvider" 73 | ], 74 | "aliases": { 75 | "Sqids": "Guava\\Sqids\\Facades\\Sqids" 76 | } 77 | } 78 | }, 79 | "minimum-stability": "dev", 80 | "prefer-stable": true 81 | } 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "conventional-changelog-conventionalcommits": "^7.0.2", 4 | "semantic-release": "^22.0.5" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel", 3 | "rules": { 4 | "method_argument_space": true, 5 | "multiline_whitespace_before_semicolons": { 6 | "strategy": "new_line_for_chained_calls" 7 | }, 8 | "types_spaces": { 9 | "space": "single" 10 | }, 11 | "concat_space": false 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuavaCZ/sqids-for-laravel/10b950654d5f7e1b7ec2aa894cfbcce32fc87253/resources/views/.gitkeep -------------------------------------------------------------------------------- /src/Concerns/HasSqids.php: -------------------------------------------------------------------------------- 1 | getSqids() 15 | ->encode($this->getKey()) 16 | ; 17 | }, 18 | ); 19 | } 20 | 21 | protected function getSqids(): Sqids 22 | { 23 | return Sqids::make(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Concerns/HasSqidsRouting.php: -------------------------------------------------------------------------------- 1 | where($this->getKeyName(), $this->getSqids()->decode($value)) 15 | : parent::resolveRouteBindingQuery($query, $value, $field); 16 | } 17 | 18 | /** 19 | * @see parent 20 | */ 21 | public function getRouteKey() 22 | { 23 | return $this->sqid; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Concerns/WithAlphabet.php: -------------------------------------------------------------------------------- 1 | alphabet = $alphabet; 12 | 13 | return $this; 14 | } 15 | 16 | public function getAlphabet(): string 17 | { 18 | return $this->alphabet ?? Sqids::DEFAULT_ALPHABET; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Concerns/WithBlocklist.php: -------------------------------------------------------------------------------- 1 | getAlphabet())); 13 | foreach ($blocklist as $word) { 14 | if (strlen((string) $word) >= 3) { 15 | $wordLowercased = strtolower($word); 16 | $wordChars = str_split($wordLowercased); 17 | $intersection = array_filter($wordChars, fn ($c) => in_array($c, $alphabetChars)); 18 | if (count($intersection) == count($wordChars)) { 19 | $filteredBlocklist[] = strtolower($wordLowercased); 20 | } 21 | } 22 | } 23 | $this->blocklist = $filteredBlocklist; 24 | 25 | return $this; 26 | } 27 | 28 | public function getBlocklist(): array 29 | { 30 | return $this->blocklist ?? Sqids::DEFAULT_BLOCKLIST; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Concerns/WithMinLength.php: -------------------------------------------------------------------------------- 1 | minLength = $minLength; 12 | 13 | return $this; 14 | } 15 | 16 | public function getMinLength(): int 17 | { 18 | return $this->minLength ?? Sqids::DEFAULT_MIN_LENGTH; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Concerns/WithSalt.php: -------------------------------------------------------------------------------- 1 | salt = crc32($salt ?? static::class); 12 | 13 | return $this; 14 | } 15 | 16 | public function getSalt(): ?int 17 | { 18 | return $this->salt; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Facades/Sqids.php: -------------------------------------------------------------------------------- 1 | getSalt()) { 19 | srand($salt); 20 | $this->alphabet = str_shuffle($this->getAlphabet()); 21 | } 22 | 23 | return parent::encode($numbers); 24 | } 25 | 26 | public function decode(string $id): array 27 | { 28 | if ($salt = $this->getSalt()) { 29 | srand($salt); 30 | $this->alphabet = str_shuffle($this->getAlphabet()); 31 | } 32 | 33 | return parent::decode($id); 34 | } 35 | 36 | public static function make(array $parameters = []): static 37 | { 38 | return app(static::class, $parameters); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/SqidsServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('sqids-for-laravel') 19 | ; 20 | 21 | $this->app->bind(Sqids::class, function ($app, $parameters) { 22 | return new Sqids(...$parameters); 23 | }); 24 | } 25 | } 26 | --------------------------------------------------------------------------------