NF2 - Framework Laravel

De wikiserver
La revisió el 12:16, 6 des 2019 per Jnoguera (Discussió | contribucions) (RUTAS BÁSICAS)
Dreceres ràpides: navegació, cerca

ESTRUCTURA DIRECTORIOS

CREAR PROYECTO LARAVEL

composer create-project --prefer-dist laravel/laravel proyecto

composer create-project --prefer-dist laravel/laravel proyecto "6.0"  //especificamos la versión

RUTAS BÁSICAS

Dentro de Routers -> Web

Route::get('mundo', function () {
    return 'Hello World';
});

Creamos un controlador vacio, App->http->Controller->

php artisan make:controller MoviesController --plain

//en route
Route::get('/ejemplo', 'PeliculasController@index');

//en controlador
public function index(){

echo "hola Julio";

}


//verbos HTTP múltiples
Route::match(['get', 'post'], '/', function () {
    //
});

//verbos HTTP cualquiera
Route::any('/', function () {
    //
});


//dentro de la misma vista, asignamos valor por defecto
Route::get('/show/{id?}',function($id="122"){

    return $id;
    
    })->name('show');


Route::get('/par-o-impar-{numero}',function($numero){    // no hace falta usar '/'

return $numero;

//return redirect()->to('/show/3');  -> te redirije a la ruta que le indicas 
//return redirect()->route('show')  -> te redirije a la ruta que tiene el nombre asignado en el name.
//return redirect()->route('show',['id' => '222'])  -> en caso de pasarle algun parámetro
} )->where(['number' => '[\d]+']);    // de esta forma añadimos una expresion regular para que solo puedan introducir numeros


Route::get('user/{name?}', function ($name = 'John') {  //$name=null
    return $name;
});

Restricciones con Expresiones Regulares

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');   //nomes poden passar lletres miníscules o Majúscules como mínim una volta 

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');   //com a mínim, a soles podem passar com a mínim un nombre.

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);   //le pasamos un array en caso de más de un elemento.


Ruta en función del ROLE

// en el navegador puedes poner /admin/modificar-usuario  o  /admin/insertar-usuario
Route::group(['prefix'=>'admin'],function(){ 
    
    Route::get('modificar-usuario',function(){

    return "modifica usuario";

    });


    Route::get('insertar-usuario',function(){

    return "insertar usuario";

    });

});


->pluck https://github.com/dbushell/Nestable

https://medium.com/@cvallejo/los-mejores-30-tips-de-laravel-d0c96a1c900e

https://www.laraveltip.com/tips-por-temas/laravel/

https://pablomonteserin.com/curso/laravel/

RELACIONES

1. Es recomendable crear primero el Modelo ya que luego crea la migración, por ejemplo: php artisan make:model Libro -m creará la migracion create_libros_table


php artisan make:migration create_categories_table --create="categories"

//la tabla en la base de datos es en plural y el modelo en singular


Se deben de hacer las relaciones de la base de datos en las migraciones y también en los modelos para facilitar a Eloquent las consultas.


RELACIÓN UNO A MUCHOS (1XM)

Una categoria tiene muchos artículos. Creamos primero las migraciones (bases datos) y luego el modelo (Entidades), también tenemos la opción de crear el modelo y luego automaticamente las migraciones pero hay que tener cuidado ya que genera el nombre de las tablas de la migración en inglés.

php artisan make:migration create_categorias_table --create="categorias"


php artisan make:migration create_articulos_table --create="articulos"



//tabla Categories
  Schema::create('categorias', function (Blueprint $table) {
            $table->increments('id')->unsigned();
            $table->text('nombre');
            $table->mediumText('masInfo');
            $table->timestamps();
        });

//tabla Posts


    Schema::create('articulos', function (Blueprint $table) {
            $table->increments('id')->unsigned();
            $table->integer('categoria_id')->unsigned();  //si hubieramos puesto categorias_id tambien hubiera cogido la relación
            $table->text('titulo');
            $table->mediumText('descripcion');
            $table->timestamps();
            //relaciones
            $table->foreign('categoria_id')->references('id')->on('categorias')->onDelete('cascade')->onUpdate('cascade');
            //category_id hace referencia a la tabla categories y el borrado y la actualización es en cascada.
        });

Creamos los modelos

php artisan make:model Categoria

//Modelo Categoria
class Categoria extends Model
{
    protected $table = 'categorias';
    //protected $primary_key = 'categoria_id';
    protected $fillable = ['nombre', 'masInfo'];

