How to get unique slug to same post-title for other time too?



PHP Snippet 1:

mysite.dev/my-post
mysite.dev/my-post-1

PHP Snippet 2:

public function setSlugAttribute($value) {

    if (static::whereSlug($slug = str_slug($value))->exists()) {

        $slug = $this->incrementSlug($slug);
    }

    $this->attributes['slug'] = $slug;
}

PHP Snippet 3:

public function incrementSlug($slug) {

    $original = $slug;

    $count = 2;

    while (static::whereSlug($slug)->exists()) {

        $slug = "{$original}-" . $count++;
    }

    return $slug;

}

PHP Snippet 4:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
class ProductController extends Controller
{
    public function store(Request $request)
    {
        $product = new Product;
        $product->title = $request->title;
        $product->slug = $this->createSlug($request->title);
        $product->save();
    }
    public function createSlug($title, $id = 0)
    {
        $slug = str_slug($title);
        $allSlugs = $this->getRelatedSlugs($slug, $id);
        if (! $allSlugs->contains('slug', $slug)){
            return $slug;
        }

        $i = 1;
        $is_contain = true;
        do {
            $newSlug = $slug . '-' . $i;
            if (!$allSlugs->contains('slug', $newSlug)) {
                $is_contain = false;
                return $newSlug;
            }
            $i++;
        } while ($is_contain);
    }
    protected function getRelatedSlugs($slug, $id = 0)
    {
        return Product::select('slug')->where('slug', 'like', $slug.'%')
        ->where('id', '<>', $id)
        ->get();
    }
}

PHP Snippet 5:

localhost:8000/kwee-dev
localhost:8000/kwee-dev-1

PHP Snippet 6:

/**
     * Create a slug from title
     * @param  string $title
     * @return string $slug
     */
    protected function createSlug(string $title): string
    {

        $slugsFound = $this->getSlugs($title);
        $counter = 0;
        $counter += $slugsFound;

        $slug = str_slug($title, $separator = "-", app()->getLocale());

        if ($counter) {
            $slug = $slug . '-' . $counter;
        }
        return $slug;
    }

    /**
     * Find same listing with same title
     * @param  string $title
     * @return int $total
     */
    protected function getSlugs($title): int
    {
        return Listing::select()->where('title', 'like', $title)->count();
    }

PHP Snippet 7:

composer require spatie/laravel-sluggable

PHP Snippet 8:

use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Post extends Model
{
    use HasSlug;

    public function getSlugOptions() : SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug');
    }

PHP Snippet 9:

composer require cviebrock/eloquent-sluggable

PHP Snippet 10:

use Cviebrock\EloquentSluggable\Sluggable;

class Post extends Model
{
    use Sluggable;

    /**
     * Return the sluggable configuration array for this model.
     *
     * @return array
     */
    public function sluggable()
    {
        return [
            'slug' => [
                'source' => 'title'
            ]
        ];
    }
}

PHP Snippet 11:

# verify and return custom slug string
    public function slugify($text)
    {
        $slug = strtolower($text);
        $slug = str_replace(array('[\', \']'), '', $slug);
        $slug = preg_replace('/\[.*\]/U', '', $slug);
        $slug = preg_replace('/&(amp;)?#?[a-z0-9]+;/i', '-', $slug);
        $slug = htmlentities($slug, ENT_COMPAT, 'utf-8');
        $slug = preg_replace('/&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);/i', '\\1', $slug );
        $slug = preg_replace(array('/[^a-z0-9]/i', '/[-]+/') , '-', $slug);

        # slug repeat check
        $latest = $this->whereRaw("slug REGEXP '^{$slug}(-[0-9]+)?$'")
                        ->latest('id')
                        ->value('slug');

        if($latest){
            $pieces = explode('-', $latest);
            $number = intval(end($pieces));
            $slug .= '-' . ($number + 1);
        }       

        return $slug;
    }

PHP Snippet 12:

$post = new POST();
        $post->title = $request->title;
        $post->slug = $school->slugify($request->title);
        $post->save();

        return redirect()->back()->with('success', 'Successfully created new record');

PHP Snippet 13:

$slug = SlugHelper::createSlug("art-street-bird-mdf-wall-plaquewall-sign-for-home-decoration-ready-to-hang-wall-decor-6mm-black-rs-199-amazon-2174");

$slug = SlugHelper::createSlug("art-street-bird-mdf-wall-plaquewall-sign-for-home-decoration-ready-to-hang-wall-decor-6mm-black-rs-199-amazon-2174", 51, true);

