Diferencia entre revisiones de «PHP Modelo - Vista - Controlador»
| (No se muestran 12 ediciones intermedias del mismo usuario) | |||
| Línea 45: | Línea 45: | ||
:* Para instalar e crear un proxecto Laravel, dende consola, <u>sen ser root</u>,escribiremos situados no cartafol onde queiramos crear o proxecto: <b>composer create-project laravel/laravel nome_proxecto"</b> | :* Para instalar e crear un proxecto Laravel, dende consola, <u>sen ser root</u>,escribiremos situados no cartafol onde queiramos crear o proxecto: <b>composer create-project laravel/laravel nome_proxecto"</b> | ||
:: <u>Nota:</u> Se non poñemos a versión, descargará a última versión de Laravel que sexa <u>compatible coa versión de PHP instalada</u>. | :: <u>Nota:</u> Se non poñemos a versión, descargará a última versión de Laravel que sexa <u>compatible coa versión de PHP instalada</u>. | ||
| − | :: Se queremos empregar unha versión anterior debemos poñer: <b>composer create-project laravel/laravel nome_proxecto " | + | :: Se queremos empregar unha versión anterior debemos poñer: <b>composer create-project laravel/laravel nome_proxecto "13.*"</b> sendo 13 a versión a instalar. |
:* Para saber as versións de Laravel e os requirimentos podedes consultar [https://laravelversions.com/en https://laravelversions.com/]. | :* Para saber as versións de Laravel e os requirimentos podedes consultar [https://laravelversions.com/en https://laravelversions.com/]. | ||
| Línea 1383: | Línea 1383: | ||
: Fixarse que tamén se indica o nome da ruta. Por exemplo, perfumes.index (o nome) apunta ao controlador PerfumeController y método index. | : Fixarse que tamén se indica o nome da ruta. Por exemplo, perfumes.index (o nome) apunta ao controlador PerfumeController y método index. | ||
| + | : Con este sistema tamén podemos indicar que non se xeren todas as rutas, exceptuando algunha ou indicando soamente cales queremos de todas, poñendo ao final: | ||
| + | :: Route::resource('perfumes', PerfumeController::class)->'''only'''(['index', 'show']); | ||
| + | :: Route::resource('perfumes', PerfumeController::class)->'''except'''(['create', 'store', 'update', 'destroy']); | ||
| Línea 1422: | Línea 1425: | ||
: Como vemos, estamos chamando á vista index dentro dun cartafol 'perfumes' creado en views. Mandamos como parámetro a lista de perfumes da base de datos ordenados polo campo descripción. | : Como vemos, estamos chamando á vista index dentro dun cartafol 'perfumes' creado en views. Mandamos como parámetro a lista de perfumes da base de datos ordenados polo campo descripción. | ||
| + | |||
| + | |||
| + | : Outra forma de facer o mesmo pero de xeito máis compacto é empregar '''compact''' á hora de enviar os datos á vista: | ||
| + | ::<syntaxhighlight lang="java" line enclose="div" highlight="8" > | ||
| + | <?php | ||
| + | |||
| + | ....... | ||
| + | |||
| + | public function index() | ||
| + | { | ||
| + | $perfumes = Perfume::orderBy('descripcion')->get(); | ||
| + | return view('perfumes.index',compact('perfumes')); | ||
| + | } | ||
| + | |||
| + | |||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| Línea 1572: | Línea 1593: | ||
:* Engadimos o '''accesor/mutator'''. | :* Engadimos o '''accesor/mutator'''. | ||
| + | :: Ademáis podemos facer o mesmo có prezo, para que cando se amose poña unha coma coma separador decimal e se asigna un valor que o garde con punto para poder ser enviado a mysql. | ||
| + | |||
::'''Arquivo /app/Models/Perfume.php''': | ::'''Arquivo /app/Models/Perfume.php''': | ||
| − | ::<syntaxhighlight lang="java" enclose="div" highlight="26-32" > | + | ::<syntaxhighlight lang="java" enclose="div" highlight="26-32,34-42" > |
<?php | <?php | ||
| Línea 1599: | Línea 1622: | ||
]; | ]; | ||
| − | protected function | + | protected function DataCompra(): Attribute |
{ | { | ||
return Attribute::make( | return Attribute::make( | ||
| Línea 1606: | Línea 1629: | ||
); | ); | ||
} | } | ||
| + | |||
| + | protected function Prezo(): Attribute | ||
| + | { | ||
| + | return Attribute::make( | ||
| + | // Cuando accedemos al valor del campo, convertimos el punto en coma | ||
| + | get: fn ($value) => number_format($value, 2, ',', '.'), | ||
| + | // Cuando se asigna el valor, reemplazamos la coma por un punto | ||
| + | set: fn ($value) => str_replace(',', '.', $value), | ||
| + | ); | ||
| + | } | ||
| + | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | : Con isto xa podemos borrar a función cambiaf_a_mysql do controlador e empregar Perfume::create cando creamos el perfume | + | : <u>'''NOTA IMPORTANTE:</u>''' Os nomes dos atributos teñen que seguir a seguinte regra: Se ten unha palabra empeza con maiúsculas. Se ten duas palabras, o inicio de cada palabra empeza con maiúsculas e van xuntas (sen guión). No nome do campo de base de datos terá que estar en minúsculas e con guión. |
| + | :: Por exemplo, o campo da base de datos é data_compra polo que o atributo ten que chamarse '''DataCompra'''. O campo da base de datos é prezo, polo que o atributo debe chamarse '''Prezo'''. | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | <br /> | ||
| + | : Con isto xa podemos borrar a función cambiaf_a_mysql do controlador e empregar Perfume::create cando creamos el perfume. | ||
::'''Arquivo /app/Models/Perfume.php''': | ::'''Arquivo /app/Models/Perfume.php''': | ||
| − | ::<syntaxhighlight lang="java" enclose="div" highlight=" | + | ::<syntaxhighlight lang="java" enclose="div" highlight="11,22" > |
<?php | <?php | ||
namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||
| Línea 1628: | Línea 1669: | ||
{ | { | ||
$this->validate($request,[ | $this->validate($request,[ | ||
| − | ' | + | 'descripcion' => 'required|max:45', |
| − | ' | + | 'prezo' => 'required|regex:/[0-9]{1,3},[0-9]{2}/', |
| − | ' | + | 'data_compra' => 'date_format:"d/m/Y"' |
| − | ]); | + | ]); |
$perfume = Perfume::create($request->all()); | $perfume = Perfume::create($request->all()); | ||
| Línea 1637: | Línea 1678: | ||
return redirect(route('perfumes.create'))->with(['idPerfume' => $perfume->id]); | return redirect(route('perfumes.create'))->with(['idPerfume' => $perfume->id]); | ||
} | } | ||
| + | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | * Agora debemos modificar a pantalla de listado de perfumes xa que o prezo xa se vai visualizar có formato correcto ao igual que a data: | ||
| + | '''Arquivo App\resources\views\index.blade.php''' | ||
| + | ::<syntaxhighlight lang="java" enclose="div" highlight="22,23" > | ||
| + | @extends('plantilla') <!-- Collemos a páxina base --> | ||
| + | @section('pageTitle', 'Lista de Perfumes') <!-- Engade o contido á sección pageTitle --> | ||
| + | @section('content') <!-- Engade o contido á sección content --> | ||
| + | <div> | ||
| + | <a href="{{ route('perfumes.create') }}">NOVO PERFUME</a> <!-- href podría tener esto: /perfumes/create pero mejor con route --> | ||
| + | </div> | ||
| + | <h5>Hai {{ $perfumes->count() }} perfumes en la base de datos.</h5> | ||
| − | + | <table> | |
| + | <tr> | ||
| + | <th>Descripción</th> | ||
| + | <th>Prezo</th> | ||
| + | <th>Data compra</th> | ||
| + | <th>Operaciones</th> | ||
| + | </tr> | ||
| + | @foreach ($perfumes as $perfume) | ||
| + | <tr> | ||
| + | <td>{{ $perfume->descripcion }}</td> | ||
| + | <td>{{ $perfume->prezo }}</td> | ||
| + | <td>{{ $perfume->data_compra }}</td> | ||
| − | + | </syntaxhighlight> | |
| − | |||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | * Como os campos do formulario para a alta e modificación son os mesmos, imos definilos nun arquivo externo e os reutilizaremos nas dúas vistas: | |
| − | + | ||
| − | + | :'''Arquivo: /resources/views/perfumes/campos_perfume.blade.php''' | |
| + | ::<syntaxhighlight lang="java" line enclose="div" highlight="" > | ||
| + | |||
| + | <div> | ||
| + | Descipción:<input type="text" maxlength="45" size="45" value="{{!empty($perfume) ? $perfume->descripcion : old('descripcion')}}" name="descripcion" /> | ||
| + | </div> | ||
| + | <div> | ||
| + | Prezo (xxx,yy):<input type="text" value="{{!empty($perfume) ? str_replace('.',',',$perfume->prezo) : old('prezo')}}" maxlength="6" size="6" name="prezo" /> | ||
| + | </div> | ||
| + | <div> | ||
| + | Data (dd/mm/yyyy):<input type="text" value="{{!empty($perfume) ? (empty($perfume->data_compra) ? '' : $perfume->data_compra->format('d/m/Y')) : old('data_compra')}}" | ||
| + | maxlength="10" size="10" name="data_compra" /> | ||
| + | </div> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Línea 1669: | Línea 1743: | ||
: O que facemos preguntando por !empty($perfume) é para saber se temos que cargar os datos dun perfume seleccionado na vista de listado de perfumes ou se temos que amosar os datos antigos por non cumprir os criterios de validación ao intentar dar de alta ou modificar os datos. Isto o facemos có operador ternario. | : O que facemos preguntando por !empty($perfume) é para saber se temos que cargar os datos dun perfume seleccionado na vista de listado de perfumes ou se temos que amosar os datos antigos por non cumprir os criterios de validación ao intentar dar de alta ou modificar os datos. Isto o facemos có operador ternario. | ||
: Ademais, no caso da data, ao igual que pasaba na vista de lista de perfumes, temos que preguntar se ven baleiro ou non (outro operador ternario). | : Ademais, no caso da data, ao igual que pasaba na vista de lista de perfumes, temos que preguntar se ven baleiro ou non (outro operador ternario). | ||
| + | |||
| + | : '''<u>Nota Importante:</u>''' Cando demos de alta o rexistro, imos empregar a forma Perfume::create($request->all()). Para que funcione, os nomes das input teñen que corresponderse cós nomes das columnas da base de datos. Se non fora o caso, teríamos que facer un $perfume = new Perfume(), asociar a cada columna o $request correspondente e facer un $perfume->save() | ||
| + | |||
| + | |||
| Línea 1681: | Línea 1759: | ||
| − | <form method="post" action="{{ | + | <form method="post" action="{{route('perfumes.store')}}" name="formulario_perfumes"> |
| + | @csrf | ||
@include('perfumes.campos_perfume') | @include('perfumes.campos_perfume') | ||
<div> | <div> | ||
| Línea 1689: | Línea 1768: | ||
</div> | </div> | ||
| − | + | ||
</form> | </form> | ||
| Línea 1710: | Línea 1789: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | * Liña 9: Utilizamos | + | * Liña 9: Utilizamos o nome da ruta para gardar os datos no método store do controlador. |
| − | * Liña 11: Incluímos os campos do formulario. | + | * Liña 11: Nun formulario necesitamos protexelo de ataques con csrf |
| + | * Liña 12: Incluímos os campos do formulario. | ||
* Liña 21-23: Isto non sería necesario xa que a un usuario non se lle vai amosar o id autonumérico que conforma a clave primaria dunha táboa. Está posto para amosar como se pode enviar un dato dende o controlador á vista e concretamente o id xerado por Mysql cando engadimos un rexistro. | * Liña 21-23: Isto non sería necesario xa que a un usuario non se lle vai amosar o id autonumérico que conforma a clave primaria dunha táboa. Está posto para amosar como se pode enviar un dato dende o controlador á vista e concretamente o id xerado por Mysql cando engadimos un rexistro. | ||
: Lembrar (está comentado anteriormente) que cando fagamos unha operación o controlador vai facer un redirect e nese caso, o paso de datos coa orde ->with van chegar á vista en forma de variables de sesión. | : Lembrar (está comentado anteriormente) que cando fagamos unha operación o controlador vai facer un redirect e nese caso, o paso de datos coa orde ->with van chegar á vista en forma de variables de sesión. | ||
| Línea 1721: | Línea 1801: | ||
| + | * Necesitaríamos ter as rutas para modificar. Son dúas: unha GET para amosar o formulario cós datos a actualizar e outra POST para modificar os datos. | ||
| + | : Como empregmamos Route::resources xa temos creado as rutas e asociados aos métodos do controlador. | ||
| + | : Si quiséramos ter outras: | ||
* '''Arquivo /app/Http/routes.php''' | * '''Arquivo /app/Http/routes.php''' | ||
::<syntaxhighlight lang="java" line enclose="div" highlight="" > | ::<syntaxhighlight lang="java" line enclose="div" highlight="" > | ||
| − | Route::get('/perfumes/{id}/edit','PerfumeController@edit')->where(['id' => '[0-9]{1,12}']); | + | Route::get('/perfumes/{id}/edit','PerfumeController@edit')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource |
| − | Route::post('/perfumes/{id}/edit','PerfumeController@update')->where(['id' => '[0-9]{1,12}']); | + | Route::post('/perfumes/{id}/edit','PerfumeController@update')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource |
</syntaxhighlight> | </syntaxhighlight> | ||
| Línea 1742: | Línea 1825: | ||
} | } | ||
| − | public function update(Request $request, $id) | + | public function update(Request $request, string $id) |
{ | { | ||
$this->validate($request,[ | $this->validate($request,[ | ||
| − | ' | + | 'descripcion' => 'required|max:45', |
| − | ' | + | 'prezo' => 'required|regex:/[0-9]{1,3},[0-9]{2}/', |
| − | ' | + | 'data_compra' => 'date_format:"d/m/Y"' |
| − | ]); | + | ]); |
$perfume = Perfume::findorFail($id); | $perfume = Perfume::findorFail($id); | ||
| − | $perfume->descripcion=$request-> | + | $perfume->descripcion = $request->descripcion; |
| − | $perfume->prezo= | + | $perfume->prezo = $request->prezo; |
| − | $perfume->data_compra= | + | $perfume->data_compra = $request->data_compra; |
$perfume->save(); | $perfume->save(); | ||
| − | return redirect()-> | + | return redirect()->route('perfumes.index')->with(['msg' => 'Perfume modificado correctamente']); |
| − | |||
| − | |||
} | } | ||
| Línea 1780: | Línea 1861: | ||
<h5>Datos do perfume <b>{{$perfume->descripcion}}</b></h5> | <h5>Datos do perfume <b>{{$perfume->descripcion}}</b></h5> | ||
| − | <form method="post" name="form_datos_perfume" action="{{ | + | <form method="post" name="form_datos_perfume" action="{{route('perfumes.update',['perfume' => $perfume->id])}}" > |
| − | + | @csrf | |
| − | + | @method('PUT') | |
| − | |||
@include('perfumes.campos_perfume') | @include('perfumes.campos_perfume') | ||
<div> | <div> | ||
| Línea 1810: | Línea 1890: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | : | + | : '''Nota:''' Nun aloxamento real, facer que apunte á mesma páxina con $_SERVER['PHP_SELF'] non me funcionou. Apuntaba á principal. Para solucionalo podemos facer uso de: '''Request::fullUrl()''' |
==== Baixa de perfume ==== | ==== Baixa de perfume ==== | ||
| − | '''Arquivo /app/Http/routes.php''' | + | * Necesitaríamos ter as rutas para dar de baixa. verbo DELETE co id do perfume a dar de baixa. |
| − | ::<syntaxhighlight lang="java" line enclose="div" highlight=" | + | : Como empregmamos Route::resources xa temos creado as rutas e asociados aos métodos do controlador. |
| − | Route:: | + | : Si quiséramos ter outras: |
| − | + | * '''Arquivo /app/Http/routes.php''' | |
| + | ::<syntaxhighlight lang="java" line enclose="div" highlight="" > | ||
| + | Route::delete('/perfumes/{id}','PerfumeController@destroy')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource | ||
| + | </syntaxhighlight> | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| Línea 1840: | Línea 1915: | ||
$perfume->delete(); | $perfume->delete(); | ||
| − | return redirect(' | + | return redirect()->route('perfumes.index'); |
} | } | ||
| Línea 1847: | Línea 1922: | ||
: Borramos o perfume có id enviado e cargamos a vista do listado de perfumes. | : Borramos o perfume có id enviado e cargamos a vista do listado de perfumes. | ||
| + | |||
| + | * En Laravel podemos inxectar o obxecto Perfume nos métodos do controlador (en calquera deles) da forma: | ||
| + | ::<syntaxhighlight lang="java" line enclose="div" highlight="1" > | ||
| + | public function destroy(Perfume $perfume) | ||
| + | { | ||
| + | |||
| + | $perfume->delete(); | ||
| + | |||
| + | return redirect()->route('perfumes.index'); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | : É como se fixéramos o find pero xa o fai Laravel. | ||
| + | |||
| + | |||
| + | * A nivel de vista xa tiñamos o código posto no arquivo app/resources/views/perfumes.blade.php | ||
| + | ::<syntaxhighlight lang="java" line enclose="div" highlight="11-19" > | ||
| + | ............... | ||
| + | |||
| + | @foreach ($perfumes as $perfume) | ||
| + | <tr> | ||
| + | <td>{{ $perfume->descripcion }}</td> | ||
| + | <td>{{ number_format($perfume->prezo, 2, ',', '') }}</td> | ||
| + | <td>{{ $perfume->data_compra ? $perfume->data_compra->format('d/m/Y') : '' }}</td> | ||
| + | <td> | ||
| + | <a style='text-decoration:none' href="{{ route('perfumes.edit', ['perfume' => $perfume->id]) }}">Modificar</a> | ||
| + | |||
| + | <form action="{{ route('perfumes.destroy', ['perfume' => $perfume->id]) }}" method="POST" | ||
| + | style="display:inline;"> | ||
| + | @csrf | ||
| + | @method('DELETE') | ||
| + | <input type="hidden" name="id" value="{{ $perfume->id }}"> | ||
| + | <button type="submit" | ||
| + | onclick="return confirm('Estás seguro de eliminar o perfume {{ $perfume->descripcion }}?');" | ||
| + | class='btn btn-link'>Eliminar</button> | ||
| + | </form> | ||
| + | </td> | ||
| + | </tr> | ||
| + | @endforeach | ||
| + | |||
| + | ............ | ||
| + | </syntaxhighlight> | ||
==== Paxinación ==== | ==== Paxinación ==== | ||
Revisión actual del 14:38 13 sep 2026
Sumario
- 1 Introdución
- 2 Manuais
- 3 Instalación
- 4 Primeiros pasos
- 5 Vistas
- 6 Controlador
- 7 HTTP Request
- 8 Response
- 9 Validación de formularios
- 10 Modelos en Laravel
- 11 Tips
- 12 Middleware
- 13 Cookies en Laravel
- 14 Aspectos varios
- 15 Bootstrap 3
Introdución
- Aquí temos unha explicación do que é Modelo-Vista-Controlador.
- Existen moitos frameworks PHP que nos permiten programar seguindo o patrón de deseño de software Model-View-Controller.
- Este manual está baseado na versión 5.1.
- Se queredes facer uso dunha versión posterior teredes que mirar os cambios que se produciron entre versións e aplicalos.
....
- A Laravel 10: https://laravel.com/docs/10.x/upgrade
- Nota: Como editor de texto para manexar os arquivos do proxecto no framework Laravel recomendo instalar Visual Studio Code.
Manuais
Instalación
- Primeiro vídeo: basicamente fala de instalar composer e con el instalar Laravel.
- Para instalar Laravel necesitamos:
- Ter php instalado.
- Ter composer instalador.
- Ter git instalado.
- Para instalar e crear un proxecto Laravel, dende consola, sen ser root,escribiremos situados no cartafol onde queiramos crear o proxecto: composer create-project laravel/laravel nome_proxecto"
- Nota: Se non poñemos a versión, descargará a última versión de Laravel que sexa compatible coa versión de PHP instalada.
- Se queremos empregar unha versión anterior debemos poñer: composer create-project laravel/laravel nome_proxecto "13.*" sendo 13 a versión a instalar.
- Para saber as versións de Laravel e os requirimentos podedes consultar https://laravelversions.com/.
- Este manual está actualizado á versión Laravel 10.
- Os enlaces son dun curso empregando Laravel 5. Poñerei debaixo de cada enlace os cambios con respecto á versión 10.
- Para lanzar o servidor web do proxecto creado, estando no cartafol raíz de dito proxecto, escribiremos: php artisan serve
- Aparecerá unha mensaxe informando de que o servidor web está levantado e escoitando no porto 8000. Escribiremos na URL do navegador: http://localhost:8000
- Para saber a versión do framework Laravel que temos instalado podemos escribir a seguinte orde dende o cartafol raíz do proxecto creado:
- php artisan --version
- Artisan é un comando de Laravel. Podedes consultalo neste enlace.
- Para executar un comando de artisan temos que escribir: php artisan comando dende o raíz do sitio web creado.
- Se escribimos soamente php artisan aparecen a lista de posibles comandos que podemos executar.
- Para obter a axuda dun comando específico temos que escribir: php artisan help comando.
- Por exemplo: php artisan help make:controler
Primeiros pasos
-
- ACTUALIZACIÓN VERSIÓN LARAVEL 10:
- O arquivo routes.php cambia de nome a web.php e se atopa na ruta /routes/web.php
- Para a creación de servizos web, se emprega o arquivo de rutas /routes/api.php
- ACTUALIZACIÓN VERSIÓN LARAVEL 10:
-
- ACTUALIZACIÓN VERSIÓN LARAVEL 10:
- Estructura actual: https://laravel.com/docs/10.x/structure
- ACTUALIZACIÓN VERSIÓN LARAVEL 10:
- Nesta parte non van ser necesarios instalar estos complementos para simular o envío de datos utilizando os verbos (get, post, put,...). Cando vexamos os servizos si que serán necesario.
- Complemento para:
- Firefox:
- Chome::
- A continuación ven un exemplo de emprego dun dos complementos.
- Exercicios: Unha vez lido os puntos anteriores deberedes facer diferentes rutas utilizando diferentes verbos có complemento.
- Coidado coa orde das rutas, xa que se temos varias rutas nas que especificamos verbos que coincidan, cargará primeiro as que estean ao final do arquivo (por exemplo, unha con get e outra con match(['get']).
- No caso das rutas que veñen na URL, se temos varias entradas no arquivo routes.php que coincidan coa mesma URL, cargará primeiro a que estea antes no arquivo routes.php.
- Exemplo de envío utilizando o método GET á url http://localhost:8000/testpost, sendo 'testpost' unha ruta previamente definida:
1 Route::get('/testpost',function() { 2 echo "Isto é un get a /testpost"; 3 });
- EXEMPLO:
- Carga unha vista
Exemplo de chamada empregando o verbo GET. Non podemos empregar o POST xa que por defecto Laravel emprega un código identificador de formulario para evitar ataques CSRF.
- Durante o manual fala de utilizar un controlador para recibir un parámetro.
- Se queredes facer a proba teredes que definir un arquivo php no cartafol: /proxecto/app/Http/Controllers/ControladorProba.php
- O nome ControladorProba.php é un exemplo.
- O código de dito arquivo pode ser algo parecido a isto:
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use App\User; 6 use App\Http\Controllers\Controller; 7 8 class ControladorProba extends Controller { 9 10 public function funcionControlador($id){ 11 return "Esta información ven dun controlador especifico. Recibido o dato $id"; 12 } 13 14 }
- Como se pode ver, o nome da clase é igual ao nome do arquivo php. Deriva da clase Controller.
- Leva unha función de nome 'funcionControlador' cun parámetro.
- Agora debemos crear a ruta que vai facer uso de esta clase controladora:
- Modificamos o arquivo routes.php.
Route::get('controlador/{identificador}','ControladorProba@funcionControlador');
- Como vemos, agora en vez de ter unha función anónima, temos o nome da clase controladora (ControladorProba) e o nome da función ao que vai chamar (funcionControlador). Dita función vai levar un parámetro que está definido na parte Get da orde route ({identificador}).
- Agora podemos poñer unha URL da forma: http://localhost:8000/controlador/1000
- Enviaremos o dato 1000 á clase controladora.
- Recurso:
- Páxina web para verificar unha expresión regular: regex101.com.
- Exercicios:
- Crea unha ruta con dous parámetros que sexan opcionais. Dalle un valor por defecto a cada un deles.
- Crea unha ruta que acepte como parámetro unha expresión regular de 5 números do 0 ao 7.
- Crea outra ruta que acepte como parámetro unha expresión regular que acepta un número-letras (número guión letras)
- Solucións:
1 Route::get('/opcionais/{param1?}/{param2?}',function($par1=1,$par2='valor defecto'){ 2 echo "O param1 ten valor $par1 e o param2 ten valor $par2"; 3 }); 4 5 Route::get('/rutaNumeros/{numero}',function($numero){ 6 echo "5 números de 0 ao 7: $numero"; 7 })->where(array('numero' => '[0-7]{5}')); 8 9 Route::get('/rutaNumerosCadea/{dato}',function($dato){ 10 echo "Dato numérico-texto: $dato"; 11 })->where(array('dato' => '[0-7]+-[a-z|A-Z]+'));
- Mellora: A validación dos parámetros que enviamos dende a URL para que cumpran unhas determinadas condicións (por exemplo, no caso dun nif, que teña 8 números e unha letra), o podemos implementar da seguinte forma:
1 Route::pattern('id', '\d+'); 2 Route::pattern('username', '[a-z]{3,16}'); 3 4 5 Route::get('usuarios/{id}', 'UserController@obterInformacion'); 6 Route::get('productos/{id}', 'ProductController@obterInformacion');
- No exemplo, ao parámetro {id} estámoslle a indicar que sexa un número.
- Establecemos con 'pattern' as condicións que teñen que cumprir os parámetros da URL.
- Desta forma, o parámetro {id} terá que cumprir as regras indicadas en todas as rutas onde sexa empregado.
- Máis información neste enlace.
- Para poder ver as rutas que imos creando dispoñemos dun comando artisan:
1 php artisan route:list
- Amosa nunha táboa todas as rutas, métodos e accións. Por cada ruta amosa os filtros asociados (o veremos posteriormente). Este comando vainos servir para comprobar que todas as rutas e filtros definimos estean creados correctamente.
- Se queremos xestionar calquera ruta que sexa enviada polo usuario temos que facer uso da ruta 'any' desta forma:
- Arquivo: /app/Http/routes.php
1 Route::get('/{any}',function(){ 2 return 'Páxina non atopada'; 3 })->where('any','.*');
Importante: A ruta debe ir ao final do arquivo routes para que primeiro xestione as que ten definidas.
Vistas
Exemplo 1 do manual anterior. Creación dunha vista
- Lembrar que as vistas é onde se atopa o código que vai amosarse ao usuario (html,css,javascript).
- A vista foi creada previamente no cartafol: /raiz_proxecto/resources/views
- Arquivo: algo.blade.php
1 <!DOCTYPE html> 2 <html lang="es"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Isto é unha vista de proba</title> 6 </head> 7 <body> 8 <h1>Vista "algo"</h1> 9 <p>Esta é a miña primeira vista en Laravel</p> 10 </body> 11 </html>
- Un exemplo de código dunha ruta (routes.php) cun if condicional para preguntar se a vista existe dende .
1 Route::get('vistas',function(){ 2 if(view()->exists("algo")){ 3 return view('algo'); 4 }else { 5 echo "A vista non existe"; 6 } 7 });
Exemplo 2 do manual anterior. Creación dunha vista nun cartafol e paso de parámetros á vista dende a ruta
- Seguindo o exemplo do manual, imos crear unha vista no cartafol /sitio_raiz/resources/views/outro.
- Arquivo: index.blade.php
1 <!DOCTYPE html> 2 <html lang="es"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Isto é unha vista de proba dentro dun cartafol</title> 6 </head> 7 <body> 8 <h1>Vista "algo" dentro dun cartafol</h1> 9 <p>Benvido {{$nomeVista}}. Xa vexo que tes {{$idadeVista}} anos :)</p> 10 </body> 11 </html>
- Liña 9: Como vemos imos facer uso de dúas variables que van vir dende a ruta (poderían vir da mesma forma dende o controlador). Como estamos nun arquivo blade.php podemos facer uso da sintaxe das plantillas, no que para 'imprimir as variables' utilizamos {{ }}. Se queremos podemos facer uso da sintaxe 'clásica' de PHP, poñendo <?php echo $variable ?> ou a sintaxe abreviada:<?= $variable ?>.
- Como norma xeral imos utilizar a sintaxe 'blade' xa que fai que o código sexa moito mais lexible.
- Podedes ver as normas xerais de uso neste enlace.
- Arquivo: routes.php
1 Route::get('vistas',function(){ 2 if(view()->exists("outro.index")){ 3 $nome='Angel'; 4 $idade=45; 5 return view('outro.index',[ 6 'nomeVista' => $nome, 7 'idadeVista' => $idade 8 ]); 9 }else { 10 echo "A vista non existe"; 11 } 12 });
- Como vemos no return view enviamos en forma de array as variables que imos utilizar na vista (nomeVista e idadeVista) cos valores das variables definidas na ruta ($nome e $idade).
- Exercicio proposto: Modifica a ruta anterior para que reciba dous parámetros e sexan os que se envíen á vista (Nota: podemos ter as dúas vistas á vez)
- Solución:
1 Route::get('vistas/{nome}/{idade}',function($nome,$idade){ 2 if(view()->exists("outro.index")){ 3 return view('outro.index',[ 4 'nomeVista' => $nome, 5 'idadeVista' => $idade 6 ]); 7 }else { 8 echo "A vista non existe"; 9 } 10 });
Exercicio 1
- Le o seguinte enlace e crea unha vista utilizando unha plantilla. Todo debe ser creado dentro dun cartafol de nome 'exemplo_plantillas'.
- Deberás crear primeiro a plantilla cunha estrutura formada por un menú vertical na parte esquerda, cun ancho do 35% do total e un contido ao carón do menú.
- Crea dúas vistas que herden esta plantilla e engade algún contido.
- Fai que a vista sexa cargada cando na URL poñamos 'vista_plantilla/1' cargará a vista primeira e 'vista_plantilla/2' cargará a vista segunda.
- Crea dúas entradas de menú e que cada un 'cargue' unha das vistas.
Solución Exercicio 1
- Arquivo: /resources/views/exemplo_plantillas/plantilla.blade.php
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Laravel</title> 5 6 <style> 7 .menu{ 8 float: left; 9 width: 30%; 10 padding-left: 5px; 11 } 12 .menu a{ 13 display: block; 14 } 15 .contido{ 16 float: left; 17 width: 65%; 18 } 19 20 </style> 21 </head> 22 <body> 23 <div class="menu"> 24 <a href='/vista_plantilla/1/'>Vista 1</a> 25 <a href='/vista_plantilla/2/'>Vista 2</a> 26 </div> 27 <div class="contido"> 28 @yield('content') 29 </div> 30 </body> 31 </html>
- Arquivo: /resources/views/exemplo_plantillas/vista1.blade.php
1 @extends('exemplo_plantillas.plantilla'); 2 3 4 @section('content') 5 <p>Este é o contido da vista 1</p> 6 @endsection
- Arquivo: /resources/views/exemplo_plantillas/vista2.blade.php
1 @extends('exemplo_plantillas.plantilla'); 2 3 4 @section('content') 5 <h5>Este é o contido da vista 2</h5> 6 @endsection
- Arquivo: /http/routes.php
1 Route::get('vista_plantilla/{numero}',function($numero){ 2 return view("exemplo_plantillas.vista$numero"); 3 })->where(['numero'=>'[1-2]']);
Controlador
- A diferenza do feito ata o de agora, non imos a chamar á vista directamente dende a páxina 'router.php', se non que imos chamar a unha páxina 'controller' que é a que vai invocar a vista.
- Ven ser unha ponte entre o controlador frontal e as vistas, e vai ser dende onde chamemos ao modelo para obter ou enviar datos á base de datos.
- As páxinas controladoras se atopan no cartafol: app/Http/Controllers
Exercicio 1. Creación dun controlador
- Para crear unha páxina controlador podemos facer uso do comando php artisan dende o raíz do noso proxecto laravel da forma:
1 php artisan make:controller CategoriasController
- Isto creará unha páxina de nome 'CategoriasController' no cartafol 'app/Http/Controllers'.
- Para crear un controlador cuns métodos definidos por defecto (por exemplo, se crea o método create onde iría a vista (o formulario) que daría de alta) teríamos que escribir:
1 php artisan make:controller --resource CategoriasController
- Nota: Soamente a partires de Laravel 5.4
- Nota: Podemos crear clases controladoras dentro de cartafoles da seguinte forma:
1 php artisan make:controller CARTAFOL/CategoriasController
- Modifica o exercicio anterior e fai que a vista sexa cargada dende o controlador.
- A forma de carga a vista é a mesma (return view) pero agora terás que enviarlle os datos que van chegar á clase controladora en forma de parámetros dende route.php.
- Solución:
Arquivo routes.php
1 Route::get('vistas/{nome}/{idade}','DatosController@amosarVista');
Arquivo DatosController.php
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 use App\Http\Requests; 8 9 class DatosController extends Controller 10 { 11 // Poñemos $param_ para amosar como non teñen que chamarse igual que os parámetros definidos en router.php 12 public function amosarVista($param_nome,$param_idade){ 13 return view('outro.index',[ 14 'nomeVista' => $param_nome, 15 'idadeVista' => $param_idade 16 ]); 17 } 18 }
Nota: Indicar que tamén podemos enviar array de datos á vista da seguinte forma
Arquivo DatosController.php
1 public function amosarVista($param_nome,$param_idade){ 2 $datos = array(); 3 $datos[]=1; 4 $datos[]=2; 5 return view('outro.index',[ 6 'nomeVista' => $param_nome, 7 'idadeVista' => $param_idade, 8 'datosArray' => $datos 9 ]); 10 }
Arquivo index.blade.php (a vista)
1 ............... 2 <p>Volcado dos datos do array como fixemos en PHP: 3 <?php 4 var_dump($datosArray); 5 ?> 6 </p> 7 <p> 8 Forma de percorrer un array en blade (máis lexible)<br /> 9 @foreach ($datosArray as $n) 10 Valor: {{ $n }} 11 @endforeach 12 </p> 13 14 <p> 15 Un dato en PHP:<?= $datosArray[0]?><br /> 16 Un dato en Blade:{{$datosArray[1]}} 17 </p> 18 </body>
Exercicio 2. Creación dun controlador
- Crea unha nova ruta que responda a petición get: www.oteusitio.es/buscar/nif/, sendo nif un nif válido (9 díxitos e unha letra).
- En caso de que sexa correcto, enviarase a unha vista de nome DatosAlumnos.blade.php, creada no cartafol ALUMNOS/, o nif xunto cun array cos seguintes datos: 'nome'=>'Angel', 'Idade=>45'. Dita vista amosará dentro dun <h5> e en cor vermella os datos enviados, en forma de lista desordenada.
- O control de se se carga unha vista ou outra deberase facerse dende unha clase Controller de nome AlumnosController, dentro dun cartafol ALUMNOS/, e unha función de nome 'buscarAlumnos'.
- Solución:
Arquivo routes.php
1 Route::get('buscar/{nif}','ALUMNOS\AlumnosController@buscarAlumnos')->where(['nif' => '[0-9]{8}[A-Z]']);
Arquivo ALUMNOS/AlumnosController.php
1 <?php 2 3 namespace App\Http\Controllers\ALUMNOS; 4 5 use Illuminate\Http\Request; 6 7 use App\Http\Requests; 8 use App\Http\Controllers\Controller; 9 10 class AlumnosController extends Controller 11 { 12 public function buscarAlumnos($nif){ 13 if (view()->exists('ALUMNOS.DatosAlumnos')){ 14 $datos=['nome'=>'Angel','idade'=>45]; 15 return view ('ALUMNOS.DatosAlumnos',[ 16 'nif' => $nif, 17 'datos' => $datos]); 18 } 19 else{ 20 return 'Non se pode cargar a páxina...'; 21 } 22 23 24 } 25 }
Arquivo ALUMNOS/DatosAlumnos.blade.php
1 <!DOCTYPE html> 2 <html lang="es"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Datos do alumno buscado</title> 6 </head> 7 <body> 8 9 <ul> 10 <li>Nif:{{ $nif }}</li> 11 @foreach ($datos as $key=>$valor) 12 <li>{{ $key }}:{{ $valor }}</li> 13 @endforeach 14 </ul> 15 16 17 </body> 18 </html>
- Controladores implícitos.
- En Laravel podemos definir unha ruta chamando a un controlador no que estean definidos diferentes métodos e automaticamente en función da ruta chamará a un método ou a outros.
- Por exemplo:
Arquivo app/Http/routes.php
1 Route::controller('proba','ControladorProbaController');
- Esta ruta 'xestionará' calquera petición que teña na url: http://sitioweb/proba
- Se agora definimos no controlador estas entradas:
Arquivo app/Http/Controllers/ControladorProbaController.php
1 public function getInicio(){ 2 return 'Inicio'; 3 } 4 public function getFinal(){ 5 return 'Final'; 6 } 7 public function postDatos(){ 8 return 'Enviando datos'; 9 }
- Este controlador responderá a estas peticións:
- http://sitioweb/proba/inicio => método get (é dicir, solicitando a páxina)
- http://sitioweb/proba/final => método get (é dicir, solicitando a páxina)
- http://sitioweb/proba/datos => método post (é dicir, enviando datos)
HTTP Request
- HTTP Request.
- Máis información en laravel.com (fixarse na versión de Laravel instalada na parte superior da páxina web)
Exemplo 1 do manual anterior. Uso de Http request
- Neste exemplo imos ver como a partires dun formulario no que se pide login-password imos recibir có método 'post' os datos do mesmo noutra vista.
- Partimos do formulario.
- Arquivo: /proxecto_raiz/resources/views/formulario/Formulario.blade.php
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 4 <head> 5 <meta charset="utf-8" /> 6 <title>Formulario</title> 7 <style> 8 .formularios{ 9 width: 30%; 10 margin: 0px auto; 11 } 12 .etiqueta{ 13 float: left; 14 width: 190px; 15 } 16 .botonesformularios{ 17 width: 50%; 18 margin: 30px auto; 19 text-align: center; 20 } 21 select { 22 width:50%; 23 } 24 </style> 25 </head> 26 <body> 27 <form id="frmValidacion" class="formularios" method="post" action="/controlador"> 28 <div> 29 <div class='etiqueta'>Login:</div> 30 <input type="text" size="15" maxlength="15" name="txtLogin" /> 31 </div> 32 <div> 33 <div class='etiqueta'>Password:</div> 34 <input type="password" size="15" maxlength="15" name="txtPassword" /> 35 </div> 36 <div class="botonesformularios"> 37 <input type='submit' value="ENVIAR" /> 38 </div> 39 </form> 40 41 </body> 42 </html>
- Liña 27: Como vemos na action do formulario imos invocar un controlador a través dunha ruta definida no arquivo routes.php.
- Definimos unha ruta para cargar a vista do formulario:
- Arquivo: proxecto_raiz/app/Http/routes.php
1 Route::get('formulario/',function(){ 2 return view('formulario.Formulario'); 3 });
- Nota: Por practicar estamos amosando a vista directamente dende a ruta, cando deberíamos pasar por un controlador.
- Se poñemos como url: http://localhost:8000/formulario aparecerá o formulario.
- Indicamos no arquivo de routes.php que se ten que facer cando reciba unha chamada do formulario. Fixarse como o verbo da ruta é post.
- Arquivo: proxecto_raiz/app/Http/routes.php
1 Route::post('controlador/','ControladorProbaController@mostrarUriUrl');
- Agora creamos a clase controladora e método mostrarUriUrl dentro dela.
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use App\User; 6 use App\Http\Controllers\Controller; 7 use Illuminate\Http\Request; 8 9 class ControladorProbaController extends Controller { 10 11 public function procedementoControlador($id){ 12 return "Esta información ven dun controlador especifico. Recibido o dato $id"; 13 } 14 15 public function mostrarUriUrl(Request $request){ 16 echo $request->path(); 17 echo "<br>"; 18 echo $request->url(); 19 echo "<br>"; 20 21 22 var_dump($request->all()); // ou dd(($request->all())); ou print_r(($request->all())); 23 24 } 25 26 }
- Nota:
- $request->all(): Devolve todos os datos enviados polo formulario.
- $request->input('txtLogin'): Devolve o texto do campo con name 'login' do formulario.
- Dará como resultado:
controlador http://localhost:8000/controlador /home/angel/laravel/first_steps/app/Http/Controllers/ControladorProbaController.php:22: array (size=2) 'txtLogin' => string 'dfsdf' (length=5) 'txtPassword' => string 'dsfds' (length=5)
- Máis información neste enlace.
Exercicio 1
- Modifica o código anterior e crea unha vista de nome 'DatosFormulario.blade.php' que se atopa no cartafol 'formulario' dentro das views, que visualice o login e password enviado polo formulario.
- Solución
Páxina: DatosFormulario.blade.php
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es"> 4 <head> 5 <meta charset="utf-8" /> 6 <title>Formulario</title> 7 </head> 8 <body> 9 LOGIN:{{$datos['txtLogin']}}<br /> 10 PASSWORD:{{$datos['txtPassword']}} 11 12 13 </body> 14 </html>
Páxina: ControladorProbaController.blade.php
1 <?php 2 ................... 3 4 public function mostrarUriUrl(Request $request){ 5 return view('formulario/DatosFormulario',['datos'=>$request->all()]); 6 7 8 } 9 }
Response
- Lembrar que xa vimos como enviar información de cabeceira ao navegador utilizando a función header de PHP.
- Podedes comprobar o código de retorno da función 'response' có programa HttpRequester:
- Tedes neste enlace os diferentes content-type que podedes utilizar para enviar na cabeceira.
Exercicio 1
- Crea unha ruta que teña unha URL deste tipo: /dato_response/{param} sendo {param} un número.
- Fai que no caso de que dito número sexa maior que 100, se informe ao usuario cunha páxina de tipo 'non atopada' e dentro dun <h1> que o número non pode exceder de 100, amosando o número, e fai que o cabo de 3 segundos cargue a páxina /dato_response/1.
- A páxina /dato_response/{param} amosará un texto de benvida amosando o número enviado como parámetro.
Solución Exercicio 1
- Arquivo: proxecto_raiz/app/Http/routes.php
1 Route::get('/dato_response/{numero}','ControladorProbaController@controlarDatoResponse')->where(['numero' => '[0-9]+']);
- Arquivo: proxecto_raiz/app/Http/Controlllers/ControladorProbaController.php
1 .............. 2 public function controlarDatoResponse($num){ 3 if ($num>100) { 4 return response("<h1>O número enviado non é válido:$num</h1>") 5 ->header('Content-Type', 'text/html') 6 ->header('status', 404) 7 ->header('Refresh', '3; url=/dato_response/1'); 8 } 9 else{ 10 return view('DatoResponse',['numero' => $num]); 11 } 12 13 } 14 ..............
- Arquivo: proxecto_raiz/resources/views/DatosResponse.blade.php
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Laravel</title> 5 </head> 6 <body> 7 <div class="container"> 8 <h1>Benvido. O teu número é {{$numero}}</h1> 9 </div> 10 </body> 11 </html>
Validación de formularios
- No manual fala de que é posible instalar os arquivos necesarios para que en caso de erro de validación, as mensaxes do array $errors saian no noso idioma.
- Para iso tedes que ir a este enlace
- Nel indica o seguinte:
- Descargar por composer (no enlace tedes outros métodos) os arquivos de tradución.
1 composer require caouecs/laravel-lang:~3.0
- Nota: A orde anterior é para versión de Laravel 5.* . Se tedes outra visitade o enlace.
- Copiamos o cartafol da linguaxe de idioma (neste caso é o español)
1 cp -r vendor/caouecs/laravel-lang/src/es/ resources/lang/
- Estando situados no cartafol onde temos o proxecto laravel.
- Modifica o arquivo config/app.php e substitúe as liñas de 'locale' polo idioma español:
1 ...... 2 3 'locale' => 'es', 4 5 ..........
Exercicio 1
- Crea unha táboa de nome AUTORES coas columnas: id_autor PK AU, apelido varchar(100), nome varchar(50)
- Crea unha vista dentro do cartafol autores, de nome form_alta_autores.blade.php que teña un formulario para dar de alta a un novo autor, enviando como datos o nome e os apelidos.
- Utiliza o método post no formulario e que o action apunte á páxina '/autores/alta
- Modifica o arquivo de rutas para que recolla este tipo de solicitude:
- http://sitioweb/autores/form/alta: Chamará ao controlador AutoresController e método create. Cargará a vista form_alta_autores.blade.php
- http://sitioweb/autores/alta: Chamará ao controlador AutoresController e método store para gardar os datos do novo autor. Como aínda non vimos o acceso a datos, amosaremos unha cadea de texto indicando que foi dado de alta correctamente e cargaremos a vista do formulario de alta ao cabo de 5 segundos.
- Valida os datos para que sexan obrigatorios e que a lonxitude do campo nome non sexa superior a 50 caracteres e a lonxitude do campo apelido non sexa superior a 100 caracteres. Os dous deberán ter a lo menos 5 caracteres. En caso de non cumprir os criterios, volver a cargar a páxina do formulario indicando os erros atopados e que os campos do formulario estean cubertos cos datos enviados.
Solución Exercicio 1
Arquivo: app/Http/routes.php
1 Route::get('/autores/form/alta','AutoresController@create'); 2 Route::post('/autores/alta','AutoresController@store');
Arquivo: app/Http/Controllers/AutoresController.php
1 public function create() 2 { 3 return view('autores.form_alta_autores'); 4 } 5 6 public function store(Request $request) 7 { 8 $this->validate($request,[ 9 'txtNome' => 'required|max:50|min:5', 10 'txtApelidos' => 'required|max:100|min:5', 11 ]); 12 13 return response("<h1>Autor dado de alta correctamente</h1>") 14 ->header('Content-Type', 'text/html') 15 ->header('status', 200) 16 ->header('Refresh', '3; url=/autores/form/alta'); 17 }
Arquivo: resources/views/autores/form_alta_autores.blade.php
1 <!DOCTYPE html> 2 <html lang="es"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Alta de autores</title> 6 </head> 7 <body> 8 9 <form action="/autores/alta" method="post"> 10 <div> 11 Apelidos: <input type="text" maxlength="100" size="60" name="txtApelidos" value="{{old('txtApelidos')}}"/> 12 </div> 13 <div> 14 Nome: <input type="text" maxlength="50" size="30" name="txtNome" value="{{old('txtNome')}}" /> 15 </div> 16 <div> 17 <input type="submit" value="Enviar" /> 18 <input type="reset" value="Borrar" /> 19 </div> 20 21 </form> 22 23 @if(count($errors) > 0) 24 <div class="errors"> 25 <ul> 26 @foreach($errors->all() as $error) 27 <li>{{ $error }}</li> 28 @endforeach 29 </ul> 30 </div> 31 @endif 32 33 </body> 34 </html>
- Nota:
- As regras de validación estarían dentro do conxunto de 'regras de negocio'. Se queremos que ditas regras estean definidas no modelo, o podemos implementar da seguinte forma:
- Información obtida dende este enlace.
- Neste exemplo fai uso do facede Input para obter os datos que veñen do formulario. Nos estamos a utilizar a forma $request->input('campo')
- Modificamos a clase do Modelo agregando as regras de validación e a función que vai validar:
1 <?php 2 3 use Validator; 4 class User extends Eloquent { 5 public static $rules = array( 6 'real_name' => 'required|min:2', 7 'email' => 'required|email|unique:users,email,id', 8 'password' => 'required', 9 'level' => 'required|numeric' 10 ); 11 public static $messages = array( 12 'real_name.required' => 'El nombre es obligatorio.', 13 'real_name.min' => 'El nombre debe contener al menos dos caracteres.', 14 'email.required' => 'El email es obligatorio.', 15 'email.email' => 'El email debe contener un formato válido.', 16 'email.unique' => 'El email pertenece a otro usuario.', 17 'password.required' => 'La contraseña es obligatoria.', 18 'level.required' => 'El nivel es obligatorio.', 19 'level.numeric' => 'El nivel debe ser numérico.' 20 ); 21 public static function validate($data, $id=null){ 22 $reglas = self::$rules; 23 $reglas['email'] = str_replace('id', $id, self::$rules['email']); // Se estamos modificando un usuario e temos unha regra que indica que o email debe ser único, debemos de excluír ao propio usuario que fai a modificación da regra de validación 24 $messages = self::$messages; 25 return Validator::make($data, $reglas, $messages); 26 } 27 } 28 ?>
- Agora para validar dende o controlador:
1 public function update($id) { 2 $user = User::find($id); 3 $user->real_name = Input::get('real_name'); 4 $user->email = Input::get('email'); 5 $user->level = Input::get('level'); 6 $validator = User::validate(array( 7 'real_name' => Input::get('real_name'), 8 'email' => Input::get('email'), 9 'password' => $user->password, 10 'level' => Input::get('level'), 11 ), $user->id); 12 if($validator->fails()){ 13 $errors = $validator->messages()->all(); 14 $user->password = null; 15 return View::make('users.save')->with('user', $user)->with('errors', $errors); 16 }else{ 17 $user->save(); 18 return Redirect::to('users')->with('notice', 'El usuario ha sido modificado correctamente.'); 19 } 20 }
Modelos en Laravel
Introdución
Exemplo 1 do manual anterior
- Temos que ter creada unha base de datos Mysql cun usuario e password que teña permiso sobre dita base de datos.
- Os pasos para instalar Mysql, un xestor de bases de datos, os tedes na wiki.
- Unha vez creada debemos editar o arquivo proxecto_raiz/.env
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_DATABASE=homestead DB_USERNAME=laravel DB_PASSWORD=laravel
Unha vez cambiado debemos parar o servidor laravel e volvelo a iniciar coa orde: php artisan serve dende o raíz do proxecto.
- Partindo que xa temos a táboa e a base de datos seguindo o manual...
- Imos facer que se amosen os datos nunha vista en forma de lista.
- Arquivo: proxecto_raiz/resources/views/basedatos/articles.blade.php
1 <!DOCTYPE html> 2 <html lang="es"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Isto é unha vista de proba dunha táboa mysql</title> 6 </head> 7 <body> 8 <!-- Formato utilizando blade --> 9 <ul> 10 @foreach ($datos as $fila) 11 <li>{{ $fila->id }}---->{{ $fila->name }}</li> 12 @endforeach 13 </ul> 14 15 16 <!-- Formato utilizando php tradicional --> 17 <ul> 18 <?php 19 foreach($datos as $fila){ 20 printf("<li>%s--->%s",$fila->id,$fila->name); 21 } 22 23 ?> 24 25 </ul> 26 </body> 27 </html>
- Liña 10: Nomeamos $datos á variable que vai vir do controlador cos datos da táboa. Segundo o manual isto non é necesario xa que podemos acceder dende calquera parte aos datos do modelo coa orde: \App\Article::all(); Pero desta forma practicamos o paso de datos dende o controlador e ademáis supoño que será a forma correcta :)
- Arquivo: /proxecto_raiz/app/Http/Controllers/ArticulosController.php
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use App\User; 6 use App\Http\Controllers\Controller; 7 use Illuminate\Http\Request; 8 9 class ArticulosController extends Controller { 10 11 public function amosarArticulos(){ 12 $datos=\App\Article::all(); 13 return view('basedatos.articles',[ 14 'datos' => $datos 15 ]); 16 17 } 18 19 20 }
- Liñas 13,14: Dende este método do controlador enviamos os datos da táboa á vista.
- Nota: Se escribimos a orde: use App\Article;
- Poderemos poñer: Artille::all()
- Arquivo: /proxecto_raiz/app/Http/routes.php
1 Route::get('articulos/','ArticulosController@amosarArticulos');
- Cando na url poñamos: http://localhost:8000/articulos chamará ao método amosarArticulos do controlador ArticulosController.
- Resultado:
1--->Probando 2--->Algo 3--->Lindo
Acceso a base de datos
- Nota: Actualizado á versión 10 de Laravel:
composer create-project laravel/laravel laravel_basico_ud6_mvc_wiki "10.*"
- Enlaces á versión 5.1
- Enlaces á versión 10
- En Laravel podemos obter información da base de datos de dúas formas diferentes:
- QueryBuilder: En este caso accedemos directamente ás táboas facendo unha especio de SQL (con joins) para obter os resultados. É a forma máis rápida de acceder.
- Eloquent: En este caso accedemos as táboas a través dos modelos e relacións definidos en Laravel. É a forma máis sinxela e intuitiva de acceso a datos. Esta é a forma que imos empregar.
Exercicio 1: Xestión dunha única táboa
- Imos desenvolver a xestión dunha táboa PERFUMES.
- Teremos as operacións de alta, baixa e modificación.
- Veremos como 'formatear' un tipo de dato DATE de Mysql. De tal forma que en Mysql gardaremos a data có formato yyyy-mm-dd e no formulario do usuario terá o formato dd/mm/yyyy.
- Veremos como 'formatear' un campo decimal de Mysql. De tal forma que en Mysql gardaremos o valor có formato XXX.YY e no formulario do usuario terá o formato XXX,YY.
- Veremos como tratar os campos optativos, que poden vir con valores baleiros dende o formulario do usuario.
- IMPORTANTE: Neste exercicio, o uso de formularios se fai utilizando as etiquetas habituais. En Laravel se poden empregar unhas 'etiquetas' específicas que van estar relacionadas cos Modelos e van permitir facer de forma inmediata 'cargar' os datos do modelo sobre os campos que conforman o formulario.
- Tedes neste enlace como facelo.
Pasos previos
- Modificar o arquivo .env no raíz do proxecto para indicar a base de datos, login e password de acceso.
- Crear a táboa en Mysql:
CREATE TABLE `perfumes` ( `id` int(11) NOT NULL AUTO_INCREMENT, `descripcion` varchar(45) COLLATE utf8_spanish2_ci NOT NULL, `prezo` decimal(8,2) NOT NULL, `data_compra` date DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;
- Creamos o modelo para poder utilizar Eloquent:
- Comando artisan no cartafol do proxecto: php artisan make:model Perfume
- Este comando vai crear un arquivo App\Models\Perfume.php có seguinte código:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Perfume extends Model { use HasFactory; }
- Con isto só cando se intente recuperar datos da base de datos empregando este modelo, Laravel vai entender que:
- A clave primaria é id
- A táboa se chama perfumes (en plural con respecto ao nome do modelo)
- A orde use HasFactory indica que o modelo pode empregar factory que é unha forma de xerar datos de proba de manera sinxela para engadir á táboa datos para empregar nos tests o en desenvolvemento. Non imos empregalo polo que podemos eliminar dita línea.
- Todo o que presupón Laravel pode ser sobreescrito para adaptalo as nosas necesidades:
- Arquivo App\Models\Pefume.php:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Perfume extends Model { protected $table ='perfumes'; // Indicamos a táboa relacionada con este modelo. protected $primaryKey='id'; // Indicamos a clave primaria da táboa public $timestamps = false; // Por defecto laravel inclúe dous campos (created_at e updated_at) de tipo datetime cando se fai unha operación de inserción e actualización sobre unha fila. Con isto indicamos que a táboa non ten eses campos. protected $casts = [ // Cando accedamos a unha fila empregando este modelo, se poñemos $fila->data_compra teremos un string. Se poñemos o cast, obteremos unha instancia da [https://carbon.nesbot.com/docs/ clase Carbon] de Laravel que nos permite facer operacións e formatear a data. 'data_compra' => 'date:d-m-Y', // Tamén se pode empregar datetime. A data se recupera formateada en forma de String. Se poñemos 'date' obtemos un obxecto da clase Carbon. ]; protected $fillable = [ // Isto xa o veremos. O que indica é que cando facemos unha operación masiva de inserción ou un insert da forma create(datos) soamente deixa enviar en datos (que é un array) as columnas indicadas nesta propiedade (as columnas indicadas son descripcion, prezo e data_compra). Faise por motivos de seguridade. 'descripcion', 'prezo', 'data_compra' ]; }
- Liña 14: Como vemos a táboa ten un campo de tipo date.
- Se queremos formatear dito campo para visualizalo na forma que queiramos (por exemplo, dd-mm-yyyy) Laravel permite converter dito campo a un obxecto da clase Carbon. Dita clase xa dispón de métodos para formatear a data (máis información neste enlace. Para obtelo debemos poñer na propiedade $cast: 'data_compra:date' (ou datetime)
- Cando obteñamos un obxecto que represente unha fila da táboa utilizando Eloquent, poderemos formatear a data desta forma: $perfume->data_compra->format('d/M/Y').
- Máis información neste enlace.
- Usaremos o sistema de plantillas de Laravel.
- Básicamente o que facemos é crear unha plantilla con dúas seccións definidas: pageTitle e content. A páxina que vai ter o contido vai empregar esta páxina como 'base' susituíndo as dúas seccións polo seu contido.
- Para engadir unha línea php dentro do html, podemos empregar {{ }} que fai como un echo de php (escapando o seu contido) e empregaremos route para que poña a ruta definida no arquivo web.php no cartafol routes.
Arquivo /resources/views/plantilla.blade.php
<!DOCTYPE html> <html> <head> <title>@yield('pageTitle')</title> <style> .menu{ float: left; width: 30%; padding-left: 5px; } .menu a{ display: block; } .contido{ float: left; width: 65%; } </style> </head> <body> <div class="menu"> <a href='{{route('perfumes.index')}}'>Operacións Perfumes</a> <!-- Se podería poñer /perfumes/listar pero mellor empregar os nomes definidos no arquivo de routes.php--> </div> <div class="contido"> @yield('content') </div> </body> </html>
Listado de perfumes
- Dende unha vista imos listar todos os perfumes que teña a base de datos e dentro da mesma imos ter as opcións de alta, baixa e modificación de novos perfumes.
- A pantalla terá este aspecto:
- Como podemos observar dispoñemos:
- Na parte esquerda dun menú coa opción 'Operacións Perfumes' que carga a páxina que se ve na imaxe.
- Na parte dos datos, temos un enlace que permite crear un novo perfume e despois na lista de perfumes, a carón de cada un deles, temos a opción de modificar ou eliminar un perfume.
- Creamos o controlador
- Podemos emplear este comando: php artisan make:controller PerfumeController --resource para crear unos métodos 'estándares' aplicadas a un modelo.
- Los métodos que se crean en el controlador serán:
- index(): Mostrar unha lista de todos os rexistros.
- create(): Mostrar un formulario para crear un novo rexistro.
- store(): Gardar o novo rexistro na base de datos.
- show(): Amosar un rexistro específico.
- edit(): Amosar un formulario para editar un rexistro existente.
- update(): Actualizar un rexistro específico na base de datos. Tería como entrada os datos do formulario amosados en edit.
- destroy(): Eliminar un rexistro específico.
- Se non queremos crealos podemos empregar a orde: php artisan make:controller PerfumeController e definir nos o nome dos métodos.
- O comando anterior crea o arquivo: : /app/Http/Controller/PerfumeController.php
- Creamos a ruta. Máis información en este enlace.
- Arquivo: /app/routes/web.php
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\PerfumeController; Route::get('/perfumes','PerfumeController@index')->name('perfumes.index'); // O nome pode ser calquera, pero mellor relacionado có método do controller / nome da vista
- Como vemos, cando na url escribamos http://dominio/perfumes (en probas sería: http://localhost:8000/perfumes) e prememos a tecla enter (acción get) se chamará ao método index do controlador PerfumeController.
- Ao darlle un nome á ruta (pode ser calquera nome, non ten porque coincidir coa ruta, pero desta forma é mais doado de acordarse) poderemos empregar dito nome para dende as vistas referenciar a ruta da forma Route('nome_ruta') ou cando facemos redirección dende o controlador (xa o veremos).
- Podemos engadir unha entrada resource no arquivo de rutas sustituindo á anterior:
Route::resource('perfumes', PerfumeController::class);
- Se executades o comando dende o terminal: php artisan route:list podedes comprobar como se crearon todas as rutas necesarias para xestionar a táboa Perfume (listado , alta, baixa, modificación e detalle).
GET|HEAD perfumes ................................................................................................................................... perfumes.index › PerfumeController@index
POST perfumes ................................................................................................................................... perfumes.store › PerfumeController@store
GET|HEAD perfumes/create .......................................................................................................................... perfumes.create › PerfumeController@create
GET|HEAD perfumes/{perfume} ........................................................................................................................... perfumes.show › PerfumeController@show
PUT|PATCH perfumes/{perfume} ....................................................................................................................... perfumes.update › PerfumeController@update
DELETE perfumes/{perfume} ..................................................................................................................... perfumes.destroy › PerfumeController@destroy
GET|HEAD perfumes/{perfume}/edit ...................................................................................................................... perfumes.edit › PerfumeController@edit
- Fixarse que tamén se indica o nome da ruta. Por exemplo, perfumes.index (o nome) apunta ao controlador PerfumeController y método index.
- Con este sistema tamén podemos indicar que non se xeren todas as rutas, exceptuando algunha ou indicando soamente cales queremos de todas, poñendo ao final:
- Route::resource('perfumes', PerfumeController::class)->only(['index', 'show']);
- Route::resource('perfumes', PerfumeController::class)->except(['create', 'store', 'update', 'destroy']);
- Imos empregar esta forma pero lembrar como se fan 'manualmente'. De forma manual podemos poñer o verbo que queiramos (post, delete,...) e enviar parámetros na url da forma http://url/parametro1.
Modificamos agora o controlador para que cargue a vista.
- Arquivo: /app/Http/Controller/PerfumeController.php
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 use App\Http\Requests; 8 use App\Perfume; 9 10 class PerfumeController extends Controller 11 { 12 ....... 13 14 public function index() 15 { 16 $perfumes = Perfume::orderBy('descripcion')->get(); 17 return view('perfumes.index') 18 ->with(['perfumes'=>$perfumes]); 19 } 20 21 22 }
- Como vemos, estamos chamando á vista index dentro dun cartafol 'perfumes' creado en views. Mandamos como parámetro a lista de perfumes da base de datos ordenados polo campo descripción.
- Outra forma de facer o mesmo pero de xeito máis compacto é empregar compact á hora de enviar os datos á vista:
1 <?php 2 3 ....... 4 5 public function index() 6 { 7 $perfumes = Perfume::orderBy('descripcion')->get(); 8 return view('perfumes.index',compact('perfumes')); 9 } 10 11 12 }
- Creamos a vista:
Arquivo /resource/views/perfumes/index.blade.php
- Nota: Creamos un cartafol dentro de /resources/views/perfumes
@extends('plantilla') <!-- Collemos a páxina base --> @section('pageTitle', 'Lista de Perfumes') <!-- Engade o contido á sección pageTitle --> @section('content') <!-- Engade o contido á sección content --> <div> <a href="{{ route('perfumes.create') }}">NOVO PERFUME</a> <!-- href podría tener esto: /perfumes/create pero mejor con route --> </div> <h5>Hai {{ $perfumes->count() }} perfumes en la base de datos.</h5> <table> <tr> <th>Descripción</th> <th>Prezo</th> <th>Data compra</th> <th>Operaciones</th> </tr> @foreach ($perfumes as $perfume) <tr> <td>{{ $perfume->descripcion }}</td> <td>{{ number_format($perfume->prezo, 2, ',', '') }}</td> <td>{{ $perfume->data_compra ? $perfume->data_compra->format('d/m/Y') : '' }}</td> <td> <a style='text-decoration:none' href="{{ route('perfumes.edit', ['perfume' => $perfume->id]) }}">Modificar</a> <form action="{{ route('perfumes.destroy', ['perfume' => $perfume->id]) }}" method="POST" style="display:inline;"> @csrf @method('DELETE') <input type="hidden" name="id" value="{{ $perfume->id }}"> <button type="submit" onclick="return confirm('Estás seguro de eliminar o perfume {{ $perfume->descripcion }}?');" class='btn btn-link'>Eliminar</button> </form> </td> </tr> @endforeach </table> @if (session()->has('msg')) <h3>{{ session('msg') }}</h3> @endif @endsection
- Liña 7: Facemos un enlace á ruta route('perfumes.create') que recordemos que apunta a PerfumeController@create. Poderíamos poñer /perfumes/create. Cargará a vista que amosa o formulario de alta dun novo perfume.
- Liña 11: Chamamos a función count() da clase Collect para amosar o número de rexistros atopados na base de datos.
- Liña 20: Percorremos cada un dos perfumes da colección.
- Liña 23: O prezo é un decimal en Mysql e se garda có punto como separación dos números decimais. O que facemos é substituír o punto por unha coma.
- Liña 24: O data de compra é un campo opcional, polo que pode vir cun valor nulo. Nese caso, a chamada á función format provocaría unha excepción polo que preguntamos utilizando o operador ternario se ten dato. En caso de que non teña amosamos a cadea baleira.
- Liña 26-36: Temos un enlace e un boton para as operacións de actualización e baixa: verbo get con route('perfumes.edit') ou /perfumes/id/edit => cargará a vista que actualiza e verbo delete con route('perfumes.destroy') ou /perfumes/id => borra o perfume.
Alta de perfume
- A pantalla de alta de novos perfumes terá este aspecto:
- Vimos coa ruta de tipo 'get' e valor /perfumes/create (é o indicado no enlace da vista de listado de perfumes do punto anterior).
- Ao dar de alta imos ter dúas rutas: a que amosa o formulario de alta e a que procesa o formulario de alta e engade o perfume á base de datos.
- Como empregamos Route::resource as rutas xa as temos definadas e asociadas a métodos do controlador.
- Se quiséramos cambiar dita asociación poderíamos poñer:
- Arquivo: \app\routes\web.php
1 Route::get('/perfumes/create','PerfumeController@create'); // Non poñer nada xa que con Route::resource xa temos as rutas 2 Route::post('/perfumes','PerfumeController@store'); // Non poñer nada xa que con Route::resource xa temos as rutas
- Temos dúas rutas, unha para amosar a vista (método get) e a outra (método post) para cando engadimos un novo rexistro (perfume).
- Modificamos o controlador:
- Arquivo: /app/Http/Controller/PerfumeController.php
1 ................ 2 3 // Formato dd/mm/YYYY => devuelve YYYY-mm-dd 4 function cambiaf_a_mysql($fecha){ 5 $numeroDia = substr($fecha,0,2); 6 $mes = substr($fecha,3,2); 7 $anio = substr($fecha,6,4); 8 return $anio . '-' . $mes . '-' . $numeroDia; 9 } 10 11 12 public function create() 13 { 14 return view('perfumes.form_alta_perfumes'); 15 } 16 17 public function store(Request $request) 18 { 19 $this->validate($request,[ 20 'txtDescripcion' => 'required|max:45', 21 'txtPrezo' => 'required|regex:/[0-9]{1,3},[0-9]{2}/', 22 'txtDataCompra' => 'date_format:"d/m/Y"' 23 ]); 24 25 $perfume = new Perfume; 26 $perfume->descripcion = $request->input('txtDescripcion'); 27 $perfume->prezo = str_replace(',','.',$request->input('txtPrezo')); 28 $perfume->data_compra = $request->has('txtDataCompra') ? $this->cambiaf_a_mysql($request->input('txtDataCompra')) : null; 29 $perfume->save(); 30 31 // Existe unha forma de crear e gardar o rexistro ao mesmo tempo: $novoPerfume = Perfume::create($request->all()) pero como neste caso imo manipular a data non o usaremos. 32 33 return redirect('/perfumes/alta')->with(['idPerfume' => $perfume->id_perfume]); 34 }
- Liñas 12-15: Función que se chama para amosar o formulario de alta.
- Liñas 19-23: Facemos que os campos cumpran as seguintes regras:
- txtDescripcion: Obrigatorio, con 45 caracteres como máximo (igual ao tamaño do campo na base de datos)
- txtPrexo: Campo obrigatorio có formato XXX,YY sendo obrigatorio poñer a coma e dous números decimais. Lembrar que en Mysql o formato debe ser XXX.YY
- txtDataCompra: Data de compra có formato dd/mm/YYYY. Lembrar que en Mysql o formato debe ser YYYY-mm-dd.
- Liñas 25-29: Cremos un novo rexistro na base de datos.
- Liña 27: Cambiamos a coma por un punto no prezo
- Liña 28: Preguntamos se temos data de compra (é optativo) cun operador ternario. Se non temos gardamos null na base de datos. Se temos cambiamos o formato da data a yyyy-mm-dd chamando a unha función de nome cambiaf_a_mysql.
- Liña 33: Rediriximos á ruta que carga o formulario de alta e enviamos como dato na variable session('idPerfume') o id do perfume xerado por Mysql.
- Emprego de Accesor e Mutators
- Para o problema das datas tamén podemos empregar os Accessor/Mutators. Son funcións que definimos no modelo e que se aplican sobre os datos antes de envialos á vista cando os queremos amosar ou antes de envialos á base de datos cando os imos gardar. Facendo uso destas funcións xa non temos que estar 'formateando' os datos e podemos recuperalos desta forma:
- Cambiamos $cast no modelo para que en vez de devolver un string devolva un obxecto da clase Carbon:
- Arquivo /app/Models/Perfume.php:
protected $casts = [ // Cando accedamos a unha fila empregando este modelo, se poñemos $fila->data_compra teremos un string. Se poñemos o cast, obteremos unha instancia da [https://carbon.nesbot.com/docs/ clase Carbon] de Laravel que nos permite facer operacións e formatear a data. 'data_compra' => 'date', // Tamén se pode empregar datetime. Devolve un Carbon ];
- Engadimos o accesor/mutator.
- Ademáis podemos facer o mesmo có prezo, para que cando se amose poña unha coma coma separador decimal e se asigna un valor que o garde con punto para poder ser enviado a mysql.
- Arquivo /app/Models/Perfume.php:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Casts\Attribute; use Carbon\Carbon; class Perfume extends Model { protected $table = 'perfumes'; // Indicamos a táboa relacionada con este modelo. protected $primaryKey = 'id'; // Indicamos a clave primaria da táboa public $timestamps = false; // Por defecto laravel inclúe dous campos (created_at e updated_at) de tipo datetime cando se fai unha operación de inserción e actualización sobre unha fila. Con isto indicamos que a táboa non ten eses campos. protected $casts = [ // Cando accedamos a unha fila empregando este modelo, se poñemos $fila->data_compra teremos un string. Se poñemos o cast, obteremos unha instancia da [https://carbon.nesbot.com/docs/ clase Carbon] de Laravel que nos permite facer operacións e formatear a data. 'data_compra' => 'date', // Tamén se pode empregar datetime. Devolve un Carbon ]; protected $fillable = [ // Isto xa o veremos. O que indica é que cando facemos unha operación masiva de inserción ou un insert da forma create(datos) soamente deixa enviar en datos (que é un array) as columnas indicadas nesta propiedade (as columnas indicadas son descripcion, prezo e data_compra). Faise por motivos de seguridade. 'descripcion', 'prezo', 'data_compra' ]; protected function DataCompra(): Attribute { return Attribute::make( get: fn($value) => $value ? Carbon::parse($value)->format('d/m/Y') : null, // Cando empregamos a data da forma echo($perfume->data_compra); convirte o obxecto Carbon a unha cadea có formato correcto set: fn($value) => $value ? Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d') : null // Cando empregamos a data da forma: $perfume->data_compra = "10/01/2025" o gardará ); } protected function Prezo(): Attribute { return Attribute::make( // Cuando accedemos al valor del campo, convertimos el punto en coma get: fn ($value) => number_format($value, 2, ',', '.'), // Cuando se asigna el valor, reemplazamos la coma por un punto set: fn ($value) => str_replace(',', '.', $value), ); } }
- NOTA IMPORTANTE: Os nomes dos atributos teñen que seguir a seguinte regra: Se ten unha palabra empeza con maiúsculas. Se ten duas palabras, o inicio de cada palabra empeza con maiúsculas e van xuntas (sen guión). No nome do campo de base de datos terá que estar en minúsculas e con guión.
- Por exemplo, o campo da base de datos é data_compra polo que o atributo ten que chamarse DataCompra. O campo da base de datos é prezo, polo que o atributo debe chamarse Prezo.
- Con isto xa podemos borrar a función cambiaf_a_mysql do controlador e empregar Perfume::create cando creamos el perfume.
- Arquivo /app/Models/Perfume.php:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Perfume; class PerfumeController extends Controller { ..... // BORRAMOS A FUNCION cambiaf_a_mysql // Cambiamos store: public function store(Request $request) { $this->validate($request,[ 'descripcion' => 'required|max:45', 'prezo' => 'required|regex:/[0-9]{1,3},[0-9]{2}/', 'data_compra' => 'date_format:"d/m/Y"' ]); $perfume = Perfume::create($request->all()); return redirect(route('perfumes.create'))->with(['idPerfume' => $perfume->id]); }
- Agora debemos modificar a pantalla de listado de perfumes xa que o prezo xa se vai visualizar có formato correcto ao igual que a data:
Arquivo App\resources\views\index.blade.php
@extends('plantilla') <!-- Collemos a páxina base --> @section('pageTitle', 'Lista de Perfumes') <!-- Engade o contido á sección pageTitle --> @section('content') <!-- Engade o contido á sección content --> <div> <a href="{{ route('perfumes.create') }}">NOVO PERFUME</a> <!-- href podría tener esto: /perfumes/create pero mejor con route --> </div> <h5>Hai {{ $perfumes->count() }} perfumes en la base de datos.</h5> <table> <tr> <th>Descripción</th> <th>Prezo</th> <th>Data compra</th> <th>Operaciones</th> </tr> @foreach ($perfumes as $perfume) <tr> <td>{{ $perfume->descripcion }}</td> <td>{{ $perfume->prezo }}</td> <td>{{ $perfume->data_compra }}</td>
- Como os campos do formulario para a alta e modificación son os mesmos, imos definilos nun arquivo externo e os reutilizaremos nas dúas vistas:
- Arquivo: /resources/views/perfumes/campos_perfume.blade.php
1 <div> 2 Descipción:<input type="text" maxlength="45" size="45" value="{{!empty($perfume) ? $perfume->descripcion : old('descripcion')}}" name="descripcion" /> 3 </div> 4 <div> 5 Prezo (xxx,yy):<input type="text" value="{{!empty($perfume) ? str_replace('.',',',$perfume->prezo) : old('prezo')}}" maxlength="6" size="6" name="prezo" /> 6 </div> 7 <div> 8 Data (dd/mm/yyyy):<input type="text" value="{{!empty($perfume) ? (empty($perfume->data_compra) ? '' : $perfume->data_compra->format('d/m/Y')) : old('data_compra')}}" 9 maxlength="10" size="10" name="data_compra" /> 10 </div>
- Como vemos, o value de cada campo pode vir de dúas fontes diferentes:
- Se estamos no formulario de alta de perfumes e non cumpre os criterios de validación, volverá a cargar o formulario e teremos que amosar os valores que tiña o formulario. Nese caso os valores estará no array global old.
- Se estamos no formulario de modificación, viremos da pantalla de listado de perfumes no que premeremos no enlace de modificar asociado a un perfume concreto. Isto levará consigo chamar a unha función do controlador que busque os datos do perfume (utilizando Eloquent) e envíe á vista os datos do perfume atopado. Ditos datos van chegar na variable $perfume.
- O que facemos preguntando por !empty($perfume) é para saber se temos que cargar os datos dun perfume seleccionado na vista de listado de perfumes ou se temos que amosar os datos antigos por non cumprir os criterios de validación ao intentar dar de alta ou modificar os datos. Isto o facemos có operador ternario.
- Ademais, no caso da data, ao igual que pasaba na vista de lista de perfumes, temos que preguntar se ven baleiro ou non (outro operador ternario).
- Nota Importante: Cando demos de alta o rexistro, imos empregar a forma Perfume::create($request->all()). Para que funcione, os nomes das input teñen que corresponderse cós nomes das columnas da base de datos. Se non fora o caso, teríamos que facer un $perfume = new Perfume(), asociar a cada columna o $request correspondente e facer un $perfume->save()
- Arquivo: /resources/views/perfumes/form_alta_perfumes.blade.php
1 @extends('plantilla'); 2 3 @section('pageTitle', 'Alta de perfumes') 4 5 @section('content') 6 <h2>Alta de novos perfumes</h2> 7 8 9 <form method="post" action="{{route('perfumes.store')}}" name="formulario_perfumes"> 10 11 @csrf 12 @include('perfumes.campos_perfume') 13 <div> 14 <input type="submit" name="btnAlta" value="Alta" onClick="return confirm('Estás seguro de dar de alta o novo perfume ');"/> 15 <input type="reset" name="btnBorrar" value="Limpar" /> 16 17 </div> 18 19 20 </form> 21 22 @if (session()->has('idPerfume')) 23 <h4>Creado un novo rexistro co id: {{session('idPerfume')}}</h4> 24 @endif 25 26 @if(count($errors) > 0) 27 <div class="errors"> 28 <ul> 29 @foreach($errors->all() as $error) 30 <li>{{ $error }}</li> 31 @endforeach 32 </ul> 33 </div> 34 @endif 35 36 @endsection
- Liña 9: Utilizamos o nome da ruta para gardar os datos no método store do controlador.
- Liña 11: Nun formulario necesitamos protexelo de ataques con csrf
- Liña 12: Incluímos os campos do formulario.
- Liña 21-23: Isto non sería necesario xa que a un usuario non se lle vai amosar o id autonumérico que conforma a clave primaria dunha táboa. Está posto para amosar como se pode enviar un dato dende o controlador á vista e concretamente o id xerado por Mysql cando engadimos un rexistro.
- Lembrar (está comentado anteriormente) que cando fagamos unha operación o controlador vai facer un redirect e nese caso, o paso de datos coa orde ->with van chegar á vista en forma de variables de sesión.
Modificar perfume
- A pantalla de modificación dun perfume terá este aspecto:
- Necesitaríamos ter as rutas para modificar. Son dúas: unha GET para amosar o formulario cós datos a actualizar e outra POST para modificar os datos.
- Como empregmamos Route::resources xa temos creado as rutas e asociados aos métodos do controlador.
- Si quiséramos ter outras:
- Arquivo /app/Http/routes.php
1 Route::get('/perfumes/{id}/edit','PerfumeController@edit')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource 2 Route::post('/perfumes/{id}/edit','PerfumeController@update')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource
- Temos dúas rutas. A primeira carga o formulario cos datos e a segundo modifica os datos.
- Á primeira ruta chegamos dende a vista de listado de perfumes, premendo no enlace que ten o href có formato /perfumes/id_perfume/edit
- Arquivo /app/Http/Controller/PerfumeController.php
1 .................. 2 3 public function edit($id) 4 { 5 $perfume = Perfume::findOrFail($id); 6 return view('perfumes.perfume_edit') 7 ->with(['perfume' => $perfume]); 8 } 9 10 public function update(Request $request, string $id) 11 { 12 $this->validate($request,[ 13 'descripcion' => 'required|max:45', 14 'prezo' => 'required|regex:/[0-9]{1,3},[0-9]{2}/', 15 'data_compra' => 'date_format:"d/m/Y"' 16 ]); 17 18 $perfume = Perfume::findorFail($id); 19 $perfume->descripcion = $request->descripcion; 20 $perfume->prezo = $request->prezo; 21 $perfume->data_compra = $request->data_compra; 22 $perfume->save(); 23 24 return redirect()->route('perfumes.index')->with(['msg' => 'Perfume modificado correctamente']); 25 }
- Liñas 3-8: Buscamos o id do perfume que ven na URL. En caso de non atopalo lanzaría unha excepción (neste código está sen controlar con try-catch). Se o atopa o envía á vista 'perfume_edit' na variable $perfume.
- Liña 11-27: Recibimos os datos modificados dun perfume da vista cargada pola ruta anterior.
- Liñas 12-16: Volvemos a validar os datos enviados. Lembrar que poderíamos utilizar un obxecto da clase Requests creada por nos ou ben levar a validación de datos ao modelo (regras de negocio) como está indicado anteriormente.
- Liñas 18-22: Recuperamos os datos enviados polo formulario e actualizamos o rexistro do perfume.
- Liña 24: Cargamos a mesma páxina (o formulario cos datos da modificación) enviando unha mensaxe de que todo foi ben.
- Arquivo /resource/views/perfumes/perfume_edit.blade.php
1 @extends('plantilla') 2 3 @section('pageTitle', 'Editar Perfume') 4 @section('content') 5 6 <h5>Datos do perfume <b>{{$perfume->descripcion}}</b></h5> 7 8 <form method="post" name="form_datos_perfume" action="{{route('perfumes.update',['perfume' => $perfume->id])}}" > 9 @csrf 10 @method('PUT') 11 @include('perfumes.campos_perfume') 12 <div> 13 <input type="submit" name="btnModificar" value="Modificar" onClick="return confirm('Estás seguro de modificar o perfume {{$perfume->descripcion}}');"/> 14 <input type="reset" name="btnBorrar" value="Limpar" /> 15 16 </div> 17 </form> 18 19 @if(session()->has('msg')) 20 <h3>{{session('msg')}}</h3> 21 @endif 22 23 24 @if(count($errors) > 0) 25 <div> 26 <ul> 27 @foreach($errors->all() as $error) 28 <li>{{ $error }}</li> 29 @endforeach 30 </ul> 31 </div> 32 @endif 33 34 @endsection
- Nota: Nun aloxamento real, facer que apunte á mesma páxina con $_SERVER['PHP_SELF'] non me funcionou. Apuntaba á principal. Para solucionalo podemos facer uso de: Request::fullUrl()
Baixa de perfume
- Necesitaríamos ter as rutas para dar de baixa. verbo DELETE co id do perfume a dar de baixa.
- Como empregmamos Route::resources xa temos creado as rutas e asociados aos métodos do controlador.
- Si quiséramos ter outras:
- Arquivo /app/Http/routes.php
1 Route::delete('/perfumes/{id}','PerfumeController@destroy')->where(['id' => '[0-9]{1,12}']); // Non poñer xa que xa as temos definidas ao empregar Routes::resource
- Arquivo: /app/Http/Controller/PerfumeController.php
1 ................ 2 public function destroy($id) 3 { 4 $perfume = Perfume::findorFail($id); 5 $perfume->delete(); 6 7 return redirect()->route('perfumes.index'); 8 }
- Borramos o perfume có id enviado e cargamos a vista do listado de perfumes.
- En Laravel podemos inxectar o obxecto Perfume nos métodos do controlador (en calquera deles) da forma:
1 public function destroy(Perfume $perfume) 2 { 3 4 $perfume->delete(); 5 6 return redirect()->route('perfumes.index'); 7 }
- É como se fixéramos o find pero xa o fai Laravel.
- A nivel de vista xa tiñamos o código posto no arquivo app/resources/views/perfumes.blade.php
1 ............... 2 3 @foreach ($perfumes as $perfume) 4 <tr> 5 <td>{{ $perfume->descripcion }}</td> 6 <td>{{ number_format($perfume->prezo, 2, ',', '') }}</td> 7 <td>{{ $perfume->data_compra ? $perfume->data_compra->format('d/m/Y') : '' }}</td> 8 <td> 9 <a style='text-decoration:none' href="{{ route('perfumes.edit', ['perfume' => $perfume->id]) }}">Modificar</a> 10 11 <form action="{{ route('perfumes.destroy', ['perfume' => $perfume->id]) }}" method="POST" 12 style="display:inline;"> 13 @csrf 14 @method('DELETE') 15 <input type="hidden" name="id" value="{{ $perfume->id }}"> 16 <button type="submit" 17 onclick="return confirm('Estás seguro de eliminar o perfume {{ $perfume->descripcion }}?');" 18 class='btn btn-link'>Eliminar</button> 19 </form> 20 </td> 21 </tr> 22 @endforeach 23 24 ............
Paxinación
- Temos neste enlace todo o necesario para paxinar os resultados.
Os pasos a seguir son:
- Modificar o controlador para que os datos que se envían á vista estean paxinados:
- Arquivo: /app/Http/Controller/PerfumeController.php
1 public function index() 2 { 3 $perfumes = Perfume::orderBy('descripcion')->paginate(5); 4 return view('perfumes.operacions_perfumes') 5 ->with(['perfumes'=>$perfumes]); 6 }
- Modificamos a vista para que amose unha lista coas páxinas de datos.
- Como a lista se amosa cunha etiqueta <ul> engadimos un style para quitar os puntos e que estean en horizontal (isto o faríamos na parte head da páxina. Aquí está na propia vista para que vexades o código:
- Arquivo: /resources/views/perfumes/operacions_perfumes.blade.php
1 .................... 2 </table> 3 <style> 4 .paxinado ul{ 5 list-style-type: none; 6 } 7 .paxinado ul li { 8 float:left; 9 margin-left:10px; 10 } 11 </style> 12 <div class="paxinado"> 13 {!! $perfumes->render() !!} 14 </div> 15 16 @if(session()->has('msg')) 17 <h3>{{session('msg')}}</h3> 18 @endif 19 20 @endsection
- TRUCO:
- Cando temos relacións establecidas entre diferentes modelos, pode darse o caso que queiramos paxinar o resultado dunha relación.
- Imaxinade que tedes unha relación 1-N entre Profesores (1) e Alumnos (n).
- Cando vexades o punto de relacións 1-N podedes comprobar que con esta orde: $alumnos = Profesor::findOrFaul($id)-> alumnos obteríamos unha colección dos alumnos aos que o profesor da clase.
- Se quixeramos paxinar o resultado non poderíamos.
- Para facelo temos que poñer parénteses despois da función que recupera os alumnos da forma: $alumnos = Profesor::findOrFail($id)-> alumnos()->orderBy('nombre')->paginate(25);
Tips
- O que devolve Eloquent cando facemos consultas á base de datos son 'coleccións'.
- Podemos ver neste enlace todas as funcións dispoñibles.
- Por exemplo, se queremos engadir un rexistro (unha instancia dun modelo) a unha colección (por exemplo a que ven de chamar a Modelo::all()) podemos facer uso da función prepend.
- Como está comentado no inicio do manual, ao manexar formularios tivemos que desactivar un Middleware (VerifyCsrfToken) para poder utilizalos.
- Este Middleware serve para protexer contra ataques CSRF (do inglés Cross-site request forgery ou falsificación de petición en sitios cruzados). Podedes ver en que consiste este tipo de ataque neste enlace.
- Para evitalo soamente temos que poñer dentro dos 'form' que fagamos e tendo unha plantilla blade o seguinte código:
1 {{ csrf_field() }}
- Cando buscamos un rexistro podemos usar a función find do Model ou tamén findOrFail que a diferenza da anterior en caso de non atopar o modelo lanzará unha excepción Illuminate\Database\Eloquent\ModelNotFoundException.
- Cando enviamos información dende o controlador á vista temos que ter en conta que:
- Se facemos un return view('vista')->with['variable' => 'dato'], o que lle chega á vista é a variable $variable có valor 'dato'.
- Se facemos un return redirect('/ruta')->->with['variable' => 'dato'], o que lle chega á vista é a variable de sesión session('variable') que ten o valor 'dato'.
- Hai unha forma simplificada de enviar datos á vista dende o controlador, mediante a función compact.
- En vez de facer isto:
1 $dato1='valor'; 2 $dato2='valor'; 3 return view('vista')->with(['dato1'=>$dato1,'dato2'=>$dato2]);
- Facemos isto:
1 $dato1='valor'; 2 $dato2='valor'; 3 return view('vista',compact('dato1','dato2'));
- Neste caso estamos a enviar o valor $dato1 e $dato2 á vista. Dita vista vai poder facer uso destas variables dende php con $dato1 e $dato2 e dende o formato blade {{ $dato1 }} e {{ $dato2 }}.
- Se vos fixades, cando creamos un controlador coa opción --resource (a partires de Laravel 5.4) aparecen unha serie de funcións por defecto. Vexamos un exemplo dunha delas:
1 /** 2 * Update the specified resource in storage. 3 * 4 * @param \Illuminate\Http\Request $request 5 * @param int $id 6 * @return \Illuminate\Http\Response 7 */ 8 public function update(Request $request, $id) 9 { 10 // 11 }
- Como vedes esta función debería realizar a actualización dun rexistro na base de datos. Espera recibir como parámetro o $id (clave) do rexistro a actualizar e os datos deberían vir no obxecto $request.
- Pero a pregunta é como facemos para enviar o id na url da forma www.meustio.es/actualizar/12 sendo 12 un exemplo do id a actualizar ?
- Se supón que o que imos ter vai ser un formulario no que imos amosar os datos dun rexistro concreto, cun action a /actualizar (por exemplo) e o id debería estar cun campo oculto dentro do formulario...Isto sería a forma 'tradicional' de facelo.
- Resulta que Laravel permite enviar o dato a URL dunha forma moi sinxela:
1 <form method="post" name="form_datos" action="{{ URL::to('/actualizar', $dato->id) }}" 2 onsubmit="if(confirm('Estas seguro de Modifcar ?')) { return true } else {return false };">
- Agora o arquivo 'routes.php' terá este aspecto:
1 Route::post('/actualizar/{id}',"ProbaController@update");
- Como vemos estamos a recibir o id como parámetro e estamos chamando ao método update do controlador que vai recibir ese id máis os datos que veñan do formulario e que serán os datos que imos poder modificar.
- Con URL::to facemos referencia a unha ruta do arquivo routes.php, pero tamén podemos utilizar 'alias' e darlle un nome a unha ruta da forma:
1 Route::post('/actualizar/{id}',array('as' => 'actualizar.dato',"ProbaController@update"));
- Agora podemos facer referencia a esta ruta dende o formulario coa orde: action="{{ URL::route('actualizar.dato', $dato->id) }}"
- Máis información neste enlace.
- Se queremos ver que sentenza SQL se executa 'detrás' das ordes Eloquent de acceso e manexo de datos temos que poñer o seguinte no arquivo routes.php:
1 // Display all SQL executed in Eloquent 2 Event::listen('illuminate.query', function($query) 3 { 4 var_dump($query); 5 });
- Información obtida deste enlace.
Middleware
- Son 'programas' ou anacos de código que se executan antes de chamar a un controlador.
- Atópanse entre o controlador frontal que recibe as peticións dos usuarios e a chamada aos controladores por parte deste controlador frontal.
- Poden ir enlazados varios middlewares un detrás doutro.
- Lembrar que para crear un middleware podemos facer uso do comando artisan:
1 php artisan make:middleware nome_middleware
- Normalmente os imos utilizar cando teñamos implementado un sistema de autenticación de usuarios, no que en función do rol do mesmo redireccionaremos a unha páxina ou outra.
- Outro exemplo de código podería ser este código, obtido de este enlace, no que se verifica se o país de procedencia da petición é de Estados Unidos...
1 class AdMiddleware 2 { 3 /** 4 * Handle an incoming request. 5 * 6 * @param \Illuminate\Http\Request $request 7 * @param \Closure $next 8 * @return mixed 9 */ 10 public function handle($request, Closure $next) 11 { 12 // Test to see if the requesters have an ip address. 13 if($request->ip() == null){ 14 throw new \Exception("IP ADDRESS NOT SET"); 15 } 16 $country=file_get_contents('http://api.hostip.info/get_html.php?ip=' . $request->ip()); 17 echo $country; 18 if(strpos($country, "UNITED STATES")){ 19 throw new \Exception("NOT FOR YOUR EYES, NSA"); 20 } else { 21 return redirect("index"); 22 } 23 24 return $next($request); 25 } 26 }
Exercicio 1
- Crea unha vista que pida introducir a idade a un usuario.
- Fai que se a idade do usuario é menor de 18 volva á vista do formulario.
- Fai que se a idade do usuario é maior de 18 cargue outra vista no que se da a benvida ao usuario amosando a súa idade.
- Utiliza un middleware para facelo e que soamente se execute cando enviemos a idade dende o formulario.
Solución Exercicio 1
- Arquivo: /proxecto_raiz/app/Http/Router.php
1 Route::get('getIdade/',function(){ 2 return view('idade'); 3 }); 4 5 Route::post('amosaridade/','IdadeController@amosarIdade')->middleware('idade_middleware');
- Liña 6: Fixarse como o verbo debe ser 'post' para capturar o evento do formulario cando introducimos a idade.
- Arquivo: /proxecto_raiz/app/Http/Kernel.php
1 ....... 2 3 'idade_middleware' => \App\Http\Middleware\IdadeMiddleware::class, 4 5 .......
- Arquivo: /proxecto_raiz/app/Http/Middleware/IdadeMiddleware.php
1 <?php 2 3 namespace App\Http\Middleware; 4 5 use Closure; 6 7 class IdadeMiddleware 8 { 9 public function handle($request, Closure $next) 10 { 11 if(!empty($request->input('txtIdade')) && 12 $request->input('txtIdade')<18){ 13 return redirect('getIdade/')->withInput()->withErrors(['msg'=>'A idade non pode ser menor que 18']); 14 } 15 16 return $next($request); 17 }
- Liña 13: En caso de que non cumpra as condicións, enviamos nunha 'variable' especial de nome $errors (withErrors) a mensaxe que queremos que se amose na pantalla do formulario. Tamén enviamos de volta o dato introducido (withInput) que será posto outra vez no value da caixa de texto.
- Para comprobar se ven a idade podemos facer uso da función 'has' da clase Request desta forma: if(!$request->has('txtIdade')).
- Fixarse que poderíamos poñer dúas condicións distintas, unha para cando non recibe datos e outra para cando a idade é menor que 18, e enviar á paxina do formulario dous erros diferentes.
- Neste exemplo deixamos introducir unha idade baleira e a mensaxe de erro será amosada na pantalla que visualiza a idade.
- Arquivo: /proxecto_raiz/app/Http/Controller/IdadeController.php
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 use App\Http\Requests; 8 use App\Http\Controllers\Controller; 9 10 class IdadeController extends Controller 11 { 12 13 public function amosarIdade(Request $request){ 14 15 $datos_form=$request->all(); 16 17 return view('amosaridade',[ 18 'datos' => $datos_form 19 ]); 20 21 } 22 }
- Arquivo: /proxecto_raiz/Resource/Views/idade.blade.php
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Laravel</title> 5 6 <link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css"> 7 8 </head> 9 <body> 10 <div class="container"> 11 <div class="content"> 12 <form name='frmIdade' action="/amosaridade" method="post"> 13 Idade: <input type="text" name="txtIdade" maxlength="3" size="3" value="{{old('txtIdade')}}"/> 14 <div><input type="submit" value="ENVIAR" /></div> 15 </form> 16 </div> 17 @if ($errors->any()) 18 <h4>{{$errors->first('msg')}}</h4> 19 @endif 20 </div> 21 </body> 22 </html>
Cookies en Laravel
Aspectos varios
Formularios coa extensión Collective
- Formularios en Laravel: En Laravel podemos facer uso de 'etiquetas' específicas para compoñentes HTML.
- Así podemos abrir e pechar formularios con etiquetas Laravel. A particularidade de facelo desta forma é que ampliamos a funcionalidade. Así, podo definir unha apertura dun formulario que se vai basear nun modelo. Cando envíe como dato á vista un obxecto de dito modelo, se teño definidos os names das caixas de texto igual ao nome das columnas, ditas caixas énchense automaticamente cos datos do modelo.
- Paquete Styde\Html: Mellora a Extensión Collective/Html (incorpora melloras para o manexo de formularios)
Aclaración das listas 'select'
- Cando usemos este paquete, poderemos encher listas cos datos que veñan do controlador, mandados como parámetros dende o mesmo.
- O problema é que a forma de cargar os datos nesta extensión para as listas, espera recibir un array con dous datos (clave e texto a amosar).
- Para facelo teremos que (se estamos a usar Eloquent ou QueryBuilde) facer uso da función plunk desta forma:
1 $datos=Modelo::select('id','texto') 2 ->orderBy('texto') 3 ->get() 4 ->pluck('banco','id')
- Nota: Se queremos engadir un elemento baleiro antes do primeiro dato da táboa teremos que facer uso da función prepend, despois de facer o pluck.
- Agora xa podemos enviar os datos á vista e cargalos da forma (as class son postas por usar bootstrap):
1 <div class="form-group"> 2 {!! Form::label('idtipo', 'Texto do label:', ['class' => 'col-sm-2 control-label']) !!} 3 <div class="col-sm-10"> 4 {!! Form::select('nomecontrol', $datos, null, ['class' => 'form-control']); !!} 5 </div> 6 </div>
- 'nomecontrol' é o name do control select, que se queremos facer un insert/update 'automático' (Modelo->create($request->all())) debería ter o mesmo nome que a columna da táboa onde vai a engadirse/actualizarse.
Breadcrumbs
- Breadcrumbs: Recurso gráfico para que o usuario saiba en que sección da aplicación se atopa.
Paxinación de resultados
- Para paxinar o resultado dunha consulta a unha base de datos:
- Se usamos o modelo para acceder aos datos: Paxinación de resultados.
- Se o que temos é unha colección: Paxinación de resultados.
- Fixarse que a través dun modelo podemos obter unha colección en base a unha relación do modelo con outra táboa. Nese caso teríamos que empregar a segunda opción.
- TRUCO:
- Cando temos relacións establecidas entre diferentes modelos, pode darse o caso que queiramos paxinar o resultado dunha relación.
- Imaxinade que tedes unha relación 1-N entre Profesores (1) e Alumnos (n).
- Cando vexades o punto de relacións 1-N podedes comprobar que con esta orde: $alumnos = Profesor::findOrFaul($id)-> alumnos obteríamos unha colección dos alumnos aos que o profesor da clase.
- Se quixeramos paxinar o resultado non poderíamos.
- Para facelo temos que poñer parénteses despois da función que recupera os alumnos da forma: $alumnos = Profesor::findOrFail($id)-> alumnos()->orderBy('nombre')->paginate(25);
Accessors e Mutators
- Os accesors son método que definimos no modelo para recuperar os datos da base de datos, pero aplicando algún tipo de formateo ou filtro. Por exemplo, pode recuperar todos os datos dun modelo en maiúsculas (aplicaría a función strtoupper aó atributo que queira).
- Os mutators son iguais os accesors pero se aplican ós atributos antes de que sexan gardados na base de datos.
Migracións e Seeders
- Migracións: Laravel dispón dun sistema para crear as táboas que van conformar a nosa base de datos. Basicamente é o conxunto de ordes que fan os create table colocadas nun arquivo e que Laravel executa automaticamente cando nos digamos. A maiores permite ter 'diferentes versións' da base de datos (creación de novas táboas, modificacións sobre a estructura) e permite volver atrás,a algunha das versións gardadas.
- Seeders: Unha vez temos as táboas creadas, Laravel permite encher de datos de proba mediante o uso de seeders.
Autenticación
- Laravel incorpora un sistema que nos permite facer que o noso sitio web teña unha seguridade baseada na autentificación de usuarios.
- Incorpora de forma automática as táboas e vistas necesarias para pedir unha autentificación.
- Máis información neste enlace.
Regresar a dúas páxinas anteriores
- Como sabemos, facendo dende o controlador un return redirect()->back() regresamos á vista anterior.
- Isto o usamos cando damos de alta un rexistro para que volva á vista do formulario de alta.
- Pero tamén pode suceder que necesitemos volver dúas páxinas anteriores á actual.
- Por exemplo, cando temos a clásica páxina na que aparecen un conxunto de resultados coas opcións de 'Modificar' e 'Eliminar' asociadas a cada un deles.
- Se prememos o botón 'Modificar' iremos á vista que enche os datos do elemento seleccionado para poder modificalos. Cando prememos o botón 'Modificar' iremos normalmente ao método 'update' do controlador.
- Se nese método facemos un back() regresaremos á vista do formulario e nos queremos ir á vista anterior a esa (a do listado).
- Para solucionalo teremos que gardar nun campo oculto na vista do formulario a url anterior e recuperar o seu valor no método update.
- Vexamos un exemplo:
Arquivo que amosa o formulario para modificar un elemento seleccionado:
1 {!! Form::model($tipoproducto,['url' => htmlentities($_SERVER['PHP_SELF']), 'class' => 'form-horizontal']) !!} 2 {!! Form::hidden('redirects_to', URL::previous()) !!} 3 4 {{ csrf_field() }}
Arquivo controlador método update:
1 .................. 2 $url = $request->only('redirects_to'); 3 return redirect()->to($url['redirects_to'])->with(['aviso'=>'Tipo de producto actualizado correctamente']);
- Información obtida deste enlace.
Posta en marcha nun servidor web Apache real
- O pasos para a posta en marcha os tedes na documentación oficial. Fixarse na versión de Laravel arriba á dereita da páxina.
- Importante: Desactivade o debugger se a aplicación vai ir a produción.
- Isto o facedes no arquivo .env:
- APP_DEBUG=false
- APP_ENV=production
- No arquivo config/app.php podedes cambiar os parámetros: timezone e locale.
- Esencialmente, necesitaredes que o servidor web Apache teña instalado e activo o módulo mod_rewrite.
- Dende consola:
1 sudo a2enmod rewrite 2 sudo service apache2 restart
- Dende consola:
- Despois teredes que ter un DNS 'apuntando' á vosa máquina e configurar o Apache para que dito DNS cargue a páxina index.php do cartafol 'public' do proxecto Laravel:
- Se non tedes un DNS podedes, para facer probas, podedes modificar o arquivo /etc/hosts para engadir o dns que ides utilizar:
1 127.0.1.1 angel-VirtualBox www.meusitio.es
- Copiamos ou movemos o proxecto Laravel ao cartafol /var/www/
- Editamos o arquivo de configuración de sitios de apache que se atopa en /etc/apache2/sites-enabled/000-default.conf e engadimos o noso dominio:
- Para versión Apache 2.2:
1 <VirtualHost *:80> 2 Options Indexes FollowSymLinks MultiViews 3 4 ServerAdmin webmaster@localhost 5 DocumentRoot /var/www/meuproxecto/public 6 ServerName www.meusitio.es 7 8 9 ErrorLog ${APACHE_LOG_DIR}/error.log 10 CustomLog ${APACHE_LOG_DIR}/access.log combined 11 12 </VirtualHost> 13 14 <Directory "/var/www/meuproxecto/public"> 15 AllowOverride All 16 Order allow,deny 17 Allow from all 18 </Directory>
- Liña 5: Indicamos o cartafol public do proxecto Laravel.
- Liña 6: Indicamos o nome DNS que imos utilizar (o que puxemos no arquivo hosts)
- Para versión Apache 2.4 ou superior:
1 <VirtualHost *:80> 2 #ServerName www.example.com 3 Options +Indexes +FollowSymLinks +MultiViews 4 5 ServerAdmin webmaster@localhost 6 DocumentRoot /var/www/meuproxecto/public 7 ServerName www.asufinprobas.es 8 9 10 ErrorLog ${APACHE_LOG_DIR}/error.log 11 CustomLog ${APACHE_LOG_DIR}/access.log combined 12 13 </VirtualHost> 14 15 <Directory "/var/www/meuproxecto/public"> 16 AllowOverride All 17 Require all granted 18 </Directory>
- Nota: Para saber a versión do servidor apache instalada executade nunha consola a orde: apache2 -v
- Máis información sobre o servidor web Apache neste enlace.
- Reiniciamos o servidor Apache:
- Dende consola:
1 sudo service apache2 restart
- Debemos dar permiso de escritura ao usuario/grupo utilizado polo servidor web Apache (normalmente www-data, pero podedes sabelo mirando este enlace) a os cartafoles storage e vendor.
1 sudo setfacl -R -m g:www-data:rwx /var/www/meuproxecto/storage/ 2 sudo setfacl -R -m g:www-data:rwx /var/www/meuproxecto/vendor/ 3 sudo setfacl -R -m u:www-data:rwx /var/www/meuproxecto/storage/ 4 sudo setfacl -R -m u:www-data:rwx /var/www/meuproxecto/vendor/
Subida de arquivos ao servidor
- Xa vimos anteriormente como subir un arquivo ao servidor e os permisos que tiñamos que dar ao cartafol onde se van gardar as imaxes.
- Agora imos ver como facer o mesmo utilizando Laravel.
Formulario
Sen BootStrap
- Neste caso fariamos o mesmo que no caso visto de PHP, primeiramente teríamos que ter un formulario coa propiedade enctype e un control 'input' de type file.
1 <form method="POST" action="/alta" enctype="multipart/form-data"> 2 3 <div> 4 <label>Sentencia:</label> 5 <div> 6 <input name="sentencia_file" type="file" id="archivo_file"> 7 </div> 8 </div> 9 10 <div> 11 <div> 12 <input type="submit" value="Subir"> 13 </div> 14 </div> 15 </form>
Con BootStrap
- O primeiro será ter un formulario cun campo de tipo file para poder subir o arquivo:
1 {!! Form::open(['url' => '/alta','files' => true, 'class' => 'form-horizontal']) !!} 2 {{ csrf_field() }} 3 <div class="form-group"> 4 {!! Form::label('archivo', 'Archivo:', ['class' => 'col-sm-2 control-label']) !!} 5 <div class="col-sm-10"> 6 {!! Form::file('archivo_file') !!} 7 </div> 8 </div> 9 10 <div class="form-group"> 11 <div class="btn-group btn-group-justified"> 12 <div class="btn-group" role="group"> 13 {!! Form::submit('Alta', ['class' => 'btn btn-primary']) !!} 14 </div> 15 <div class="btn-group" role="group"> 16 {!! Form::reset('Limpiar', ['class' => 'btn btn-default']) !!} 17 </div> 18 </div> 19 </div> 20 21 {!! Form::close() !!}
Código en Laravel
- Como sempre capturamos a URL en routes.php y a enviamos ao controlador correspondente:
Arquivo: routes.php
1 Route::post('/alta','ProbaController@store');
- Agora imos ao controlador para gardar a imaxe (por reducir o código non se valida ningún campo máis):
Arquivo: ProbaController.php
1 public function store(Request $request) 2 { 3 $this->validate($request,'archivo_file' => 'mimes:pdf', 4 ]); 5 6 if($request->hasFile('archivo_file')){ 7 $file = $request->file('archivo_file'); 8 $destinationPath = Config('constantes.RUTA_REAL'); 9 $filename = $file->getClientOriginalName(); 10 11 if (File::exists($destinationPath . '/' . $filename)){ 12 13 return redirect()->back()->witherrors(["Xa existe un arquivo subido con ese nome"]); 14 } 15 16 $file->move($destinationPath, $filename); 17 18 19 }
- Na liña 3 validamos que o tipo de arquivo que se poida subir sexa un pdf (é un exemplo de tipo posible).
- Fixarse na liña 8. Estamos a empregar un arquivo onde gardamos en forma de constantes as rutas que nos interesan ou outro tipo de información.
- Desta forma podemos acceder a ditas constantes dende calquera páxina de Laravel de la forma indicada no exemplo.
- O arquivo, de nome constantes.php está gardado no cartafol /config de Laravel:
Arquivo: ProbaController.php
1 <?php 2 3 return [ 4 'imagenes' => [ 5 'habitacion' => 'https://www.meusitio.com/images/habitacion.png', 6 'casa' => 'https://www.meusitio.com/images/casa.png', 7 ], 8 'RUTA_REAL' => base_path() . '/public/archivos' 9 ];
- No exemplo vemos como a constante RUTA_REAL 'apunta' ao sitio web e dentro del ao cartafol archivos.
- Fixarse que podemos ter constantes 'anidadas' como: Config('constantes.imagenes.habitacion') que devolvería: 'https://www.meusitio.com/images/habitacion.png'
- Se queremos facer uso das constantes nas vistas lembrar que deben ir entre '{ {' e '} }' da forma: { {Config('constantes.imagenes.habitacion')} } (as chaves van xuntas, no separadas por espazos)
Bootstrap 3
- BootStrap é un framework para o deseño de sitios web utilizando javascript e CSS.
- A principal vantaxe é que permite a adaptación do contido ao tipo de dispositivo que vai visualizar o sitio web. É o que se coñece como Deseño adaptativo ou Design Adapter.
- Na web bootswatch.com podemos ver diferentes deseños para un sitio web utilizando bootstrap.
- Un dos conceptos máis importantes consiste en dividir o contido da páxina en filas e columnas. O número máximo de columnas que podemos ter é de 12. A cada contido podemos indicarlle cantas columnas vai ocupar, axustándose o espazo total ao espazo de cada elemento.
Instalando Bootstrap con Laravel 5
- Primeiro debemos instalar o paquete Laravel / Colletive.
- Para iso seguiredes os pasos indicados na web https://laravelcollective.com escollendo na parte superior a versión de Laravel que teñades instalada ata o punto Opening form (non facelo).
- Despois deberedes descargar o framework bootstrap da web.
- Chega con descargar a 'Compiled and minified CSS, JavaScript, and fonts. No docs or original source files are included.' (a opción da esquerda).
- Unha vez baixada e descomprimida, teredes tres cartafoles (css,fonts e js). Imos mover ditos cartafoles ao cartafol 'public/assets' do voso proxecto Laravel. O cartafol 'assets' teredes que crealo.
- Agora imos crear unha 'plantilla' para todas as vistas (información obtida desde enlace).
Arquivo: resources/views/layout.blade.php
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>Laravel</title> 8 9 {!! Html::style('assets/css/bootstrap.css') !!} 10 11 <!-- Fonts --> 12 <link href='//fonts.googleapis.com/css?family=Roboto:400,300' rel='stylesheet' type='text/css'> 13 14 <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> 15 <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> 16 <!--[if lt IE 9]> 17 <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> 18 <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> 19 <![endif]--> 20 </head> 21 <body> 22 <nav class="navbar navbar-default"> 23 <div class="container-fluid"> 24 <div class="navbar-header"> 25 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> 26 <span class="sr-only">Toggle Navigation</span> 27 <span class="icon-bar"></span> 28 <span class="icon-bar"></span> 29 <span class="icon-bar"></span> 30 </button> 31 <a class="navbar-brand" href="#">Laravel</a> 32 </div> 33 34 35 </div> 36 </nav> 37 38 @yield('content') 39 40 41 <!-- Scripts --> 42 <script src="http://code.jquery.com/jquery.js"></script> 43 {!! Html::script('assets/js/bootstrap.min.js') !!} 44 </body> 45 </html>
- Liñas 9 e 43: Estamos a cargar o arquivo CSS e Javascript necesarios para bootstrap. Fixarse como na ruta vai o cartafol 'assets' (parte do cartafol 'public', cando a páxina se carga).
- Liña 38: Definimos unha etiqueta que vai ser o contido que van utilizar as vistas do noso sitio web.
- Neste caso estamos poñendo 'en común' a todas as páxinas a cabeceira e a barra de navegación. Nada impide crear etiquetas para cada un delas e ter un contido diferente para cada vista do noso sitio web.
- Liña 42: A librería jquery é necesaria para executar os scripts de javascript. Podería descargarse a local.
- Como a esta vista dámoslle o nome de 'layout.blade.php', as vistas que cremos que teñan como base esta, deberán 'extender' dese nome:
Arquivo: resources/views/inicio.blade.php
1 @extends('layout') 2 3 @section('content') 4 <div class="container"> 5 <div class="row"> 6 <div class="col-md-10 col-md-offset-1"> 7 <div class="panel panel-default"> 8 <div class="panel-heading">Inicio</div> 9 10 <div class="panel-body"> 11 Usando bootstrap 12 </div> 13 </div> 14 </div> 15 </div> 16 </div> 17 @endsection
- Como vemos estamos a substituír o 'content' do layout.blade.php.
- Temos neste enlace un exemplo para facer unha vista para o rexistro e validación de usuarios tendo ao final de todo a versión para Laravel utilizando 'Blade'.
- Neste enlace incorpora dunha forma diferente o framework bootstrap, xa que o carga dende Internet utilizando Content Delivery Network (CDN). Todas as clases, CSS e código javascript está aloxado en servidores de Internet, de tal forma que todo o código para incorporar bootstrap ao teu proxecto non se carga dende o teu sitio web, se non que está repartido en diferentes servidores en Internet, reducindo a carga de traballo do teu servidor.
Modificando o theme (aspecto)
- Como comentamos anteriormente, na web http://bootswatch.com temos diferentes themes a instalar.
- Existen multitude de sitios onde podedes atopar outros themes.
- Para modificar o theme, temos dúas opcións:
- Se estamos a utilizar CDN, soamente debemos cambiar a URL a cargar.
- Podemos ver nesta web as diferentes 'rutas' CDN en función do theme escollido.
- Se estamos a utilizar bootstrap copiado 'localmente' deberemos substituír o arquivo 'bootstrap.css' que se atopa (se seguíchedes o exemplo) en 'public/assets/css', polo do theme seleccionado.
- Despois teremos que descubrir como se chaman as clases de cada un dos controis para que se visualicen de acordo ao theme seleccionado.
- Vexamos un exemplo:
- Cambiando o aspecto
Integrando bootstrap 3 con extensión Collective de Laravel
-- Ángel D. Fernández González -- (2016).