Crear tu Primera Aplicación con Laravel

By Posted on 14301 views

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>

Iniciando MySQL desde la línea de comando
Iniciando MySQL desde la línea de comando

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
Crear nuevo proyecto Laravel
Crear nuevo proyecto Laravel

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: 

  1. migratios
  2. password_resets
  3. 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:

  1. Registry.php el modelo.
  2. 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 

Vista Aplicación Laravel
Vista Aplicación Laravel

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 Listado Laravel
Vista del listado de registros

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.

¿Qué piensas del artículo?

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

20 + veinte =

9 Comments
  • Alexis Figueroa
    septiembre 18, 2019

    excelente tutorial me ha servido mucho… un millon de gracias…

    • Davis Alvarez
      noviembre 12, 2019

      Con mucho gusto.

      • Darwing Salgado
        mayo 16, 2023

        Gracias 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, 2019

    Wow 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, 2019

    Muy bueno
    Mo pruebo y comento el resultado

    • Davis Alvarez
      noviembre 12, 2019

      Me alegra que te sirva.

  • David Parra
    julio 4, 2021

    De pana me sirvió de mucho agradecido

  • Juan Carlos
    octubre 3, 2022

    Hola, 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.