Table of Contents - WebTech · 2019. 2. 18. · Conexión con bases de datos Laravel tiene soporte...

Post on 20-Sep-2020

1 views 0 download

Transcript of Table of Contents - WebTech · 2019. 2. 18. · Conexión con bases de datos Laravel tiene soporte...

1.1

1.2

1.3

1.4

1.5

1.6

1.7

1.8

1.9

1.10

1.11

1.12

1.13

1.14

1.15

1.16

1.17

1.18

1.19

TableofContentsIntroduction

Introducción

Capítulo1.Instalación

Capítulo2.PSR-4ynamespaces

Capítulo3.Conexiónconbasededatos

Capítulo4.EstructuradeunproyectoenLaravel

Capítulo5.JSON

Capítulo6.MigracionesySeeders

Capítulo7.ModelosyusodeEloquent

Capítulo8.Modelfactories(Poblarbasededatosconfaker)

Capítulo9.Enrutamientobásico

Capítulo10.VistasymotordeplantillasBlade

Capítulo11.Controladores

Capítulo12.ValidacionesenLaravel

Capítulo13.Middlewares

AnexoA.HTML5

AnexoB.CSS

AnexoC.CRUDconLaravel

AnexoD.ComponenteDatatable

2

IntroducciónaLaravel5Laravelesunframeworkparaaplicacioneswebconsintaxisexpresivayelegante.Creemosqueeldesarrollodebeserunaexperienciaagradableycreativaparaqueseaverdaderamenteenriquecedora.Laravelbuscaeliminarelsufrimientodeldesarrollofacilitandolastareascomunesutilizadasenlamayoríadelosproyectosweb,comolaautenticación,enrutamiendo,sesionesyalmacenamientoencaché.

LaravelesunframeworkparaellenguajedeprogramaciónPHP.AunquePHPesconocidoportenerunasintaxispocodeseable,esfácildeusar,fácildedesplegaryselepuedeencontrarenmuchosdelossitioswebmodernosqueusasdíaadía.Laravelnosoloofreceatajosútiles,herramientasycomponentesparaayudarteaconseguireléxitoentusproyectosbasadosenweb,sinoquetambiénintentaarreglaralgunadelasflaquezasdePHP.

Laraveltieneunasintaxisbonita,semánticaycreativa,quelepermitedestacarentrelagrancantidaddeframeworksdisponiblesparaellenguaje.HacequePHPseaunplacer,sinsacrificarpotenciayeficiencia.Essencillodeentender,permitemucholamodularidaddecódigolocuálesbuenoenlareutilizacióndecódigo.

BeneficiosdeLaravel

1. IncluyeunORM:AdiferenciadeCodeIgniter,LaravelincluyeunORMintegrado.Porlocualnodebesinstalarabsolutamentenada.

2. Bundles:existenvariospaquetesqueextiendenaLaravelytedanfuncionalidadesincreíbles..

3. Programasdeunaformaeleganteyeficiente:Nomáscódigobasuraoespaguettiquenoseentienden,aprenderásaprogramar‘conclase’yordenartucódigodemaneradequesealomásre-utilizableposible.

4. ControlaslaBDdesdeelcódigo:Puedesteneruncontroldeversionesdeloquehacesconella.Aestosellamanmigrations,esunaexcelenteherramienta,porquepuedesmanejartododesdetuIDE,inclusivemontardatosentustablas.

5. DasoporteaPHP5.3.

6. Rutaselegantesyseguras:UnamismarutapuederesponderdedistintomodoaunmétodoGEToPOST.

7. CuentaconsupropiomotordeplatillasHTML.

Introduction

3

8. Seactualizafacilmentedesdelalíneadecomandos:Elframeworkesactualizableutilizandocomposerupdateylisto,nadadedescargarunZIPyestarremplazando.

9. Cuentaconunacomunidadactivaquedaapoyorápidoalmomentodequelonecesitas.

Requerimientosiniciales

ParaempezaratrabajarconLaravelesnecesariocumplirconlossiguientesrequisitosiniciales:

Unentornodedesarrolloweb:Apache,IIS,NginxPHP5.3osuperiorBasededatos:MySQL,Sqlite,PostgresqlosqlserverLibreríasphp:Mcrypt

ComposeresunaherramientaparaadministracióndedependenciasenPHP.Tepermitedeclararlaslibreríasdelascuálestuproyectodependeonecesitayéstelasinstalaenelproyectoporti.

Composernoesunadministradordepaquetes.Sí,éltratacon"paquetes"o"librerías",perolasgestionaenfuncióndecadaproyectoynoinstalanadaglobalmenteentuequipo,porlocualsoloadministralasdependenciasdelmismo.

ComposerusaunarchivodentrodetuproyectodeLaravelparapoderadministrarlasdependenciaselcualsellama:composer.json.EsteusaunformatoJSONelcualseexplicarámásadelante,unejemplodeélsemuestraeestaimagen:

Introduction

4

Ahora,composernoselimitaasuusounicamenteconproyectosLaravel,sinoqueenLaravelelusodecomposernosfacilitaelcontroldedependenciasyenlaactualizacióndecadaunacomoseexplicóanteriormente.ParaestecursosetrabajaráconestearchivopueseselquesevaacrearalmomentodeinstalarLaravel.

Enestearchivopodemosobservarciertoordenenelacomododelainformación.

"name":Enestasecciónsedescribeelnombredelusuariopropietariodelproyectoseguidodelnombredelrepositorioquealojaelproyectoseparadosporunabarra(/).

"description":Sirveparafacilitarunabrevedescripcióndelpaquete.Debemossermuyclarosybrevessideseamoscolocarunadescripcióndenuestropaquete.

"keywords":Estaspalabrasclavessonunamatrizdecadenasusadaspararepresentartupaquete.Sonsimilaresaetiquetasenunaplataformadeblogsy,esencialmente,sirvenalmismopropósito.Lasetiquetasteofrecenmetadatosdebúsquedaparacuandotupaquetesealistadoenunrepositorio.

"homepage":Laconfiguracióndelapáginaesútilparapaquetesquevanaserdecódigolibre.PuedesusarestapáginaparaelproyectooquizáparalaURLdelrepositorio.Loquecreasqueesmásinformativo.

"license":Situpaqueteestápensadoparaserredistribuido,querrásofrecerunalicenciaconél.Sinunalicenciamuchosprogramadoresnopodránusarelpaqueteporrestriccioneslegales.Escogeunalicenciaqueseajusteatusrequisitos,peroquenoseamuyrestrictivaparaaquellosqueesperanusartucódigo.ElproyectodeLaravelusalalicenciaMITqueofrecegranlibertad.

"authors":ofreceinformaciónsobrelosautoresdelpaquete,ypuedeserútilparaaquellosusuariosquequierancontactarconelautoroautores.Tenencuentaquelaseccióndeautorespermiteunamatrizdeautoresparapaquetescolaborativos.

Gestordedependencias

Unadelasopcionesinteresantesdelarchivocomposer.jsoneselcampo“require”,enelseagregancomounarregloelnombredelospaquetesquequeremosincluirennuestroproyectoseguidodelaversióndecadadependencia.

Alfinalcuandosehanagregadotodaslasdependenciasquequeremosparanuestroproyectoentoncessolobastaconusarelsiguientecomandoennuestraconsola:

composerinstall

Introduction

5

Conestoleindicamosacomposerquedebedescargarnuestrasdependenciasylasdependenciasdeestasdependenciasparasatisfacerlasnecesidadesdenuestroproyecto.Paramásinformaciónsobrecomposer,suscamposysuformadeusopodemosconsultarsupáginaoficialhttps://getcomposer.org/doc/lacuálseencuentraeninglés.

AprendermássobreHTML5ParaprofundizarunpocomásenHTML5esrecomendableeltutorialdew3schools.

Introduction

6

Preparandonuestroentornodetrabajo.Laravelnecesitaunservidorweb.NoimportacuálseaperolamayoríadelacomunidadusaApacheoNginxyhacerlomismotepondrálascosasmásfácilesalahoradebuscarayudasilanecesitas.

InstalacióndeXAMPP(Windows)XAMPPesunprogramaquenosofreceunadistribucióndeApache,MySQL,PHPyPerlmuysimpledeinstalar,administraryutilizar.Podemosdescargarloaquí.

InstalacióndeLAMP(Linux)LAMPeselconjuntodeaplicacionesApache,MySQL,PHPoPythonenentornosLinuxquenosfacilitaneldesarrollodesistemas.

EnUbuntuoderivadaspodemosinstalarloconlossiguientescomandos:

sudoapt-getupdate

sudoapt-getupgrade

sudoapt-getinstalllamp-server^

sudoapt-getinstallphp5-mcrypt

sudophp5enmodmcrypt

DespuesdetenerinstaladonuestroServidorweb,esnecesarioinstalarcomposerelcuálesungestordedependenciasphpmuyútilydelcuálsehablarámástarde.

Instalacióndecomposer(Windows)LaformamássencilladeinstalarComposerentuordenadorWindowsconsisteendescargaryejecutarelarchivoComposer-Setup.exe,queinstalalaversiónmásrecientedeComposeryactualizaelPATHdetuordenadorparaquepuedasejecutarComposersimplementeescribiendoelcomandocomposer.

Instalacióndecomposer(Linux)

Capítulo1.Instalación

7

Enubuntubastaráconejecutarlossiguientescomandosenlaterminal.

sudoapt-getinstallcurl

curl-sShttps://getcomposer.org/installer|php

sudomvcomposer.phar/usr/local/bin/composer

sudoecho'PATH=$PATH:~/.composer/vendor/bin'>>~/.profile

InstalacióndeLaravelExistendiferentesformasdeinstalarlaravelennuestracomputadora.

PodemosclonarelrepositorioLaraveldegithub.Usandoelinstalador:

composerglobalrequire"laravel/installer=~1.1"

laravelnewProyecto

Usandocomposer:

composercreate-projectlaravel/laravel--prefer-distProyecto

Unavezinstaladolaravelesrecomendablesituarseenlaraízdelproyectoyejecutar:

composerupdate

phpartisankey:generate

phpartisanapp:nameCurso

Capítulo1.Instalación

8

PSR-4ynamespaces

¿QuéesPSR-4?

Esunaespecificaciónparalaautocargadeclasesdesdelarutadelosarchivos.Describedóndeseencuentranubicadoslosarchivosqueseránautocargados.PSR-4haceusodenamespacesparadistinguirunaclasedeotra,estoesdegranayudacuandoocupamoslibreríasdetercerosporqueenmuchasocacionesexistiránclasesconelmismonombrequelasnuestrasypodríansobreescribirseousarunaquenoqueremos.

PSR-4fuecreadaporelgrupodeinteroperabilidaddePHP,elloshantrabajadoenlacreacióndeespecificacionesdedesarrolloparaestelenguajeparaqueestandarizemosdiferentesprocesos,comoesenestecasoelcomonombrarlasclasesdenuestroproyectoyhacerusodeellas.

UsarespecificacionesPSR-4noesobligatorioysuusopuedesercompletooparcial,aunqueesrecomendablenoomitirloporqueaComposerlepermitecargarnuestrasclasesautomaticamente.

¿Quéesunautoloader?

AparecierondesdelaversióndePHP5ynospermiteencontrarclasesparaPHPcuandollamamoslasfuncionesnew()oclass_exists().Deestaformanotenemosqueseguirhaciendousoderequire()oinclude().

PSR-4nospermitedefinirnamespacesdeacuerdoalarutadelosarchivosdelasclases,esdecir,sitenemosunaclase"Pdf"eneldirectorioClases/Templates/,eseserásunamespace.Podemoshacerunsimilconelimportdejava.

ElnamespacedeClases/Templatesquedaríadelasiguienteforma:Clases\Templates\Pdf.php

ParausarPSR-4encomposerpodemosdefinirelnamespacedenuestraaplicaciónyeldirectoriodóndeseránalojadaslasclases,porejemplo:

{

"autoload":{

"psr-4":{

"Taller\\":"app/"

}

}

}

Capítulo2.PSR-4ynamespaces

9

Parausarlosnamespacesdentrodenuestrosarchivosphpbastaconreferenciarlosdelasiguienteforma:

useTaller\Clase;

¿Quéesclassmap?

Esunautoloaderquenospermiteregistrarnuestrasclasesparapoderocuparlassinnecesidaddeunnamespace,ladesventajarespectoaPSR-4eslacolisióndeclasesconmismonombre,laprincipalventajaeslarápidezdeautocargadeclases.Otroinconvenientedeusarclassmapesquedebemosejecutarconstantenteelcomando"composerdump-autoload"porcadaclasenuevaeneldirectorioqueindiquemosotengamosregistradoenelarchivo"composer.json".

Ejemplo:

{

"classmap":[

"database"

],

}

Capítulo2.PSR-4ynamespaces

10

ConexiónconbasesdedatosLaraveltienesoporteparalosmotoresdebasesdedatosmáspopularescomo:

MySQLPostgresqlSQLite3SQLServer

VeremoscomoutilizarMySQLconlaravel.

Dentrodelarchivodatabase.phpeneldirectorioconfigconfiguramoseldriverdelaconexión,pordefectovendráconmysql,siqueremoscambiarloporotromotordebasededatostendremosquecambiarelvalormysqlporsqlite,pgsql,sqlsrv.

'default'=>env('DB_CONNECTION','mysql')

Tendremosqueconfigurarelarchivo.envubicadoenlaraízdelproyecto.

DB_HOST=localhost

DB_DATABASE=curso

DB_USERNAME=root

DB_PASSWORD=12345

Unavezquetengamostodoconfigurado,nosdirigimosalaterminalyejecutamoselcomandophpartisanmigrateparacrearlasmigraciones,sitodohasalidobientendremosqueverlastablas:

migrationspassword_resetsusers

SieresunapersonacuriosahabrásnotadoqueelnombredelastablasenLaravelsiempresonescritasenplural,estonoesporpurocapricho,espartedeunaconvención:Convencióndelaconfiguración,dichaconvenciónlepermiteaLaravelhacermagíapornosotros,nosevitarealizarconfiguraciónypasosextrasdelaasociacióndeModeloscontablasentreotrascosas.

Capítulo3.Conexiónconbasededatos

11

EstructuradeunproyectoenLaravelTodoslosproyectosnuevosenLaravel5.1tienenlasiguienteestructuradedirectorios:

app/bootstrap/config/database/public/resources/storage/tests/vendor/.env.env.example.gitattributes.gitignoreartisancomposer.jsoncomposer.lockgulpfile.jspackage.jsonphpspec.ymlphpunit.xmlreadme.mdserver.php

Acontinuacióndescribiremoslosdirectoriosyarchivosmásimportantesparaquenosayudenaentendermáselfuncionamientodelframework.

Eldirectorioapp

Appesusadoparaofrecerunhogarpordefectoatodoelcódigopersonaldetuproyecto.Esoincluyeclasesquepuedanofrecerfuncionalidadalaaplicación,archivosdeconfiguraciónymás.Esconsideradoeldirectoriomásimportantedenuestroproyectoyaqueesenelquemástrabajaremos.

EldirectorioapptieneasuvezotrossubdirectoriosimportantesperounodelosmásutilizadoseseldirectorioHttpenelcuálubicaremosnuestrosControllers,MiddlewaresyRequestsensuscarpetascorrespondientes,ademásdentrodelsubdirectorioHttp

Capítulo4.EstructuradeunproyectoenLaravel

12

encontremostambiénelarchivoroutes.phpdondeescribiremoslasrutasdelaaplicación.

AniveldelaraízdeldirectorioappencontraremoselmodeloUser.php,losmodeloscomunmenteseubicaránaniveldelaraízdelacarpetaappaunqueigualesposibleestructurarlosdelaformaquequeramos,porejemplo,enunacarpetallamadaModels.

Eldirectorioconfig

Laconfiguracióntantoparaelframeworkcomoparatuaplicaciónsemantieneenestedirectorio.LaconfiguracióndeLaravelexistecomounconjuntodearchivosPHPquecontienenmatricesclave-valor.Entrelosarchivosmásusadosdeldirectorioconfigseencuentran:

app.php:Enestearchivonospuedeinteresarconfigurarellenguajedenuestraaplicación,lazonahoraria,losprovidersyaliasesdelasclasesmáscomunes.database.php:Enestearchivopodemosconfigurarprincipalmenteelmotordebasededatosalcuáldeseamosconectarnos.

Eldirectoriodatabase

Aquíseencontraranlosarchivosrelacionadosconelmanejodelabasededatos.Dentrodeestedirectorioseencuentranlossubdirectorios:

factories:Aquíescribiremosnuestrosmodelfactories.migrations:Todaslasmigracionesquecreamosseubicanenestesubdirectorio.seeds:Contienetodaslasclasesdetiposeed.

Capítulo4.EstructuradeunproyectoenLaravel

13

Eldirectoriopublic

