Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
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