$slug = SlugHelper::createSlug("art-street-bird-mdf-wall-plaquewall-sign-for-home-decoration-ready-to-hang-wall-decor-6mm-black-rs-199-amazon-2174", 51, false);

$slug = SlugHelper::createSlug("art-street-bird-mdf-wall-plaquewall-sign-for-home-decoration-ready-to-hang-wall-decor-6mm-black-rs-199-amazon-2174", 51, true, true, Product::class, 'sku');

// If you used Laravel Eloquent Model's SoftDeletes (https://laravel.com/docs/8.x/eloquent#soft-deleting) 
// then pass true as a one more addition parameter which named **`includeTrashed`** 
// after the `attribute` parameter` in `createSlug` function. otherwise pass false. 
// default value of includeTrashed is also false. see below 
$slug = SlugHelper::createSlug("art-street-bird-mdf-wall-plaquewall-sign-for-home-decoration-ready-to-hang-wall-decor-6mm-black-rs-199-amazon-2174", 51, true, true, Product::class, 'sku', true);

PHP Snippet 14:

<?php 

namespace Modules\CoreProduct\Utilities;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Modules\CoreProduct\Entities\Product;
use Illuminate\Support\Str;

class SlugHelper
{
    /**
     * model Obj, mandatory if wants to unique slug
     *
     * @var Model
     */
    public static $modelObj;

    /**
     * The attribute is a database field name for check uniqueness of slugs. mandatory if you pass $uniqueSlug as true. 
     * for ex: I have "sku" named DB field then I have to pass $attribute = "sku"
     *
     * @var string
     */
    public static $attribute;

    /**
     * if you wants to Enforce uniqueness of slugs with Soft Deleted Rows also
     *
     * @var boolean
     */
    public static $includeTrashed;

    /**
     * If you are setting a maximum length on your slugs, you may not want the
     * truncated string to split a word in half.
     * 
     * e.g. with a maxLength of 12: 
     *      if you pass true, "my source string" -> "my-source" . 
     *      if you pass false, "my source string" -> "my-source-st"
     *
     * @var bool
     */
    public static $maxLengthKeepWords;

    /**
     * The first suffix to add to a slug to make it unique
     * 
     * default value is 2. for adding incremental integers, we start counting 
     * at 2, so the list of slugs would be, 
     * 
     * e.g.:
     *   - my-post
     *   - my-post-2
     *   - my-post-3
     *
     * @var integer
     */
    public static $firstSuffix = 2;

    /**
     * Separator to use when generating slugs. Defaults to a hyphen.
     *
     * @var string
     */
    public static $separator = '-';


    /**
     * Generate a URL friendly "slug" from a given string
     *
     * @param string $title
     * @param integer|null $maxLength // maximum length of a generated slug. pass it as a positive integer if you want to make sure your slugs aren't too long.
     * @param boolean $maxLengthKeepWords // pass bool true if you may not want the truncated string to split a word in half. e.g. with a maxLength of 12: "my source string" -> "my-source" . if you pass false then output will like this "my source string" -> "my-source-st"
     * @param boolean $uniqueSlug // pass bool true if you wants to Enforce uniqueness of slugs 
     * @param Model $modelObj // pass Model. mandatory if you pass $uniqueSlug as true.
     * @param string $attribute // database field name for check uniqueness of slugs. mandatory if you pass $uniqueSlug as true. for ex: I have "sku" named DB field then I have to pass $attribute = "sku"
     * @param boolean $includeTrashed // if you wants to Enforce uniqueness of slugs with Soft Deleted Rows also
     * @return string
     */
    public static function createSlug(string $title, ?int $maxLength = null, bool $maxLengthKeepWords = true, bool $uniqueSlug = false, $modelObj = null, string $attribute = null, bool $includeTrashed = false)
    {
        self::$modelObj = $modelObj;
        self::$attribute = $attribute;
        self::$maxLengthKeepWords = $maxLengthKeepWords;
        self::$includeTrashed = $includeTrashed;
        echo $slug = Str::slug($title);
        
        $slug = self::truncateOverLimitSlug($slug, $maxLength, self::$separator);
        
        $slug = self::makeSlugUnique($slug, self::$separator, $uniqueSlug, $maxLength);
        echo "<h3>". $slug . "</h3>";
        return $slug;
    }