    public function articulos()
    {
        return $this->hasMany('App\Articulo');
    }
}


//Modelo Artículos

class Articulo extends Model
{
    protected $table = 'articulos';
    protected $fillable = ['titulo', 'descripcion'];

    public function categoria()
    {
        return $this->belongsTo('Categoria');
    }
}

En el controlador

public function insertar()
    {
        $categoria = Categoria::find(3);   //buscamos que ya tenemos almacenada o la creamos.

        $articulo = new Articulo(['titulo' => 'Pedazo Artículo', 'descripcion' => 'toda la descripción']);  //creamos artículo.
        $categoria->articulos()->save($articulo);  //guardamos dentro de categoria un artículo.
       
       //en caso que tengamos varios artículos
       /* $categoria->articulos()->saveMany([
            new Articulo(['titulo' => 'A new comment.', 'descripcion' => 'hola']),
            new Articulo(['titulo' => 'Another comment.',  'descripcion' => 'hola']),
        ]);*/
        
    }

http://documentacion-laravel.com/eloquent-relationships.html#insertando-y-actualizando-modelos-relacionados

mostrar artículos

//Métodos de relación

 $categoria = Categoria::find(3);  //debe existir categoria y artículos
 return $categoria->articulos()->where('descripcion', "hola")->get();


//Propiedades dinámicas

$categoria = Categoria::find(3);

foreach ($categoria->articulos as $articulo) {
     print_r($articulo->titulo);
    }

Borrado

//borra la categoria 9 y todos los articulos relacionados (cascada)
$Categoria = Categoria::find(9);
$Categoria->delete();

//borra artículo
$articulo = Articulo::find(2);        
$articulo->delete();

Relaciones Uno a Muchos Migraciones

un usuario tiene muchos post y un post lo tiene un usuario

//tabla Categories
  Schema::create('categories', function (Blueprint $table) {
            $table->increments('id')->unsigned();
            $table->text('nombre');
            $table->mediumText('masInfo');
            $table->timestamps();
        });

//tabla Posts


    Schema::create('posts', function (Blueprint $table) {
            $table->increments('id')->unsigned();
            $table->integer('category_id')->unsigned();
            $table->text('titulo');
            $table->mediumText('descripcion');
            $table->timestamps();
            //relaciones
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade')->onUpdate('cascade');
            //category_id hace referencia a la tabla categories y el borrado y la actualización es en cascada.
        });


class Articulo extends Model
{
    protected $table = 'articulos';

    public function escritor()
    {
        return $this->belongsTo('App\Escritor');
    }
}
class Escritor extends Model
{
    protected $table = 'escritores';
    protected $primary_key = 'escritor_id';

    public function articulo()
    {
        return $this->hasMany('App\Articulo');
    }
}

https://medium.com/@hemnys25/de-0-a-100-con-eloquent-de-laravel-parte-0-d5347c060ad7

RELACION DE NXM (MUCHOS A MUCHOS)

Un post puede tener muchas Etiquetas y una etiqueta puede tener muchos Posts, por tanto habrá que crear una tabla auxiliar.

php artisan make:migration create_etiquetas_table --create="etiquetas"

php artisan make:migration create_posts_table --create="posts"

php artisan make:migration create_etiqueta_post_table --create="etiqueta_post"

//ETIQUETAS
Schema::create('etiquetas', function (Blueprint $table) {
            $table->increments('id');

            $table->string('nombre',128);
            $table->string('slug',128);

            $table->timestamps();
        });

//POSTS
   Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');

             $table->string('nombre',128)->unique();
             $table->string('slug',128);
             $table->text('cuerpo');
             $table->enum('status',['PUBLISHED','DRAFT'])->default('DRAFT');
             $table->string('file', 128)->nullable();
 
             $table->timestamps();
             
        });

//ETIQUETA_POST
 Schema::create('etiqueta_post', function (Blueprint $table) {
            $table->increments('id');

            $table->integer('post_id')->unsigned();
            $table->integer('etiqueta_id')->unsigned();

            $table->timestamps();

             //relaciones
             $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade')->onUpdate('cascade');
             $table->foreign('etiqueta_id')->references('id')->on('etiquetas')->onDelete('cascade')->onUpdate('cascade');
        });


