Desde su lanzamiento inicial en 2011, Laravel ha experimentado un crecimiento exponencial. En 2015 se convirti贸 en el m谩s destacado framework PHP en GitHUb.聽
La filosof铆a de Laravel es desarrollar c贸digo PHP聽de forma elegante y simple basado en un modelo MVC(Modelo-Vista-Controlador).聽Cuenta con un c贸digo modular y extensible por medio de un administrador de paquetes y un soporte robusto para el manejo de bases de datos.
Esta gu铆a esta elaborada pensando en personas que est谩n iniciando con Laravel, se desarrollar谩 un sistema de registro para cubrir聽 las operaciones b谩sicas de creaci贸n, lectura, actualizaci贸n y borrado de registros, com煤nmente conocido como CRUD.聽
Requisitos del Servidor
Todos los requerimientos del servidor para el desarrollo de esta gu铆a se encuentran en el art铆culo Instalar Laravel con Apache y MySQL
Crear Base de Datos
Ejecutar en la terminal el siguiente comando:聽
mysql -u root -p
Te pedir谩 la contrase帽a del usuario root, una vez ingreses la contrase帽a correctamente te mostrara el prompt de mysql>

Tambi茅n puedes usar phpmyadmin para crear la base de datos, si lo tienes instalado.聽
Desde la terminal crear la base de datos a utilizar:
CREATE DATABASE laravelcrud;
Crear el usuario y contrase帽a, el cual ser谩 asignado a la base de datos creada:
CREATE USER 'laravel_user'@'127.0.0.1' IDENTIFIED BY 'LaB_101
Asignar a la base de datos el usuario creado:
GRANT ALL ON laravelcrud.* TO 'laravel_user'@'127.0.0.1';
Para recargar la tabla de privilegios, se ejecuta el siguiente comando:
FLUSH PRIVILEGES;
Crear Proyecto Laravel
Ejecutar comando que crear谩 un nuevo proyecto llamado laravelcrud,聽 este comando generar谩 toda la estructura de carpetas,archivos y dependencias necesarias para correr la aplicaci贸n:聽
laravel new laravelcrud