Dentrodeestedirectoriocolocaremostodoslosrecursosestáticosdenuestraaplicación,esdecir,archivoscss,js,imágenesyfuentes.

Esrecomendablecrearunacarpetaporcadatipoderecurso.

Eldirectorioresources

Dentrodeestedirectorioseencuentranlossubdirectorios:

assets:Aquíseubicantodoslosarchivoslessdenuestraaplicación(útilparadesarrolladoresfront-end).lang:Aquíseencuentrantodoslosarchivosdeinternacionalización,esdecir,losarchivosparapoderpasarnuestroproyectodeunidiomaaotro.Normalmentehabráunacarpetaporcadaidioma,ejemplo:

en:idiomaingléses:idiomaespañol

views:Aquíubicaremosnuestrasvistasenformatophpophp.blade,esrecomendablecrearunacarpetaporcadacontrolador,ademásagregarunacarpetatemplatesparalasplantillas.Unaplantillaesunavistageneral,quetienesegmentosquepuedenserreemplazadosmediantelaherenciadeplantillas,másadelantesehablarádeestetema.

Eldirectoriostorage

CuandoLaravelnecesitaescribiralgoeneldisco,lohaceeneldirectoriostorage.Porestemotivo,tuservidorwebdebepoderescribirenestaubicación.Aquípodemosencontrarotrosdirectoriosentreloscualeselmásrelevanteeselsubdirectorioframework,esahí

Capítulo4.EstructuradeunproyectoenLaravel

14

dondesealmacenaelcacheylasvistascompiladas.

Eldirectoriotests

Aquíescribiremoslosarchivosdepruebasqueseránejecutadasposteriormenteporphpunit.

Elarchivo.envy.env.example

Elarchivo.envnoexistecuandoinstalamoslaravel,enestearchivoseconfiguraráelmodoenqueseejecutanuestraaplicación,pordefectoseráelmododebug,ademáspodemosconfigurarlaconexiónalabasededatosylaconexiónconelservidordecorreoelectronico.Elarchivo.envlocreamoscopiandoelarchivo.env.exampleyrenombrandolacopiacomo.env.

Pormotivosdeseguridaddelabasededatoselarchivo.envnuncasesubecuandohacemosunpushennuestrorepositorio.Esporesoqueapareceescritodentrodelarchivo.gitignoreenlaraízdenuestroproyecto.

Capítulo4.EstructuradeunproyectoenLaravel

15

JSONJSONesunacrónimodeJavaScriptObjectNotation,unformatoligerooriginalmenteconcebidoparaelintercambiodedatosenInternet.JSONnospermiterepresentarobjetos,arrays,cadenas,booleanosynúmeros.

LaventajadeusarJSONparalatransferenciadeinformaciónesquepuedeserparseadaporvarioslenguajesyesunformatoestandarizado,esdecirquecualquierlenguajepuedeintercambiardatosconotromedianteJSON.

Pordefecto,JSONseguardasinespaciosentresusvaloreslocuallopuedehacerunpocomásdifícildeleer.Estosehacenormalmenteparaahorraranchodebandaaltransferirlosdatos,sinlosespaciosenblancoadicionales,lacadenaJSONserámuchomáscortayportantohabrámenosbytesquetransferir.

Sinembargo,JSONnoseinmutaconlosespaciosenblancoosaltosdelineaentrelasclavesyvalores,asíquepodemoshacerusodeellosparahacerlounpocomáslegible.JSONesunformatodetransferenciadedatoynounlenguaje.

DebemostenersiempreencuentaqueenelformatoJSONlascadenassiemprevanencomillasdobles,además,loselementosclaveyvalordebesestarseparadascondospuntos(:),ylasparejasclave-valorporunacoma(,).

Porejemplo:

{

"Frutas":[

{

"Nombre":"Manzana",

"Cantidad":20,

"Precio":10.50,

"Podrida":false

},

{

"Nombre":"Pera",

"Cantidad":100,

"Precio":1.50,

"Podrida":true

}

]

}

LostiposdevaloresaceptadosporJSON

Capítulo5.JSON

16

LostiposdevaloresquepodemosencontrarenJSONsonlossiguientes:

Numéricos(enterooflotante)Stringsocadenas(entrecomillasdobles)Booleans(trueofalse)Arraysoarreglos(entrecorchetes[])Objetos(entrellaves{})Null

¿PorquéaprenderJSON?

JSONesutilizadoampliamenteen:

Elarchivocomposer.jsondeproyectosPHPIntercambiodeinformaciónRepresentacióndeunabasededatosAJAXWebServices

ValidacióndeJSON

JSONesununformatoparaelintercambiodeinformaciónmuyrígidoyestricto,sitenemosunerrordesintaxis,obtendremosunerrorynopodremosparsearelJSON.Parasolucionarestetipodeproblemas,existeneninternetungrannúmerodeherramientasquenosayudanaescanearyencontrarposibleserroresenlaformacióndenuestroJSON.

PodemosocuparJSONLintqueesunamuybuenaopción,bastaráconcopiarypegarnuestroJSONeneláreadetextoyacontinuacióndarclickenelbotón"Validate".

JSONLintnosinformarásiescorrectoelformatooencasocontrarionosmostraráloserroressintácticosdenuestroJSON.

Capítulo5.JSON

17

MigracionesCuandocreamosnuestrasbasesdedatossolemoscreardiagramasquenosfacilitanlaabstraccióndecomosevaaalmacenarnuestrainformación,perolaformadellevarloalarealidadenalgungestordebasesdedatos,comoporejemplo:MySQL,SQLite,PostgreSQL,SQLServer,etc.,lomáscomunesmeternosallenguajedescriptencargadodeimplementarnuestraideadelaBDyejecutardichoscript,oinclusoocuparprogramasmásavanzadosquenossirvencomointerfazparacrearlasdeunaformamásgráficaysinlanecesidaddeprofundizardemasiadoenellenguaje,comoWorkbenchoNavicat.

EnLaravelsellevaaotrocontextoestasituación,puestoquevistodelaformatradicionalsiserequierencambiosenlabasededatostenemosquemeternosyaseaaotroprogramaparacambiareldiagramadelabaseoaunarchivoSQLconunasintaxisusualmentecomplicadaodifícildeleeryejecutarloscambiosparareflejarlosenelproyecto,sinembargo,conestonocontamosconuncontroldeloscambios(controldeversiones)sobrelabasededatos,sinecesitamosconsultaruncambioanterioroderepentelasoluciónpreviaoinicialeralaquesenecesitaalmomentodebemosre-escribirtodootravez,cosaqueconlamigracionessesolucionainstantaneamente.

Lasmigracionessonarchivosqueseencuentranellarutadatabase/migrations/denuestroproyectoLaravel,pordefectoenlainstalacióndeLaravel5seencuentrandosmigracionesyacreadas,create_users_tableycreate_password_resets_table.

ParacrearnuestrasmigracionesenLaravelseusaelsiguientecomando:

phpartisanmake:migrationnombre_migracion

quenoscreaelarchivolimpioparaescribirnuestramigración,obienelcomando:

phpartisanmake:migrationnombre_migracion--create=nombre_tabla

quenosagregaunaplantilladetrabajobásicaparaempezaratrabajar.

Comoejemplodelcursosetomaráestecomando:

phpartisanmake:migrationcrear_tabla_pasteles--create=pasteles

elcualnosdaráesteresultado:

Capítulo6.MigracionesySeeders

18

CreatedMigration:2015_06_23_054801_crear_tabla_pasteles

Ynoscrearáademáselsiguientearchivo:

Ahorabiensepuedeobservarqueelarchivocomotalnosellamasimplementecrear_tabla_pastelessino2015_06_23_054801_crear_tabla_pasteles,estopasaporqueLaravelalcrearunamigraciónagregacomopréfijolafechayhoraenlaquefuécreadalamigraciónparapoderordenarquémigraciónvaantesqueotra,porlocualsituejecutasestecomando,obviamenteelnombredetuarchivoserádiferentepueslafechayhoranopuedenserlasmismasquelamiaalcrearesteejemplo.AdemáslasmigracionesquevienenpordefectoenLaraveltambiénseencuentranconesteformatoporlocualpodemosobservarqueestosdosarchivossitienenelmismonombre.

Dentrodelaestructuradelarchivopodemosverdosfunciones,unallamadaup()yotrallamadadown(),laprimerfunciónesendondevamosaespecificarlaestructuradenuestratabla,inicialmenteygraciasalcomandoseencuentranyaalgunascosasescritascomolosonlaclaseSchemaenlacualsellamaalmétodocreate,elcualnospermitecrearlatabla

Capítulo6.MigracionesySeeders

19

ennuestrabasededatos,estarecibedosparámetros,elprimeroeselnombrequevaarecibirlatablaquesinomalrecuerdaneselqueseledioenelcomandoyporlocualyaseencuentraensulugar,yelsegundoparámetroesunafunciónclosureofunciónanónimaqueloquehaceesdefinirlascolumnasdenuestratabla,asuvezestafunciónanónimarecibecomoparámetrounobjetodetipoBlueprintqueseagregódentrodelnamespaceconlapalabrauseenlacabeceradelarchivo,elobjeto$tableesconelquevamosatrabajarparadefinirloscampos,comoseveenlaimagenanteriorestoselograescribiendo$table->tipo_dato('nombre');,yestopuedevariardependiendoeltipodedatoqueseuseyparaellopodemosrevisarladocumentaciónoficialdeLaravelaquíparapodervertodoslostiposdecamposconlosquecontamos.

Enelejemploobservamosqueyatenemoselcampo'id'detipoincrementsqueesequivalenteauncampoenSQLasí:

createtablepasteles(idintauto_increment);

Yuncampodetipotimestampssinnombre,elefectoquetendráseráagregardoscolumnasmuyútilesquesoncreated_atyupdated_atquesoncamposqueseusanpara(comosunombrelodice)guardarelregistrodecuandofuecreadoycuandofueactualizadoelregistro,detallesmuyimportantescuandoqueremosobtenerinformesconbaseeneltiempodelainformacióndenuestratabla,porejemplosiquisieramossabercualessonlospastelesquesedierondealtaenelcatálogoenelmesdeabrilpodriamoscrearunfiltroparaobtenersololospastelesdeesemesusandoelcampogeneradocreated_at.

Ahorabiensilafunciónupcreanuestratablaenlabasededatos,lafuncióndownlogicamentehaceloopuesto,yesoeseliminarlatabladelabasededatos,poresodentrodeestafunciónpodemosobservarquedelamismaclaseSchemasellamaalmétododropquesignificadejarcaerodardebaja.

Sibiencadafunciónrealizaunatareaenespecifico,¿Cuandoesqueseusan?o¿Comosemandanallamar?.Buenoparaestoiremosnuevamenteanuestralineadecomandos.

Paracorreroiniciarnuestrasmigracionesusamoselcomando:

phpartisanmigrate

Conestosieslaprimeravezqueseejecutaestecomandosecrearáennuestrabasededatoslatablamigrationsqueeslaencargadadellevarelcontroldequemigracionesqueyahansidoejecutadas,conelfindenocorrerelmismoarchivomásdeunavezsielcomandoseusanuevamente.

Capítulo6.MigracionesySeeders

20

Entoncessicreamosnuestramigracióncrear_tabla_pastelesyusamoselcomandophpartisanmigratecomoresultadoennuestrabasededatosseagregarálatablapastelesyenlatablamigrationsseañadiráelregistrodelamigraciónrecienejecutada.

Pero,¿siquisieraeliminarlatablaconlafuncióndowndelamigracióncrear_tabla_pasteles?

Estosepuederesolverdedosformasbásicamente:

1. Conelcomandophpartisanmigrate:rollbackqueloqueharáesdeshacerlaúltimamigraciónejecutadayregistradaenlabasededatos.

2. Conelcomandophpartisanmigrate:resetqueloqueharáesdeshacertodaslasmigracionesdelabasededatos.

Nota:Uncomandoextraquenospermiteactualizarlasmigracioneseselcomandophpartisanmigrate:refresh,elcualesequivalenteausarphpartisanmigrate:resetydespuésphpartisanmigrate.

Eneldadocasoquenecesitaramosagregarmáscamposalatablapasteles,podríamossimplementeiralamigracióncrear_tabla_pastelesyenlafunciónupponerlanuevacolumna,peroconestoperderiamoslaprimerversióndelatabla,entoncesparapoderejeplificarcomoseagregancolumnasconlasmigracionescrearemosunanuevaquesellameagregar_campos_tabla_pastelesconloscomandosqueyahemosvisto:

1. Primeroejecutamoselcomando:phpartisanmake:migrationagregar_campos_tabla_pasteles,paracrearlamigraciónsimplesinlaplantilla.

2. Dentrodelafunciónupagregamosloscamposquenecesitamos,enestecasosoloagregaremoselnombreyelsabor.

3. Despuéscomolafuncióndownhaceloopuestoquelafunciónup,dentrodeestaeliminaremosloscamposrecienagregados.

Ahoraelarchivoresultantequedaríaasí:

Capítulo6.MigracionesySeeders

21

ParapoderagregarmáscolumnasalastablasdesdeLaravelenvezdellamaralmétodocreatellamamosalmétodotabledelaclaseSchemapasandolecomoprimerparámetroaquetablasevaaagregarloscamposycomosegundoparámetrolafunciónanónimadondedefinimosquecolumnasseagregaran.

Yenlafuncióndownparaeliminarcolumnasquevendríasiendoloopuestodeagregarlas,sellamaalmétodotableydentrodelafunciónanónimadelobjeto$tableseusaelmétododropColumn()querecibecomoparámetroyaseaelnombredeunasolacolumnaounarreglocontodaslascolumnasquesedeseaneliminar.

Y¡listo!,conestopodemostenerunaideainicialdecomousarlasmigraciones,loqueparaesteejemplopodríacontinuarseríaagregarmáscolumnasalatablapastelesyprobarloscomandosnecesariosparapoderdeshacerloscambiosdelaprimeravezquesecorriolamigraciónconunanuevaversión,yaseasobreelmismoarchivoosobreotronuevo.

Beneficios

Tenemosunmayorcontroldelasversionesdelabasededatos.

Capítulo6.MigracionesySeeders

22

Podemosconunsimplecomandoverreflejadosloscambiosdenuestrabasededatos.

EllenguajeenelcualsetrabajasiguesiendoPHP,porlocualnosediferenciatantodeloqueyanosacostumbraremosconLaravel.

LaultimaversióndenuestrabasesiempreestaráactualizadaparatodoslosmiembrosdelequipodetrabajosiusamosuncontroldeversionescomoGIT.

Proveedeportabilidadparadiferentesgestores,usandoelmismocódigo.

SeedersLosSeedersporotrapartesonarchivosquenosvanapermitirpoblarnuestrabasededatosparanotenerqueperdereltiempoescribiendodeformamanualtodoslosdatos,unejemplo,imaginallenar15tablascon100registroscadaunaypiensaenqueentrecadatabladebenexistirregistrosqueserelacionanentresí,esosuenadeverdadhorribleytedioso,porlocualLaravelnossalvaconestosarchivosSeeders.

UnSeederseubicaenlacarpetadatabase/seeds/denuestroproyectodeLaravelyparapodercrearunnuevoSeederseusaelcomando:

phpartisanmake:seedernombre_seeder

Estonoscrearáunarchivoenlacarpetadatabase/seeds/quetendráelnombrequeledemosenelcomando,porejemplocrearemosunoretomandoelejemploanteriordelasmigraciones,sellamaráPastelesSeeder,porlocualelcomandoquedariadelasiguienteforma:

phpartisanmake:seederPastelesSeeder

Conestoyatenemoselarchivoperonoestodoloquenecesitamosparapodertrabajarcondatosautogenerados,paraellousaremosuncomponentellamadoFakerelcualseencargarádegenerarestosdatos,pordefectoelboilerplatedelproyectodeLaravel5.1queestamostrabajandovieneyaconFakerdentrodelcomposer.jsonporlocualyadebeestarinstaladodentrodenuestroproyecto,ahorabiensiestamostrabajandoconunainstalaciónLaravel5.0sinelcomponenteFakerbastaconiralarchivocomposer.jsonyagregarenel"require-dev"lasdependenciasyparatenerunaideamásclarapodemosiralapáginadePackagistdondeseencuetraFakeroasuRepositorioenGithubyahínosmuestraqueesloquesedebeagregar.

Capítulo6.MigracionesySeeders

23

AlfinalsoloseocupaelcomandocomposerupdateparaactualizarlasdependenciasydescargarFakeralproyecto.

UnavezyateniendoFakeriremosanuestroarchivoPastelesSeederydentropodremosobserverqueseencuentraunafunciónllamadarun()queesdondenosotrosvamosausarFakerparapoblar,ahorabienantesdetododebemosagregarlaclasedeFakeranuestroSeeder,paraestoagregamosaliniciodelarchivolalinea:

useFaker\FactoryasFaker;

Quedandoelarchivodelasiguienteforma:

Despuéscrearemosunavariablellamada$fakerquenosserviraparapoblarlabasededatos,ahorabienusandolaclaseDB,sibiendentrodelejemploqueremoscrear50pastelesvamosacrearunforparaqueejecutenuestrocódigodeinserción50vecesyelcomponentedeFakerencadapasadacambiarálosvaloresdelregistroquesevaaagregar,quedandodeestaforma:

$faker=Faker::create();

for($i=0;$i<50;$i++){

\DB::table('pasteles')->insert(array(

'nombre'=>$faker->firstNameFemale,

'sabor'=>$faker->randomElement(['chocolate','vainilla','cheesecake']),

'created_at'=>date('Y-m-dH:m:s'),

'updated_at'=>date('Y-m-dH:m:s')

));

}

Capítulo6.MigracionesySeeders

24

CreamosnuestroobjetoFaker,elcualpuedegenerarinformaciónfalsaparanuestrabasededatosyahorausamoslaclaseDBelmétodotableparallamarlatabladondesevaainsertarlainformaciónyseleconcatenaelmétodoinsert()elcualrecibeporparametrounarregloclave=>valorconloscamposdelatabla.

Fakertienemuchasvariedadesdedatos,loscualespodemosconsultarensuRepositoriodeGithubasícomosuusobásico.

EnesteejemplousamosunapropiedadquesellamafirstNameFemaleparadarlenombrealpastelylapropiedadrandomElementquedeunarregloqueseledaasignaunelementodeesearregloaleatoriamente.

YahoraloquesigueesabrirunarchivollamadoDatabaseSeeder.php,enestearchivosemandanallamartodoslosseedersenelordenquelosnecesitemos,enestearchivoseagregarálalinea:

$this->call('PastelesSeeder');

queensimandaráallamarnuestroseederreciencreadoyparaejecutarestearchivoseusaelcomando:

phpartisandb:seed

Yconestoquedapobladalatablapastelesylopuedesverificarentugestordebasededatos.

CuandotrabajamosconMigracionesySeederporprimeravezpuedeparecerunpocomáscomplicadoquealoqueestamosacostumbradosperolasventajasquenosdasuperanpormuchoalaformaconvencional,ademásdeserunaformamásprofesionaldetrabajar.

Unoscomandosextrasquenospuedenserutilesson:

phpartisanmigrate--seed

Elcomandoanteriorloquehaceesrealizarunacombinaciónentreloscomandosphpartisanmigrateyphpartisandb:seed.

phpartisanmigrate:refresh--seed

Elcomandoanteriorloquehaceesrealizarunacombinaciónentreloscomandosphpartisanmigrate:refreshyphpartisandb:seed.

Capítulo6.MigracionesySeeders

25

Capítulo6.MigracionesySeeders

26

ModelosyusodeEloquent

Eloquent

EnLaravelpodemoshacerusodeunORMllamadoEloquent,unORMesunMapeoObjeto-Relacionalporsussiglaseningles(Object-Relationalmapping),queesunaformademapearlosdatosqueseencuentranenlabasededatosalmacenadosenunlenguajedescriptSQLaobjetosdePHPyviceversa,estosurgeconlaideadeteneruncodigoportableconelquenotengamoslanecesidaddeusarlenguajeSQLdentrodenuetrasclasesdePHP.

EloquenthaceusodelosModelospararecibiroenviarlainformaciónalabasededatos,paraestoanalizaremoselmodeloquevienepordefectoenLaravel,esteeselmodeloUserqueseubicaenlacarpetaapp/,losmodeloshacenusodePSR-4ynamespaces,unmodelonosayudaadefinirquetabla,atributossepuedenllenaryqueotrossedebenmantenerocultos.

LosmodelosusanconvencionesparaqueaLaravelselefaciliteeltrabajoynosahorretantolíneasdecódigocomotiempopararelacionarmásmodelos,lascualesson:

Elnombredelosmodelosseescribeensingular,encontrasteconlastablasdelaBDqueseescribenenplural.

UsannotacionUpperCamelCaseparasusnombres.

Estasconvencionesnosayudanadetectarautomaticamentelastablas,porejemplo:elmodeloUserseencuentraensingularyconnotacionUpperCamelCaseyparaLaravelpoderdefinirquetablaeslaqueestaligadaaestemodeloleessuficienteconrealizarlaconversionanotacionunderscoreyplural,dandocomoresultadolatabla:users.

Yestoaplicaparacuandoqueremoscrearnuestrosmodelos,sitenemosunatablaenlabasededatosconlaquequeremostrabajarquesellamauser_profiles,vemosqueseencuentraconlasconvencionesparatablasdebasesdedatos(pluralyunderscore),entonceselmodeloparaestatablacambiandolasconvencionesseria:UserProfile(singularyUpperCamelCase).

RetomandoelejemploquevimosenelCapítulo6sobrelamigraciondepasteles,crearemosahoraunmodeloparapodertrabajarconesatabla,elcualrecibiraelnombredePastelyelcomandoparapodercrearnuestromodeloses:

phpartisanmake:modelPastel

Capítulo7.ModelosyusodeEloquent

27

ConestosegeneraraelarchivoendondeyaseencuentraelmodeloUserenlacarpetaapp/ydentrodeelvamosadefinirlatablaquesevaausarconestalinea:

protected$table='pasteles';

¿PeronosesuponiaqueLaravelidentificabaautomáticamentequetablausar?

SilohaceperosicambiamoslasconvencionesdelmodeloPastelelresultadoseriapastelsynuestratablasellamapasteles,estoesunproblemaparanosotrosporelhechodelusodellenguajeespañolporquelaconversiondesingularapluralnoeslamismaquelaformaenquesehaceeningles,debidoaestonosvemosforzadosadefinirelnombredelatabla.

Bienunavezcreadonuestromodelopasaremosacrearunarutadetipogetennuestroarchivoroutes.php,posteriormenteestudiaremoselenrutamientobásicoenLaravelenelCapítulo9,porelmomentosoloseguiremoselejemplo,quequedariadelasiguienteforma:

Route::get('pruebasPastel',function(){

});

Dentrodeestarutadepruebavamosausarnuestromodelo,perocomoestamosusandolaespecificacionPSR-4debemosincluirelnamespacedelmodeloaliniciodelarchivo,queseriaigualaesto:

useCurso\Pastel;

ConestoestamosdiciendoqueincluyalaclasePastelqueesnuestromodelo,yconestopodemosyahacerconsultasanuestraBDymapearaobjetosPHP.EnladocumentacionoficialdeLaravelpodemosvertodaslasopcionesquenospermiteEloquent,unasdelasinstruccionesbasicasdeestesonget()quenosregresatodoslosregistrosdelaBDyfirst()quenosregresaelprimerregistrodeunaseleccion.

AsuvezpodemosunirestoamásfiltrosdeseleccionSQL,comoporejemploseleccionarelprimerpasteldevainilla,lasintaxisdeEloquentserialasiguiente:

$pastel=Pastel::where('sabor','vainilla')->first();

Estonosvaadarelprimerpastelsaborvainilla,perosiquisieramostodoslospastelesdevainillacambiariamoselmetodofirst()porelmetodoget()paraobtenertodos.

Capítulo7.ModelosyusodeEloquent

28

Ysiqueremosverelresultadodeestoyquedeverdadestamoshaciendolocorrectopodemosusarlafunciondd()paramostrarenpantallaelvalordeunavariable,conestoentoncesnuestrarutaleagregariamoslosiguiente:

Route::get('pruebasPastel',function(){

$pasteles=Pastel::where('sabor','vainilla')->get();

dd($pasteles);

});

Yenelnavegadordeberiamosveralgocomoesto:

Estoeslafuncióndd($pasteles)mostrandoelcontenidodelavariable$pasteles.Ahorabiensituvieramoslanecesidadderealizarsiempreunmismofiltro,Eloquentnosproveedeunaherramientallamadascopesqueloquerealizansonconsultasenespecificoencapsulandolasdentrodefuncionesenelmodelo,porejemplosiquisieramosqueelmodeloPasteltuvieraunafuncionquemedieratodoslospastelesdevainilla,otradechocolateyotrafunciónmasparacheesecake,entoncespodriacrearunscopeparacadauna.

ConelejemplodelarutapruebasPastelparaelsaborvainilla:

publicfunctionscopeVainilla($query){

return$query->where('sabor','vainilla');

}

Capítulo7.ModelosyusodeEloquent

29

LosscopesenlafunciónsedebeiniciarelnombredelafunciónconlapalabrascopeyseguidoennotacioncamelCaseelnombreconelcualsevaallamarelscope.Ysuequivalentedentrodelarutaserialasiguiente:

Route::get('pruebasPastel',function(){

$pasteles=Pastel::vainilla()->get();

dd($pasteles);

});

Tambiénpodemoscrearscopesdinámicosdelasiguienteforma:

publicfunctionscopeSabor($query,$sabor){

return$query->where('sabor',$sabor);

}

Estonosdariaunafuncióngenéricaparaobtenerlospastelesdeciertosaborysuimplementaciónseríaasi:

Route::get('pruebasPastel',function(){

$pasteles=Pastel::sabor('vainilla')->get();

dd($pasteles);

});

AdemásconEloquenttambienpodemosinsertar,actualizaroeliminarregistros,porejemplo:

Parainsertarlasintaxisserialasiguiente:

$pastel=newPastel;

$pastel->nombre='PastelRichosStyle';

$pastel->sabor='chessecake';

$pastel->save();

Paraactualizarserialasiguiente:

$pastel=Pastel::find(51);

$pastel->sabor='chocolate';

$pastel->save();

Paraeliminarserialasiguiente:

Capítulo7.ModelosyusodeEloquent

30

$pastel=Pastel::find(51);

$pastel->delete();

obienpodriamosdestruirelregistrodirectamenteconelmodelositenemossuID:

Pastel::destroy(51);

Capítulo7.ModelosyusodeEloquent

31

ModelFactoriesLosmodelfactoriessonunaexcelenteformadepoblarnuestrabasededatoscondatosdepruebageneradosautomáticamente.Laravelensuversión5.1incorporaestenuevocomponentepordefecto,enversionesanterioresaLaravel5.1eranecesarioagregarelcomponentefakerennuestrocomposer.jsonyrealizarelprocesodemaneramanualenlosarchivosseeders,paramásinformaciónsobreestreprocesopuedesvisitarellinkdegithubdelcomponenteFaker.

LosmodelFactoriesenrealidadtambiéntrabajanconelcomponenteFaker,estolopodemosconfirmarsimiramosnuestrocomposer.json,sinembargo,nosofrecenunamaneramáseleganteyordenadadetrabajar.

Laravel5.1traeunejemplodecomousarestenuevocomponente,lopodemosencontrarenelarchivodatabase/factories/ModelFactory.php.

Elmétodo$factory->define()regresaunarrayconlosdatosdelmodeloquesevaapoblar,recibecomoprimerparámetroelmodeloconelquedeseamostrabajarycomosegundoparámetrounafunciónquerecibecomoparámetrounobjeto$faker.

Ejemplo:

$factory->define(App\User::class,function($faker){

return[

'name'=>$faker->name,

'email'=>$faker->email,

'password'=>str_random(10),

'remember_token'=>str_random(10),

];

});

Elmétodo$factory->defineAs()regresaunarrayconlosdatosdelmodeloquesevaapoblar,recibecomoprimerparámetroelmodeloconelquedeseamostrabajar,comosegundoparámetrountipoespecificodepobladoycomotercerparámetrounafunciónquerecibecomoparámetrounobjeto$faker.

Ejemplo:

Capítulo8.Modelfactories(Poblarbasededatosconfaker)

32

//Creamosunmodelfactoryparapoblarusuariosdetipoadministrador

$factory->defineAs(App\User::class,'administrador',function($faker){

return[

'name'=>$faker->name,

'email'=>$faker->email,

'password'=>str_random(10),

'type'=>'administrador',

'remember_token'=>str_random(10),

];

});

//Creamosunmodelfactoryparapoblarusuariosdetipoencargado

$factory->defineAs(App\User::class,'encargado',function($faker){

return[

'name'=>$faker->name,

'email'=>$faker->email,

'password'=>str_random(10),

'type'=>'encargado',

'remember_token'=>str_random(10),

];

});

EnelejemplodearribahemoscreadodostiposdepobladoparaelmodeloUser,unoseráparapoblarusuariosdetipo"administrador"yotroparausuariosdetipo"encargado".

UnavezcreadoslosModelFactories,debemosiralarchivodatabase/seeds/DatabaseSeeder.phpyejecutarelpobladodentrodelmétodoruncomoenelsiguienteejemplo:

publicfunctionrun()

{

Model::unguard();

factory('Curso\User',50)->create();

factory('Curso\User','administrador',1)->create();

//$this->call('UserTableSeeder');

Model::reguard();

}

Elobjetofactoryrecibecomoparámetroselnombredelmodelo,eltipodepobladocomoparámetroopcionalyelnúmeroderegistrosquedeseamoscrear.Conelmétodocreaterealizamoselpobladodedatos.

Ejemplos:

Capítulo8.Modelfactories(Poblarbasededatosconfaker)

33

factory('Curso\User',100)->create();

//Opcionalmentepodemosagregareltipodepoblado

factory('Curso\User','administrador',100)->create();

Capítulo8.Modelfactories(Poblarbasededatosconfaker)

34

EnrutamientobásicoLasiguienteimágenmuestraelprocesoqueserealizacuandoingresamosaunaURL.AdemásmuestralaarquitecturadelpatrónMVCqueutilizalaravelparaeldesarrollodeproyectos.

CuandoingresamosaunaurldirectamentedesdeelnavegadorlohacemosmedianteunapeticiónhttpdetipoGET,estasolicitudseenvíaalarchivoroutes.phpubicadodentrodeapp/Http/routes.php,encasodenoexistirnosdaráunerror,silarutaexiste,nosllevaráauncontroladorenelcuálseencuentralalógica,elcontroladorinteraccionaráconunmodelo(opcionalmente)pararecuperarinformacióndeunabasededatos.Estainformaciónllegaalcontroladorydesdeelcontroladorinvocamosunavista,lasvistasseencuentraneneldirectorioresources/views,finalmentelavistasecargaysemuestraenelnavegador.

AsíescomofuncionaelmodeloMVC(Model-View-Controller).

SupongamosquequeremosingresaralasiguienteURLhttp:/dominio.com/saludoydesplegarunapáginaconelmensaje“Bienvenido:)”.Enlaravellaporción/saludoperteneceríaaunarutaqueregresaunarespuestaounavistadependiendolocomplejoquellegueaserloquequeramosmostrar.Lapartededominio.comperteneceríaalocalhost

Capítulo9.Enrutamientobásico

35

siloandamosprobandodemaneralocal.Ennuestroejemploloquemostraremosesunmensajemuysimpleporlocualnoesnecesariohacermostrarunavista.Paralograrloharemoslosiguiente:

Route::get('saludo',function(){

return"Bienvenido:)";

});

Loquedeberíamostrarunmensajesimilaraeste:

TiposderutasporencabezadoHttp

LasrutasestánsiempredeclaradasusandolaclaseRoute.Esoesloquetenemosalprincipio,antesde::.Lapartegeteselmétodoqueusamospara‘capturar’laspeticionesquesonrealizadasusandoelverbo‘GET’deHTTPhaciaunaURLconcreta.

Comoverás,todaslaspeticionesrealizadasporunnavegadorwebcontienenunverbo.Lamayoríadelasveces,elverboseráGET,queesusadoparasolicitarunapáginaweb.SeenvíaunapeticiónGETcadavezqueescribesunanuevadirecciónwebentunavegador.

Aunquenoeslaúnicapetición.TambiénestáPOST,queesusadaparahacerunapeticiónyofreceralgunosdatos.NormalmenteseusaparaenviarunformularioenlaquesenecesitaenviarlosdatossinmostrarloenlaURL.

HayotrosverbosHTTPdisponibles.Heaquíalgunosdelosmétodosquelaclasedeenrutadotienedisponibleparati:

Route::get();

Route::post();

Route::any();

Route::delete();

Route::put();

CualquiermétododelaclaseRouterecibesiempredosargumentos,elprimeroeslaURIconlaquequeremoshacercoincidirlaURLyelsegundoeslafunciónarealizarqueenestecasoesunClousurequenoesotracosaqueunafunciónanonima,esdecir,quenotieneunnombre.

Rutasdetipoget

Capítulo9.Enrutamientobásico

36

Enestecasoocuparemoselmétodoestáticogetparaescribirunarutaquerespondaaunapeticióndeestetipo,lasrutasdetipogetsonlasmásusadas.Elmétodoestáticogetrecibecomoprimerparámetrounstringindicandolaurlconlacuálvamosaingresar,elstring"/alumnos"responderáalasolicitudhttp://localhost:8000/alumnos,elstring"/"equivaleahtpp://localhost:8000,esdecir,larutapordefecto.Comosegundoparámetroelmétodoestáticogetrecibeunclosure(unafunciónsinnombre)quepuededevolverunaviewounstring.

