Genero en admin.php una ruta de tipo resources que me genere las rutas para el crud de las categorías. Antes creo un controlador para categorías que me genere ya los 7 métodos.
1
2
enrique@enrique-server:/var/www/laravel/blog_laravel$ php artisan make:controller Admin/CategoryController -r
Controller created successfully.
<?phpnamespaceApp\Http\Controllers\Admin;useApp\Http\Controllers\Controller;useIlluminate\Http\Request;classCategoryControllerextendsController{/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/publicfunctionindex(){//
}/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/publicfunctioncreate(){//
}/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/publicfunctionstore(Request$request){//
}/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionshow($id){//
}/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionedit($id){//
}/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionupdate(Request$request,$id){//
}/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctiondestroy($id){//
}}
Dentro del archivo admin.php creo la ruta de tipo resources para categorías se la asigno al controlador CategoryController y le digo que los nombres de las rutas comiencen por admin.categories.
Si observo las rutas creadas veo que los parámetros que pasamos son de tipo categoy (en singular)
Esto no coincide con los parámetros que pasamos en los métodos del controlador. Los cambio en el controlador para que sean objetos de tipo Category, y añado las vistas que quiero que muestren los metodos index, show, edit y create
<?phpnamespaceApp\Http\Controllers\Admin;useApp\Http\Controllers\Controller;useApp\Models\Category;useIlluminate\Http\Request;classCategoryControllerextendsController{/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/publicfunctionindex(){returnview('admin.categories.index');}/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/publicfunctioncreate(){returnview('admin.categories.create');}/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/publicfunctionstore(Request$request){//
}/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionshow(Category$category){returnview('admin.categories.show',compact('category'));}/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionedit(Category$category){returnview('admin.categories.edit',compact('category'));}/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionupdate(Request$request,Category$category){//
}/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctiondestroy(Category$category){//
}}
Creo las vistas de dichos métodos (index, show, edit y create) resources/views/admin/categories/index.blade.php, resources/views/admin/categories/show.blade.php, resources/views/admin/categories/edit.blade.php y resources/views/admin/categories/create.blade.php y extiendo la plantilla adminLTE a cada una de ellas. Por ejemplo:
create.blade.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@extends('adminlte::page')@section('title','Blog con Laravel')@section('content_header')<h1>Crearcategoría</h1>@stop@section('content')<p>AquivaunformularioparaCrearcategoria.</p>@stop@section('css')<linkrel="stylesheet"href="/css/admin_custom.css">@stop@section('js')<script>console.log('Hi!');</script>@stop
Quiero empezar mostrando el listado de las categorías en una tabla. Para ello modifico la plantilla resources/views/admin/categories/index.blade.php y el método index del controlador CategoryController.php.
método index de CategoryController.php
1
2
3
4
5
6
7
8
9
10
11
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/publicfunctionindex(){$categories=Category::all();returnview('admin.categories.index',compact('categories'));}
En esta vista he creado una tabla dentro de la que listo las categorías por su id y su nombre. Le añado a cada una un botón para editarla que me dirige a ala vista edit.blade.php y otro botón mediante un formulario que me permite utilizar la ruta admin.categories.destroy y el método destroy del controlador. Este formulario lo envío usando el método delete que recomienda laravel para lo cual debo incluir @method('delete')en el formulario.
También he creado un botón para crear una nueva categoría que me redirige mediante la ruta admmin.categories.create a la vista create.blade.php donde un formulario me permite crear una nueva categoría. La vista index.blade.php se ve así.
Para crear los formularios del blog me voy a ayudar de un componente de laravel llamado laravelcollective cuyo sitio web me indica en su sección docs que para poder usar el paquete debo usando composer desde la linea de comandos y escribir el siguiente comando:
@extends('adminlte::page')@section('title','Blog con Laravel')@section('content_header')<h1>Crearcategoría</h1>@stop@section('content')<p>AquivaunformularioparaCrearcategoria.</p><divclass="card"><divclass="card-body">{!!Form::open(['route'=>'admin.categories.store'])!!}<divclass="form-group">{!!Form::label('name','Nombre')!!}{!!Form::text('name',null,['class'=>'form-control','placeholder'=>'ingresa el nombre de la categoria'])!!}</div><divclass="form-group">{!!Form::label('slug','Slug')!!}{!!Form::text('slug',null,['class'=>'form-control','placeholder'=>'ingresa el slug de la categoria','readonly'])!!}</div>{!!Form::submit('Crear categoría',['class'=>'btn btn-primary'])!!}{!!Form::close()!!}</div></div>@stop
Para automatizar la creación del slug voy a utilizar un pluging de JQuery, de manera que el usuario no tenga que escribir nada y evitar errores.
Lo descargo en la carpeta public/vendor desde su página web.
Creo una sección js debajo de la sección content y copio dos script, uno para importar el archivo jquery.stringToSlug.min.js y otra donde escribo el código que relaciona los inputs de name y slug.
@extends('adminlte::page')@section('title','Blog con Laravel')@section('content_header')<h1>Crearcategoría</h1>@stop@section('content')<p>AquivaunformularioparaCrearcategoria.</p><divclass="card"><divclass="card-body">{!!Form::open(['route'=>'admin.categories.store'])!!}<divclass="form-group">{!!Form::label('name','Nombre')!!}{!!Form::text('name',null,['class'=>'form-control','placeholder'=>'ingresa el nombre de la categoria'])!!}</div><divclass="form-group">{!!Form::label('slug','Slug')!!}{!!Form::text('slug',null,['class'=>'form-control','placeholder'=>'ingresa el slug de la categoria','readonly'])!!}</div>{!!Form::submit('Crear categoría',['class'=>'btn btn-primary'])!!}{!!Form::close()!!}</div></div>@stop@section('js')<scriptsrc="{{asset('vendor/jQuery-Plugin-stringToSlug-1.3/jquery.stringToSlug.min.js')}}"></script><script>$(document).ready(function(){$("#name").stringToSlug({setEvents:'keyup keydown blur',getPut:'#slug',space:'-'});});</script>@endsection
Al hacer clic en el botón de submit los datos del formulario se envían por la ruta admin.categories.storeal método store del controlador CategoryController.php. En este método valido los datos y los almaceno en la tabla categories de la base de datos. Dedo habilitar la asignación masiva en el modelo app/Models/Category.php. Para lo cual declaro la propiedad fillable dentro de la entidad Category.php.
Category.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?phpnamespaceApp\Models;useIlluminate\Database\Eloquent\Factories\HasFactory;useIlluminate\Database\Eloquent\Model;classCategoryextendsModel{useHasFactory;protected$fillable=['name','slug'];//habilito la asignación masiva en name y slug
// Relaccion uno a muchos posts
publicfunctionposts(){return$this->hasMany(Post::class);}}
Ambos campos son requeridos y ademas el campo slug debe de ser único en la tabla categorias.
CategoryController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....../**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/publicfunctionstore(Request$request){$request->validate(['name'=>'required','slug'=>'required|unique:categories']);Category::create($request->all());returnredirect()->route('admin.categories.index');}.....
Inserto los posibles errores de validación (dentro de la directiva de blade @error) de los campos name y slug en la vista
..........@section('content')<p>AquivaunformularioparaCrearcategoría.</p><divclass="card"><divclass="card-body">{!!Form::open(['route'=>'admin.categories.store'])!!}<divclass="form-group">{!!Form::label('name','Nombre')!!}{!!Form::text('name',null,['class'=>'form-control','placeholder'=>'ingresa el nombre de la categoria'])!!}@error('name')<spanclass=" text-danger">{{$message}}</span>@enderror</div><divclass="form-group">{!!Form::label('slug','Slug')!!}{!!Form::text('slug',null,['class'=>'form-control','placeholder'=>'ingresa el slug de la categoria','readonly'])!!}@error('slug')<spanclass=" text-danger">{{$message}}</span>@enderror</div>{!!Form::submit('Crear categoría',['class'=>'btn btn-primary'])!!}{!!Form::close()!!}</div></div>@stop..........
Compruebo el funcionamiento del formulario para crear una categoría haciendo clic en el botón crear categoría de la lista de categorias. Aparece una vista donde puedo crear una nueva categoría.
Al rellenar el campo de nombre, se auto rellena el de slug y al hacer clic en el botón Crear categoría se validan los campos antes de crear el registro en la tabla, si hay errores en algún campo se muestran debajo de el.
Si la validación ha sido correcta, guarda el registro en la tabla categories y me redirige al listado de categorías.
Actualizar o editar un registro
Hago clic en el boton editar de una categoria cualquiera y la ruta admin.categories.edit me dirige al método edit del controllador el cual pasa a la vista edit.blade.php el objeto almacenado en la variable $category para mostrarlo en el formulario de la vista en el que se va a editar sus campos. Me baso en el formulario realizado para la vista create.blade.php y lo modifico.
@extends('adminlte::page')@section('title','Blog con Laravel')@section('content_header')<h1>Editaunacategoría.</h1>@stop@section('content')<p>Editardetalledelacategoría.</p><divclass="card"><divclass="card-body">{!!Form::model($category,['route'=>['admin.categories.update',$category],'method'=>'put'])!!}<divclass="form-group">{!!Form::label('name','Nombre')!!}{!!Form::text('name',null,['class'=>'form-control','placeholder'=>'ingresa el nombre de la categoría'])!!}@error('name')<spanclass=" text-danger">{{$message}}</span>@enderror</div><divclass="form-group">{!!Form::label('slug','Slug')!!}{!!Form::text('slug',null,['class'=>'form-control','placeholder'=>'ingresa el slug de la categoría','readonly'])!!}@error('slug')<spanclass=" text-danger">{{$message}}</span>@enderror</div>{!!Form::submit('Actualizar categoría',['class'=>'btn btn-primary'])!!}{!!Form::close()!!}</div></div>@stop@section('js')<scriptsrc="{{asset('vendor/jQuery-Plugin-stringToSlug-1.3/jquery.stringToSlug.min.js')}}"></script><script>$(document).ready(function(){$("#name").stringToSlug({setEvents:'keyup keydown blur',getPut:'#slug',space:'-'});});</script>@endsection
El método utilizado para enviar este formulario es el método put y la ruta debe de ser admin.categories.update a la que debo pasar como parámetro $category. Para rellenar los campos con los datos de la categoría a editar para ello cambio Form::open por Form::model y le paso la variable $category. Quedaría así: {!! Form::model($category, ['route' => ['admin.categories.update', $category], 'method' => 'put']) !!}.
Si hago clic en el botón actualizar categoría la información del formulario se envía a la ruta admin.categories.updateque es administrada por el método update del controlador CategoryController.php. En este método valido la información recibida y si pasa la validación la actualizo en la base de datos y que me redireccione a la ruta admin.categories.edit. Además quiero que ignore el slug del registro que quiero actualizar (cambio 'required|unique:categories' por "required|unique:categories,slug,$category->id" ignorando el slug de la categoría que quiero actualizar).
Por último quiero que se muestre una alerta indicando que se ha actualizado el registro con éxito. Lo condigo enviando un mensaje de sesión (with('info', 'La categoría se actualizó con éxito.')) que debo de recoger la vista admin.categories.edit.
......../**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctionupdate(Request$request,Category$category){$request->validate(['name'=>'required','slug'=>"required|unique:categories,slug,$category->id"//ignora el slug de la categoria que quiero actualizar
]);$category->update($request->all());returnredirect()->route('admin.categories.edit',$category)->with('info','La categoría se actualizó con éxito.');}.........
@section('content')<p>Editardetalledelacategoría.</p>@if(session('info'))<divclass=" alert alert-success"><strong>{{session('info')}}</strong></div>@endif<divclass="card"><divclass="card-body">{!!Form::model($category,['route'=>['admin.categories.update',$category],'method'=>'put'])!!}<divclass="form-group">{!!Form::label('name','Nombre')!!}{!!Form::text('name',null,['class'=>'form-control','placeholder'=>'ingresa el nombre de la categoría'])!!}@error('name')<spanclass=" text-danger">{{$message}}</span>@enderror</div><divclass="form-group">{!!Form::label('slug','Slug')!!}{!!Form::text('slug',null,['class'=>'form-control','placeholder'=>'ingresa el slug de la categoría','readonly'])!!}@error('slug')<spanclass=" text-danger">{{$message}}</span>@enderror</div>{!!Form::submit('Actualizar categoría',['class'=>'btn btn-primary'])!!}{!!Form::close()!!}</div></div>@stop
Esta alerta se puede crear en el método store para que se muestre en la plantilla index al crear una categoría nueva.
Eliminar una categoría
Si hago clic en el botón eliminar la información de la categoría se envía a la ruta admin.categories.destroyque es administrada por el método destroy del controlador CategoryController.php. En este método elimino el registro en la base de datos y que me redirecciona a la ruta admin.categories.index donde me muestra una alerta de borrado del registro.
1
2
3
4
5
6
7
8
9
10
11
12
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/publicfunctiondestroy(Category$category){$category->delete();returnredirect()->route('admin.categories.index')->with('info-del','La categoría se ha eliminado con éxito');}
En la vista añado una condición al if para que recoja la variable de sesión infodel y muestre la alerta de borrado de la categoría.
<?phpnamespaceApp\Models;useIlluminate\Database\Eloquent\Factories\HasFactory;useIlluminate\Database\Eloquent\Model;classCategoryextendsModel{useHasFactory;protected$fillable=['name','slug'];publicfunctiongetRouteKeyName(){return"slug";}// Relaccion uno a muchos posts
publicfunctionposts(){return$this->hasMany(Post::class);}}
Ahora ya muestra el slug como se puede apreciar el la siguiente imagen.