Mostrando entradas con la etiqueta Slug. Mostrar todas las entradas
Mostrando entradas con la etiqueta Slug. Mostrar todas las entradas

Url Amigable: Que al hacer un enlace no pase el id sino el slug

// En el modelo donde queramos hacerlo (por ejemplo app\Models\Category.php):
public function getRouteKeyName() {
return 'slug';
}

Y luego desde cualquier view:
<a href="{{ route('categories.show', $category) }}">... </a>

Slug controlar excepciones

 Crear en App/Exception/InvalidEntrySlugException.php:


<?php

namespace App\Exceptions;


use App\Entry;

use Exception;

use Throwable;


class InvalidEntrySlugException extends Exception {

    private $entry;


    public function __construct(Entry $entry, $message = "", $code = 0, Throwable $previous = null)

    {

        $this->entry = $entry;

        parent::__construct($message, $code, $previous);

    }


    public function render()

    {

        return redirect($this->entry->getUrl());

    }

}

?>


En App/providers/RouteServiceProvider.php

$entry = Entry::findOrFail($id);

if ($entry->slug."-".$entry->id === $value) {

    return $entry;

}

else {

   // forzará a q se vaya a la url correcta por si se pone lo-xxxx-viento-se-llevo-3

   throw new InvalidEntrySlugException($entry);

}


Laravel 7: Slug

Lo primero de todo en App/providers/RouteServideProvider.php modificar la función boot:
public function boot() {
   parent::boot();

   // para hacer que coga el id del slug por si se cambie el slug tire siempre del id
   Route::bind('entry', function($value) {
     $arrAux = explode("-", $value);
     $id = end($arrAux);
     return Entry::findOrFail($id);
   });
}

En \config\database.php en mysql poner:
'strict' => false,

En el migration de esa tabla añadir:
$table->string('slug');

En el modelo que queramos hacer el slug (por ejemplo Entry.php):
// crear un mutator para el slug
public function setTitleAttribute($value) {
$this->attributes['title'] = $value;
$this->attributes['slug'] = Str::slug($value);
}

// para q el controller busque por ese campo en vez de por el id
public function getRouteKeyName() {
return 'slug';
}

// esto es para q desde las views sea más cómodo y no haya q escribir tanto
public function getUrl() {
return url('entries/'.$this->slug.'-'.$this->id);
}

Y finalmente en la vista en la q se enlace:
<a href="{{ $item->getUrl() }}">
   {{ $item->title}}
</a>

En routes/web.php no hay que cambiar absolutamente nada pues va a seguir entrando como parámetro un objeto $entry pero en vez de buscarlo por id lo hará por el slug

Ejecutar para generar todo de nuevo:
php artisan migrate:fresh --seed

Generar slug

public function generarSlug($titulo) {
$slug = str_slug($titulo);
$arrAux = Pelicula::select('slug')->where('slug', $slug)->get();
$cont = 1;
while (count($arrAux) == 1) {
$slug .= "-".$cont;
$arrAux = Pelicula::select('slug')->where('slug', $slug)->get();
$cont++;
}
return $slug;
}

// Para llamarlo dentro del mismo controller
$slug = $this->generarSlug($request->get("titulo")." ".$request->get("anno"));