NF2 - Framework Laravel
ESTRUCTURA DIRECTORIOS
Contingut
- 1 COMANDOS INDISPENSABLES LARAVEL
- 2 Estructura Laravel 6
- 3 RUTAS BÁSICAS
- 4 VISTA
- 5 SESIONES
- 6 MENSAJES FLASH
- 7 ALERT SWEET
- 8 TOASTR
- 9 BASES DE DATOS
- 10 SEEDER (SEMILLAS)
- 11 CONSTRUCTOR DE CONSULTAS (Query Builder)
- 12 CONSULTAS SQL NATIVAS
- 13 ELOQUENT
- 14 PAGINAR
- 15 PLUCK
- 16 CRUD
- 17 RELACIONES
- 18 RELACIÓN UNO A MUCHOS (1XM)
- 19 CONSULTAS EN MULTIPLES TABLAS
- 20 RELACION DE MUCHOS A MUCHOS (NXM)
- 21 SLUG (babosa)
- 22 MANEJAR VALIDACIONES
- 23 TRY ... CATCH
- 24 TRADUCCIÓN
- 25 AUTENTIFICACIÓN
- 26 MIDDLEWARE o FILTRO
- 27 ROLE
- 28 RECUPERAR CONTRASEÑA POR CORREO
- 29 SUBIR FICHEROS
- 30 DRAG & DROP
- 31 DESCARGAR FICHEROS .ZIP
- 32 AJAX
- 33 CLASES PERSONALIZADAS
- 34 TRAITS
- 35 GENERAR PDF
- 36 DEBUGBAR
- 37 EJERCICIO 1
- 38 API
COMANDOS INDISPENSABLES LARAVEL
/*CREAR PROYECTOS*/
composer create-project --prefer-dist laravel/laravel proyecto
composer create-project --prefer-dist laravel/laravel proyecto "6.0" //especificamos la versión
composer require facade/ignition //instalar nueva página errores
/*CONTROLADORES*/
php artisan make:controller PeliculasController //añadir CONTROLADOR vacio
php artisan make:model Trainer -m //crea el modelo Trainer y además hace la migracion
php artisan make:model Task -mcr //modelo migracion controlador
/*MODELO*/
php artisan make:model Categoria
/*MIGRACIONES*/
php artisan make:migration create_categorias_table --create="categorias" //creamos la migración (la tabla en la base de datos es en plural y el modelo en singular)
php artisan make:migration anadir_telefono_tabla_cate --table="categorias" //editar tabla (podemos crear otra migración con otro atributo)
php artisan migrate:rollback //deshacer la última migración ejecutada y registrada en la base de datos.
php artisan migrate:fresh //borra la base de datos y la carga de nuevo.
/*RUTAS*/
php artisan routes //genera todas las rutas get,put,post de un crud... Route::resource()
php artisan route:list -v ////Para listar las rutas, en terminal
Estructura Laravel 6
RUTAS BÁSICAS
Dentro de Routers -> Web
Route::get('mundo', function () {
return 'Hello World';
});
Le pasamos a la ruta un identificador que tendrá un valor por defecto y esa ruta tendrá un nombre
//dentro de la misma vista, asignamos valor por defecto
Route::get('/show/{id?}',function($id="122"){
return $id;
})->name('show');
Otra forma de ruta y utilizando un pattern númerico (sólo pueden introducir números)
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
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";
});
});
Ruta que nos lleva directamente a una vista e incluso pasarle un argumento.
Route::view('/welcome', 'welcome'); //en el caso que sólo queramos enviar a una vista sin pasar por el controlador
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
Especificamos que podemos usar GET y POST para una ruta
//verbos HTTP múltiples
Route::match(['get', 'post'], '/', function () {
//
});
//verbos HTTP cualquiera
Route::any('/', function () {
//
});
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";
}
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/
VISTA
Podemos aprovechar herencia en las vistas, por ello, vamos a crear.
También podemos crear una carpeta que contiene vistas "menú" y dentro las páginas, para acceder a ellos, habría que poner "menu.pagina"
Vista Padre LAYOUT.blade.php
<!DOCTYPE html>
<head>
<title>
@yield('titulo')
</title>
</head>
<body>
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#news">News</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="#about">About</a></li>
</ul>
@yield('contenido')
</body>
</html>
Vista Layout Hija hija.blade.php
@extends('layout')
@section('titulo','Página Heredada')
@section('contenido')
<h1>Página Hija</h1>
@endsection
SESIONES
https://laravel.com/docs/6.x/session
/*diferentes formas de crear variables de sesión en el CONTROLADOR*/
$request->session()->put(['Julio'=>'Administrador']); //crea variable sesión con clave Julio y valor Administrador
session(['nombre'=>'Julio']); //otra forma de crear variables sesión
$nombre= session('nombre')
$request->session()->forget('Juan'); //Borra Juan
$request->session()->flush(); //borra todo
return $request->session()->all(); //muestra todas las variables de sesión
dd(session()->all()) //muestra todas las variables de sesión
/*mostrar variables sesión en blade VISTA*/
{{session('julio')}}
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/guides/
<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');
TOASTR
En la página siguiente podemos hacer las modificaciones del script como más nos guste y sustituirlo en vez "toastr.info(....);"
https://codeseven.github.io/toastr/demo.html
https://github.com/CodeSeven/toastr
/*En la VISTA*/
<!--Añadir librerias BOOTSTRAP-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<!--Añadir librerias TOASTR-->
<link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
.......
<script>
@if(Session::has('info'))
toastr.info("{{ session('info') }}");
@endif
</script>
/*En el CONTROLADOR*/
return back()->with('info','Hemos recibido el mensaje');
</script>
BASES DE DATOS
Para crear una base de datos empezaremos con una tabla, es recomendable primero crear la migracion que corresponde con la tabla en la base de datos "articulos" y a continuación crearemos el modelo que corresponde con la entidad "Articulo". Es preferible crearlo en ese orden, también hay que tener cuidado a la hora de crear la migración en plural y la entidad en singular.
php artisan make:migration create_articulos_table --create="articulos"
php artisan make:model Articulo
//Tabla articulos
Schema::create('articulos', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->text('titulo');
$table->mediumText('descripcion');
$table->timestamps();
});
IMPORTANTE - TIPOS DE COLUMNAS
https://laravel.com/docs/6.x/migrations#creating-columns
//Modelo Articulo
class Articulo extends Model
{
protected $table = 'articulos'; //hacemos referencia a la tabla artículos
protected $fillable = ['titulo', 'descripcion']; //fillable para proteger los campos que desea que permitan la actualización a la hora de insertar en la base de datos por asignación masiva
}
SEEDER (SEMILLAS)
SEEDER normal
php artisan make:seeder NombreSeeder
//dentro de database->seeds se genera la nueva semilla.
//luego en la clase DataBaseSeeder (otro fichero) activamos dentro de la clase $this->call(NombreSeeder::class);
//y en la clase NombreSeeder:
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
......
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') ]);
}
Para generar los datos insertarmos en terminal
php artisan db:seed
https://laravel.com/docs/6.x/seeding
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')
]);
}
}
}
https://github.com/fzaninotto/Faker#formatters
CONSTRUCTOR DE CONSULTAS (Query Builder)
Cuando estamos usando conexiones múltiple
//añadimos
use DB;
....
//obtenemos todos los usuarios
$users = DB::table('users')->get();
foreach ($users as $user)
{
echo $user->name;
}
//Más ejemplos de consultas
$user = DB::table('users')->first();
$user = DB::table('users')->where('name', 'julio')->get();
$users = DB::table('users')->where('edad', '>', 100)->get();
$users = DB::table('users')->where('estado', '<>', 'active')->get();
$users = DB::table('users')->where('name', 'like', 'J%')->get();
CONSULTAS SQL NATIVAS
//seleccionar
$results = DB::select('select * from users where id = :id', ['id' => 1]);
//insertar en la Base users
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']);
//actualizar
$affected = DB::update('update users set votes = 100 where name = ?', ['John']);
//borrar
$deleted = DB::delete('delete from users');
//Ejecutando una instrucción general que no devuelve ningún valor
DB::statement('drop table users');
http://documentacion-laravel.com/database.html#ejecutando-consultas-sql-nativas
ELOQUENT
findOrNew https://laravel-news.com/firstornew-firstorcreate-firstor-updateorcreate
withCount
has whereHas()
$escritor= App\Escritor::findOrFail(1);
$escritor= App\Escritor::where('edad', '>', 100)->firstOrFail();
$escritor= App\Escritor::whereEdad(100)->get(); //es más eficiente especificar las columnas Escritor::select('id','name')->whereEdad(100)->get()
//insertar
$escritor = new Escritor();
$escritor->nombre = 'Julio';
$escritor->save();
//actualizar
$escritor = Escritor::find(1); //$escritor = App/Escritor::find(1);
$escritor->nombre = 'Pepe'; //$request->name;
$escritor->save();
//borrar
$escritor= App\Escritor::find(1);
$escritor->delete();
¿Cúal forma es mejor o más óptima? ¿SQL NATIVE o QUERY BUILDER o ELOQUENT?
https://www.laraveltip.com/que-es-mejor-eloquent-query-builder-o-sql/
PAGINAR
/*en CONTROLADOR de index*/
$datos=Dato::latest()->paginate(3);
/*en la VISTA debajo de forelse */
//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>
{{$datos->links()}} //DEBAJO DEL FORELSE
//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
PLUCK
En caso de obtener una colección y filtrar la parte que nos interesa.
$users = User::all(); // Devuelve una colección de usuarios, por ejemplo, ['name' => 'John', 'age' => 55],['name' => 'Melissa', 'age' => 18],['name' => 'Bob', 'age' => 43]
$usernames = $users->pluck('name'); // tenemos una colección de ['John', 'Melissa', 'Bob', 'Sara']
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();
});
Para generar las rutas podemos hacer dos cosas:
1)Generarlas automáticamente con el nombre de las rutas en inglés.
Generas las rutas insertando el fichero Web
Route::resource('blogs','blogController');
//Para listar las rutas, en terminal
php artisan route:list -v
Creamos Controlador
php artisan make:controller blogController --resource
1.index()
2.create()
3.store()
4.show()
5.edit()
6.update()
7.destroy()
2) Diseñar nuestras rutas y controlador en castellano uno a uno
//Diseñamos nuestras 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');
Diseñamos la migración y el modelo, en caso de necesitarlo
//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']; //¿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.
}
añadimos las rutas
INDEX-MOSTRAR DATOS
/*en el CONTROLADOR*/
public function index(){
$datos=Dato::all();
return view('index',['datos'=>$datos]); //view('index',compact('datos');
}
/*en la VISTA*/
@forelse ($datos as $item)
<li>
{{$item->nombre}} {{$item->descripcion}}
<a href="{{ route('editar', $item->id)}}" >Edit</a> <!--añadimos también EDITAR-->
<form action="{{ route('borrar', $item->id)}}" method="post"> <!--añadimos también BORRAR-->
@csrf
@method('DELETE')
<button type="submit">borrar</button>
</form>
</li>
@empty
<li>NO HAY NADA </li>
@endforelse
INSERTAR -STORE
/*En el CONTROLADOR*/
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') }}"> <!-- action="{{ action('RelacionController@almacenar') }}" //con esto vamos directamente al controlador desde la vista -->
@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
<label for="price">Descripcion:</label>
<input type="text" name="descripcion" value="{{old('descripcion')}}"/>
<!--{!! $errors->first('descripcion', '<small>:message</small><br>' )!!} -->
<button type="submit">Crear</button>
</form>
EDITAR
/*EN EL CONTROLADOR*/
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 para 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>
/*En el CONTROLADOR para ALMACENAR DATOS ya MODIFICADOS*/
public function actualizar(Request $request, $id){
$validacion=$request->validate([
'nombre' => 'required|min:1|max:10',
'descripcion' => 'required',
]);
Dato::whereId($id)->update($validacion); //otra opción
/* //otra forma de almacenar pero sin validar
$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();*/
//return redirect()->route('index');
}
//$request->input() es un array
BORRAR
//en el controlador borrar
public function borrar($id){
$dato = Dato::findOrFail($id);
$dato->delete();
return redirect()->route('index');
}
/*Otra forma de Borrar*/
use App\Dato; //añadimos el modelo en el controlador
....
public function borrar(Dato $dato){
$dato->delete();
return redirect()->route('index');
}
RELACIONES
Se puede crear primero el Modelo(Entidad) y luego generar la migración, el problema es que si diseñamos el modelo Escritor(Entidad) generará automáticamente la migración Escritors, habría que definir la tabla en la entidad.
Por tanto, la otra opción es diseñar primero la migración (tablas) y luego los modelos (entidades)
https://laravel.com/docs/6.x/eloquent-relationships
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"
Tablas migraciones
//tabla Categories
Schema::create('categorias', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->text('nombre');
$table->mediumText('masInfo');
$table->timestamps();
});
//tabla articulos
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';
//public $timestamps = true; //especificamos si queremos crear created_at y updated_at en la base de datos
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('App\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']),
]);*/
}
PROBLEMA N+1 - LAZY LOADING
//muestra el nombre de todas las categorias de todos los artículos. Una consulta para obtener todos los artículos en la tabla, después otra consulta para cada articulos para obtener quien es el autor
$articulos = Articulo::all();
foreach ($articulos as $articulo) {
dump($articulo->categoria->nombre);
}
SOLUCIÓN - EAGER LOADING //al usar la carga previa o carga impaciente (Eager Loading) para reducir esta operación a solo 2 consultas
$articulos = Articulo::with('categoria')->get();
foreach ($articulos as $articulo) {
echo $articulo->categoria->nombre ."</br>";
}
https://styde.net/lazy-loading-vs-eager-loading/
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();
Consultas interesantes para 1xN
//Métodos de relación
//Toda la info de Categoria
$categoria = Categoria::find(3); //debe existir categoria y artículos
return $categoria->articulos()->where('descripcion', "hola")->get(); //->whereDescripcion('hola')
//Obtenemos del artículo el nombre de la Categoria relacionada
$articulo = Articulo::findOrFail(2);
dump($articulo->categoria->nombre);
https://desarrollowebtutorial.com/laravel-eloquent-orm-query-builder-consultas-sql/
HAS
Es como el WHERE, devuelve las categorias que tiene al menos 1 articulo
$categorias=Categoria::has('articulos')->get();
Categoria::where('descripcion','like','%#'.$etiqueta.'%')->get();
https://blog.coffeedevs.com/como-evitar-consultas-de-mas-al-utilizar-eloquent-orm/
https://medium.com/@hemnys25/de-0-a-100-con-eloquent-de-laravel-parte-0-d5347c060ad7
https://stackoverflow.com/questions/30231862/laravel-eloquent-has-with-wherehas-what-do-they-mean
CONSULTAS EN MULTIPLES TABLAS
Ejemplo// Tablas: a, b, c, d, e, f
Quiero traer los datos de todas las tablas relacionadas, los datos de a, b, c, d,e,f.
A está relacionado con B (1,n) B con C (1,n) C con D (1,n) D con E (1,n) E con F (1,n)
Solución: https://es.stackoverflow.com/questions/173727/consultas-en-m%C3%BAltiples-tablas-con-laravel-5-5
RELACION DE MUCHOS A MUCHOS (NXM)
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"
Dentro de la tabla de migraciones
//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');
});
Dentro de los modelos
//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);
}
//OBTENER DATOS DE LA otra TABLA RELACIONADA.
return Post::find(1)->etiquetas()->get();
return Post::find(1)->etiquetas()->where('nombre','etiqueta1')->get();
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');
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
}
TRY ... CATCH
/*Las Rutas*/
Route::get('/formularioBusqueda', 'ProductController@formulario')->name('formularioBusqueda');
Route::post('/product/resultado', 'ProductController@resultado')->name('resultadoBusqueda');
/*En la vista 'formularioBusqueda'*/
@if (session('error'))
<div>{{ session('error') }}</div> <!--En caso de no encontrar el producto en la BBDD muestra error-->
@endif
<form action="{{ route('resultadoBusqueda') }}" method="POST">
@csrf
<input id="title name="title" type="text" value="{{ old('product') }}" placeholder="Product Title">
<input type="submit" value="Search">
</form>
/*En el controlador */
public function resultado(Request $request)
{
try {
$product = Product::where('title',$request->get('title')); //busca el producto en la BBDD
} catch (ModelNotFoundException $exception) {
return back()->withError($exception->getMessage())->withInput(); //en caso de no encontrar en la BBDD captura la excepción y envia la info a la misma vista
}
return view('resultadoBusqueda', compact('product')); //en caso de encontrar el producto manda otra vista el resultado
}
https://www.tutsmake.com/laravel-try-catch/
TRADUCCIÓN
Podemos hacerlo de dos formas:
1) Manualmente:
- En el caso que queramos hacer validaciones en Castellano, deberemos ir a la carpeta Resources>Lang y crear una llamada ES. Luego para establecer el lang por defecto hay que cambiarlo en configuración APP>CONFIG>app.php y buscar la linea 'locate'=> 'es'.
2)También podemos instalar complemento:
- composer require laraveles/spanish
- php artisan vendor:publish --tag=lang
https://github.com/Laraveles/spanish
AUTENTIFICACIÓN
//Crear usuario en versiones anteriores a 6
php artisan make:auth
//Laravel 6
composer require laravel/ui "^1.0"
php artisan ui vue --auth
//para visualizar el login y registro con css, habrá que instalar nodejs y usar npm install y npm run dev
- Después si accedemos dentro routes->Web podemos ver que se ha creado Auth::routes();
- Para cambiar la redirección después de Logearnos, tendremos que ir dentro app->http->Controller->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 BLADE
@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.
@if(auth()->get()) //si el usuario está autentificado
@endif
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;
También podemos indicarlo directamente en el constructor de un controlador
public function __construct()
{
$this->middleware('auth');
}
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]);
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 o FILTRO
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.
php artisan make:middleware DomingoMiddleware
<?php
namespace App\Http\Middleware;
use Closure;
class DomingoMiddleware
{
public function handle($request, Closure $next)
{
if(date('w')==='0'){
//echo "Es domingo!";
redirect()->route('home');
}else{
echo "No es domingo";
}
return $next($request);
}
}
Luego hay dos formas de registrar el MiddleWare
1) de Forma GLOBAL en app/Http/Kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
// otros middleware
// ...
\App\Http\Middleware\DomingoMiddleware::class,
];
2)Una ruta determinada o un controlador en app/Http/Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
// otros middleware de rutas...
'domingo' => \App\Http\Middleware\DomingoMiddleware::class,
];
Ahora podemos probar que funciona nuestro middleware
//pruebas en route web
Route::get('/test', ['middleware' => 'domingo', function(){
return 'Probando ruta con middleware';
}])
Route::get('/test1','MoviesController@insertar')->name('insertar')->middleware('domingo');
//segunda prueba en route web
Route::group(['middleware' => 'domingo'], function(){
Route::get('/probando/ruta', function(){
//código a ejecutar cuando se produzca esa ruta y el verbo
return 'get';
});
Route::post('/probando/ruta', function(){
//código a ejecutar cuando se produzca esa ruta y el verbo POST
return 'post';
});
});
//también se puede llamar desde dentro de un controlador y afectará a todas las acciones de dentro.
class PrimerController extends Controller
{
public function __construct(){
$this->middleware('domingo');
}
}
https://programacionymas.com/blog/restringir-acceso-solo-administradores-laravel-usando-middlewares
https://desarrolloweb.com/articulos/laravel-middleware.html
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'])->default('user');
//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)
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('public/logos',$fileName); //almacena el fichero dentro de storage->app->public->logos
return back()->with('success','Tu imagen se ha subido satisfactoriamente'); //retorna a la misma página
//public_path() , storage_path()
}
Cuando subimos imágenes y queremos mostrarla en la vista, por defecto se almacenan dentro de storage->app->public->logos, el problema es que esa carpeta no es pública para todo el mundo, por tanto, si ejecutamos el comando php artisan storage:link creará un enlace simbólico creando una nueva carpeta dentro public->storage->logos
//vista (las imágenes deben estar en la carpeta app/storage/public/logos)
<img src="{{ url('storage/logos/'.$imagen) }}">
<img src="{{ asset('storage/logos') }}/{{$b->imagen}}">
http://documentacion-laravel.com/filesystem.html#introduccion
http://documentacion-laravel.com/filesystem.html#configuracion
DRAG & DROP
Creamos la vista y luego en el controlador tenemos que guardar al igual que subimos un fichero
/*En la VISTA*/
//librerias
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/min/dropzone.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js"></script>
</head>
<body>
<div class="container">
<h2>Laravel 6 Subir multiples imágenes</h2><br/>
<form method="post" action="{{ route('almacenar') }}" enctype="multipart/form-data" class="dropzone" id="dropzone">
@csrf
</form>
</div>
<script type="text/javascript">
Dropzone.options.dropzone =
{
maxFilesize: 10,
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: false,
timeout: 60000,
success: function (file, response) {
console.log(response);
},
error: function (file, response) {
return false;
}
};
</script>
</body>
/*En el CONTROLADOR*/
//otra forma de subir fichero en la carpeta Public
public function subidoFicheroPost(Request $request){
$image = $request->file('file');
$avatarName = $image->getClientOriginalName();
$image->move(public_path('images'),$avatarName); //guarda en la ruta ->public->images
//$image->move(storage_path('\app\public\images'),$avatarName); //almacena en la ruta storage->app->public->images
}
https://appdividend.com/2018/05/31/laravel-dropzone-image-upload-tutorial-with-example/
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/
//instalamos paquete yajra
composer require yajra/laravel-datatables-oracle
Cambiar -> config/app.php
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>
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\Helper;
//use App\Helpers;
class TuController extends Controller
{
public function metodo()
{
Helper::strUp('mostrar este texto en mayúsculas!');
}
}
TRAITS
/*En el CONTROLADOR*/
use App\Http\Traits\Mayusculas;
.....
class PeliculasController extends Controller
{
use Mayusculas;
public function ejemplo()
{
echo Mayusculas::convertir("Julio Noguera");
}
}
Nos creamos un fichero en app->Http->Traits->Mayusculas.php
<?php
namespace App\Http\Traits;
trait Mayusculas
{
public static function convertir(string $string)
{
$mayusculas=strtoupper($string);
return $mayusculas;
}
}
https://diego.com.es/traits-en-php
GENERAR PDF
Instalamos libreria
composer require barryvdh/laravel-dompdf
añadimos la siguiente ruta en config/app.php en el array 'provider'
Barryvdh\DomPDF\ServiceProvider::class,
luego añadimos la siguiente ruta en config/app.php en el array 'aliases'
'PDF' => Barryvdh\DomPDF\Facade::class,
crearmos ruta en Web
Route::get('/imprimir', 'RelacionController@imprimir')->name('imprimir');
y una vista llamada 'imprimir.blade.php' con código en html
<body>
<h1>Página de prueba</h1>
</body>
use PDF;
......
public function imprimir(){
$pdf = PDF::loadView('imprimir');
return $pdf->download('ejemplo.pdf');
}
https://www.nigmacode.com/laravel/Generar-pdf-Dompdf-Laravel
DEBUGBAR
composer require barryvdh/laravel-debugbar --dev
Dentro de config->App añadimos en provider
Barryvdh\Debugbar\ServiceProvider::class,
En aliases
'Debugbar' => Barryvdh\Debugbar\Facade::class,
EJERCICIO 1
1. Se desea crear una filmografía de películas, por ello, debemos crear una página web que liste todas las películas que tiene almacenada localmente (array, fichero), también cabe la posiblidad de tener un formulario donde se pueda introducir el nombre de la película, año, director, descripción y una imagen (url) y se almacene.
Habrá que crear las rutas (crear, buscar/{id}, listar) y las correspondientes vistas(herencia). Lo ideal es que se muestre la imagen de película y clicando sobre ella muestre el resto de la información.
API
Creamos proyecto
composer create-project --prefer-dist laravel/laravel blog
Descargamos paquete Passport
composer require laravel/passport
config/app.php
/*Añadimos providers*/
'providers' =>[
Laravel\Passport\PassportServiceProvider::class,
],
php artisan migrate
Generamos instalamos en el proyecto y generamos Tokens php artisan passport:install
Añadimos HasApiTokens en ruta app/User.php
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable; /*añadimos HasApiTokens*/
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];}
Añadimos linea Passport::routes(); en ruta app/Providers/AuthServiceProvider.php
<?php
namespace App\Providers;use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes(); /*añadimos esta linea*/
}
}
Añadimos api en config/auth.php
<?php
return ['guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [ /*añadimos linea api*/
'driver' => 'passport',
'provider' => 'users',
],
],
Añadimos rutas en Routes->api.php
Route::post('login', 'API\UserController@login');
Route::post('register', 'API\UserController@register');
Route::group(['middleware' => 'auth:api'], function () {
Route::get('details', 'API\UserController@details');
Route::get('logout', 'API\UserController@logout');
});
Añadimos nuestras funciones en el controlador dentro de la carpeta API
php artisan make:controller API\UserController
<?php
namespace App\Http\Controllers\API;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Facades\Auth;
use Validator;
class UserController extends Controller
{
public $successStatus = 200;
/**
* login api
*
* @return \Illuminate\Http\Response
*/
public function login()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->accessToken;
return response()->json(['success' => $success], $this->successStatus);
} else {
return response()->json(['error' => 'Unauthorised'], 401);
}
}
/**
* Register api
*
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'c_password' => 'required|same:password',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$input = $request->all();
$input['password'] = bcrypt($input['password']);
$user = User::create($input);
$success['token'] = $user->createToken('MyApp')->accessToken;
$success['name'] = $user->name;
return response()->json(['success' => $success], $this->successStatus);
}
/**
* details api
*
* @return \Illuminate\Http\Response
*/
public function details()
{
$user = Auth::user();
return response()->json(['success' => $user], $this->successStatus);
}
public function logout(Request $request)
{
$isUser = $request->user()->token()->revoke();
if($isUser){
$success['message'] = "Successfully logged out.";
return response()->json(['success' => $isUser], $this->successStatus);
}
else{
return response()->json(['error' => 'Unauthorised'], 401);
}
}
}
1. Pruebas Postman.
REGISTER
localhost/api/public/api/register -> método POST
name
email
password
c_password
LOGIN
localhost/api/public/api/login -> método POST
email
password
DETAILS
localhost/api/public/api/details-> método GET
'Authorization' => 'Bearer '.$NuestroToken,
LOGOUT
localhost/api/public/api/logout-> método GET
'accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded'
'Authorization' => 'Bearer '.$NuestroToken,
https://medium.com/@bapunawarsaddam/rest-api-with-laravel-5-8-using-laravel-passport-53b5953798bb
https://medium.com/@devfelipe.mansilla/usando-graphql-con-laravel-446f0de02424
Intersante
Lazy Size