├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── Attributes └── Slug.php ├── Concerns └── HasSlug.php ├── LaravelSlugServiceProvider.php └── Support.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-slug` will be documented in this file. 4 | 5 | ## v1.1.1 - 2022-10-14 6 | 7 | **Full Changelog**: https://github.com/ryangjchandler/laravel-slug/compare/v1.1.0...v1.1.1 8 | 9 | ## v1.1.0 - 2022-10-14 10 | 11 | ### What's Changed 12 | 13 | - chore(deps): bump dependabot/fetch-metadata from 1.3.0 to 1.3.1 by @dependabot in https://github.com/ryangjchandler/laravel-slug/pull/2 14 | - chore(deps): bump dependabot/fetch-metadata from 1.3.1 to 1.3.3 by @dependabot in https://github.com/ryangjchandler/laravel-slug/pull/3 15 | - chore(deps): bump dependabot/fetch-metadata from 1.3.3 to 1.3.4 by @dependabot in https://github.com/ryangjchandler/laravel-slug/pull/4 16 | - feature: support forcing unique slugs by @ryangjchandler in https://github.com/ryangjchandler/laravel-slug/pull/6 17 | 18 | ### New Contributors 19 | 20 | - @dependabot made their first contribution in https://github.com/ryangjchandler/laravel-slug/pull/2 21 | - @ryangjchandler made their first contribution in https://github.com/ryangjchandler/laravel-slug/pull/6 22 | 23 | **Full Changelog**: https://github.com/ryangjchandler/laravel-slug/compare/v1.0.0...v1.1.0 24 | 25 | ## v1.0.0 - 2022-04-08 26 | 27 | **Full Changelog**: https://github.com/ryangjchandler/laravel-slug/commits/v1.0.0 28 | 29 | ## 1.0.0 - 202X-XX-XX 30 | 31 | - initial release 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) ryangjchandler 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 | # Simple slugs for your Laravel models. 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/ryangjchandler/laravel-slug.svg?style=flat-square)](https://packagist.org/packages/ryangjchandler/laravel-slug) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/ryangjchandler/laravel-slug/run-tests?label=tests)](https://github.com/ryangjchandler/laravel-slug/actions?query=workflow%3Arun-tests+branch%3Amain) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/ryangjchandler/laravel-slug/Check%20&%20fix%20styling?label=code%20style)](https://github.com/ryangjchandler/laravel-slug/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/ryangjchandler/laravel-slug.svg?style=flat-square)](https://packagist.org/packages/ryangjchandler/laravel-slug) 7 | 8 | This packages provides an opinionated, attribute-driven trait for automatically generating slugs when creating Laravel models. 9 | 10 | ## Installation 11 | 12 | You can install the package via Composer: 13 | 14 | ```bash 15 | composer require ryangjchandler/laravel-slug 16 | ``` 17 | 18 | ## Usage 19 | 20 | Use the `RyanChandler\Slug\Concerns\HasSlug` trait on your model class. 21 | 22 | ```php 23 | use RyanChandler\Slug\Concerns\HasSlug; 24 | 25 | class Post extends Model 26 | { 27 | use HasSlug; 28 | } 29 | ``` 30 | 31 | By default, this package will generate a slug using a `title` column on your model and store the value in a `slug` column. 32 | 33 | This can be changed using the `RyanChandler\Slug\Attribute\Slug` attribute. 34 | 35 | ```php 36 | use RyanChandler\Slug\Concerns\HasSlug; 37 | use RyanChandler\Slug\Attribute\Slug; 38 | 39 | #[Slug(source: 'name', column: 'my_slug')] 40 | class Post extends Model 41 | { 42 | use HasSlug; 43 | } 44 | ``` 45 | 46 | The `source` argument should contain the name of the column you'd like to generate a slug from. The `column` argument should contain the name of the column you'd like to store the generated slug in. 47 | 48 | ## Testing 49 | 50 | ```bash 51 | composer test 52 | ``` 53 | 54 | ## Changelog 55 | 56 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 57 | 58 | ## Contributing 59 | 60 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 61 | 62 | ## Security Vulnerabilities 63 | 64 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 65 | 66 | ## Credits 67 | 68 | - [Ryan Chandler](https://github.com/ryangjchandler) 69 | - [All Contributors](../../contributors) 70 | 71 | ## License 72 | 73 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 74 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ryangjchandler/laravel-slug", 3 | "description": "Simple slugs for your Laravel models.", 4 | "keywords": [ 5 | "ryangjchandler", 6 | "laravel", 7 | "laravel-slug" 8 | ], 9 | "homepage": "https://github.com/ryangjchandler/laravel-slug", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Ryan Chandler", 14 | "email": "support@ryangjchandler.co.uk", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.1", 20 | "spatie/laravel-package-tools": "^1.9.2", 21 | "illuminate/contracts": "^9.0" 22 | }, 23 | "require-dev": { 24 | "nunomaduro/collision": "^6.0", 25 | "nunomaduro/larastan": "^2.0.1", 26 | "orchestra/testbench": "^7.0", 27 | "pestphp/pest": "^1.21", 28 | "pestphp/pest-plugin-laravel": "^1.1", 29 | "phpstan/extension-installer": "^1.1", 30 | "phpstan/phpstan-deprecation-rules": "^1.0", 31 | "phpstan/phpstan-phpunit": "^1.0", 32 | "phpunit/phpunit": "^9.5", 33 | "spatie/laravel-ray": "^1.26" 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "RyanChandler\\Slug\\": "src", 38 | "RyanChandler\\Slug\\Database\\Factories\\": "database/factories" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "RyanChandler\\Slug\\Tests\\": "tests" 44 | } 45 | }, 46 | "scripts": { 47 | "analyse": "vendor/bin/phpstan analyse", 48 | "test": "vendor/bin/pest", 49 | "test-coverage": "vendor/bin/pest --coverage" 50 | }, 51 | "config": { 52 | "sort-packages": true, 53 | "allow-plugins": { 54 | "pestphp/pest-plugin": true, 55 | "phpstan/extension-installer": true 56 | } 57 | }, 58 | "extra": { 59 | "laravel": { 60 | "providers": [ 61 | "RyanChandler\\Slug\\LaravelSlugServiceProvider" 62 | ], 63 | "aliases": { 64 | "LaravelSlug": "RyanChandler\\Slug\\Facades\\LaravelSlug" 65 | } 66 | } 67 | }, 68 | "minimum-stability": "dev", 69 | "prefer-stable": true 70 | } 71 | -------------------------------------------------------------------------------- /src/Attributes/Slug.php: -------------------------------------------------------------------------------- 1 | column; 19 | $source = $options->source; 20 | $slug = Str::slug($model->{$source}); 21 | 22 | $model->{$column} = $options->forceUniqueness ? $model->makeSlugUnique($slug, $options) : $slug; 23 | }); 24 | } 25 | 26 | protected function makeSlugUnique(string $slug, Slug $options): string 27 | { 28 | $count = static::query() 29 | ->where(function (Builder $query) use ($options, $slug) { 30 | $query 31 | ->where($options->column, $slug) 32 | ->orWhere($options->column, 'LIKE', "{$slug}-%"); 33 | }) 34 | ->count(); 35 | 36 | if ($count === 0) { 37 | return $slug; 38 | } 39 | 40 | return $slug . '-' . $count; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/LaravelSlugServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('laravel-slug'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Support.php: -------------------------------------------------------------------------------- 1 | getAttributes(Slug::class)) { 17 | return $attributes[0]->newInstance(); 18 | } 19 | 20 | return new Slug(); 21 | } 22 | } 23 | --------------------------------------------------------------------------------