//Modelo POST
class Post extends Model
{
    protected $table = 'posts';
    //protected $primary_key = 'categoria_id';
    protected $fillable = ['nombre', 'cuerpo','status'];

    public function etiquetas()
    {
        return $this->belongsToMany('App\Etiqueta');
    }
}

//Modelo ETIQUETA

class Etiqueta extends Model
{
    protected $table = 'etiquetas';
    //protected $primary_key = 'categoria_id';
    protected $fillable = ['nombre', 'slug'];

    public function posts()
    {
        return $this->belongsToMany('App\Post');
    }
}

//INSERTAR Tabla intermedia

public function insertarTablaIntermedia(){
        $etiqueta=Etiqueta::find(1);
        $post = Post::find(2);
        $post->etiquetas()->attach($etiqueta);
       }

findOrNew

Para las relaciones NxM Muchos a Muchos. Un post puede tener muchas Etiquetas y una etiqueta puede tener muchos Posts, por tanto habrá que crear una tabla auxiliar.

//Tabla Post
 Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');

           // $table->integer('user_id')->unsigned();
           // $table->integer('category_id')->unsigned();
            
            $table->string('name',128)->unique();
            $table->string('slug',128)->unique();

            $table->mediumText('excerpt')->nullable();
            $table->text('body');
            $table->enum('status',['PUBLISHED','DRAFT'])->default('DRAFT');

            $table->string('file', 128)->nullable();

            $table->timestamps();

            //relaciones
            //$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
            //$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade')->onUpdate('cascade');

        });

//tabla Tags

Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');

            $table->string('name',128);
            $table->string('slug',128)->unique();

            $table->timestamps();
        });


//tabla auxiliar

  Schema::create('post_tag', function (Blueprint $table) {
            $table->increments('id');

            $table->integer('post_id')->unsigned();
            $table->integer('tag_id')->unsigned();

            $table->timestamps();

             //relaciones
             $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade')->onUpdate('cascade');
             $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade')->onUpdate('cascade');
 
        });

CRUD

Creas la tabla

php artisan make:migration create_blogs_table --create=blogs


Luego en la migración creas los campos para la base de datos

Schema::create('blogs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('blog_title');
$table->text('blog_content');
$table->timestamps();
});

Generas las rutas insertando el fichero Web

Route::resource('blogs','blogController');

//Para listar las rutas, en terminal 

php artisan route:list -v

Creamos el modelo

php artisan make:model Blog

//dentro del modelo 
class Blog extends Model
{
protected $fillable = ['blog_title', 'blog_content'];

//¿Qué atributos deberías incluir en dicho array?

//Aquellos que consideres sensibles y que no deberían modificarse o asignarse en cierta forma, el más típico es el id, el cual normalmente no se modifica ni se asigna de forma manual.
}

Creamos Controlador

php artisan make:controller blogController --resource
1.index()

2.create()

3.store()

4.show()

5.edit()

6.update()

7.destroy()

https://www.expertsphp.com/laravel-6-crud-create-read-update-delete-generator-for-beginners-with-example/

//creamos la migracion que es la tabla en la base de datos "datos"

Schema::create('datos', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('nombre');
            $table->text('descripcion');
            $table->timestamps();
        });

//creamos el modelo "Dato" que es la Entidad que vamos a trabajar y dentro ponemos los datos que queremos proteger.

protected $fillable = ['nombre', 'descripcion'];

añadimos las rutas
public function index(){

    $datos=Dato::all();

    return view('index',['datos'=>$datos]);
   } 

//en la vista
@forelse ($datos as $item)
<li> {{$item->nombre}} {{$item->descripcion}} <a href="{{ route('editar', $item->id)}}" >Edit</a>
   <form action="{{ route('borrar', $item->id)}}" method="post">
        @csrf
        @method('DELETE')
        <button type="submit">borrar</button>
    </form>
 </li>
@empty
<li>NO HAY NADA </li>
@endforelse


public function almacenar(Request $request){

//LA MEJOR FORMA DE INSERTAR DATOS ya que se hace la comprobación de los campos obligatorios para que no hagan inyeccion y luego inserta.
    $datos=request()->validate([
        'nombre'=>'required|max:25', 
        'descripcion'=>'required']
    );

    Dato::create($datos);

    return redirect()->route('index');
 //return back(); //te redirecciona a la misma página
   } 

//en la vista


@if ($errors->any())  //esto muestra todos los errores seguidos
    <ul>
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
    </ul>
