table of contents - webtech · 2019. 2. 18. · conexión con bases de datos laravel tiene soporte...
TRANSCRIPT
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