Como crear URLs Amigables con Base de Datos MySQL en Laravel 5.6

Publicado el 11 agosto 2018 por Juan Ricardo Castro Lurita @pepoflex

Demo Github

Si tienes un proyecto en Laravel con muchas páginas creadas dinámicamente desde la Base de Datos, por ejemplo si tienes una página sobre Dulces o Postres y dentro de ella  tienes una página productos, cada producto tiene que tener su propia página en donde puedas mostrar todos los detalles, como el precio, stock, fotos, etc. Esto hace que cada página maneje su propia URL, en este artículo te vamos a enseñar como crear dinámicamente una URL desde la Base de Datos para cada producto, vamos con el artículo.

Base de Datos

Creamos una tabla en donde añadiremos una columna llamada url, en esta columna almacenaremos las urls amigables para las páginas

CREATE TABLE `postres` (
  `id` int(11) NOT NULL,
  `nombre` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `stock` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `precio` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `img` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `fecha_creacion` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Cuando llenos nuestra tabla postres con productos, deberíamos tener la siguiente estructura

Laravel Deployment

Crear Producto

Algo importante, a la hora de crear un nuevo producto en la base de datos es generar las url amigables en base al nombre del producto, para ello usamos la función str_slug() que nos ofrece Laravel en su lista de Helpers, por ejemplo en nuestro método store() para guardar un nuevo producto le pasamos la función str_slug() al campo nombre que lo recibimos desde nuestra vista que contiene un formulario para Crear nuevo producto.

Si creamos un postre con el nombre Torta de Chocolate, lo que hará la función str_slug() es convertirlo a torta-de-chocolate y se guarda en la Base de datos.

Creamos el archivo ProductosController.php ustedes le pueden poner el nombre que deseen y agregamos

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Productos;
use Session;
use Redirect;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\ProductosCreateRequest;
use App\Http\Requests\ProductosUpdateRequest;
use Illuminate\Support\Facades\Validator;
use DB;
use Input;
use Storage;

class ProductosController extends Controller
{
    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $productos = Productos::all();
        return view('admin.productos.create', compact('productos'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(ProductosCreateRequest $request)
    {
        \App\Proyectos::create([
            'nombre' => $request['nombre'],
            'stock' => $request['stock'],            
            'precio' => $request['precio'],
            'url' => str_slug($request['nombre'], '-'),  // Acá le pasamos la funcion str_slug() al nombre y generamos la URL amigable y la guardamos en la Base de Datos
            'img' => $request['img'],
        ]);

        return redirect('admin/productos')->with('message','Creado Satisfactoriamente !');
    }
    

}

Ahora vamos a crear las rutas para poder visualizar las url amigables en la barra de navegación, vamos al archivo de rutas web.php y agregamos

// Vista Home
Route::get('/', ['as' => '/', 'uses' => 'FrontController@index']);

// Vista para los detalles de un producto
Route::get('productodetalle/{url}', ['as' => 'productodetalle', 'uses' => 'FrontController@productodetalle']);

Ahora creamos nuestro modelo llamado Productos.php y accedemos a la tabla postres para usar los campos correspondientes

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Carbon\Carbon;

class Productos extends Model
{
     /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'postres';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['nombre', 'precio', 'stock', 'url', 'img', 'fecha_creacion'];


    /* :::::: Subir una sola imagen :::::: */
    public function setPathAttribute($path){
        $this->attributes['path'] = Carbon::now()->second.$path->getClientOriginalName();
        $name = Carbon::now()->second.$path->getClientOriginalName();
        \Storage::disk('local')->put($name, \File::get($path));
    }


    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
}

Ahora vamos a crear un controlador para la vista de los productos y listarlos en esta vista, creamos controlador con el nombre FrontController.php y agregamos la función productodetalle($url) en esta función pasamos la url que llega desde la ruta productodetalle/{url} que creamos en nuestro archivo web.php y aparecerá en la barra de navegación

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Productos;
use Session;
use Redirect;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use DB;
use Input;
use Illuminate\Support\Facades\Redirect as BaseController;
use Laracasts\Flash\Flash;
use Auth;

class FrontController extends Controller
{

  public function index()
  {
      $productos = Productos::all();
      return view('welcome', compact('productos'));
  }

  // Detalles del Producto
    public function productodetalle($url)
    {
        $productos = Productos::where('url','=', $url)->firstOrFail();
        return view('productodetalle', compact('productos'));
    }

}

Por ultimo vamos listar los productos en nuestra vista llamada con el nombre de archivo welcome.blade.php y colocamos {{ url(‘productodetalle’, [$pro->url]) }} que es como pasara la url con los datos del producto a una nueva pagina llamada productodetalle.blade.php en donde visualizaremos todos los detalles del producto

<div class="row">

    @foreach ($productos as $pro)

       <div class="col-md-4">
         <div class="card mb-4 shadow-sm">
            <img src="img/{{ $pro->img }}" title="{!!$pro->nombre!!}" alt="{!!$pro->nombre!!}">
             <div class="card-body">
                <p class="card-text">{!!$pro->nombre!!}</p>
                <div class="d-flex justify-content-between align-items-center">
                    <div class="btn-group">
                      <button onclick="location.href='{{ url('productodetalle', [$pro->url]) }}'" href="" type="button" class="btn btn-sm btn-outline-secondary">Ver</button>
                    </div>
                    <small class="text-muted">Postres</small>
                </div>
             </div>
         </div>
      </div>

   @endforeach

</div>

Ahora crearemos una vista llamada productodetalle.blade.php y llamamos a todos los datos del producto que deseamos mostrar

<section class="text-center">
   <div class="container">
       <h1 class="jumbotron-heading">{!!$productos->nombre!!}</h1>
   </div>
</section>

<div class="album py-5 bg-light">

    <div class="container">

        <div class="row">

            <div class="col-md-5">
                <img src="../img/{{ $productos->img }}" alt="">
            </div>

            <div class="col-md-7">

                <strong>Stock:</strong> {{$productos->stock}}

                <br>

                <strong>Precio:</strong> {{$productos->precio}}

                <br>

                <strong>Publicado:</strong> {{ date('d-m-Y', strtotime($productos->fecha_creacion)) }}

            </div>

        </div>

    </div>

</div>

De esta manera, podemos crear miles de productos o registros en nuestra base de datos y se le va generar siempre una url amigable diferente para cada producto, pueden usar funciones adicionales para manipular la creación de la url y evitar nombres duplicados.

Nota

Existen otras maneras de crear url amigables en Laravel, esta es una de ellas, quizás en próximas versiones de Laravel 5.6 en adelante, no permita esta manera de crear url amigables, te pedimos encarecidamente que escribas en los comentarios cual es la nueva forma de hacerlo, asi estaremos contribuyendo con los demás desarrolladores web que también buscan aprender.

Síguenos en las Redes Sociales para que no te pierdas nuestros próximos contenidos.