<br/>
@endif
<form method="post" action="{{ route('almacenar') }}">
    <div>
        @csrf
        <label for="name">Nombre:</label>
        <input type="text" name="nombre" value="{{old('nombre')}}"/>  //ponemos old porque en el caso que carguemos el formulario y diera error habría que volver a introducir todos los campos, así recuerda o guarda los campos que están bien
    <!-- {!! $errors->first('name', '<small>:message</small><br>' )!!}  --> // así especificamos los errores debajo
    </div>
    <div>
        <label for="price">Descripcion:</label>
        <input type="text" name="descripcion" value="{{old('descripcion')}}"/>
    <!--{!! $errors->first('descripcion', '<small>:message</small><br>' )!!}  -->
    </div>

    <button type="submit">Crear</button>
</form>


public function editar($id){

    $dato = Dato::findOrFail($id);  //como no está el dato si nos equivocamos de id nos muestra la página de error 404, podemos crear uno personalizado en la view->errors->404.blade.php , creamos carpeta "errors"


    return view('editar', compact('dato'));
   } 


//en la vista de Editar

@if ($errors->any())
        <div class="alert alert-danger">
            <strong>Whoops!</strong> There were some problems with your input.<br><br>
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif

<form method="post" action="{{ route('actualizar', $dato) }}">  //No es necesario especificar el Id ya que la nueva versión laravel ya busca dentro del Objeto
          <div > 
              @method('PATCH')
              @csrf
              
              <label for="name">nombre:</label>
              <input type="text"  name="nombre" value="{{ $dato->nombre }}"/>
          </div>
          <div >
              <label for="descripcion">descripcion</label>
              <input type="text"  name="descripcion" value="{{ $dato->descripcion }}"/>
          </div>
         
          <button type="submit" >Actualizar</button>
      </form>
  </div>
</div>

//hacer el actualizar

public function actualizar(Request $request, $id){

         $validacion=$request->validate([
        'nombre' => 'required',
        'descripcion' => 'required',
        ]);
       
       $datos = Dato::find($id);   //podremos utilizar findOrFail($id) para que en caso de no encontrar no falle
        $datos->nombre = $request->get('nombre');  //$request->nombre;    //$request->input('nombre');
        $datos->descripcion = $request->get('descripcion');  //$request->descripcion;     //$request->input('descripcion'); 

        $datos->update();
        
        
        // Dato::whereId($id)->update($validacion); //otra opción

       //return redirect()->route('index');
      
    } 

//$request->input() es un array


//en el controlador borrar

    public function borrar($id){

        $dato = Dato::findOrFail($id);
        
        $dato->delete();
    
        return redirect()->route('index');
       }


//rutas en Web
Route::get('/index', 'DatosController@index')->name('index');
Route::post('/almacenar', 'DatosController@almacenar')->name('almacenar');
Route::get('/editar/{id}', 'DatosController@editar')->name('editar');
Route::patch('/actualizar/{id}', 'DatosController@actualizar')->name('actualizar');
Route::delete('/borrar/{id}', 'DatosController@borrar')->name('borrar');


PAGINAR

en controlador de index
        $datos=Dato::latest()->paginate(3);
y en vista debajo de forelse 

{{$datos->links()}}


//en el momento que insertamos datos dentro de la tabla y queremos mostrar los datos de forma más humana.
<ul>
  @forelse ($datos as $item)
              <li>  {{$item->title}}  {{$item->created_at->diffForHumans() }} </li>  
            @empty
                <li>NO HAY NADA </li>
            @endforelse
        </ul>


//obtener datos.

use app\Dato; 

$datos=Dato::get();
$datos=Dato::orderBy('nombre','DESC')->get();
$datos=Dato::latest('created_at')->get();   //muestra los últimos que se han añadido


MANEJAR VALIDACIONES

Para hacer las validaciones hay que evitar ponerlo en el controlador ya que es una mala práctica, por tanto el controlador solo debe tener la responsabilidad de tratar las solicitudes.

https://styde.net/como-trabajar-con-form-requests-en-laravel/

https://www.laraveltip.com/que-son-como-y-por-que-utilizar-los-form-request-de-laravel/