//rutadetipoGETquedevuelveunavista

Route::get('/',function(){

returnview('welcome');

});

//rutadetipoGETquedevuelveunsimplestring

Route::get('/',function(){

return"Holamundo";

});

Elmétodoviewdentrodelclosurerecibecomoparámetroelnombredeunavistasinlaextensión.Enelejemplodearribalavistawelcomeseencuentraubicadaenresources/views/welcome.blade.phpsiescribimosview('pasteles.lista_pasteles')estamosindicandoqueregresaráelarchivolista_pasteles.blade.phpubicadoenresources/views/pasteles/lista_pasteles.blade.php.Lasvistaslasveremosenelcapítulo10.

Lasrutaspuedenserrelacionadasconmétodosdeuncontrolador.Enelsiguienteejemplo,larutahttp://localhost:8000/homeregresaráloqueindiquemosenelmétodoindexdelControllerHomeController.

Route::get('home','HomeController@index');

Parametrosenlasrutasdetipoget

Losparámetrosdelasrutaspuedenserutilizadosparaintroducirvaloresderellenoentusdefinicionesderuta.EstocrearáunpatrónsobreelcualpodamosrecogersegmentosdelaURIypasarlosalgestordelalógicadelaaplicación.Paradejarlounpocomásclaropondremosunosejemplos.

Capítulo9.Enrutamientobásico

37

Deigualformaesposiblerestringirrutaspormediodeexpresionesregularescomoporejemplo:

Enlaimagenanteriorpodemosverdosconceptosnuevos,elusodevalorespordefaultlocúallogramosconelsimbolo(?)despuesdelnombredelavariableyenlafunciónasignandoleunvalorpordefecto,enestecasoelentero1.

LosegundoquevemoseselusodelmétodowhereelcúalnospermiteestablecerexpresionesregularesalasvariablesqueusamosenlaconstruccióndelasURIs.

Capítulo9.Enrutamientobásico

38

VistasyBladeLasvistasenLaravelsonlapartepúblicaqueelusuariodenuestrosistemavaapoderver,seescribenenHTMLjuntoconunmotordeplantillasllamadoBlade.Lasvistasseencuentranubicadasenlacarpetaresources/views/yLaravelpordefectotrabajaconlaideadequetenemosqueescribirlamenorcantidaddecódigorepetido,modularizarnuestrocódigoendondemassepueda,ysiestoloaplicamosennuestrosmodelos,controladoresydemáspartesdenuestroproyecto,entonces,¿Porquenohacerlotambienenlasvistas?.

Laravelusaunosarchivosquesellamanplantillasotemplatesquesuelensernuestrosarchivosprincipales,quetienenlossegmentosdecódigoqueserepitenenmasdeunavista,comoporejemplolabarradenavegacion,unmenúdeopciones,laestructuradelacomododenuestroproyecto,etc.ycomodebendeestarpracticamentepresentesentodoslados,notienesentidoestarlosrepitiendoentodaslasvistas.PordefectoLaravelcontieneuntemplatellamadoapp.blade.php,usualmentelostemplatescontienenelheaddelHTML,lasligasdelCSSdelsistemayunaseccionexclusivaparalosarchivosJavascript.

Ademásdelostemplates,secuentanconarchivosquesellamanpartials,estosarchivossonpequeñossegmentosdecódigoquesuelenserusadoscomunmenteenpartesdelsistemaenespecifico,comolosformulariososeccionesdemensajes,estosarchivossurgenporelcódigoqueesmaspequeñoquerepetimosmuchoperonoeslosuficientementegrandecomoparaconsiderarlountemplate.

Estohacequelasvistasdecadapartedelproyecto,quesuelenserllamadasporunarutaocontroladorseanmuchomaspequeñasqueusandootrotipodeframeworksparadesarrolloWeb,yparapoderunirtodosestosarchivosopiezasdelrompecabezasusamoselmotordeplantillasdeLaravelllamadoBLADE.

AntesdevermassobreelmotordeplantillasBlade,veremoscomotrabajarconlasVistasyllamarlasdesdeunaruta,crearemosunvistasimpleconunarchivonuevoenlacarpetaresources/views/llamadosaludo.blade.phpconelsiguientecódigo:

Capítulo10.VistasymotordeplantillasBlade

39

<!DOCTYPEhtml>

<html>

<head>

<metacharset="utf-8">

<metahttp-equiv="X-UA-Compatible"content="IE=edge">

<title>Vistaejemplo</title>

</head>

<body>

<h1>HolamundodesdeLaravel</h1>

</body>

</html>

EsunHTMLsimpleconuntitulo1,ahoravamosacrearunarutaquenosmuestreestavista:

Route::get('saludo',function(){

returnview('saludo');

});

Deestaformaconlafunciónview()leestamosdiciendoaLaravelquebusquedentrodelacarpetaresources/views/lavistasaludo.blade.php,porconvensionlasvistasLaravelnonecesitaqueespecifiquemoslaextension.blade.php,sinosolosunombre.Unavezhechoestodebemosveresteresultadoounosimilar:

ContinuandoconelejemplodelosPastelesvamosamandaralavistaelnombredeunpastel,dentrodelarutasaludovamosaobtenerelprimerPasteldechocolatedenuestraBDyaponeresenombreenvezdelmensaje.Paraestopodemosusarelscopedesabor

Capítulo10.VistasymotordeplantillasBlade

40

paraobtenerlospastelesdechocolateydespuesdecirlequeconelmetodofirst()nosregreseelprimerpastelyesoguardarloenunavariable,dejandolarutadelasiguienteforma:

Route::get('saludo',function(){

$pastel=Pastel::sabor('chocolate')->first();

returnview('saludo')->with('pastel',$pastel->nombre);

});

Deestaformaestamosdiciendoalarutaquenosregreselavistasaludo.blade.phpconunavariablellamadapastel,queeselnombredelpastel,peroestoporsisolonolovaamostrarelnavegador,solovaamandarlavariable,paraqueelnavegadorlamuestredebemosagregaruntitulodondeesteesavariabledeestaforma:

<h2>{{$pastel}}</h2>

EstalineavajustoabajodelmensajeHolamundodesdeLaravel,yahorasidebemosdeveralgoparecidoaestoyaquenuestrasBDtienencosasdiferentesygraciasaFakerningunodenuestrosresultadosdeberiaserigual:

Ahorasibienusamosloscaracteresdelasdoblesllavesynosabemosbienqueson,estoespartedelasintaxisqueahoraveremosconBlade.

Blade

Capítulo10.VistasymotordeplantillasBlade

41

Bladenosproveedemuchasventajas(asicomocasitodoenLaravel),ademásdemodularizarnuestrasvistasdeunaformasorprendente,tambiennospermiteusarestructurasdecontrolyvariablesdePHPdirectamenteenellas,aunqueestoyaeraposibleantesusandolasetiquetasdephp,porejemplo:

<?phpecho$var?>

<?=$var?>

Peroestoademásdeserunpocoincomododeescribirdejanuestrasvistasmuchomásdifícilesdeentenderysuciasporlamezcladetantocódigo.

Entoncesparaelejemploanteriorusamoselsiguientecódigo:

{{$pastel}}

Estoeselequivalentea<?=$pastel?>yaunqueconunejemplotansencillonosevedemasiadadiferencia,conlosiguientepodremosverificarlapotenciadeestemotordeplantillas.

UsualmentelasestructurasdecontrolqueconocemoslasusamosenlosarchivosPHPdedicadosalBack-end(ladodelservidor),perobladenosdaunasintaxismuycomodaparaestetipodeestructurasqueconPHPplanosonmuysuciaseincomodasdeusar.

ParacadaunadeestasestructurascomolosonIf,else,elseif,for,foreach,etc.,seanteponeun@parausarestasestructurasylisto!!esoensuficiente,peroadiferenciadecomoestamosacostumbradosdeencapsularungrupodesentenciasolineasdecódigoconllaves{},enbladedefinimoselfindeunaestructuraconun@endseguidodelnombredelaestructuraqueusamos,porejemplo:

<h1>Listadepasteles</h1>

@foreach($pastelesas$pastel)

<h2>{{$pastel->nombre}}</h2>

@endforeach

Entoncesenlarutadonderegresamossolounnombredeunpastel,podriamosregresartodoslospastelesyescribirunalistadetodolospastelesdeunciertosaboreimprimirlaenlavista.

Unejemploparaelifseria:

Capítulo10.VistasymotordeplantillasBlade

42

@if($pasteles->count()>10)

<h1>HaymuchosPasteles</h1>

@endif

<h1>Listadepasteles</h1>

@foreach($pastelesas$pastel)

<h2>{{$pastel->nombre}}</h2>

@endforeach

Elifnosdice,sielnumerodepastelesquerecibimosesmayora10entoncesescribeeltituloHaymuchosPasteles.

Estoaplicaparatodaslasestructuras,sulógicaeslamismaperosolocambiaunpocosusintaxis,perohacequeelHTMLquedemaslimpioquesiincrustaramosPHPplanodentrodenuestravista.

TemplatesyPartialsAnteriormentehablabamosdetemplatesypartials,describiremosunpocodecomosetrabajaconestaestructurasdeBladeysusbeneficios:

Templates

EstosarchivoscomosemencionaalprincipiodelcapítulosonplantillasquenosahorranmuchocódigooleguajeHTML,yparausaruntemplateseusalasentencia:

@extends('template')

Claramentesetendriaquesustituirlapalabratemplatedentrodelasentenciaextendsporelnombredelavistaquevaafuncionarcomotemplateoplantilla.

Untemplateesunavistacomolasdemás,simplementequedentrodeellaseusanotrassentenciasquenosvaapermitirdefinirareasdelarchivoquesevanapodersustituirmasadelantedentrodeotravistasiesquelodeseamos.Paraestoseocupalasentencia:

@yield('nombre_seccion')

Paradeclararunaseccionquesevaarellenarenotrolugar:

@section('nombre_seccion')

Capítulo10.VistasymotordeplantillasBlade

43

quefuncionadelamismaformaqueyield()conladiferenciaqueenlaseccionpuedesdefinirHTMLpordefectoencasodenodefinirlaseccionconunnuevoHTML.

Definiremosnuestravistareciencreadasaludo.blade.phpparaqueuseuntemplate,pordefectoLaraveltraeunoquesellamaapp.blade.php,eseeselqueusaremosparaesteejemplo.

Eltemplateapppordefectotienedefinidaunyieldllamadocontentquesignificacontenido,porlocuallalistadepastelesquetenemoslavamosaagregarenestaparteylavistaquedariadelasiguienteforma:

@extends('app')

@section('content')

<h1>Listadepasteles</h1><br>

@if($pasteles->count()>10)

<h2>HaymuchosPasteles</h2><br>

@endif

@foreach($pastelesas$pastel)

<h4>{{$pastel->nombre}}</h4>

@endforeach

@stop

AhoranuestravistayanotieneelencabezadoHTMLnormalnilasetiquetas<body>ni<html>,sinoqueestamosdiciendoquevamosaextenderdeltemplateappyqueelyieldcontentlovamosasustituirpornuestropropiocontenido,cabemencionarqueaunqueeneltemplateseusolasentenciayield('content'),almomentodesustituirlalavamosacambiarporsection('content'),porlocualentodaslasvistashijasdeltemplatesolosevaadefinirseccionesyelfindeesaseccionsevaadeclararconlaentencia@stop.

Ahoraelresultadoseriaalgoparecidoaesto:

Capítulo10.VistasymotordeplantillasBlade

44

Nospodemosdarcuentaquecambiaronmuchascosas,ahoratenemosunabarradenavegacionenlapartesuperiordelaventanayeldebugbarenlaparteinferior,ademásdequelatipografiahacambiado.EstoesporquedentrodeltemplateappseestanagregandohojasdeestiloCSS.

Partials

Continuaremosconlospartials,basicamenteeslomismoqueyahemosvistoperoconunasentenciamasquesellamainclude('nombre.partial'),lacualestaincluyendooincrustandounarchivodeHTML,podemoshacerunsimilconlosusedePSR-4olosimportdeJava,adiferenciadequeestoloinlcuyejustoenellugardondelodefinimos.

Vamosaverloconunejemplopractico.

Dentrolaactualvistasaludo.blade.php,vamosaquitartodoelHTMLBladequedefinimosparacrearestalistapequeñadepastelesylovamosaguardarennuevoarchivo,paraestovamosacrearunacarpetallamadapastelesydentrootracarpetallamadapartials,dondevamosaguardarlavistadenuestronuevopartial,quedandolarutadelasiguienteforma:resources/views/pasteles/partials/.

Ahivamosacrearunarchivollamadolista.blade.phpydentrodeestearchivovamosacortarelcódigodenuestravistasaludo,quedandoasi:

Capítulo10.VistasymotordeplantillasBlade

45

<h1>Listadepasteles</h1><br>

@if($pasteles->count()>10)

<h2>HaymuchosPasteles</h2><br>

@endif

<ul>

@foreach($pastelesas$pastel)

<li>{{$pastel->nombre}}</li>

@endforeach

</ul>

Ynuestravistasaludo.blade.phpquedariadeestaformaunavezqueyaincluyamosnuestropartial:

@extends('app')

@section('content')

@include('pasteles.partials.lista')

@stop

Sitodolohacemosbiennuestravistaenelnavegadordebeseguirviendosedelamismamanera,perosisedancuentaahoraseencuentramuchomasmodularnuestroHTML,silalistadePasteleslanecesitaramosenotravistaahorasolonecesitamoshacerun@include('pasteles.partials.lista')yconesoyatendremosnuestralistaagregadaencualquiervistadondelanecesitemos.

Resumen,AnotacioneseinformacionadicionalBladeesunmotordeplantillaspotentequenospermitemodularizaryestilizaraungrannivelnuestroHTML.

ComorecordatoriolistaremosalgunasdelassentenciasdeBladejuntoconsufuncion:

@extends('nombre_template'):Estasentencianosayudaadecirleaunavistacualvaasereltemplatequesevaausar.

@yield('nombre'):EstasentencianospermitedeclararunfuturosectiondenuestroHTMLquesedefiniraenlasvistasquesonheredadasynopuedeagregarsealguntipodecontenidopordefecto,estesóloseusaenarchivosquetomanelroldeTemplate.

@section('nombre'):Estasentenciatienedosusosdependiendodequequeremosdeclarar,elprimeroesquenospermitedeclararcomosunombrelodiceunaseccióndentrodeltemplatequepuedeteneruncontenidopordefectoquesinoesredefinidoenlavistaqueheredeeltemplateentoncesaparecera;elsegundonospermiteasignar

Capítulo10.VistasymotordeplantillasBlade

46

elcontenidoenunaseccionquefuedeclaradaennuestrotemplate,esdecirestapalabrasectionseusatantoeneltemplatecomoenlasvistashijas,unadiferenciamasesquesiseusaeneltemplateentonceslaseccionteminaconun@show,perosiseusaenunavistahijaentoncesterminalaseccionconun@stop.

@show:Estasentenciaseusaparadecirdondeterminaelsectiondefinidoeneltemplate.

@parent:Estasentencianosayudaacargarelcontenidopordefectodeunsectiondeltemplate,estopodemosusarlocuandoqueremosagregarmascontenidodentroperosinalterarelcontenidopordefecto,esdeciragregarlemasHTML,estasentenciaseusadentrodeunsection,podemoshacerunsimilconelsuper()deJavaquesirveparallamaralcontructordelasuperclasedelaquesehereda.

@stop:Estasentencianospermitedecirdondeterminaunsectioncuandoseusaelsectiondentrodelasvistashijas.

@include('ruta.nombre'):Estasentencianosagregaenellugardondeseausadaunarchivoblade.phpquecontieneunpartialofragmentoparcialdeHTML,siesepartialseencuentraenlaraízdelasvistasnonecesitamasqueelnombresinlaextensionblade.php,perosiestadentrode,porejemplo,lacarpeta"views/admin/users/"llamadotable.blade.phpparapoderserincluidoseusaríalarutajuntoconelnombrequedandocomo@include('admin.users.table'),viewsnosecontemplapueseslaraizdelasvistas.

ParamasinformaciondeBladepodemosiraladocumentacionoficialdeLaravelsobretemplates.

Capítulo10.VistasymotordeplantillasBlade

47

ControladoresEnlugardedefinirensutotalidadlalógicadelaspeticionesenelarchivoroutes.php,esposiblequedeseeorganizarestecomportamientousandoclasestipoController.LosControladorespuedeagruparlaspeticionesHTTPrelacionadaconlamanipulaciónlógicaenunaclase.LosControladoresnormalmentesealmacenaneneldirectoriodeaplicaciónapp/Http/Controllers/.

Uncontrollerusualmentetrabajaconlaspeticiones:

GET.POST.PUT.DELETE.PATCH.