Abrir Proyecto en el Editor de Preferencia
Una vez generado el nuevo proyecto Laravel, abrirlo desde el editor de preferencia, personalmente me gusta utilizar Visual Code.聽
Por medio de la terminal acceder a la carpeta del proyecto:
cd laravelcrud
Establecer Configuraci贸n De Base De Datos
Buscar el archivo .env y proceder a poner la configuraci贸n de la base de datos creada y que ser谩 utilizada por la aplicaci贸n:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravelcrud DB_USERNAME=laravel_user DB_PASSWORD=LaB_101$
Para estar seguro que exista conexi贸n entre nuestra aplicaci贸n y la base de datos ejecutar el comando:
php artisan migrate
Este comando crear谩 3 tablas en la base de datos por defecto:聽
- migratios
- password_resets
- users
En la terminal conectado al prompt de MySQL ejecutar :
mysql> use laravelcrud; mysql> show tables;
Adicional en el proyecto se crearon autom谩ticamente las migraciones para esas tablas en la carpeta generada app–>database->migrations聽
Crear Modelo y Migraci贸n
En la terminal ejecutar :
php artisan make:model Registry -m
Se crear谩n dos archivos:
- Registry.php el modelo.
- create_registries_table.php la migraci贸n.
Se necesita crear la estructura (schema) de la tabla de registry para ello se modifica el archivo de la migraci贸n reci茅n creado que se encuentra en app–>database–>migrations–>create_registries_table.ph
En la clase creada para la migraci贸n se generan autom谩ticamente dos m茅todos up y down, modificar de la siguiente manera:
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateRegistriesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('registries', function (Blueprint $table) { $table->integer('id')->unsigned(); $table->string('first_name',50); $table->string('second_name',50)->nullable(); $table->string('surename',50); $table->string('second_surename',50)->nullable(); $table->string('email',100); $table->string('cell_phone',50)->nullable(); $table->string('phone',50)->nullable(); $table->string('coments',500)->nullable(); $table->integer('age'); $table->boolean('flosspainfo')->nullable(); $table->boolean('fedorainfo')->nullable(); $table->boolean('latansecinfo')->nullable(); $table->timestamps(); $table->primary(array('id', 'email')); }); DB::statement('ALTER TABLE registries MODIFY id INTEGER NOT NULL AUTO_INCREMENT'); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('registries'); } }
Volver a ejecutar el comando de migraciones :
php artisan migrate
Para validar la creaci贸n de la tabla ejecute comando de base de datos utilizado anteriormente y para validar la creaci贸n de las columnas ejecute desde la terminal con MySQL:
use laravelcrud; show columns from registries;
Crear Vista Registro
Se genera la primera vista, para ello crear la carpeta registries聽dentro de app–>resources –> views聽聽 y luego聽 聽crear dentro de esta carpeta el archivo create.blade.php:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>FLOSSPA Asistencia Evento </title> <link rel="stylesheet" href="{{asset('css/app.css')}}"> <link rel="stylesheet" href="{{asset('css/registry.css')}}"> </head> <body> <div class="container"> <img alt="FLOSSPA" srcset="{{ URL::to('/images/logo-flosspa.svg') }}"> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div><br /> @endif @if (\Session::has('success')) <div class="alert alert-success"> <p>{{ \Session::get('success') }}</p> </div><br /> @endif <form method="post" action="{{url('registries')}}" id="formRegistry"> {{csrf_field()}} <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Primer Nombre:</label> <input type="text" class="form-control" name="first_name" value={{old('first_name')}}> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Segundo Nombre:</label> <input type="text" class="form-control" name="second_name" value={{old('second_name')}}> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Primer Apellido:</label> <input type="text" class="form-control" name="surename" value={{old('surename')}}> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Segundo Apellido:</label> <input type="text" class="form-control" name="second_surename" value={{old('second_surename')}}> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Email:</label> <input type="text" class="form-control" name="email" value={{old('email')}}> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Edad:</label> <input type="text" class="form-control" name="age" value={{old('age')}}> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">T茅lefono Residencial:</label> <input type="text" class="form-control" name="phone" value={{old('phone')}}> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Celular:</label> <input type="text" class="form-control" name="cell_phone" value={{old('cell_phone')}}> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Desea recibir informaci贸n de:</label> <div class="checkbox"> <label> <input type="checkbox" name="flosspainfo" @if(old('flosspainfo') !== NULL ){{ 'checked' }}@endif> FLOSSPA</label> </div> <div class="checkbox"> <label> <input type="checkbox" name="fedorainfo" @if(old('fedorainfo') !== NULL ){{ 'checked' }}@endif> FEDORA</label> </div> <div class="checkbox disabled"> <label> <input type="checkbox" name="latansecinfo" @if(old('latansecinfo') !== NULL ){{ 'checked' }}@endif> LATANSEC</label> </div> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-12 col-md-12"> <label for="name">Comentarios:</label> <textarea class="form-control" rows="5" name="coments" >{{old('coments')}}</textarea> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-12 col-md-12"> <button type="submit" class="btn btn-success">Agregar Asistencia</button> </div> </div> </form> </div> <div id="toast-container" class="toast-top-right"> </div </body> </html>
Para evitar ataques CSRF (del ingl茅s Cross-site request forgery o falsificaci贸n de petici贸n en sitios cruzados) es un tipo de exploit malicioso de un sitio web en el que comandos no autorizados son transmitidos por un usuario en el cual el sitio web conf铆a. Esta vulnerabilidad es conocida tambi茅n por
otros nombres como XSRF, enlace hostil, cabalgamiento de sesi贸n, y ataque autom谩tico. Larvel provee la protecci贸n {{csrf_field()}}聽.
Para preservar la informaci贸n en el formulario se logra聽 agregando en cada uno de los controles a帽adidos value={{old(‘first_name’)}}聽.
Ahora crear el controlador para desplegar la vista , ejecutar el siguiente comando:
php artisan make:controller RegistryController --resource
Dentro de la carpeta app–>Http–>Controllers se encontrar谩 el controlador, generado autom谩ticamente con todos los m茅todos necesarios para el CRUD.
Para poder tener acceso a los m茅todos creados, se debe agregar una ruta que haga referencia al controlador, para ello se modifica el archivo app–>routes –> web.php
<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::resource('registries','RegistryController');
Para ver la lista de rutas que se pueden utilizar, ejecutar:
php artisan route:list
En el m茅todo create del controlador se agrega:聽
public function create() { return view('registries.create'); }
Iniciar el servidor de desarrollo de Laravel y se podr谩 ver la primera vista:聽
php artisan serve
Cargar en el buscador la URL http://localhost:8000/registries/create聽