//Para mantener el código limpio y no tener que poner  app->http->request
php artisan make:request CreateDatosRequest   // [Nombre-del-modelo-que-impacta]+[Acción]+Request


 public function authorize()
    {
        return true;  //cambiar a true
    }

    public function rules()
    {
        return [
        'nombre' => 'required',
        'descripcion' => 'required',
        ];
    }

    public function messages()
    {
        return [
        'nombre.required' => 'El :attribute es obligatorio campeón',
        'descripcion.required' => 'El :attribute es obligatorio también',
        ];
    }

// en el controlador bastará con poner


public function actualizar(CreateDatosRequest $request){
//quitamos la validación
}


SESIONES

https://laravel.com/docs/6.x/session

$request->session()->put(['Julio'=>'Administrador']); //crea variable sesión con clave Julio y valor Administrador


session(['julio'=>'Estudiante']);

$request->session()->forget('Juan'); //Borra Juan

$request->session()->flush(); //borra todo

return $request->session()->all();  //muestra todas las variables de sesión

MENSAJES FLASH

//cuando en una página queremos enviar un mensaje flahs podemos poner

return back()->with('status','hemos recibido el mensaje'); //guardamos un mensaje flash

//luego en la misma pagina (back) ponemos una condicion en blade si hay mensaje de sesion muestra sino formulario.
 @if(session('status'))
{{session('status')}}
@else
 formulario
@endif

//como vamos a repetir este codigo en muchos lados, podemos ponerlo en un fichero partial (resources-views-partial) y luego en el codigo lo sustituimos por @include en el editar.blade.php

ALERT SWEET

https://sweetalert.js.org/docs/

<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>

//ponerlo debajo del DOM en la vista
<script>
@if (session('success'))
swal("Buen Trabajo!", "{{ session('success') }}", "success");
@endif
</script>


//en el controlador 
return back()->with('success','Hemos recibido el mensaje');

AUTENTIFICACIÓN

//Crear usuario en versiones anteriores a 6

php artisan make:auth

//Laravel 6

composer require laravel/ui

php artisan ui vue --auth

Después podremos ver que en las rutas Web ha creado Auth::routes();

Dentro app->http->Auth cambiamos las rutas de register y login cambiando ruta a /

Quitamos la ruta /home dentro de las rutas en web

"para borrar la sesion podemos borrar el fichero dentro storage->framework->session como prueba" MUESTRA USUARIO

@auth    //sirve para mostrar en caso de estar autentificado, estar logeado
{{auth()->user()->name}}
@endauth
//tambien cambiar la ruta de middleware en caso de estar autentificado y volver hacer login peta y te manda a home por tanto cambiar a raiz.

LOGOUT

//usar directiva @guest- invitado. en caso de no estar logueado no muestra
@guest 
<a href="{{route('login')}}">Login</a>
@else   
<a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"> Logout </a>

  <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
    {{ csrf_field() }}
  </form>
@endguest

DESHABILITAR REGISTRO

vamos a Web y modificamos ruta

Auth::routes(['register'=>false]);

SABER SI ESTÁ LOGEADO EN EL CONTROLADOR

use Illuminate\Support\Facades\Auth;

if(Auth::check()){ 
 return "estas logeado";
}else { 
 return "no estas logeado";
} 

//usuario en controlador
use Illuminate\Support\Facades\Auth;

// Obtiene el objeto del Usuario Autenticado
$user = Auth::user();

// Obtiene el ID del Usuario Autenticado
$id = Auth::id();
$user->name;



BLOQUEAR USUARIO, INTENTOS FALLIDOS

En el caso que querramos bloquear al usuario por intentos de ingresos fallidos y penalizar el tiempo a la hora de volver autenficarte, bastará con añadir el controlador por defecto app->http->Controller->auth-> LoginController

class LoginController extends Controller
{
   
    use AuthenticatesUsers;

    public $maxAttempts = 2;   //número máximo de intentos
    public $decayMinutes = 2;  //tiempo que durará el bloqueo

MIDDLEWARE

filtran las peticiones http, en nuestro caso que compruebe si el usuario está autentificado o no. Son puertas que una peticion de usuario tiene que pasar antes de llegar al controlador que tiene la logica a la que el usuario intenta acceder. dos formas:

1) añadir a la ruta dentro de Web ->middleware('auth');
Route::get('/insertar','MoviesController@insertar')->name('insertar')->middleware('auth');

2) Dentro del controlador añadimos dentro del constructor
public __construct(){
  $this->middleware('auth')->only('create', 'edit'); //y con esto especificamos que redirija a login en caso de entrar a create y no está logeado.
//  $this->middleware('auth')->except('create', 'edit');  // lo contrario, bloquea a todos los metodos/controladores excepto el create y edit que podrán acceder.
}