    /**
     * Checks if the slug should be unique, and makes it so if needed.
     *
     * @param string $slug
     * @param string $separator
     * @param boolean $uniqueSlug
     * @param integer|null $maxLength
     * @return string
     */
    private function makeSlugUnique(string $slug, string $separator, bool $uniqueSlug, ?int $maxLength = null)
    {
        if(!$uniqueSlug){
            // $slug = self::truncateOverLimitSlug($slug, $maxLength, $separator);
            return $slug;
        }

        $original = $slug;
        $suffix = self::$firstSuffix;
        while(self::getExistingSlugs($slug, self::$includeTrashed)){
            if($maxLength){
                $newMaxLength = $maxLength - strlen($separator . $suffix);
            }
            $slug = self::truncateOverLimitSlug($original, $newMaxLength, self::$separator) . "{$separator}" . $suffix;
            // $slug = "{$original}". "{$separator}" . $suffix;
            $suffix++;
        }
        return $slug;

        /* if(!$uniqueSlug){
            $slug = self::truncateOverLimitSlug($slug, $maxLength, $separator);
            return $slug;
        }
        $list = self::getExistingSlugs($slug, true);

        if($list->count() === 0 || $list->contains($slug) === false){
            return $slug;
        }

        $suffix = self::generateSuffix($slug, $separator, $list, self::$firstSuffix);
        if($maxLength){
            $maxLength = $maxLength - strlen($separator . $suffix);
        }
        $slug = self::truncateOverLimitSlug($slug, $maxLength, $separator);
        return $slug . $separator . $suffix; */
    }

    /**
     * Truncate the slug using maxLength parameter 
     *
     * @param string $slug
     * @param integer|null $maxLength
     * @param string $separator
     * @return string
     */
    private function truncateOverLimitSlug(string $slug, ?int $maxLength = null, string $separator)
    {
        $len = mb_strlen($slug);
        if (is_string($slug) && $maxLength && $len > $maxLength) {
            $reverseOffset = $maxLength - $len;
            $lastSeparatorPos = mb_strrpos($slug, $separator, $reverseOffset);
            if (self::$maxLengthKeepWords && $lastSeparatorPos !== false) {
                $slug = mb_substr($slug, 0, $lastSeparatorPos);
            } else {
                $slug = trim(mb_substr($slug, 0, $maxLength), $separator);
            }
        }
        return $slug;
    }

    // /**
    //  * Generate a unique suffix for the given slug (and list of existing, "similar" slugs.
    //  *
    //  * @param string $slug
    //  * @param string $separator
    //  * @param Collection $list
    //  * @param integer $firstSuffix
    //  * @return mixed
    //  */
    // private function generateSuffix(string $slug, string $separator, Collection $list, int $firstSuffix)
    // {
    //     $len = strlen($slug . $separator);

    //     // If the slug already exists, but belongs to
    //     // our model, return the current suffix.
    //     if ($list->search($slug) === 'sku') {
    //         $suffix = explode($separator, $slug);

    //         return end($suffix);
    //     }

    //     $list->transform(function($value, $key) use ($len) {
    //         return (int) substr($value, $len);
    //     });

    //     $max = $list->max();

    //     // return one more than the largest value,
    //     // or return the first suffix the first time
    //     return (string) ($max === 0 ? $firstSuffix : $max + 1);
    // }

    /**
     * Get all existing slugs that are similar to the given slug.
     *
     * @param string $slug
     * @param boolean $includeTrashed
     * @return bool
     */
    private function getExistingSlugs(string $slug, bool $includeTrashed)
    {
        if(is_string(self::$modelObj)){
            $modelObj = new self::$modelObj(); // initialize the Model Class, if user pass Product::class. because of string type.
        }else{
            $modelObj = self::$modelObj; // instance of Model Class, means user passed object of equivalent model class
        }
        $query = $modelObj;
        if($includeTrashed === true){
            $query = $modelObj->withTrashed();
        }
        $query = $modelObj->where(self::$attribute, $slug);
        return $query->exists();
        // var_dump(self::$modelObj);
        /* $results = $modelObj->where(self::$attribute, $slug)->select(self::$attribute)->get();
        return $results->pluck(self::$attribute); */
    }
}

PHP Snippet 15:

{
    $slug=Str::slug($name);
    // dd($slug,"show");

    if (Business::where('profile_link',Str::slug($name))->exists()) {

        $max = Business::where('name','LIKE',$name)->latest()->value('profile_link');
        if(is_numeric($max[-1])) {
            // dd($max);
            
            return preg_replace_callback('/(\d+)$/', function($mathces) {
                // dd($mathces[1] + 1);
                return $mathces[1] + 1;
                
            }, $max);

        }
        // dd("{$slug}-2");
        return "{$slug}-2";

    }
    // dd($slug);
    return $slug;

}