En la carpeta public–>css聽 se agreg贸 CSS personalizado y adem谩s se creo la carpeta images para agregar la imagen que se muestra en pantalla. El c贸digo lo puedes bajar desde mi cuenta de GitHub.
En el modelo se debe manejar la vulnerabilidad Mass Assignment para ellos se modifica la clase que se encuentra en app–>Registry.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Registry extends Model { protected $fillable = ['first_name','second_name','surename','second_surename', 'email','age','phone','cell_phone','flosspainfo','fedorainfo','latansecinfo','coments']; }
Para poder guardar los datos que se env铆en desde la vista se debe modificar el controlador RegistryController.php, incluyendo la clase Registry聽 y la interfaz est谩tica(Facades) Input聽.
use App\Registry; use Illuminate\Support\Facades\Input;
Ahora se debe modificar el m茅todo store:
public function store(Request $request) { $registry = $this->validate(request(), [ 'first_name' => 'required', 'surename' => 'required', 'email' => 'required|email', 'age' => 'integer|min:0' ]); $flosspainfo = Input::get('flosspainfo') == 'on' ? true :false; $fedorainfo = Input::get('fedorainfo') == 'on' ? true :false; $latansecinfo = Input::get('latansecinfo') == 'on' ? true :false; Registry::create([ 'first_name'=> Input::get('first_name'), 'second_name'=> Input::get('second_name'), 'surename'=> Input::get('surename'), 'second_surename'=> Input::get('second_surename'), 'email'=> Input::get('email'), 'cell_phone' => Input::get('cell_phone'), 'phone'=> Input::get('phone'), 'coments'=> Input::get('coments'), 'age'=> Input::get('age'), 'flosspainfo'=> $flosspainfo, 'fedorainfo'=> $fedorainfo, 'latansecinfo'=> $latansecinfo ]); return back()->with('success', 'Informaci贸n almacenada con 茅xito'); }
Cargar la vista y tratar de guardar sin llenar los datos, se recibir谩n mensajes de validaci贸n.
Para desplegar los mensajes en espa帽ol se puede utilizar el siguiente el paquete de traducci贸n en espa帽ol.
聽
Vista Listado
Ahora se crear谩 un listado de todos los registros guardados, crear la vista en
app–>resources–>views–> registries–>index.blade.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Index Page</title> <link rel="stylesheet" href="{{asset('css/app.css')}}"> </head> <body> <div class="container"> <img src="equilateral.png" alt="FLOSSPA" srcset="{{ URL::to('/images/logo-flosspa.svg') }}"> <br /> @if (\Session::has('success')) <div class="alert alert-success"> <p>{{ \Session::get('success') }}</p> </div><br /> @endif <table class="table table-striped"> <thead> <tr> <th>ID</th> <th>Nombre</th> <th>Apellido</th> <th >Email</th> <th >Tel茅fono</th> <th >Celular</th> <th colspan="2">Acci贸n</th> </tr> </thead> <tbody> @foreach($registries as $registry) <tr> <td>{{$registry['id']}}</td> <td>{{$registry['first_name']}}</td> <td>{{$registry['surename']}}</td> <td>{{$registry['email']}}</td> <td>{{$registry['phone']}}</td> <td>{{$registry['cell_phone']}}</td> <td><a href="{{action('RegistryController@edit', $registry['id'])}}" class="btn btn-warning">Edit</a></td> <td> <form onsubmit="return confirm('Do you really want to delete?');" action="{{action('RegistryController@destroy', $registry['id'])}}" method="post"> {{csrf_field()}} <input name="_method" type="hidden" value="DELETE"> <button class="btn btn-danger" type="submit">Delete</button> </form> </td> </tr> @endforeach </tbody> </table> </div> </body> </html
Modificar el controlador agregando la carga de la vista:聽
public function index() { $registries = Registry::all()->toArray(); return view('registries.index', compact('registries')); }
Cargar聽 la vista http://localhost:8000/registries