https://programacionymas.com/blog/restringir-acceso-solo-administradores-laravel-usando-middlewares

ELOQUENT

$escritor= App\Escritor::findOrFail(1);

$escritor= App\Escritor::where('edad', '>', 100)->firstOrFail();


//insertar
        $escritor = Escritor::find(1);  //$escritor = App/Escritor::find(1);
        $escritor->nombre = 'Pepe';     //$request->name;
        $escritor->save();
//borrar
        $escritor= App\Escritor::find(1);
        $escritor->delete();


//Toda la info de escritor
$escritor = Escritor::find(1);
$escritor->articulo()->get();


//Muestra todos los articulos del escritor 1.
$escritor = Escritor::find(1);
foreach ($escritor->articulo as $articulo) {
   dump($articulo);
 }


//el artículo 1 devuelve quién es su escritor
$articulos = Articulo::find(1);
dump($articulos->escritor->nombre);


//muestra el nombre de todos los escritores de todos los artículos. Una consulta para obtener todos los libros en la tabla, despues otra consulta para cada libro para obtener el autor
$articulos = Articulo::all();
foreach ($articulos as $articulo) {
    echo $articulo->escritor->nombre;
 }


//al usar la carga previa para reducir esta operación a solo 2 consultas
 $articulos = Articulo::with('escritor')->get();
       foreach ($articulos as $articulo) {
           echo $articulo->escritor->nombre ."</br>";
        }

https://desarrollowebtutorial.com/laravel-eloquent-orm-query-builder-consultas-sql/

ROLE

Añadimos en la tabla de migracion users un nuevo atributo role de tipo enum y luego hacemos la migración

$table->enum('role',['user','admin']);

//hacemos la migración
php artisan migrate

Añadimos la autentificación de usuarios en este caso para Laravel 6.0

composer require laravel/ui 

php artisan ui bootstrap --auth

Creamos el MiddleWare y dentro introducimos el siguiente código app->http->Middleware

//php artisan make:middleware Admin

  public function handle($request, Closure $next)
    {
        if (auth()->user()->role == "admin") {

            return $next($request);
        }
        return redirect('home')->with('error', 'You dont have admin access');
    }

Luego registramos dentro del fichero Kernel.php el middleware en $routeMiddleware

'admin' => \App\Http\Middleware\Admin::class,

Creamos la ruta nueva

Route::get('admin/routes', 'HomeController@admin')->middleware('admin');

En el controlador de HomeController, son las dos rutas que hemos indicado en caso de ser user o admin

public function index()
    {
        return view('home');
    }

    public function admin()
    {
       return view('admin');
    }

Creamos las dos vistas

home.blade

@extends('layouts.app')
 
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">USER NORMAL</div>
 
                <div class="card-body">
                    @if(auth()->user()->is_admin == "admin")
                    <a href="{{url('admin/routes')}}">Admin</a>
                    @else
                    <div class="panel-heading">Normal User</div>
                    @endif
                </div>
            </div>
        </div>
    </div>
</div>
@endsection


admin.blade.php

@extends('layouts.app')
 
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">ADMINISTRADOR</div>
 
                <div class="card-body">
                    @if(auth()->user()->is_admin == "admin")
                    <a href="{{url('admin/routes')}}">Admin</a>
                    @else
                    <div class="panel-heading">Normal User</div>
                    @endif
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

//nota: habrá que cambiar la ruta del fichero loginController a la ruta /admin/routes para que haga el middleware

https://w3path.com/laravel-6-multiple-authentication-system-example-tutorial/ https://stackoverflow.com/questions/39555865/laravel-routegroup-for-admins

Ejercicio: Modificar el registro de usuarios para que pueda añadirse el diferente tipo de role con un desplegable (user o Admin)


LISTAR RUTAS php artisan route:list

BORRAR MODELO O MIGRACION

Borramos el fichero y luego ejecutamos

composer dump-autoload

RECUPERAR CONTRASEÑA POR CORREO

https://stackoverflow.com/questions/33939393/failed-to-authenticate-on-smtp-server-error-using-gmail

https://github.com/facade/ignition-code-editor

SUBIR FICHEROS

RUTAS

Route::view('/subir','subir')->name('subir');   //va directamente a la vista, no hace falta poner controlador

