From d630bde8e5f3dbc607b627d4fd4a1cac080bcfdb Mon Sep 17 00:00:00 2001 From: Sam Taylor Date: Sat, 8 Apr 2017 16:22:46 -0400 Subject: [PATCH] Initial Commit Version 1 --- LICENSE.md | 21 ++++++ README.md | 11 ++++ composer.json | 20 ++++++ src/ModelSlugger.php | 86 ++++++++++++++++++++++++ src/ServiceProvider.php | 32 +++++++++ src/Slugger.php | 140 ++++++++++++++++++++++++++++++++++++++++ src/SluggerObserver.php | 18 ++++++ src/config/slugger.php | 10 +++ 8 files changed, 338 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 composer.json create mode 100644 src/ModelSlugger.php create mode 100644 src/ServiceProvider.php create mode 100644 src/Slugger.php create mode 100644 src/SluggerObserver.php create mode 100644 src/config/slugger.php diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7c6ec47 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 taylornetwork + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a53b1c --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# ModelSlugger + +## Credits + +- Main Author: [Sam Taylor][link-author] + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. + +[link-author]: https://github.com/taylornetwork \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6b68d55 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "taylornetwork/model-slugger", + "description": "Automatically add slugs to eloquent models", + "require": { + "php": ">=5.4.0", + "laravel/framework": "5.4.*", + "cocur/slugify": "^2.3" + }, + "authors": [ + { + "name": "Sam Taylor", + "email": "sam@taylornetwork.ca" + } + ], + "autoload": { + "psr-4": { + "TaylorNetwork\\ModelSlugger\\": "src/" + } + } +} diff --git a/src/ModelSlugger.php b/src/ModelSlugger.php new file mode 100644 index 0000000..dbb66a4 --- /dev/null +++ b/src/ModelSlugger.php @@ -0,0 +1,86 @@ +sluggerRouteModelBind) && $this->sluggerRouteModelBind) + { + if (isset($this->sluggerConfig()['column'])) + { + return $this->sluggerConfig()['column']; + } + return config('slugger.defaults.column'); + } + return parent::getRouteKeyName(); + } + + /** + * Find similar slugs with the same parents + * + * @param Builder $query + * @param Model $model + * @param $config + * @param $slug + * @param null $parent_column + * @return mixed + */ + public function scopeParentSimilarSlugs (Builder $query, Model $model, $config, $slug, $parent_column = null) + { + if ($parent_column === null) + { + if (!isset($config['parentColumn']) || $config['parentColumn'] === null) + { + $parent_column = strtolower(class_basename($config['parent'])) . '_' . (new $config['parent'])->getKeyName(); + } + else + { + $parent_column = $config['parentColumn']; + } + } + + return $query->where($parent_column, $model->$parent_column)->similarSlugs($config, $slug); + } + + /** + * Find similar slugs + * + * @param Builder $query + * @param $config + * @param $slug + * @return Builder|static + */ + public function scopeSimilarSlugs (Builder $query, $config, $slug) + { + return $query->where($config['column'], $slug)->orWhere($config['column'], 'LIKE', $slug . $config['separator'] . '%'); + } + + /** + * Slugger config + * + * Minimum: + * return [ 'source' => 'sourceField' ]; + * + * @return mixed + */ + abstract public function sluggerConfig(); +} \ No newline at end of file diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php new file mode 100644 index 0000000..63f8822 --- /dev/null +++ b/src/ServiceProvider.php @@ -0,0 +1,32 @@ +publishes([ + __DIR__.'/config/slugger.php' => config_path('slugger.php'), + ]); + } + + /** + * Register the application services. + * + * @return void + */ + public function register() + { + $this->mergeConfigFrom( + __DIR__.'/config/slugger.php', 'slugger' + ); + } +} \ No newline at end of file diff --git a/src/Slugger.php b/src/Slugger.php new file mode 100644 index 0000000..d32c573 --- /dev/null +++ b/src/Slugger.php @@ -0,0 +1,140 @@ +model = $model; + $this->config = $model->sluggerConfig() + config('slugger.defaults'); + $this->generator = new Slugify([ 'separator' => $this->getConfig('separator') ]); + $this->method = 'slugify'; + } + + /** + * Generate slug for model + */ + public function slug () + { + $slug = $this->buildSlug($this->model->{$this->getConfig('source')}); + $this->saveSlug($slug); + } + + /** + * Build the slug + * + * @param $text + * @return string + */ + public function buildSlug($text) + { + return $this->makeUnique($this->generator->{$this->method}($text)); + } + + /** + * Make slug unique either with all slugs, similar parents, or not at all + * + * @param $slug + * @return string + */ + public function makeUnique($slug) + { + switch (strtolower($this->getConfig('unique'))) + { + case 'parent': + $total = count($this->model->newQuery()->parentSimilarSlugs($this->model, $this->getConfig(), $slug)->get()); + return $this->appendIfNeeded($slug, $total); + break; + case 'all': + $total = count($this->model->newQuery()->similarSlugs($this->getConfig(), $slug)->get()); + return $this->appendIfNeeded($slug, $total); + break; + } + return $slug; + } + + /** + * Append a number to make slug unique if needed + * + * @param $slug + * @param $total + * @return string + */ + public function appendIfNeeded($slug, $total) + { + if ($total > 0) + { + return $slug . $this->getConfig('separator') . $total; + } + return $slug; + } + + /** + * Save the slug to the model + * + * @param $slug + */ + public function saveSlug($slug) + { + $this->model->setAttribute($this->getConfig('column'), $slug); + } + + + /** + * Get config + * + * @param mixed $key + * @return mixed + */ + public function getConfig($key = null) + { + switch(gettype($key)) + { + case 'string': + return $this->config[$key]; + break; + case 'array': + return array_only($this->config, $key); + break; + case 'object': + return array_only($this->config, (array) $key); + break; + } + return $this->config; + } +} \ No newline at end of file diff --git a/src/SluggerObserver.php b/src/SluggerObserver.php new file mode 100644 index 0000000..fc5cc26 --- /dev/null +++ b/src/SluggerObserver.php @@ -0,0 +1,18 @@ +slug(); + } +} \ No newline at end of file diff --git a/src/config/slugger.php b/src/config/slugger.php new file mode 100644 index 0000000..0cc74ea --- /dev/null +++ b/src/config/slugger.php @@ -0,0 +1,10 @@ + [ + 'unique' => 'none', + 'column' => 'slug', + 'separator' => '-', + ], +]; \ No newline at end of file