Vista Edici贸n
Crear la funcionalidad de edici贸n de un registro, para ello se inicia creando la vista que es bastante similar a la de la creaci贸n app–>resources–>views–> registries–>edit.blade.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>FLOSSPA Editar Asistencia Evento </title> <link rel="stylesheet" href="{{asset('css/app.css')}}"> <link rel="stylesheet" href="{{asset('css/registry.css')}}"> </head> <body> <div class="container"> <img src="equilateral.png" alt="FLOSSPA" srcset="{{ URL::to('/images/logo-flosspa.svg') }}"> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div><br /> @endif @if (\Session::has('success')) <div class="alert alert-success"> <p>{{ \Session::get('success') }}</p> </div><br /> @endif <form method="post" action="{{action('RegistryController@update', $id)}}" id="formRegistry"> {{csrf_field()}} <input name="_method" type="hidden" value="PATCH"> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Primer Nombre:</label> <input type="text" class="form-control" name="first_name" value="{{$registry->first_name}}" > </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Segundo Nombre:</label> <input type="text" class="form-control" name="second_name" value="{{$registry->second_name}}"> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Primer Apellido:</label> <input type="text" class="form-control" name="surename" value="{{$registry->surename}}"> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Segundo Apellido:</label> <input type="text" class="form-control" name="second_surename" value="{{$registry->second_surename}}"> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Email:</label> <input type="text" class="form-control" name="email" value="{{$registry->email}}"> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Edad:</label> <input type="text" class="form-control" name="age" value="{{$registry->age}}"> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">T茅lefono Residencial:</label> <input type="text" class="form-control" name="phone" value="{{$registry->phone}}"> </div> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Celular:</label> <input type="text" class="form-control" name="cell_phone" value="{{$registry->cell_phone}}"> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-6 col-md-6"> <label for="name">Desea recibir informaci贸n de:</label> <div class="checkbox"> <label> <input type="checkbox" name="flosspainfo" @if($registry->flosspainfo == true ){{ 'checked' }}@endif> FLOSSPA</label> </div> <div class="checkbox"> <label> <input type="checkbox" name="fedorainfo" @if($registry->fedorainfo == true){{ 'checked' }}@endif> FEDORA</label> </div> <div class="checkbox disabled"> <label> <input type="checkbox" name="latansecinfo" @if($registry->latansecinfo == true ){{ 'checked' }}@endif> LATANSEC</label> </div> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-12 col-md-12"> <label for="name">Comentarios:</label> <textarea class="form-control" rows="5" name="coments" >{{$registry->coments}}</textarea> </div> </div> <div class="row"> <div class="form-group col-xs-12 col-sm-12 col-md-12"> <button type="submit" class="btn btn-success">Update</button> </div> </div> </form> </div> <div id="toast-container" class="toast-top-right"> </div </body> </html>
Modificar el m茅todo edit, as铆 como el m茅todo update del controlador :
/** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { $registry = Registry::find($id); return view('registries.edit',compact('registry','id')); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $registry = Registry::find($id); $this->validate(request(), [ 'first_name' => 'required', 'surename' => 'required', 'email' => 'required|email', 'age' => 'integer|min:0' ]); $registry->first_name = Input::get('first_name'); $registry->second_name = Input::get('second_name'); $registry->surename = Input::get('surename'); $registry->second_surename = Input::get('second_surename'); $registry->email = Input::get('email'); $registry->cell_phone = Input::get('cell_phone'); $registry->phone = Input::get('phone'); $registry->coments = Input::get('coments'); $registry->age = Input::get('age'); $registry->flosspainfo = Input::get('flosspainfo') == 'on' ? true :false; $registry->fedorainfo = Input::get('fedorainfo') == 'on' ? true :false; $registry->latansecinfo = Input::get('latansecinfo') == 'on' ? true :false; $registry->save(); return back()->with('success', 'Registry updated successfully'); }
Borrado De Registro
Para borrar un registro agregar en el m茅todo destroy del controlador lo siguiente:
public function destroy($id) { $registry = Registry::find($id); $registry->delete(); return redirect('registries')->with('success','Registry has been deleted'); }
Puedes encontrar el proyecto completamente funcional en mi cuenta de GitHub.
Alexis Figueroa
septiembre 18, 2019excelente tutorial me ha servido mucho… un millon de gracias…
Davis Alvarez
noviembre 12, 2019Con mucho gusto.
Darwing Salgado
mayo 16, 2023Gracias David ,ha Ciro muy util para mi estoy iniciando en esto de la programaci贸n y la verdad me encanta mucho ,quisiera hacer una aplicaci贸n funcional para registrar datos y manipulaci贸n de datos en un peque帽o negocio .pero no tengo mucha idea creo con el tiempo aprender茅 m谩s .
Gabriel Gamboa
noviembre 3, 2019Wow Davis, genial, no sab铆a conoc铆a este nivel de expertise en Laravel de tu parte, estoy iniciando y encuentro este interesante y completo art铆culo amigo,
Simplemente, genial,
Muchas Gracias por tu tiempo
Davis Alvarez
noviembre 12, 2019脡xitos en tu proceso de aprendizaje de esta herramienta.
Julio ayala
noviembre 9, 2019Muy bueno
Mo pruebo y comento el resultado
Davis Alvarez
noviembre 12, 2019Me alegra que te sirva.
David Parra
julio 4, 2021De pana me sirvi贸 de mucho agradecido
Juan Carlos
octubre 3, 2022Hola, tengo problemas al trabajar su c贸digo.
Me aparece el siguiente c贸digo. Target class [RegistryController] does not exist. Mi error me aparece en Laravel 9.
Ayuda, por favor.