Asociandolosmétodosdelasiguienteforma:

GET:index,create,show,edit.POST:store.PUT:update.DELETE:destroy.PATCH:update.

Loscontroladoresnosayudanaagruparestaspeticionesenunaclasequeseligaalasrutas,enelarchivoapp/Http/routes.php,paraestousamosuntipoderutallamanaresource:

Route::resource('pasteles','PastelesController');

Estarutanoscrearaungrupoderutasderecursosconlaspeticionesqueestasmencionadasarriba:index,create,show,edit,store,update,destroy.EstassonlasoperacionesmasusadasenunaclaseyparanotenerquecrearunarutaparacadamétodoesqueLaravelagrupatodoestoconunarutadetiporesourcequeseligaauncontrolador.

Estosmétodossignifican:

index:Eselmétodoinicialdelasrutasresource,usualmentelousamosparamostrarunavistacomopáginaprincipalquepuedeconteneruncatalogooresumendelainformacióndelmodeloalcualperteneceobiennomostrarinformaciónysolotenerlafuncióndepáginadeinicio.

Capítulo11.Controladores

48

create:Estemétodolopodemosusarparadireccionarelsistemaalavistadondesevanarecolectarlosdatos(probablementeconunformulario)paradespuésalmacenarlosenunregistronuevo,usualmenteredirigealindex.

show:Aquipodemoshacerunnaconsultadeunelementodelabasededatosodetodosloselementosoregistrospormediodelmodelopararealizarunadescripcion.

edit:Estemétodoessimilaraldecreateporquelopodemosusarparamostrarunavistaquerecolectalosdatosperoadiferenciadecreateesconelfindeactualizarunregistro.

store:Aquiesdondeseactualizaunregistroenespecificoqueprovienedelmétodocreateynormalmenteredirigealindex.

update:Aligualqueelstore,soloqueenvezdeprovenirdecreateprovienedeedityenvezdecrearunnuevoregistro,buscaunexistenteylomodifica,tambiensueleredirigiralindex.

destroy:EnestemétodousualmentesedestruyeoeliminaunregistroylapeticiónpuedeprovenirdedondeseasiempreycuandoseallamadoconelmétodoDELETE,despuéspuederedirigiralindexoaotrositiodependiendosilogroeliminarono.

Ahoraestonoquieredecirqueuncontroladornecesariamentedebeejecutarestaspeticionesobligatoriamente,podemosomitirlasoinclusoagregarmas.

ParacrearcontroladoresenLaravelusamosartisanconelsiguientecomando:

phpartisanmake:controllerNameController

Elcomandoanteriorcrearauncontroladorenlacarpetaapp/Http/Controllers/quepordefectovaatenertodosestosmétodosdentrodesi,entoncesagregaremoslarutadetiporesourseanterioralarchivoderutasycorreremoselsiguientecomandoenlaconsola:

phpartisanmake:controllerPastelesController

Conestovamosapodertrabajarparacadamétododelcontroladorunarutaylasfuncionesinternassonlasquesevanaejecutar,elarchivocreadoseverádelasiguientemanera:

Capítulo11.Controladores

49

Enlalineadecomandospodemosvertodaslasrutasquenuestroproyectotieneregistradas:

phpartisanroute:list

Estecomandonosvaamostrarenlaconsolaunresultadosimilaraesto:

Capítulo11.Controladores

50

aquipodemosverelnombredenuestrasrutas,dequetiposon,siesquerecibenparametrosycomosellaman,estainformaciónesmuyutilparapoderasociarlosmétodosdelcontroladorconlasrutasytambiencomoesquelasvamosausarenelnavegador.

Porejemplolarutapateles/{pasteles}detipoGETconelnombrepasteles.index,seasociaalafunciónindex()delcontroladorPastelesControlleryporconsecuenteloquehagamosenesafunciónlopodremosverenelnavegador.

Loscontroladoressonuntemacomplicadoyextensoasicomoelenrutamientoaunqueenelcursosolovimosenrutamientobasico,porlocualdejamosloslinksdeladocumentacionoficialdeControladoresydeEnrutamientoenlaversion5.1deLaravel.

Capítulo11.Controladores

51

ValidacionesenLaravelExistenvariasformasdevalidarnuestraaplicaciónparacubriraspectosdeseguridadcomoSQLInjection,ataquesXSSoCSRF,algunasdeellasson:

Validacióndeladodelcliente(JavascriptyetiquetasHTML).Validaciónaniveldebasededatos(Migracionesymodelos).Validacióndeformularios(Request).

Validacióndelladodelcliente:Podemosvalidarqueloscamposdeunformularioseanrequeridosalagregarelatributorequired.

<formaction="demo_form.asp">

Username:<inputtype="text"name="username"required>

<inputtype="submit">

</form>

Elatributorequiredesunatributobooleano.Cuandoestapresente,esteespecificaqueuncampodebeserrellenadoantesdeserenviadoelcontenidodelformulario.

Elatributorequiredtrabajaconlossiguientestiposdeinput:

textsearchurltelemailpassworddatapickersnumbercheckbox

Elatributopattern

Consemencionoanteriormente,conrequiredsolosenecesitadecualquiervalorenelelemento<input>paraserválido,peroutilizandoelatributopatternenconjunto,selograqueseverifiquenosololapresenciadeunvalor,sinoqueestevalordebecontenerun

Capítulo12.ValidacionesenLaravel

52

formato,unalongitudountipodedatoespecifico.Estoúltimoselogradefiniendounpatrónconexpresionesregulares.

<labelfor="tel">Teléfono10dígitosempezandopor228</label>

<inputtype="text"pattern="^228\d{8}$">

Parautilizarelatributopatternesrecomendableutilizareltype="text"ynountypedelospredefinidosenHTML5queyacuentanconpatronesdevalidaciónenelpropionavegador.Mezclarambospuedellevararesultadosinesperados.

ValidacióndeformulariosconpluginsJQuery

ElmejorpluginJQueryparavalidarformulariosesformvalidation.Sinembargoformvalidationesunpluginquetieneuncostodependiendolalicenciaquequeramosocupar.

Formvalidationescompatibleconlosformulariosdelosframeworkscssmáspopulares:

BootstrapFoundationPureSemanticUIOtros

SmokeeselmáscompletopluginJQuerydiseñadoparatrabajarconbootstrap3,ademásesopensourceeincluyelassiguientescaracterísticas:

Validacióndeformularios.Sistemadenotificaciones.Progressbar.Soporteparafullscreen.Agregarfuncionalidadextraalospanelesdebootstrap.Helpersparaconversióndetipos.

Paraincluirsmokeennuestroproyectosólotenemosquedescargarelplugindeaquí.

Extraerlosarchivosdelzip,ycolocarlosarchivosCSSyJSdentrodelacarpetapublic/assetsdenuestroproyectoenLaravel:

Capítulo12.ValidacionesenLaravel

53

public/

assets/

css/

smoke.css

smoke.min.css

js/

smoke.js

smoke.min.js

lang/

es.js

es.min.js

Unavezhechoesto,debemoshacerreferenciaalosestilosyscriptsdesdenuestrodocumentohtmlenlaseccióndeheadybody:

<!DOCTYPEhtml>

<html>

<head>

<metacharset="utf-8">

<title>EjemploSmoke</title>

{!!Html::style('assets/css/smoke.css')!!}

</head>

<body>

{!!Html::script('assets/js/smoke.js')!!}

{!!Html::script('assets/lang/es.js')!!}

</body>

</html>

Losejemplossobrevalidaciones,notifiaciones,progressbar,etclosencontrarásenlapáginaoficialdeSmoke.

Validacióndelladodelservidor(Request).LaravelpermitevalidarlosdatosenviadosporunformulariodeformamuysencillaocupandounMecanismollamados"Requests".VeamosunejemploocupandoelcontrollerPastelesControllervistoenelcapítuloanterior,dandoleusoalosmétodosstoreyupdate,elfuncionamientoylógicapuedesverloenelAnexoC.CRUDconLaravelparacomprendersufuncionamiento:

LoprimeroquedebemoshacerescrearunrequestparaelmétodostoredePastelesControlleryaquenecesitamosvalidarquelosdatosenviadosenelformularioparacrearunnuevopastelseanválidos.

Ejemplo:

Capítulo12.ValidacionesenLaravel

54

phpartisanmake:requestCrearPastelesRequest

ConestecomandoCrearemoselRequestCrearPastelesRequestubicadoen:

app/Http/Request/CrearPastelesRequest

Sucontenidoeselsiguiente:

<?php

namespaceCurso\Http\Requests;

useCurso\Http\Requests\Request;

classCrearPastelesRequestextendsRequest

{

/**

*Determineiftheuserisauthorizedtomakethisrequest.

*

*@returnbool

*/

publicfunctionauthorize()

{

returnfalse;

}

/**

*Getthevalidationrulesthatapplytotherequest.

*

*@returnarray

*/

publicfunctionrules()

{

return[

//

];

}

}

Losiguientequeharemosserácambiarelvalorqueregresaelmétodoauthorize()defalseatrueparapermitirqueelRequestlopuedaocuparcualquierusuario.

publicfunctionauthorize()

{

returntrue;

}

Capítulo12.ValidacionesenLaravel

55

Posteriormenteenelmétodorules()agregaremoslasreglasdevalidacióndelformularioparacrearpastelesquedandoasí:

publicfunctionrules()

{

return[

'nombre'=>'required|string|max:60',

'sabor'=>'required|in:chocolate,vainilla,cheesecake'

];

}

AlfinalelarchivoCrearPastelesRequestdeberáverseasí:

<?php

namespaceCurso\Http\Requests;

useCurso\Http\Requests\Request;

classCrearPastelesRequestextendsRequest

{

/**

*Determineiftheuserisauthorizedtomakethisrequest.

*

*@returnbool

*/

publicfunctionauthorize()

{

returntrue;

}

/**

*Getthevalidationrulesthatapplytotherequest.

*

*@returnarray

*/

publicfunctionrules()

{

return[

'nombre'=>'required|string|max:60',

'sabor'=>'required|in:chocolate,vainilla,cheesecake'

];

}

}

DeigualformacrearemoselRequestparaelmétodoupdatedePastelesController.

phpartisanmake:requestEditarPastelesRequest

Capítulo12.ValidacionesenLaravel

56

Yelarchivolodejaremoscomosemuestraacontinuación.

<?php

namespaceCurso\Http\Requests;

useCurso\Http\Requests\Request;

classEditarPastelesRequestextendsRequest

{

/**

*Determineiftheuserisauthorizedtomakethisrequest.

*

*@returnbool

*/

publicfunctionauthorize()

{

returntrue;

}

/**

*Getthevalidationrulesthatapplytotherequest.

*

*@returnarray

*/

publicfunctionrules()

{

return[

'nombre'=>'required|string|size:60',

'sabor'=>'required|in:chocolate,vainilla,cheesecake'

];

}

}

LasreglasdevalidaciónocupadasenelejemploanteriorlaspodemosencontrarexplicadasconmayordetalleenlapáginadeValidacionesdeLaravel.

ParaocuparelnuevorequestenPastelesControllerdebemosincluirlo:

useCurso\Http\Requests\CrearPastelesRequest;

useCurso\Http\Requests\EditarPastelesRequest;

EnelmodeloPastelagregaremosunapropiedad$fillableparaindicarqueatributosdelatablapastelespodránserocupadosconelmétodo$request->all().

Elmodelopastelesquedaríaasí:

Capítulo12.ValidacionesenLaravel

57

<?php

namespaceCurso;

useIlluminate\Database\Eloquent\Model;

classPastelextendsModel

{

protected$table='pasteles';

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

publicfunctionscopeSabor($query,$sabor){

return$query->where('sabor',$sabor);

}

publicfunctionscopeId($query,$id){

return$query->where('id',$id);

}

}

LosmétodosstoreyupdaterecibiráncomoparámetrounobjetoRequestparaaplicarlasreglasdevalidación,alfinalelcontroladorPastelesControllerdebetenerelsiguienteaspecto:

<?php

namespaceCurso\Http\Controllers;

useIlluminate\Http\Request;

useCurso\Http\Requests;

useCurso\Http\Controllers\Controller;

useCurso\Pastel;

useCurso\Http\Requests\CrearPastelesRequest;

useCurso\Http\Requests\EditarPastelesRequest;

classPastelesControllerextendsController

{

/**

*Displayalistingoftheresource.

*

*@returnResponse

*/

publicfunctionindex()

{

$pasteles=Pastel::get();

returnview('pasteles.index')->with('pasteles',$pasteles);

}

Capítulo12.ValidacionesenLaravel

58

/**

*Showtheformforcreatinganewresource.

*

*@returnResponse

*/

publicfunctioncreate()

{

returnview('pasteles.create');

}

/**

*Storeanewlycreatedresourceinstorage.

*

*@returnResponse

*/

publicfunctionstore(CrearPastelesRequest$request)

{

$pastel=Pastel::create($request->all());

returnredirect()->route('pasteles.index');

}

/**

*Displaythespecifiedresource.

*

*@paramint$id

*@returnResponse

*/

publicfunctionshow($id)

{

//

}

/**

*Showtheformforeditingthespecifiedresource.

*

*@paramint$id

*@returnResponse

*/

publicfunctionedit($id)

{

$pastel=Pastel::find($id);

returnview('pasteles.edit')->with('pastel',$pastel);

}

/**

*Updatethespecifiedresourceinstorage.

*

*@paramint$id

*@returnResponse

*/

publicfunctionupdate(EditarPastelesRequest$request,$id)

{

$pastel=Pastel::find($id);

Capítulo12.ValidacionesenLaravel

59

$pastel->fill($request->all());

$pastel->save();

returnredirect()->route('pasteles.index');

}

/**

*Removethespecifiedresourcefromstorage.

*

*@paramint$id

*@returnResponse

*/

publicfunctiondestroy($id)

{

$pastel=Pastel::find($id);

$pastel->delete();

Pastel::destroy($id);

returnredirect()->route('pasteles.index');

}

}

SiteinteresaverelprocesoconelcualsecompletaronlosmétodosterecomendamosiralAnexoC.CRUDconLaravelparamayorinformaciónyasípoderprobaradecuadamentelosRequest.

Capítulo12.ValidacionesenLaravel

60

MiddlewaresEnestepuntodebemostenernuestroCRUDparalaclasePasteles,encasodenotenerlorecomiendoverelAnexoC.CRUDconLaravelparapodercontinuar.Ahorabiensiyapodemosrealizarlasoperacionesbásicasnopodemospensarenllevaraunambienterealocomercialunproyectoenestenivel.AunsifuncionacorrectamentenohemoscontempladotodoslosposiblescasosoamenazasqueseencuentranafueraenlaWeb,talescomosonhackers,estafadoresoinclusolasfallasusualesdelosusuariosfinales.

ParasolucionarestoLaravelutilizalosMiddleware,quenospermitenprotegerlasrutasdeaccesosnoautorizados,comosunombreloindica(middle)seubicaenelmediodelapeticion(Request),entoncessideseamosagregarunnuevoniveldeseguridadanuestrosistemalosMiddlewaresonlarespuesta.

PrimerovamosaanalizarunMiddlewareparalaautenticacionologueodelosusuariosennuestrasrutas.PordefectoennuestroproyectodeLaraveldebemosdecontarconunmiddlewarellamadoauth,estemiddlewaredeloqueseencargaesdeverqueelusuarioseencuentreconunasesionactiva,recuerdenqueenLaravelyatenemospordefectoelmanejodesesionesjuntoconlastablasdelabasededatos.Paradecirleanuestroproyectoquelasrutasdenuestrocontroladordepastelesvanaestarprotegidasporelmiddlewareauthusamoselmétodomiddleware('name');dentrodelconstructordenuestraclasedelasiguienteforma:

publicfunction__construct(){

$this->middleware('auth');

}

RecuerdenqueestodebeubicarsedentrodenuestrocontroladorPastelesControllercomounafunciónmas,usualmenteestafuncióneslaprimeraqueseveporlocualrecomiendoquealmomentodeagregarestecodigolohaganeliniciodesuclase.

Conestecambiosedarancuentadequesiingresanalasrutasenlascualesyaantespodiamosvernuestrocrudlosredirigeallogin,sicreanunacuentadeusuarioylointentannuevamenteveranqueelaccesoyaselesvaaconceder,ademáselnombreyusuarioconelqueaccedanseveraenlabarrasuperiordenavegacionalladoderecho,comprobandolassesionesqueLaravelnosdacomounregalo.

Analizaremosunpocolosarchivos,siempreesimportantesabercomofuncionaloqueestamosusandoynoquedarnossoloconlaideadequefuncionasintenerlamasremotaideadeloquesucede.Silaautenticaciónyaestahechaestolopodemosverificarenel

Capítulo13.Middlewares

61

archivoKernel.phpdentrodelarutaapp/Http/,enestearchivovamosaveruncodigosimilaraeste:

enelpodemosverunavariableprotegidallamada$routeMiddlewaredondeestandefinidoslosmiddlewaredelsistema,podemosobservartantolaubicacioncomoelnombreconelcualpodemosusarlo,estossonauth,auth.basicyguest.

ElarchivoquehacereferenciaalmiddlewareauthsellamaAuthenticate.phpqueseencuentraenapp/Http/Middleware/,dentrodeestearchivopodemosobservarlaestructuradeunMiddlewarenormal,estetipodearchivoscuentanconunafunciónllamadahandle()queeslaqueseejecutacuandosellamaalmiddleware,lafunciónhadledeestearchivoeslasiguiente:

Capítulo13.Middlewares

62

Enellapodemosobservarquerealizaunaseriedepreguntasparasaberquerespuestadaryadonderedirigir,primeropreguntasielusuarioestalogueadoconlapreguntaif($this->auth->guest()),guestsignificainvitadoyporlógicasiestainvitadoquieredecirquenocuentaconunasesioniniciada.SiesefueraelcasoentoncesdebemosverificarsiellogueoseintentarealizarpormediodeAJAXysilapeticionesdeestetipoentoncesrechazarlaymandarunarespuestadeaccesonoautorizado,perosinoesdetipoAJAXentoncesredirigirdirectoalavistadelogueo.Enelcasodequenoseauninvitadoentoncesquieredecirquesitieneiniciadasusesionporlocualpasaralapeticiónalsiguientemiddlewarehastaquelleguealúltimoyterminelasverificacionesdelsistema.

CreandonuestrospropiosMiddlewares

PreparativosAhorabien,estonoeslasoluciónatodosnuestrosproblemas(aun),aunqueeltenerlaautenticaciónhechapordefectoesunagranayudapodemosrequerirmásprotección,porejemplosimanejamosrolesennuestraaplicación,digamosqueelCRUDdepastelessololopodemosversitenemosunacuentadeadministradorenelsistemaperonositenemosunacuentanormal.

Vamosamodificaralgunosarchivosparapoderaplicarnuestronuevomiddleware,primerolamigraciondeusuariosllamadacreate_users_table.phpenlacarpetadelasmigraciones,vamosaagregaruncampodetipodeestaforma:

Capítulo13.Middlewares

63

<?php

useIlluminate\Database\Schema\Blueprint;

useIlluminate\Database\Migrations\Migration;

classCreateUsersTableextendsMigration

{

/**

*Runthemigrations.

*

*@returnvoid

*/

publicfunctionup()

{

Schema::create('users',function(Blueprint$table){

$table->increments('id');

$table->string('name');

$table->string('email')->unique();

$table->string('password',60);

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

$table->rememberToken();

$table->timestamps();

});

}

/**

*Reversethemigrations.

*

*@returnvoid

*/

publicfunctiondown()

{

Schema::drop('users');

}

}

PeroenelmodelodeUsersquevienepordefectoconLaravel5sedefinenloscamposquesepuedenllenarylosocultos,vamosadecirlealmodeloquetambienpuedellenarelcampotypedeestaforma:

protected$fillable=['name','email','password','type'];

ElmodeloUserseencuentraenapp/Http/,ahorarevisaremoselcontroladorderegistro,esdecirelcontroladorAuthControllerenlacarpetaapp/Http/Controllers/Auth/,buscaremoselmétodocreateyvamosadejarlodeestaforma:

Capítulo13.Middlewares

64

protectedfunctioncreate(array$data)

{

returnUser::create([

'name'=>$data['name'],

'email'=>$data['email'],

'password'=>bcrypt($data['password']),

'type'=>$data['type'],

]);

}

Hastaahorasoloestamosdiciendolealmétodoqueagregueotroelementoquevaaprovenirdelavistallamado'type'.

Ahoranecesitamospodercrearunadministradorounusuarionormal,porestovamosaagregaruncamposelectennuestravistaderegistroparacompletarlasmodificaciones,vamosamodificarlavistaregister.blade.phpdentrodelacarpetaresources/views/auth/.Levamosaagregarelcampoydeberaversedeestaforma:

@extends('app')

@section('content')

<divclass="container">

<divclass="row">

<divclass="col-md-6col-md-offset-3">

<divclass="panelpanel-default">

<divclass="panel-heading">SignUp</div>

<divclass="panel-body">

{!!Form::open(['route'=>'auth/register','class'=>'form'])!!

}

<divclass="form-group">

<label>Name</label>