Route::post('/subidoFichero','PruebasController@subidoFicheroPost')->name('subidoFicheroPost');

VISTA Subir

@if ($message = Session::get('success'))
<strong>{{ $message }}</strong>  <!-- muestra el mensaje flash en caso de ser cierto-->
@endif

@if (count($errors) > 0)
<div>
    <strong>Uppss!</strong> Hay algunos problemas en la subida.<br><br>
    <ul>
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif


<form action="{{ route('subidoFicheroPost')}}" method="post" enctype="multipart/form-data">
    @csrf
    <div class="form-group">
        <input type="file" name="fileToUpload" id="exampleInputFile" aria-describedby="fileHelp">
        <small id="fileHelp">El tamaño del fichero no debe ser superior a 2 MB.</small>
    </div>
    <button type="submit">Subir</button>
</form>
</div>
</div>
</div>
</div>

CONTROLADOR SubidaFicheroPost

public function subidoFicheroPost(Request $request){
        $request->validate([
            'fileToUpload' => 'required|file|max:1024',
        ]);

       // $request->fileToUpload->store('logos');   //almacena el fichero dentro de storage->app->logos

       $fileName = "fileName".time().'.'.request()->fileToUpload->getClientOriginalExtension();  //filename+ tiempo desde inicio UNIX + extensión fichero (.pdf...)

        $request->fileToUpload->storeAs('logos',$fileName); //almacena el fichero dentro de storage->app->logos

        return back()->with('success','Tu imagen se ha subido satisfactoriamente');  //retorna a la misma página

    }

DESCARGAR FICHEROS .ZIP

composer require chumper/zipper

//dentro de config/app.php
//en providers
Chumper\Zipper\ZipperServiceProvider::class,
//en aliases
'Zipper' => Chumper\Zipper\Zipper::class,

Controlador

use Zipper;

class Controller extends BaseController
{
 

    public function comprimirDescargar()
    {
        /*Añadimos la ruta donde se encuentran los archivos que queramos comprimir,
          en este ejemplo comprimimos todos los que se encuentran en la carpeta 
          storage/app/public*/
        $files = glob(storage_path('app/public/*'));
        
        /* Le indicamos en que carpeta queremos que se genere el zip y los comprimimos*/
        Zipper::make(storage_path('app/public/ejemplo.zip'))->add($files)->close();
        
        /* Por último, si queremos descarlos, indicaremos la ruta del archiv, su nombre
        y lo descargaremos*/
        return response()->download(storage_path('app/public/ejemplo.zip'));
    }


}

RUTA

Route::get('/comprimir', 'Controller@comprimirDescargar')->name('comprimir');

VISTA

<a href="{{route('comprimir')}}">Comprimir y descargar</a>

AJAX

https://www.tutsmake.com/laravel-6-install-yajra-datatables-example-tutorial/

https://laraveles.com/implementacion-datatables-laravel-5-4/

Cambiar -> config/app.php

//instalamos paquete yajra	
composer require yajra/laravel-datatables-oracle

añadir en alias
'Datatables' => yajra\Datatables\Datatables::class,

añadir en providers
yajra\Datatables\DatatablesServiceProvider::class,

hacer público el archivo de configuración con el siguiente comando, el cual nos crea el archivo config/datatables.php	
php artisan vendor:publish --tag=datatables


//Migración
 Schema::create('tareas', function (Blueprint $table) {
            $table->increments('id');
            $table->string('nombre');
            $table->string('apellido');
            $table->string('estado');
            $table->timestamps();
        });

//Modelo

class Tarea extends Model
{
    protected $table = 'tareas';
    protected $primary_key = 'tareas_id';
}


// web
Route::get('/', 'PruebaController@index');
Route::get('/tareas', 'PruebaController@getTareas')->name('datatable.tareas');


//controlador

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Redirect,Response,DB,Config;
use Datatables;
use App\tarea;

class PruebaController extends Controller
{
    public function index()
    {
        return view('vista');
    }
 
    /**
     * @return mixed
     */
    public function getTareas()
    {
        $tareas = Tarea::select(['id','nombre','apellido','estado']);
 
        return Datatables::of($tareas)->make(true);
    }
}


//vista


<!DOCTYPE html>
 
<html lang="en">
<head>
<title>Laravel DataTable - Tuts Make</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">  
<link  href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>  
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
</head>
<body>
 
<div class="container">
    <table id="task" class="table table-hover table-condensed">
        <thead>
        <tr>
            <th>Id</th>
            <th>Task</th>
            <th>Category</th>
            <th>State</th>
        </tr>
        </thead>
    </table>
</div>
 
<script type="text/javascript">
    $(document).ready(function() {
        oTable = $('#task').DataTable({
            "processing": true,
            "serverSide": true,
            "ajax": "{{ route('datatable.tareas') }}",
            "columns": [
                {data: 'id', name: 'id'},
                {data: 'nombre', name: 'nombre'},
                {data: 'apellido', name: 'apellido'},
                {data: 'estado', name: 'estado'}
            ]
        });
    });
</script>
</body>
</html>

SLUG (babosa)

Para mejorar el posicionamiento SEO de nuestra web en las url hay que evitar poner "/detalle/1" y darle un signficado a nuestras rutas "/detalle/julio-profesor"

Por tanto, podemos añadir a nuestra tabla de la base de datos un nuevo campo, por ello, podemos editar la tabla:

//php artisan make:migration anadir_slug_tabla_tareas --table=tareas
//creará una nueva migración donde añadiremos un nuevo campo, en este caso slug.

class AnadirSlugTablaTareas extends Migration
{
    public function up()
    {
        Schema::table('tareas', function (Blueprint $table) {
            $table->string('slug')->unique;
        });
    }
    public function down()
    {
        Schema::table('tareas', function (Blueprint $table) {
        $table->dropColumn('slug');    //eliminar campo.
        });
    }
}

Luego en el campo slug habrá que añadir "julio-profesor"

//CONTROLADOR
   public function mostrar()   //muestro todos los campos
    {
        $datos = Tarea::all();
        return view('datos', ['datos' => $datos]);
    }

    public function detalle($slug)   //Recibe el campo slug de la base de datos  y busca el resultado en la base de datos.
    {
        $tarea = Tarea::where('slug', $slug)->first();
        return $tarea;
    }
//VISTA
@forelse ($datos as $item)
<li> {{$item->nombre}}  <a href="{{ route('detalle', $item->slug)}}" >detalles</a></li>
@empty
<li>NO HAY NADA </li>
@endforelse
//RUTAS
Route::get('/mostrar', 'PruebaController@mostrar')->name('mostrar');
Route::get('/detalle/{slug}', 'PruebaController@detalle')->name('detalle');

SEEDER (SEMILLAS)

SEEDER normal


php artisan make:seeder NombreSeeder

//dentro de database->seeds se genera la nueva semilla.

//luego en dataBaseSeeder activamos dentro de la clase $this->call(NombreSeeder::class);

//y en la clase NombreSeeder:

  for ($i=0; $i<10; $i++) {
        DB::table('projects')->insert([
            'title' => Str::random(10),
            'description' => Str::random(10).'@gmail.com',
            'created_at' => date('Y-m-d'),
            'updated_at' => date('Y-m-d')        ]);
    }

CLASE FAKER

//si queremos utilizar la clase FAKER

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Faker\Factory as Faker;

class ContactosSeeder extends Seeder
{
  public function run(){
    // puntero para recorrer Faker
    $handle = Faker::create();

    for ($i=0; $i<10; $i++) {
      DB::table('contactos')->insert([
        'nombre' => $handle->firstName,
        'apellidos' => $handle->lastName,
        'created_at' => date('Y-m-d'),
        'updated_at' => date('Y-m-d')
      ]);
    }
  }
}

CLASES PERSONALIZADAS

//Crear nuestra Clase Personaliza Helper.php dentro de un directorio Helpers dentro de nuestra carpeta app de laravel quedando de la siguiente forma: app/Helpers/Helper.php con la siguientes lineas de codigo,

# Ubicacion app\Helpers\Helper.php

namespace App\Helpers;

class Helper
{
    public static function strUp(string $string)
    {
        return strtoupper($string);
    }
}

Crear Alias en nuestra aplicacion

# Ubicacion: config/app.php

    'aliases' => [
     ...
        'Helper' => App\Helpers\Helper::class,
     ...

Usarlo en nuestras plantillas Blade

{{ Helper::strUp('mostrar este texto en mayúsculas!') }}

Usarlos en nuestro controlador

namespace App\Http\Controllers;

use Helper;
//use App\Helpers;

class TuController extends Controller
{

    public function metodo()
    {
        Helper::strUp('mostrar este texto en mayúsculas!');
    }
}