{!!Form::input('text','name','',['class'=>'form-contr

ol'])!!}

</div>

<divclass="form-group">

<label>Email</label>

{!!Form::email('email','',['class'=>'form-control'])!

!}

</div>

<divclass="form-group">

<labelfor="type">Type</label>

<selectname="type"class="form-control">

<optionvalue=""disabledselected>Eligeunaopcion...

</option>

<optionvalue="admin">Administrador</option>

<optionvalue="user">Usuarionormal</option>

Capítulo13.Middlewares

65

</select>

</div>

<divclass="form-group">

<label>Password</label>

{!!Form::password('password',['class'=>'form-control'])

!!}

</div>

<divclass="form-group">

<label>Passwordconfirmation</label>

{!!Form::password('password_confirmation',['class'=>'fo

rm-control'])!!}

</div>

<div>

{!!Form::submit('send',['class'=>'btnbtn-primary'])!!

}

</div>

{!!Form::close()!!}

</div>

</div>

</div>

</div>

</div>

@endsection

CrearelmiddlewareIsAdminConloanteriortendremostodosloscambiosnecesariosparaadministrarrolesennuestrosistema.LosiguienteescrearelmiddlewareisAdmin,paraestoartisannoproveeestecomando:

phpartisanmake:middlewarename

Elcomandoparanuestroejemploseriaigualaesto:

phpartisanmake:middlewareIsAdmin

estonosvaacrearunarchivodentrodelacarpetaapp/Http/Middleware/conelnombrequeledimosconlafunciónhandlequeexplicamosanteriormente.Parapoderverificarsielusuariologueadoesunadministradordebemospoderobtenerelusuarioporlocualvamosaagregarunaclaseparapoderobtenereseusuario,inyectaremosladependencia,vamosacrearunatributoqueserálaautenticaciónquevienedelmiddlewareanterioryelconstructordeestaforma:

Capítulo13.Middlewares

66

<?php

namespaceCurso\Http\Middleware;

useIlluminate\Contracts\Auth\Guard;

useClosure;

classIsAdmin

{

protected$auth;

publicfunction__construct(Guard$auth)

{

$this->auth=$auth;

}

/**

*Handleanincomingrequest.

*

*@param\Illuminate\Http\Request$request

*@param\Closure$next

*@returnmixed

*/

publicfunctionhandle($request,Closure$next)

{

if($this->auth->user()->type!='admin'){

$this->auth->logout();

if($request->ajax()){

returnresponse('Unauthorized.',401);

}else{

returnredirect()->to('auth/login');

}

}

return$next($request);

}

}

ParalalógicapodemosemularloquepasaenelMiddlewaredeAuthenticate,vamosapreguntareltipodeusuarioyvamosapreguntarsilapeticionesAJAXparadirigirlarutadelapeticionadondeseaelcaso,sielusuarioesdetipoadminentoncesvamosaredirigirlapeticionalsiguienteMiddleware,sinoentoncesvamosacerrarlasesionypreguntaremossilapeticionesAJAX,encasodeserAJAXvamosadenegarla,sinoentoncesvamosamandarallogin.Usaremoslafunción->to();porquesinosquedamosconlafunciónguest()esoguardalarutadedestinoalaquequeremosllegarynuncavamosapoderiniciarsesionconusuariosnormales.

Capítulo13.Middlewares

67

Ahoravamosaregistrarnuestromiddlewareparapoderusarloyaqueporsimismonolovamosapoderintegraralcontrolador,paraestotenemosquemodificarelKernel.php,lounicoaquiesagregarenel$routeMiddlewareunnombreparanuestroMiddlewareylaubicaciondelmismo,asiescomoseveria:

protected$routeMiddleware=[

'auth'=>\Curso\Http\Middleware\Authenticate::class,

'auth.basic'=>\Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,

'guest'=>\Curso\Http\Middleware\RedirectIfAuthenticated::class,

'is_admin'=>\Curso\Http\Middleware\IsAdmin::class,

];

EntoncesconestoyapodemosligarloalcontroladordentrodesuconstructoryparacadafuncióndentrodeestesevaamandarallamarelMiddlewareis_admin:

publicfunction__construct(){

$this->middleware('auth');

$this->middleware('is_admin');

}

Asipodemosprobarentrandoaunarutaconunacuentadeusuarionormalydenuevoconunacuentadeadministrador,entoncesveremosquesolosiusamosunacuentadeadministradorpodemosverloqueyateniamosalinicioperodeotromodocerrarálasesiónynonosdejaraentraraverelcontenido.

ParamasinformacionleanladocumentacionoficialsobreMiddlewaresdeLaravel5.

Capítulo13.Middlewares

68

¿QuéesHTML5?HTML5eslanuevaversióndellenguajedemarcadoqueseusaparaestructurarpáginasweb,actualmentesigueenevolucion,HTML5incorporacaracterísticasnuevasymodificacionesquemejorarásignificativamentelaformadeconstruirsitiosweb.

HTML5nospermitecreardocumentosHTMLdeunaformamássimplificadaysencillaquesusversionesanteriores.

¿QuéhaydenuevoenHTML5?LadeclaraciónDOCTYPEesahoramássimple:

<!DOCTYPEhtml>

Lacodificacióndecaracteressehacedelasiguientemanera:

<metacharset="UTF-8">

Nuevostags(etiquetas)

Nuevoselementossemánticoscomo:<header>,<footer>,<article>,y<section>.Nuevoselementosparaelcontroldeformularios:number,date,time,calendar,yrange

Nuevoselementosgráficos:<svg>y<canvas>.Nuevoselementosmultimedia:<audio>y<video>.

NuevasAPI's

HTMLGeolocationHTMLDragandDropHTMLLocalStorageHTMLApplicationCacheHTMLWebWorkersHTMLSSE

AnexoA.HTML5

69

PlantillabásicadeundocumentoenHTML5CualquierdocumentoenHTML5debecontenerlasiguienteestructurabásica.

<!DOCTYPEhtml>

<html>

<head>

<metacharset="UTF-8">

<title>Títulodelapágina</title>

</head>

<body>

Cuerpodeldocumento

</body>

</html>

Enlaseccióndelacabecera<head>escribiremos:

Lacodificaciónqueocuparemosparaeldocumento,esrecomendadousarUTF-8.EltítulodelapáginaLoselementoslinkparautilizarlosarchivosCSS.

Enlaseccióndelcuerpo<body>escribiremos:

BarrádenavegaciónEncabezadosSeccionesParrafosElementosmultimedia:audio,video,imgTextoennegritas,cursivaysubrayado.TablasListasFormulariosHipervínculosetc.

EncabezadosLosencabezadosenhtmltienen6tamañosdiferentesyseescribendelasiguienteforma:

AnexoA.HTML5

70

HTML Resultado

Secciones(divisiones)Podemosdividirnuestrodocumentoenseccionesdistintasconlaetiqueta<div>paratenerunmayorordensobrenuestrodocumentoyaplicardiferentesestilossegúnlasección.

HTML Resultado

FormatodetextoPodemosdefinirdiferenteselformatodeltextocomo:negrita,cursiva,subrayado,tipodeletra,tamañodefuente,saltosdelínea,párrafos,citas,etc.

AnexoA.HTML5

71

HTML Resultado

<b> Textoennegrita

<i> Textoencursiva

<u> Textosubrayado

<p> Parrafo

<code>Escribirenformatocódigodeprogramación

<p> Parrafo

<em> Textoconénfasis

<br> Saltodelínea

<!--Texto--> ComentariosenlenguajeHTML

<hr> Líneahorizontalparadividirsecciones<fontface="verdana"size="10"

color="red">Formateartexto

FormulariosHTML Resultado

<form> DefineunFormularioHTML

<input>

<textarea> Defineuntextareaparaguardarunagrancantidaddetexto.

<button> Defineunbotón

<select> Defineunalistadesplegable

<option> Defineunaopciónenunalistadesplegable

<label> Defineunaetiquetaparauninput

AtributosdelosformulariosSeccionendesarrollo.

AnexoA.HTML5

72

TablasEjemplodeunatablabásica:

<table>

<thead>

<tr>

<th>cabecera</th>

<th>cabecera</th>

<th>cabecera</th>

</tr>

</thead>

<tfoot>

<tr>

<td>celda</td>

<td>celda</td>

<td>celda</td>

</tr>

</tfoot>

<tbody>

<tr>

<td>celda</td>

<td>celda</td>

<td>celda</td>

</tr>

</tbody>

</table>

Lastablasseescribenconlaetiqueta<table>,dentrodelatablatendremosfilasycolumnas,laetiqueta<tr>definelasfilasylaetiqueta<td>definelascolumas.

HipervínculoseimágenesLasimágenespuedenserdeformatopng,jpgogifyseescribenconlaetiqueta<img>entresusprincipalesatributostenemos:

src:LaURIalaimágen.alt:Textoquesedesplegaráencasodequelaimagennoseadesplegada.width:Anchodelaimagen,puedeserescritaenpixelesoenporcentaje.height:Altodelaimagen,puedeserescritaenpixelesoenporcentaje.

Ejemplo:

<imgsrc="html5.gif"alt="HTML5Icon"width="128"height="128">

AnexoA.HTML5

73

LosHipervínculosolinkssondefinidosconlaetiqueta<a>quecuentaconlossiguientesatributos:

href:especificalaURIdedestino.target:especificaendóndeseabriráelnuevodocumentodellink.

_blank:Abreelnuevodocumentoenunanuevaventanaopestaña._self:Abreelnuevodocumentoenelmismoframe(acciónpordefecto)._parent:Abreelnuevodocumentoenelframepadre._top:Abreelnuevodocumentoentodoelcuerpodelaventana.

Ejemplodeunlink:

<ahref="https://www.facebook.com/oca159">Facebook</a>

Dentrodelasetiquetas<a>puedeiruntextoounaimagen.

<ahref="default.asp">

<imgsrc="smiley.gif"alt="HTMLtutorial">

</a>

Loshipervínculostambiénpuedenredireccionaraunsegmentoespecíficodelapáginaweb.

Ejemplo:Primerocreamosunasecciónconunatributoid.

<divid="Encabezado">Seccióndeencabezado</div>

Entoncesagregamosunlinkquenosenvíeaesaseccióndelapágina.Paralograresteobjetivo,agregamosenelatributohrefeliddelasecciónprecedidodeunsigno#.

<ahref="#Encabezado">Visitarlaseccióndeencabezado</a>

AprendermássobreHTML5ParaprofundizarunpocomásenHTML5esrecomendableeltutorialdew3schools.

AnexoA.HTML5

74

CSS3(Hojasdeestiloencascada)EsunlenguajeusadoparadefinirycrearlapresentacióndeundocumentoestructuradoescritoenHTMLoXML.

Laideaessepararelcontenido(Texto)desupresentación(formato).

LainformacióndeestilopuedeserdefinidaenundocumentoseparadooenelmismodocumentoHTML.Enesteúltimocasopodríandefinirseestilosgeneralesenlacabeceradeldocumentooencadaetiquetaparticularmedianteelatributo<style>.

SintaxisUnahojadeestilosecomponedeunalistadereglas.Cadareglaoconjuntodereglasconsisteenunoomásselectoresyunbloquededeclaración(o«bloquedeestilo»)conlosestilosaaplicarparaloselementosdeldocumentoquecumplanconelselectorquelesprecede.Cadabloquedeestilossedefineentrellaves,yestáformadoporunaovariasdeclaracionesdeestiloconelformatopropiedad:valor;.

EnelCSS,losselectoresmarcaránquéelementosseveránafectadosporcadabloquedeestiloquelessiga,ypuedenafectaraunoovarioselementosalavez,enfuncióndesutipo,nombre(name),ID,clase(class),posicióndentrodelDocumentObjectModel,etcétera.

AbajopuedeverseunejemplodeunapartedeunahojadeestilosCSS:

selector[,selector2,...][:pseudo-class][::pseudo-element]{

propiedad:valor;

[propiedad2:valor2;

...]

}

/*comentarios*/

Unconjunodereglasconsisteenunselectoryunbloquededeclaraciones.

AnexoB.CSS

75

FormasdeinsertarCSSennuestrodocumentoHTMLExisten3formasdeinsertarCSS:

Unahojadeestiloexterno(Archivoconextensión.css).Unahojadeestilointerna(DentrodelHTMLocupandoeltag<style>).Estiloinline(usandoelatributostylesobreunelementoHTML).

Hojadeestiloexterna

PodemosescribirnuestroCSSenunarchivodenuestrosistemaconextensión.css,paraincluirunareferenciaalahojadeestiloexternaescribiremoslarutadentrodelatributohrefdelaetiqueta<link>,esconvenienteescribirestadefinicióndentrodelaetiqueta<head>.

<head>

<linkrel="stylesheet"type="text/css"href="mystyle.css">

</head>

Hojadeestilointerna

Unahojadeestilosinternapuedeserusadasiunaúnicapáginatieneunúnicoestilo.

Lashojasdeestilointernassondefinidasdentrodelaetiqueta<style>yenlaseccióndelaetiqueta<head>.

AnexoB.CSS

76

<head>

<style>

body{

background-color:linen;

}

h1{

color:maroon;

margin-left:40px;

}

</style>

</head>

Estilosinline

Unestiloinlinepuedeserusadoparaaplicarunúncioestiloparaunúnicoelementodeunapágina.

Parausarestilosinline,agregamoselatributostylealelementohtml.

<h1style="color:blue;margin-left:30px;">Thisisaheading.</h1>

ComentariosenCSSLoscomentariossonunaformadeexplicarydocumentarelcódigo,puedenserdeutilidadcuandoqueremoseditarelcódigotiempodespués.Loscomentariossonignoradosporelnavegador.

EnCSSuncomentarioempiezacon/*yterminacon*/.

p{

color:red;

/*Thisisasingle-linecomment*/

text-align:center;

}

/*Thisis

amulti-line

comment*/

Selectores

AnexoB.CSS

77

CSS3puedeaplicardiferentesestilosaungrupodeelementosHTMLdependiendoeltipodeselectorqueocupemos,veremoscadaunodeellos.

Selectorporelemento

Seleccionaelementosbasándoseenelnombredelelemento.

Porejemploparaseleccionartodosloselementos<p>deunapáginayaplicarleselestilo:textoalineadoalcentroydecolorrojo.

p{

text-align:center;

color:red;

}

Selectorporid

ElselectorporidutilizaelatributoiddeunelementoHTMLparaespecificarelelementoalqueselevaaaplicarunestilo.

CadaidesunvalorúnicodentrodeunapáginaHTML,porlocuállaselecciónsóloseaplicarásobreunúnicoelementoenparticular.

Paraseleccionarunelementoconunidespecifico,escribeunsignodenumeralogatoseguidoporelvalordeliddelelemento.

LasiguientereglaseaplicaráaunelementoHTMLconelid="dato1".

#dato1{

text-align:center;

color:red;

}

Elnombredeunidjamásempiezaconunnúmero,aligualqueladefinicióndevariablesenloslenguajesdeprogramación.

Selectorporclase

ElselectorporclaseseleccionatodosloselementosHTMLconunatributoclassespecífico.

Paraseleccionarelementosconunaclaseespecífica,escribimosunpuntoseguidoporelnombreelnombredelaclase.

AnexoB.CSS

78

EnelejemplodeabajoseleccionaremostodosloselementosHTMLconclass="center"ylosalinearemosalcentro.

.center{

text-align:center;

color:red;

}

DeigualformaesposibleseleccionarelementosdeuntipoHTMLenespecificoyluegoaquellosconunaclaseenparticular.

Enelejemplodeabajoseleccionaremoslosparrafosconclass="center"ylosalinearemosalcentro.

p.center{

text-align:center;

color:red;

}

Aligualquelosids,lasclasesnodebennombrarseempezandoconunnúmero.

Agruparselectores

Enelcasodequetuvieramosvariosseleccionesqueapliquenelmismoestilo:

h1{

text-align:center;

color:red;

}

h2{

text-align:center;

color:red;

}

p{

text-align:center;

color:red;

}

Podemosreducirelcódigoagrupandolosselectoresseparandocadaselectorporunacoma.

AnexoB.CSS

79

h1,h2,p{

text-align:center;

color:red;

}

AprendermássobreCSS3ParaaprendermássobretodosaspropiedadesyvaloresexistentesenCSS3asícomoguíassobrediseñoresponsivoyotrostemasrecomendamosvisitarlapáginaw3schools.

AnexoB.CSS

80

CreaciondelCRUDconLaraveldesde0EsteanexodellibrodeLaravel5estapensadopararesumirelcontenidodeunaformaaplicada,demodoquesepuedanverenconjuntotodoslosconocimientosadquiridosduranteelcurso.

Seexplicaraelprocesoparadaraltas,bajas,cambiosyconsultasdelatablapastelesoCRUDquesignificaCreate,Read,UpdateandDeleteporsussiglaseningles.

Primeroretomaremoslasmigracionesylosseeders,creandolamigracionyunpequeñoseederparapoblarnuestraBD.

Paracrearlamigracionconlaplantillabasicausaremoselcomando

phpartisanmake:migrationcrear_tabla_pasteles--create=pasteles

Ahoradentrodelamigracionvamosadefinirlaestructuradelatablaquetendrasolocuatrocamposqueseran:id,nombre,saborytimestamps(estoenBDesigualacreated_atyupdated_at).

Dandounresultadocomolosiguiente:

AnexoC.CRUDconLaravel

81

<?php

useIlluminate\Database\Schema\Blueprint;

useIlluminate\Database\Migrations\Migration;

classCrearTablaPastelesextendsMigration

{

/**

*Runthemigrations.

*

*@returnvoid

*/

publicfunctionup()

{

Schema::create('pasteles',function(Blueprint$table){

$table->increments('id');

$table->string('nombre',60);

$table->enum('sabor',['chocolate','vainilla','cheesecake']);

$table->timestamps();

});

}

/**

*Reversethemigrations.

*

*@returnvoid

*/

publicfunctiondown()

{

Schema::drop('pasteles');

}

}

Ahoracrearemoselseederconelcomando:

phpartisanmake:seederPastelesSeeder

yvamosausarelcomponenteFakerparacrear50pastelesdeformaautomatica,elarchivofinalquedaradelasiguienteforma,recuerdenqueparausarFakeresnecesarioimportarlaclaseconlaintruccionuse:

AnexoC.CRUDconLaravel

82

<?php

useIlluminate\Database\Seeder;

useFaker\FactoryasFaker;

classPastelesSeederextendsSeeder

{

/**

*Runthedatabaseseeds.

*

*@returnvoid

*/

publicfunctionrun()

{

$faker=Faker::create();

for($i=0;$i<50;$i++){

\DB::table('pasteles')->insert(array(

'nombre'=>'Pastel'.$faker->firstNameFemale.''.$faker->las

tName,

'sabor'=>$faker->randomElement(['chocolate','vainilla','cheeseca

ke']),

'created_at'=>date('Y-m-dH:m:s'),

'updated_at'=>date('Y-m-dH:m:s')

));

}

}

}

Conestoyatendremoslaestructuradelatablayunseederparapoblar,conestoahorausaremoselsiguientecomandoparacrearlatablaenlaBDyllenarla:

phpartisanmigrate--seed

AhoravamosapasaracrearelModelo,elcualnosvaaservirparamapearlatabladelaBDaunaclasedeLaravelcomolovimosenelcapítulo7.Vamosausarelcomando:

phpartisanmake:modelPastel

Laravelnosrecomiendaseguirlasconvencionesparafacilitarnoseltrabajo,porloquelastablasdelaBasededatosdebenencontrarseennotacionunderscoreyenplural,ylosmodelosdebenencontrarseennotacionUpperCamelCaseyensingular.

ConestoLaravelnoscrearaelarchivoPastel.phpenlacarpetaapp/,siseguimoslasconvencionesdeLaravelpordefectoestoserialouniconecesario,perodebidoaquenuestrolenguajenoconviertelaspalabrasapluraldelamismaformaqueelingles

AnexoC.CRUDconLaravel

83

entoncesdebemosdefiniralmodeloconquetablavaaestartrabajando.Agregaremosdentrodelmodeloelatributoprotected$table='pasteles';,yesoseriatodoparaelmodelo,quedandodelasiguientemanera:

<?php

namespaceCurso;

useIlluminate\Database\Eloquent\Model;

classPastelextendsModel

{

protected$table='pasteles';

}

Yatenemoslistonuestromanejodedatos,ahoravamosaprocederacrearnuestrasvistasparaquedesdeelnavegadorpodamosmandarlainformacionyuncontroladorparapoderdefinirnuestrasoperaciones,ademasdeespecificarlasrutasdenuestrosistema.

Paracomenzarvamosacrearnuestrocontroladorconelcomando:

phpartisanmake:controllerPastelesController

Laravelautomaticamentecreaunarchivodentrodelarutaapp/Http/Controllersconelnombrequeespecificamosydentrodeellasfuncionesparalosmetodos:index,create,store,show,edit,update,delete.Estosmetodoslosvamosadefinirmasadelante,porelmomentovamosacrearennuestroarchivoderutasungrupoderutasasociadasacadaunodelosmetodosdelcontroladorqueacabamosdecrear,estosehaceconunarutadetipoResourceorecurso,modificandoelarchivoroutesagregandoelsiguientecodigo:

Route::resource('pasteles','PastelesController');

Conestoyatendremosnuestrocontrolador(aunvacio)ynuestrasrutasdelsistema,locualpodemosverificarconelcomando:

phpartisanroute:list

Ahoravamosaterminardellenarnuestrocontrolador,debemosimportarlaclasePastelanuestrocontroladorparapoderhacerusodelModeloyasitrabajarconlabasededatos,estoconlaayudadeEloquent,comovimosduranteelcursoparacrearunnuevoregistroconEloquentbastacondefinirunavariabledeunnewModelo,enestecasoPastel,segun

AnexoC.CRUDconLaravel

84

sedescribeenelcapitulo11losmetodosrespondenaunarutaenespecificodelarutaresourcequeagregamosenroutes.php,paraestecasovamosadefinircadaunodeellosenorden:

Index-PaginadeInicio

CuandoentramosaunapaginaprincipaldeadministracionsepuedenverenocasioneslainformacionqueseencuentraenlaBDyaccesoalasoperacionesbasicasdelCRUD,porlocualdebemossercapacesderecibirenelindexlosregistrosdelaBD.Dentroelmetodoindex(),vamosausaEloquentparaobtenertodoslospastelesyenviarlosaunavistaquevamosadefinirmasadelante,quedandodelasiguienteforma:

publicfunctionindex()

{

$pasteles=Pastel::get();

returnview('pasteles.index')->with('pasteles',$pasteles);

}

EloquentnosfacilitamucholasconsultasalaBDyhacequeseaportablenuestrocodigo,enelmetododecimosqueseleccionetodoslospastelesyosenvieaunavistallamaindexubicadaenlacarpetaresoures/views/pasteles/,comovimosenelcapitulo10lasrutasenbladecambianla/(diagonal)porun.(punto),lafuncionview('pasteles.index');tomacomocarpetaraizaresources/views/porloquenotenemoslanecesidaddeagregarloenlaruta.Ademasseestaconcatenandoelmetodowith('nombre',$var);quecomoprimerparametropideelnombreconelcualsevaapoderusarunavariabledelladodelavista,ycomosegundoparametrorecibelavariablequesevaamandaralavista.

Create-Paginaderegistro

EstemetodoesmuysencillopuestoquesolovaadevolverunavistasinningunavariableniusodeEloquent,porlocualquedadelasiguientemanera:

publicfunctioncreate()

{

returnview('pasteles.create');

}

Store-Funciondealmacenamiento

Estemetodoesdondedespuesdehaberentradoacreateserecibenlosdatosyseguardanenlabasededatos,parapoderrecibirlainformacionenesteejemplovamosausarlaclaseRequestquesignificapeticionyesunaclasequeLaravelagregapornosotros

AnexoC.CRUDconLaravel

85

cuandocreamoselcontrolador,vamosapasarporparametrolapeticionenelmetododefiniendoqueesunavariabledelaclaseRequestydespuesdeesopodemosrecuperarporelnombredelcampodelformulario(atributoname)lainformacionenviada,entonceselmetodoquedariadelasiguienteforma:

publicfunctionstore(Request$request)

{

$pastel=newPastel;

$pastel->nombre=$request->input('nombre');

$pastel->sabor=$request->input('sabor');

$pastel->save();

returnredirect()->route('pasteles.index');

}

EnlafuncionestamoscreandounainstanciadeunnuevoPastelyasignandolosatributosdelaclasequesellamanigualqueloscamposdelaBDlosvaloresdelformularioconlavariablerequestyelmetodoinput('name');querecibecomoparametroelnombredelcampodelformulario,paramasdetallereviselasecciondelAnexoAdeHTMLquehablasobrelosatributosdelosformularios.

Despuesdeasignarlosvaloresdelapeticionalavariable$pastel,seusaelmetodosave();paraqueelmodeloseencarguedeguardarlosdatosenlaBDyfinalmenteredireccionaralindexconlosmetodosencadenados:redirect()->route('pasteles.index');.

Show-Paginadedescripcion

Losentimos,seccionendesarrollo.

Edit-Paginadeedicion

Lafunciondeeditessimilaraladecreatepuessolomuestraunavista,conunapequeñadiferencia,lacualesquesevaabuscarelpastelquesequiereeditarysevaamandaralavista,estoesobiopuesdebemospoderverlainformacionquevamosaeditar.Lafuncionquedariadelasiguienteforma:

publicfunctionedit($id)

{

$pastel=Pastel::find($id);

returnview('pasteles.edit')->with('pastel',$pastel);

}

AnexoC.CRUDconLaravel

86

Esmuyclaro,enunavariableseguardaelpastel,graciasalmodeloestosesolucionafacilmenteconelmetodofind(),eliddelpastelsemandaenlaurl,ahorabiensiestoespreocupantepuestoqueelidsevedirectamenteenlaURLrecordemosqueestonomodificaaun,solonosmandaalapaginaquevaapoderhacerunanuevapeticionparaactualizar.

Update-Funciondeactualizacion

Bien,despuesdeentrarenlapaginadeeditvamosapodereditarlainformacionyregresarlaalcontroladorparaqueefectueloscambios,dentrodelmetodoupdatevamosarecuperarnuevamenteelPastelpormediodesuidquetambienvaenlaurlyserecibecomoparametrodelafuncion,ademasvamosaagregarotroparametroqueseraelRequestaligualqueenlafuncioncreatepararecuperarlainformaciondelladodelclienteenelcontrolador,dejandolafunciondeestaforma:

publicfunctionupdate(Request$request,$id)

{

$pastel=Pastel::find($id);

$pastel->nombre=$request->input('nombre');

$pastel->sabor=$request->input('sabor');

$pastel->save();

returnredirect()->route('pasteles.index');

}

Estafuncionessimilaraladecreatelounicoquecambiaesqueenvezdecrearunnuevopastelvamosarecuperarunoexistenteycambiarsusatributos.

Destroy-Funciondeborrado

EstemetodotienelafunciondeeliminarelregistrodelaBD,peroparaefectuarlotenemosdosopciones,laprimerforma:crearunavariable$pastelydespuesusarelmetododelete()deEloquent.obienlasegunda:directamentedelmodelousarelmetododeEloquentdestroy($id),queseencargadedirectamentebuscaryeliminarelregistro,finalmentevamosaredirigiralindex,elmetodoalfinalquedaradelasiguienteforma:

AnexoC.CRUDconLaravel

87

//Estaeslaprimeropcion

publicfunctiondestroy($id)

{

$pastel=Pastel::find($id);

$pastel->delete();

returnredirect()->route('pasteles.index');

}

//Estaeslasegundaopcion

publicfunctiondestroy($id)

{

Pastel::destroy($id);

returnredirect()->route('pasteles.index');

}

VistasdelCRUDEstassonlaultimapartequevamosacrear,primerodebemosprepararlosdirectoriosylosarchivosqueusaremos.

Laestructuradelacarpetaquedariadelasiguienteforma:

resources/

views/

pasteles/

partials/

fields.blade.php

table.blade.php

create.blade.php

edit.blade.php

index.blade.php

UsaremoseltemplatepordefectodeLaravelllamadoapp.blade.phpquefuimosmodificandoduranteelcursoporlocualsolodeberemoscrearlosarchivosrestantes.

Ahoraenelarchivoapp.blade.phpvamosamodificarloparaqueelcontenidoestemejoracomodadousandoBootstrapyvamosaagregarlosestilosyscriptsparaquelatabladondevamosamostrarelcontenidofuncionecomounDataTable,dejandoelarchivoappdelasiguienteforma:

TemplateApp

AnexoC.CRUDconLaravel

88

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8">

<metahttp-equiv="X-UA-Compatible"content="IE=edge">

<metaname="viewport"content="width=device-width,initial-scale=1">

<title>Laravel</title>

@section('styles_laravel')

{!!Html::style('assets/css/bootstrap.css')!!}

{!!Html::style('assets/css/datatable-bootstrap.css')!!}

<!--Fonts-->

<linkhref='//fonts.googleapis.com/css?family=Roboto:400,300'rel='stylesheet'type

='text/css'>

@show

@yield('my_styles')

</head>

<body>

@include('partials.layout.navbar')

@include('partials.layout.errors')

<divclass="container">

<divclass="row">

<divclass="col-md-10col-md-offset-1">

@yield('content')

</div>

</div>

</div>

<!--Scripts-->

{!!Html::script('assets/js/jquery.js')!!}

{!!Html::script('assets/js/jquery.dataTables.js')!!}

{!!Html::script('assets/js/bootstrap.min.js')!!}

{!!Html::script('assets/js/datatable-bootstrap.js')!!}

<script>

$(document).ready(function(){

$('#MyTable').dataTable();

});

</script>

@yield('my_scripts')

</body>

</html>

Loscambiosmasnotoriosquepodemosobservaresqueel@yield('content')semetiodentrodeunacolumnaconunoffset,esodentrodeunafilaytododentrodeuncontenedor.Asinuestrocontenidonolovamosatenertodopegadoalaizquierdadenuestronavegador.

Nota:parapoderhacerestosoNnecesarioslosarchivosqueseincluyenconblade,sinolosagreganlatablaseveramassencillaperoestonoquieredecirquenovaafuncionar,yasoloescuestiondeestilo,siquierenobtenerlosarchivosdejamosloslinksacontinuacion

AnexoC.CRUDconLaravel

89

paraquelosdescarguenylosguardendentrodelacarpetarespectiva,esdecirlosCSSenpublic/assets/css/ylosJSdentrodepublic/assets/js/:

EstilosparaelDataTable:datatable-bootstrap.css.

ArchivoJQuery:jquery.js.

ArchivoJQueryparaDataTable:jquery.dataTables.js.

ArchivoJQueryparaDataTabledebootstrap:datatable-bootstrap.js.

Nota:tambienlesinvitoaverelanexodeDataTableparamayorinformacion.

VistaIndex

Estavistaserefierealarchivoindex.blade.phpdentrodelacarpetaresources/views/pasteles/,aquivamosamostrarlatablayunbotonparacrearnuevospasteles.Ahorabienparaestodebemostenernuestropartialdelatabla,masadelantelovamosamostrarperoporelmomentoelarchivoindexquedariadelasiguienteforma:

@extends('app')

@section('content')

<aclass="btnbtn-successpull-right"href="{{url('/pasteles/create')}}"role="b

utton">Nuevopastel</a>

@include('pasteles.partials.table')

@endsection

Recuerdenquegraciasabladenuestrasvistasquedandetamañospequeñosmasfacilesdeentender,aquisoloestamosheredandolaplantillaappydefiniendolaseccioncontentconunlinkqueledaremosestilodebotonconlarutaparamostrarlavistadecrearpasteles,ademasdeimportarnuestratabla,elarchivopartiallodefiniremosahora.

Partials:tableyfields

Table

EstosarchivoslostrabajaremosenpartialsporcomodidadyporquesoncomponentesdeunsistemaWebquesuelenrepetirseconstantemente,empezaremosporeltable.

Primerorecordemosunpocodelpasado,ennuestrocontroladorenelmetodoindexdefinimosqueretornarialavistaindexjuntoconunavariablellamada$pastelesqueconteneriatodoslospastelesdelsistema,ahorabienesospasteleslosvamosavaciarenla

AnexoC.CRUDconLaravel

90

tablapuessibiennoespecificamosqueesavariablevaallegaralpartialtablecomoloestamosincluyendoenelindextambiencompartelasvariablesquetengaindex,entonceselenviopuedeversedelasiguientemanera:

Entoncesvamosausarunforeachconblade,parallenarelcontenidodelatablaconlosatributosdelospasteles,dejandoelarchivoasi:

AnexoC.CRUDconLaravel

91

<h1class="text-primary">ControldePasteles</h1>

<tableclass="tabletable-bordered"id="MyTable">

<thead>

<tr>

<thclass="text-center">ID</th>

<thclass="text-center">Nombre</th>

<thclass="text-center">Sabor</th>

<thclass="text-center">Fecha</th>

<thclass="text-center">Acciones</th>

</tr>

</thead>

<tbody>

@foreach($pastelesas$pastel)

<tr>

<tdclass="text-center">{{$pastel->id}}</td>

<tdclass="text-center">{{$pastel->nombre}}</td>

<tdclass="text-center">{{$pastel->sabor}}</td>

<tdclass="text-center">{{$pastel->created_at}}</td>

{!!Form::open(['route'=>['pasteles.destroy',$pastel->id],'method'=>'DEL

ETE'])!!}

<tdclass="text-center">

<buttontype="submit"class="btnbtn-dangerbtn-xs">

<spanclass="glyphiconglyphicon-remove"aria-hidden="true"></span

>

</button>

<ahref="{{url('/pasteles/'.$pastel->id.'/edit')}}"class="btnbtn-i

nfobtn-xs">

<spanclass="glyphiconglyphicon-edit"aria-hidden="true"></span>

</a>

</td>

{!!Form::close()!!}

</tr>

@endforeach

</tbody>

<tfoot>

<tr>

<thclass="text-center">ID</th>

<thclass="text-center">Nombre</th>

<thclass="text-center">Sabor</th>

<thclass="text-center">Fecha</th>

<thclass="text-center">Acciones</th>

</tr>

</tfoot>

</table>

AnexoC.CRUDconLaravel

92

Laestructuradelatablalapuedenverenestelink,peroloimportanteestadentrodel<tbody>,endondeconBLADEvamosausarunforeachdiciendoqueparacadapasteldentrodelavariable$pastelesquellegodelcontroladorsevanavaciarsusdatosdentrodelafiladelatabla,primerovamosaagregarsuid,nombreyfechadecreacion,perosevaaagregarunacolumnadeaccionesquecontengadosbotones,unoparaeliminareseregistroyotroparaeditarlo,elbotondeeliminardebeserdetiposubmitparaenviarlapeticionDELETEyparaestoesqueseabreunformularioconlaclaseForm::deLaravel,paraqueasiquedesintaxismaslegible,agregamosloscamposnecesariosquesonlarutayelmetododelformulario;paraelbotondeeditbastaconunlink<a>queconlafuncionurl()deLaravellavamosadirigirconelIDdecadapastel.

Nota:Bootstrapnospermiteteneradisposicioniconosparaquelosbotonesdenuestrasaccionesseveanmasprofesionales,porlocualesloqueseagregaeltag<span>,paramasinformacioniralapaginaoficialdeBootstrap.

ConestodebemossercapacesdepoderverahoranuestratablacomounDataTable(encasodehaberagregadolonecesario)llenaconlainformaciondepasteles:

Fields

Ahoravamosacrearunpartialsconloscamposquevaarequerirnuestroproyecto,sibiensabemosesnecesariopediralusuarioelnombreysabordelpastel,perolafechadecreacionyultimaactualizacionsoncamposqueLaravelponeautomaticamentecuandoseejecutaelmetodosave()enelcontrolador,porlocualnuestropartialsolodeberatenerdoscamposdeentradayunbotonparaenviarlasolicitud.

Entoncesparaestearchivosolovamosaagregarcomosunombreloindicaloscamposdeentradaparaunpaste,dejandolodelasiguienteforma:

AnexoC.CRUDconLaravel

93

<divclass="form-group">

{!!Form::label('nombre','Nombre',['for'=>'nombre'])!!}

{!!Form::text('nombre',null,['class'=>'form-control','id'=>'nombre','pla

ceholder'=>'Escribeelnombredelpastel...'])!!}

</div>

<divclass="form-group">

{!!Form::label('sabor','Sabor',['for'=>'sabor'])!!}

<selectname="sabor"class="form-control">

<optionvalue=""disabledselected>Eligeunsabor...</option>

<optionvalue="chocolate">Chocolate</option>

<optionvalue="vainilla">Vainilla</option>

<optionvalue="cheesecake">Cheesecake</option>

</select>

</div>

SibienlaclaseForm::nosehaexplicadodetalladamentedejoellinkdeladocumentacionoficialdeLaravel,aunqueseencuentraensuversion4.2esdebidoaqueparalasversionesmasactualesnoseencuentraexplicada,perosiguesiendocompletamentecompatibleconLaravel5y5.1.

Conestepartialvamosapoderllamarloscamposdeentradaparacrearoeditarunpastel.

VistaCreate

Enestavistaaligualqueelindexquedaramuycorta:

@extends('app')

@section('content')

{!!Form::open(['route'=>'pasteles.store','method'=>'POST'])!!}

@include('pasteles.partials.fields')

<buttontype="submit"class="btnbtn-successbtn-block">Guardar</button>

{!!Form::close()!!}

@endsection

Extendemosdeltemplateapp,definimoselcontenidoabriendounformularioperocomosetratadeunalmacenamientoelmetodosevaatrabajarconstoreyPOST,dentrovamosaincluirelpartialdefieldsparatenerloscamposdetexto,elmenudeopcionesyunbotondetiposubmitparamandarlapeticion.

Deberiaquedarunresultadosimilaraeste:

AnexoC.CRUDconLaravel

94

VistaEdit

AlteneryalistosnuestrosarchivosHTMLlavistadeeditsecreadelamismaformaqueladecreateconladiferenciadequeenvezdeabrirunformulariovamosaabrirunmodelo,esdeirvamosaabrirelobjetoqueseenviodelcontroladoralavistaparapodereditarloscampos,comoobservacionpodrannotarcuandoloejecutenenelnavegadorqueunselectnoseasignaautomaticamenteenvaloranterior,porelmomentovamosavercomoquedarialavista:

@extends('app')

@section('content')

<h4class="text-center">EditarPastel:{{$pastel->nombre}}</h4>

{!!Form::model($pastel,['route'=>['pasteles.update',$pastel],'method'=>'P

UT'])!!}

@include('pasteles.partials.fields')

<buttontype="submit"class="btnbtn-successbtn-block">Guardarcambios</butto

n>

{!!Form::close()!!}

@endsection

Aligualquelasdemasvistasseestaheredadndodeappyseagregauntituloparasaberquepastelseestaeditando,peroelForm::model()abrenuestravariable$pastelqueenviamosdesdeelcontroladorycreaunformulariollenoapartirdelosvaloresdelmodelo,claroqueestosoloparaloscamposquecoincidanconlosnombresdelosatributosdelmodelo.

Elresultadoseriaalgosimilaraesto:

AnexoC.CRUDconLaravel

95

YconestoquedariannuestrasvistasdelsistematerminadasyelCRUDbasicodelosPastelesfinalizadotambien,paramasinformacionpuedenretomarloscapitulosdeestelibroparaanalizarlasdiferentesopcionesquetenemospararesolveresteejemplopuesestaessolounapropuesta,nounasoluciondefinitiva.

nota:Lasecciondeshownosehacontempladoparaesteanexoconunavista,disculpenlasmolestias.

AnexoC.CRUDconLaravel

96

DataTableLosDataTablessonunplug-inparalalibreríaJQuerydeJavascript.Nospermitenunmayorcontrolsobreunelemento<table>deHTML.Algunasdesuscaracteristicasprincipalesson:

PaginaciónautomáticaBúsquedainstantáneaOrdenamientomulticolumnaSoportaunagrancantidaddedatosfuente.

DOM(ConvertirunelementoHTML<table>enunDataTable).Javascript(UnarreglodearreglosenJavascriptpuedesereldatasetdeunDataTable).AJAX(UnDataTablepuedeleerlosdatosdeunatabladeunjsonobtenidovíaAJAX,eljsonpuedeserservidomedianteunWebServiceomedianteunarchivo.txtquelocontenga).Procesamientodelladodelservidor(UnDataTablepuedesercreadomediantelaobtencióndedatosdelprocesamientodeunscriptenelladodelservidor,estescriptcomúnmentetendráinteracciónconlabasededatos).

HabilitartemasCSSparaelDataTablefácilmente.CrearuntemaTemaJQueryUITemaBootstrapTemaFoundation

Ampliavariedaddeextensiones.Altamenteinternacionalizable.Esopensource(CuentaconunalicenciaMIT).

¿CómousarDataTables?Paraocupardatablestenemosdosformas:

Descargarelcódigofuentedelosarchivosjsycssdedatatablesenelsiguientelink.OcuparunCDN

CSS//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.cssJS//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js

UsarDataTabledescargandoelcódigofuente

AnexoD.ComponenteDatatable

97

Antesquenadadebemostenerdescargadojquery,elcuálpodemosdescargardeaquí.UnavezquehemosdescargadolosarchivoscssyjsdeDataTablesdeestelinkdebemosextraerelcontenidoyubicarlosarchivosenlacarpetacssyjscorrespondientedentrodeldirectoriopublicdeLaravel.

Ejemplo:

public/

assets/

css/

datatable-bootstrap.css

js/

datatable-bootstrap.js

jquery.dataTables.js

jquery.js

LosiguienteseráhacerunareferenciadelosscriptyarchivoscssdentrodenuestrodocumentoHTML.

Losscriptlosubicaremosdentrodelaetiqueta<body>perohastaelfinaldelamisma.

<body>

<!--Contenido-->

<!--Scripts-->

{!!Html::script('assets/js/jquery.js')!!}

{!!Html::script('assets/js/jquery.dataTables.js')!!}

{!!Html::script('assets/js/bootstrap.min.js')!!}

{!!Html::script('assets/js/datatable-bootstrap.js')!!}

<script>

$(document).ready(function(){

$('#MyTable').dataTable();

});

</script>

</body>

Enelejemplodearribaestamosindicandoquelatablaconelid#MyTableseráunelementodetipodataTable.LaobtencióndedatoslahacemosmedianteelDOM.

Porotrolado,losarchivosparatemasdeldatatablelosubicaremosdentrodelaetiqueta<head>denuestrodocumentoHTML.

<head>

<!--MásarchivosCSS-->

{!!Html::style('assets/css/datatable-bootstrap.css')!!}

</head>

AnexoD.ComponenteDatatable

98

DeestaformahemosconseguidocrearnuestroprimerDataTable.

CrearunDataTableExistendiversasformasdellenarunDataTablecondatos,veremosalgunasdelasmásusadas.

OcupandoelDOM(etiqueta<table>)OcuparemosunatablaHTMLconunid="example",posteriormenteconvertiremoslatablaenunDataTablemedianteunscript.

HTMLdelatabla

ElcódigoJavascriptparaconvertirlatablaconid="example"enunDataTablees:

$(document).ready(function(){

$('#example').dataTable();

});

OcupandoundatasetenJavacriptUnarreglodearreglosenJavascriptpuedesereldatasetdeunDataTable.

Javascriptdeldataset

Unavezdefinidoeldatasetbastaráconejecutarlasiguientefunciónparacrearunatableenundivconid="demo"ennuestroHTML.

AnexoD.ComponenteDatatable

99

$(document).ready(function(){

$('#demo').html('<tablecellpadding="0"cellspacing="0"border="0"class="display

"id="example"></table>');

$('#example').dataTable({

"data":dataSet,

"columns":[

{"title":"Engine"},

{"title":"Browser"},

{"title":"Platform"},

{"title":"Version","class":"center"},

{"title":"Grade","class":"center"}

]

});

});

ElcódigoHTMLeselsiguiente:

<html>

<head>

</head>

<body>

<divid="demo">

</div>

</body>

</html>

OcupandoAJAXUnDataTablepuedeleerlosdatosdeunatabladeunjsonobtenidovíaAJAX,eljsonpuedeserservidomedianteunWebServiceomedianteunjson.txtquelocontenga.

ElarchivoJSON

ElcódigoJavascriptparalacreacióndeDataTableocupandoeljson.

$(document).ready(function(){

$('#example').dataTable({

"ajax":'json.txt'

});

});

ElarchivoHTMLcontieneunatablaconunid="example".

AnexoD.ComponenteDatatable

100

<tableid="example"class="display"cellspacing="0"width="100%">

<thead>

<tr>

<th>Name</th>

<th>Position</th>

<th>Office</th>

<th>Extn.</th>

<th>Startdate</th>

<th>Salary</th>

</tr>

</thead>

<tfoot>

<tr>

<th>Name</th>

<th>Position</th>

<th>Office</th>

<th>Extn.</th>

<th>Startdate</th>

<th>Salary</th>

</tr>

</tfoot>

</table>

InternacionalizarundataTableEsposiblecambiarelidiomadelasetiquetasdeundatatablesibajamoselarchivodelatraducciónenelsiguientelink.

ParaocuparlotenemosquehacerreferenciaenlafuncióndelacreacióndelDataTable:

<scripttype="text/javascript"src="jquery.dataTables.js"></script>

<scripttype="text/javascript">

$(document).ready(function(){

$('#example').dataTable({

"language":{

"url":"dataTables.spanish.lang"

}

});

});

</script>

FiltrardatosdeunDataTable

AnexoD.ComponenteDatatable

101

PodemosocuparelcampodetextodebúsquedadelDataTableybuscarbajodiferentescríteriosseparandoporunespacioenblanco.

Ejemplo:

ParabuscarunadministradorcuyonombreempiececonlaletraOysuteléfonoseaextensión228,podemosponeradministradorO228

AnexoD.ComponenteDatatable

102