Upload
others
View
12
Download
0
Embed Size (px)
Citation preview
Laravel:UpandRunningAFrameworkforBuildingModernPHPApps
MattStauffer
Laravel:UpandRunningbyMattStauffer
Copyright©2017MattStauffer.Allrightsreserved.
PrintedintheUnitedStatesofAmerica.
PublishedbyO’ReillyMedia,Inc.,1005GravensteinHighwayNorth,Sebastopol,CA95472.
O’Reillybooksmaybepurchasedforeducational,business,orsalespromotionaluse.Onlineeditionsarealsoavailableformosttitles(http://oreilly.com/safari).Formoreinformation,contactourcorporate/institutionalsalesdepartment:[email protected].
Editor:AllysonMacDonald
ProductionEditor:ColleenLobner
Copyeditor:RachelHead
Proofreader:KimCofer
Indexer:AngelaHoward
InteriorDesigner:DavidFutato
CoverDesigner:RandyComer
Illustrator:RebeccaDemarest
December2016:FirstEdition
http://oreilly.com/safari
RevisionHistoryfortheFirstEdition2016-11-14:FirstRelease
Seehttp://oreilly.com/catalog/errata.csp?isbn=9781491936085forreleasedetails.
TheO’ReillylogoisaregisteredtrademarkofO’ReillyMedia,Inc.Laravel:UpandRunning,thecoverimageofagemsbok,andrelatedtradedressaretrademarksofO’ReillyMedia,Inc.
Whilethepublisherandtheauthorhaveusedgoodfaitheffortstoensurethattheinformationandinstructionscontainedinthisworkareaccurate,thepublisherandtheauthordisclaimallresponsibilityforerrorsoromissions,includingwithoutlimitationresponsibilityfordamagesresultingfromtheuseoforrelianceonthiswork.Useoftheinformationandinstructionscontainedinthisworkisatyourownrisk.Ifanycodesamplesorothertechnologythisworkcontainsordescribesissubjecttoopensourcelicensesortheintellectualpropertyrightsofothers,itisyourresponsibilitytoensurethatyourusethereofcomplieswithsuchlicensesand/orrights.
978-1-491-93608-5
[LSI]
http://oreilly.com/catalog/errata.csp?isbn=9781491936085
DedicationThisbookisdedicatedtomygraciousandinspiringwife,Tereva,myjoyfulandcourageousson,Malachi,andmybeautifuldaughter,Mia,whospentthemajorityofthisbook’screationinhermama’sbelly.
Preface
ThestoryofhowIgotstartedwithLaravelisacommonone:IhadwrittenPHPforyears,butIwasonmywayoutthedoor,pursuingthepowerofRailsandothermodernwebframeworks.Railsinparticularhadalivelycommunity,aperfectcombinationofopinionateddefaultsandflexibility,andthepowerofRubyGemstoleverageprepackagedcommoncode.
Somethingkeptmefromjumpingship,andIwasgladforthatwhenIfoundLaravel.ItofferedeverythingIwasdrawntoinRails,butitwasn’tjustaRailsclone;thiswasaninnovativeframeworkwithincredibledocumentation,awelcomingcommunity,andclearinfluencesfrommanylanguagesandframeworks.
SincethatdayI’vebeenabletosharemyjourneyoflearningLaravelthroughbloggingandspeakingatconferences;I’vewrittendozensofappsinLaravelforsideandworkprojects,andI’vemetthousandsofLaraveldevelopersonlineandinperson.Ihaveplentyoftoolsinmytoolkitatourconsultancy,butIamhonestlyhappiestwhenIsitdowninfrontofacommandlineandtypelaravelnewproject.
WhatThisBookIsAboutThisisnotthefirstbookaboutLaravel,anditwon’tbethelast.Idon’tintendforthistobeabookthatcoverseverylineofcodeoreveryimplementationpattern.Idon’twantthistobethesortofbookthatgoesoutofdatewhenanewversionofLaravelisreleased.Instead,itsprimarypurposeistoprovidedeveloperswithahigh-leveloverviewandconcreteexamplestolearnwhattheyneedtogetstarted,asquicklyaspossible.Ratherthanmirroringthedocs,IwanttohelpyouunderstandthefoundationalconceptsbehindLaravel.
LaravelisapowerfulandflexiblePHPframework.Ithasathrivingcommunityandawideecosystemoftools,andasaresultit’sgrowinginappealandreach.ThisbookisfordeveloperswhoalreadyknowhowtomakewebsitesandapplicationsandwanttoquicklylearnhowtodosoinLaravel.
Laravel’sdocumentationisthoroughandexcellent.IfyoufindthatIdon’tcoveranyparticulartopicdeeplyenoughforyourliking,Iencourageyoutovisittheonlinedocumentationanddigdeeperintothatparticulartopic.
Ithinkyouwillfindthebookacomfortablebalancebetweenhigh-levelintroductionandconcreteapplication,andbytheendyoushouldfeelcomfortablewritinganentireapplicationinLaravel,fromscratch.And,ifIdidmyjobwell,you’llbeexcitedtotry.
http://laravel.com/docs
WhoThisBookIsForThisbookassumesknowledgeofbasicobject-orientedprogrammingpractices,PHP(oratleastthegeneralsyntaxofC-familylanguages),andthebasicconceptsoftheModel–View–Controller(MVC)patternandtemplating.Ifyou’venevermadeawebsitebefore,youmayfindyourselfinoveryourhead.Butaslongasyouhavesomeprogrammingexperience,youdon’thavetoknowanythingaboutLaravelbeforeyoureadthisbook—we’llcovereverythingyouneedtoknow,fromthesimplest“Hello,world!”
Laravelcanrunonanyoperatingsystem,buttherewillbesomeBash(shell)commandsinthebookthatareeasiesttorunonLinux/MacOS.WindowsusersmayhaveahardertimewiththesecommandsandwithmodernPHPdevelopment,butifyoufollowtheinstructionstogetHomestead(aLinuxvirtualmachine)running,you’llbeabletorunallofthecommandsfromthere.
HowThisBookIsStructuredThisbookisstructuredinwhatIimaginetobeachronologicalorder:ifyou’rebuildingyourfirstwebappwithLaravel,theearlychapterscoverthefoundationalcomponentsyou’llneedtogetstarted,andthelaterchapterscoverlessfoundationalormoreesotericfeatures.
Eachsectionofthebookcanbereadonitsown,butforsomeonenewtotheframework,I’vetriedtostructurethechapterssothatit’sactuallyveryreasonabletostartfromthebeginningandreaduntiltheend.
Whereapplicable,eachchapterwillendwithtwosections:“Testing”and“TL;DR.”Ifyou’renotfamiliar,TL;DRmeans“toolong;didn’tread.”Thesefinalsectionswillshowyouhowtowritetestsforthefeaturescoveredineachchapterandgiveahigh-leveloverviewofwhatwascovered.
ThebookiswrittenforLaravel5.3,butbecauseLaravel5.1isthelatestLTSrelease,anyfeaturesthatarenewin5.2or5.3willbeidentified.
ConventionsUsedinThisBookThefollowingtypographicalconventionsareusedinthisbook:
ItalicIndicatesnewterms,URLs,emailaddresses,filenames,andfileextensions.
Constantwidth
Usedforprogramlistings,aswellaswithinparagraphstorefertoprogramelementssuchasvariableorfunctionnames,databases,datatypes,environmentvariables,statements,andkeywords.
Constantwidthbold
Showscommandsorothertextthatshouldbetypedliterallybytheuser.
Constantwidthitalic
Showstextthatshouldbereplacedwithuser-suppliedvaluesorbyvaluesdeterminedbycontext.
TIPThiselementsignifiesatiporsuggestion.
NOTEThiselementsignifiesageneralnote.
WARNINGThiselementindicatesawarningorcaution.
O’ReillySafariNOTE
Safari(formerlySafariBooksOnline)ismembership-basedtrainingandreferenceplatformforenterprise,government,educators,andindividuals.
Membershaveaccesstothousandsofbooks,trainingvideos,LearningPaths,interactivetutorials,andcuratedplaylistsfromover250publishers,includingO’ReillyMedia,HarvardBusinessReview,PrenticeHallProfessional,Addison-WesleyProfessional,MicrosoftPress,Sams,Que,PeachpitPress,Adobe,FocalPress,CiscoPress,JohnWiley&Sons,Syngress,MorganKaufmann,IBMRedbooks,Packt,AdobePress,FTPress,Apress,Manning,NewRiders,McGraw-Hill,Jones&Bartlett,andCourseTechnology,amongothers.
Formoreinformation,pleasevisithttp://oreilly.com/safari.
http://oreilly.com/safarihttp://oreilly.com/safari
HowtoContactUsPleaseaddresscommentsandquestionsconcerningthisbooktothepublisher:
O’ReillyMedia,Inc.
1005GravensteinHighwayNorth
Sebastopol,CA95472
800-998-9938(intheUnitedStatesorCanada)
707-829-0515(internationalorlocal)
707-829-0104(fax)
Wehaveawebpageforthisbook,wherewelisterrata,examples,andanyadditionalinformation.Youcanaccessthispageathttp://bit.ly/laravel-up-and-running.
Tocommentorasktechnicalquestionsaboutthisbook,[email protected].
Formoreinformationaboutourbooks,courses,conferences,andnews,seeourwebsiteathttp://www.oreilly.com.
FindusonFacebook:http://facebook.com/oreilly
FollowusonTwitter:http://twitter.com/oreillymedia
WatchusonYouTube:http://www.youtube.com/oreillymedia
http://bit.ly/laravel-up-and-runningmailto:[email protected]://www.oreilly.comhttp://facebook.com/oreillyhttp://twitter.com/oreillymediahttp://www.youtube.com/oreillymedia
AcknowledgmentsThisbookwouldnothavehappenedwithoutthegracioussupportofmyamazingwifeTerevaortheunderstanding(“Daddy’swriting,buddy!”)ofmysonMalachi.Andwhileshewasn’texplicitlyawareofit,mydaughterMiawasaroundforalmosttheentirecreationofthebook,sothisbookisdedicatedtothewholefamily.Thereweremany,manylongeveninghoursandweekendStarbuckstripsthattookmeawayfrommyfamily,andIcouldn’tbemoregratefulfortheirsupportandalsotheirpresencejustmakingmylifeawesome.
Additionally,theentireTightenCo.familyhassupportedandencouragedmethroughthewritingofthebook,severalevenediting(KeithDamiani,editorextraordinaire)andhelpingmewithchallengingcodesamples(AdamWathan,KingoftheCollectionPipeline).DanSheetz,mypartnerinTightencrime,hasbeengraciousenoughtowatchmewhileawaymanyaworkhourcrankingonthisbookandwasnothingbutsupportiveandencouraging;andDaveHicking,ouroperationsmanager,helpedmearrangemyscheduleandworkresponsibilitiesaroundwritingtime.
TaylorOtwelldeservesthanksandhonorforcreatingLaravel—andthereforecreatingsomanyjobsandhelpingsomanydevelopersloveourlivesthatmuchmore.Hedeservesappreciationforhowhe’sfocusedondeveloperhappinessandhowhardhe’sworkedtohaveempathyfordevelopersandtobuildapositiveandencouragingcommunity.ButIalsowanttothankhimforbeingakind,encouraging,andchallengingfriend.Taylor,you’reaboss.
ThankstoJeffreyWay,whoIstillcontendtobeoneofthebestteachersontheInternet.HeoriginallyintroducedmetoLaravelandstillintroducesmorepeopleeveryday.He’salso,unsurprisingly,afantastichumanbeingwhomI’mgladtocallafriend.
ThankyoutoJessD’Amico,ShawnMcCool,IanLandsman,andTaylorforseeingvalueinmeasaconferencespeakerearlyonandgivingmeaplatformtoteachfrom.ThankstoDayleReesformakingitsoeasyforsomanytolearnLaravelintheearlydays.
ThankstoeverypersonwhoputtheirtimeandeffortintowritingblogpostsaboutLaravel,especiallyearlyon:EricBarnes,ChrisFidao,MattMachuga,JasonLewis,RyanTablada,DriesVints,MaksSurguy,andsomanymore.
AndthankstotheentirecommunityoffriendsonTwitter,IRC,andSlackwho’veinteractedwithmeovertheyears.IwishIcouldnameeveryname,butIwouldmisssomeandthenfeelawfulaboutmissingthem.Youallarebrilliant,andI’mhonoredtogettointeractwithyouonaregularbasis.
ThankstomyO’Reillyeditor,AllyMacDonald,andallofmytechnicaleditors:KeithDamiani,MichaelDyrynda,AdamFairholm,andMylesHyson.
And,ofcourse,thankstotherestofmyfamilyandfriends,whosupportedmedirectlyorindirectlythroughthisprocess—myparentsandsiblings,theGainesvillecommunity,otherbusinessownersandauthors,otherconferencespeakers,andtheinimitableDCB.Ineedto
stopwritingbecausebythetimeIrunoutofspacehereI’llbethankingmyStarbucksbaristas.
Chapter1.WhyLaravel?
Intheearlydaysofthedynamicweb,writingawebapplicationlookedalotdifferentthanitdoestoday.Developersthenwereresponsibleforwritingthecodefornotjusttheuniquebusinesslogicofourapplications,butalsoeachofthecomponentsthataresocommonacrosssites—userauthentication,inputvalidation,databaseaccess,templating,andmore.
Today,programmershavedozensofapplicationdevelopmentframeworksandthousandsofcomponentsandlibrarieseasilyaccessible.It’sacommonrefrainamongprogrammersthat,bythetimeyoulearnoneframework,threenewer(andpurportedlybetter)frameworkshavepoppedupintendingtoreplaceit.
“Justbecauseit’sthere”mightbeavalidjustificationforclimbingamountain,buttherearebetterreasonstochoosetouseaspecificframework—ortouseaframeworkatall.It’sworthaskingthequestion:whyframeworks?Morespecifically,whyLaravel?
WhyUseaFramework?It’seasytoseewhyit’sbeneficialtousetheindividualcomponents,orpackages,thatareavailabletoPHPdevelopers.Withpackages,someoneelseisresponsiblefordevelopingandmaintaininganisolatedpieceofcodethathasawell-definedjob,andintheorythatpersonhasadeeperunderstandingofthissinglecomponentthanyouhavetimetohave.
FrameworkslikeLaravel—andSymfony,Silex,Lumen,andSlim—prepackageacollectionofthird-partycomponentstogetherwithcustomframework“glue”likeconfigurationfiles,serviceproviders,prescribeddirectorystructures,andapplicationbootstraps.So,thebenefitofusingaframeworkingeneralisthatsomeonehasmadedecisionsnotjustaboutindividualcomponentsforyou,butalsoabouthowthosecomponentsshouldfittogether.
“I’llJustBuildItMyself”Let’ssayyoustartanewwebappwithoutthebenefitofaframework.Wheredoyoubegin?Well,itshouldprobablyrouteHTTPrequests,soyounowneedtoevaluatealloftheHTTPrequestandresponselibrariesavailableandpickone.Thenarouter.Oh,andyou’llprobablyneedtosetupsomeformofroutesconfigurationfile.Whatsyntaxshouldituse?Whereshoulditgo?Whataboutcontrollers?Wheredotheylive,andhowaretheyloaded?Well,youprobablyneedadependencyinjectioncontainertoresolvethecontrollersandtheirdependencies.Butwhichone?
Furthermore,whatifyoudotakethetimetoanswerallthosequestionsandsuccessfullycreateyourapplication—what’stheimpactonthenextdeveloper?Whataboutwhenyouhavefoursuchcustom-framework–basedapplications,oradozen,andyouhavetorememberwherethecontrollersliveineach,orwhattheroutingsyntaxis?
ConsistencyandFlexibilityFrameworksaddressthisissuebyprovidingacarefullyconsideredanswertothequestion“Whichcomponentshouldweusehere?”andensuringthattheparticularcomponentschosenworkwelltogether.Additionally,frameworksprovideconventionsthatreducetheamountofcodeadevelopernewtotheprojecthastounderstand—ifyouunderstandhowroutingworksinoneLaravelproject,forexample,youunderstandhowitworksinallLaravelprojects.
Whensomeoneprescribesrollingyourownframeworkforeachnewproject,whatthey’rereallyadvocatingistheabilitytocontrolwhatdoesanddoesn’tgointoyourapplication’sfoundation.Thatmeansthebestframeworkswillnotonlyprovideyouwithasolidfoundation,butalsogiveyouthefreedomtocustomizetoyourheart’scontent.Andthis,asI’llshowyouintherestofthisbook,ispartofwhatmakesLaravelsospecial.
AShortHistoryofWebandPHPFrameworksAnimportantpartofbeingabletoanswerthequestion“WhyLaravel?”isunderstandingLaravel’shistory—andunderstandingwhatcamebeforeit.PriortoLaravel’sriseinpopularity,therewereavarietyofframeworksandothermovementsinPHPandotherwebdevelopmentspaces.
RubyonRailsDavidHeinemeierHanssonreleasedthefirstversionofRubyonRailsin2004,andit’sbeenhardtofindawebapplicationframeworksincethenthathasn’tbeeninfluencedbyRailsinsomeway.
RailspopularizedMVC,RESTfulJSONAPIs,conventionoverconfiguration,ActiveRecord,andmanymoretoolsandconventionsthathadaprofoundinfluenceonthewaywebdevelopersapproachedtheirapplications—especiallywithregardtorapidapplicationdevelopment.
TheInfluxofPHPFrameworksItwascleartomostdevelopersthatRails,andsimilarwebapplicationframeworks,werethewaveofthefuture,andPHPframeworks,includingthoseadmittedlyimitatingRails,startingpoppingupquickly.
CakePHPwasthefirstin2005,anditwassoonfollowedbySymfony,CodeIgniter,ZendFramework,andKohana(aCodeIgniterfork).Yiiarrivedin2008,andAuraandSlimin2010.2011broughtFuelPHPandLaravel,bothofwhichwerenotquiteCodeIgniteroffshoots,butinsteadproposedasalternatives.
SomeoftheseframeworksweremoreRails-y,focusingondatabaseobject-relationalmappers(ORMs),MVCstructures,andothertoolstargetingrapiddevelopment.Others,likeSymfonyandZend,focusedmoreonenterprisedesignpatternsandecommerce.
TheGoodandtheBadofCodeIgniterCakePHPandCodeIgniterwerethetwoearlyPHPframeworksthatweremostopenabouthowmuchtheirinspirationwasdrawnfromRails.CodeIgniterquicklyrosetofameandby2010wasarguablythemostpopularoftheindependentPHPframeworks.
CodeIgniterwassimple,easytouse,andboastedamazingdocumentationandastrongcommunity.Butitsuseofmoderntechnologyandpatternsadvancedslowly,andastheframeworkworldgrewandPHP’stoolingadvanced,CodeIgniterstartedfallingbehindintermsofbothtechnologicaladvancesandout-of-the-boxfeatures.Unlikemanyotherframeworks,CodeIgniterwasmanagedbyacompany,andtheywereslowtocatchupwithPHP5.3’snewerfeatureslikenamespacesandthemovestoGitHubandlaterComposer.Itwasin2010thatTaylorOtwell,Laravel’screator,becamedissatisfiedenoughwithCodeIgniterthathesetofftowritehisownframework.
Laravel1,2,and3ThefirstbetaofLaravel1wasreleasedinJune2011,anditwaswrittencompletelyfromscratch.ItfeaturedacustomORM(Eloquent);closure-basedrouting(inspiredbyRubySinatra);amodulesystemforextension;andhelpersforforms,validation,authentication,andmore.
EarlyLaraveldevelopmentmovedquickly,andLaravel2and3werereleasedinNovember2011andFebruary2012,respectively.Theyintroducedcontrollers,unittesting,acommand-linetool,aninversionofcontrol(IoC)container,Eloquentrelationships,andmigrations.
Laravel4WithLaravel4,Taylorrewrotetheentireframeworkfromthegroundup.BythispointComposer,PHP’snow-ubiquitouspackagemanager,wasshowingsignsofbecominganindustrystandardandTaylorsawthevalueofrewritingtheframeworkasacollectionofcomponents,distributedandbundledtogetherbyComposer.
TaylordevelopedasetofcomponentsunderthecodenameIlluminateand,inMay2013,releasedLaravel4withanentirelynewstructure.Insteadofbundlingthemajorityofitscodeasadownload,LaravelnowpulledinthemajorityofitscomponentsfromSymfony(anotherframeworkthatreleaseditscomponentsforusebyothers)andtheIlluminatecomponentsthroughComposer.
Laravel4alsointroducedqueues,amailcomponent,facades,anddatabaseseeding.AndbecauseLaravelwasnowrelyingonSymfonycomponents,itwasannouncedthatLaravelwouldbemirroring(notexactly,butsoonafter)thesix-monthlyreleasescheduleSymfonyfollows.
Laravel5Laravel4.3wasscheduledtoreleaseinNovember2014,butasdevelopmentprogressed,itbecameclearthatthesignificanceofitschangesmeritedamajorrelease,andLaravel5wasreleasedinFebruary2015.
Laravel5featuredarevampeddirectorystructure,removaloftheformandHTMLhelpers,theintroductionofthecontractinterfaces,aspateofnewviews,Socialiteforsocialmediaauthentication,Elixirforassetcompilation,Schedulertosimplifycron,dotenvforsimplifiedenvironmentmanagement,formrequests,andabrandnewREPL(read–evaluate–printloop).
What’sSoSpecialAboutLaravel?SowhatisitthatsetsLaravelapart?WhyisitworthhavingmorethanonePHPframeworkatanytime?TheyallusecomponentsfromSymfonyanyway,right?Let’stalkabitaboutwhatmakesLaravel“tick.”
ThePhilosophyofLaravelYouonlyneedtoreadthroughtheLaravelmarketingmaterialsandREADMEstostartseeingitsvalues.Tayloruseslight-relatedwordslike“Illuminate”and“Spark.”Andthentherearethese:“Artisans.”“Elegant.”Also,these:“Breathoffreshair.”“Freshstart.”Andfinally:“Rapid.”“Warpspeed.”
Thetwomoststronglycommunicatedvaluesoftheframeworkaretoincreasedeveloperspeedanddeveloperhappiness.Taylorhasdescribedthe“Artisan”languageasintentionallycontrastingagainstmoreutilitarianvalues.Youcanseethegenesisofthissortofthinkinginhis2011questiononStackExchangeinwhichhestated,“SometimesIspendridiculousamountsoftime(hours)agonizingovermakingcodelookpretty”—justforthesakeofabetterexperienceoflookingatthecodeitself.Andhe’softentalkedaboutthevalueofmakingiteasierandquickerfordeveloperstotaketheirideastofruition,gettingridofunnecessarybarrierstocreatinggreatproducts.
Laravelis,atitscore,aboutequippingandenablingdevelopers.Itsgoalistoprovideclear,simple,andbeautifulcodeandfeaturesthathelpdevelopersquicklylearn,start,anddevelop,andwritecodethat’ssimple,clear,andwilllast.
TheconceptoftargetingdevelopersisclearacrossLaravelmaterials.“Happydevelopersmakethebestcode”iswritteninthedocumentation.“Developerhappinessfromdownloadtodeploy”wastheunofficialsloganforawhile.Ofcourse,anytoolorframeworkwillsayitwantsdeveloperstobehappy.Buthavingdeveloperhappinessasaprimaryconcern,ratherthansecondary,hashadahugeimpactonLaravel’sstyleanddecision-makingprogress.Whereotherframeworksmaytargetarchitecturalpurityastheirprimarygoal,orcompatibilitywiththegoalsandvaluesofenterprisedevelopmentteams,Laravel’sprimaryfocusisonservingtheindividualdeveloper.
http://bit.ly/2dT5kmS
HowLaravelAchievesDeveloperHappinessJustsayingyouwanttomakedevelopershappyisonething.Doingitisanother,anditrequiresyoutoquestionwhatinaframeworkismostlikelytomakedevelopersunhappyandwhatismostlikelytomakethemhappy.ThereareafewwaysLaraveltriestomakedevelopers’liveseasier.
First,Laravelisarapidapplicationdevelopmentframework.Thatmeansitfocusesonashallow(easy)learningcurveandonminimizingthestepsbetweenstartinganewappandpublishingit.Allofthemostcommontasksinbuildingwebapplications,fromdatabaseinteractionstoauthenticationtoqueuestoemailtocaching,aremadesimplerbythecomponentsLaravelprovides.ButLaravel’scomponentsaren’tjustgreatontheirown;theyprovideaconsistentAPIandpredictablestructuresacrosstheentireframework.Thatmeansthat,whenyou’retryingsomethingnewinLaravel,you’remorethanlikelygoingtoendupsaying,“…anditjustworks.”
Thisdoesn’tendattheframeworkitself,either.Laravelprovidesanentireecosystemoftoolsforbuildingandlaunchingapplications.YouhaveHomesteadandValetforlocaldevelopment,Forgeforservermanagement,andEnvoyerforadvanceddeployment.Andthere’sasuiteofadd-onpackages:Cashierforpaymentsandsubscriptions,EchoforWebSockets,Scoutforsearch,PassportforAPIauthentication,Socialiteforsociallogin,andSparktobootstrapyourSaaS.Laravelistryingtotaketherepetitiveworkoutofdevelopers’jobssotheycandosomethingunique.
Next,Laravelfocuseson“conventionoverconfiguration”—meaningthatifyou’rewillingtouseLaravel’sdefaults,you’llhavetodomuchlessworkthanwithotherframeworksthatrequireyoutodeclareallofyoursettingsevenifyou’reusingtherecommendedconfiguration.ProjectsbuiltonLaraveltakelesstimethanthosebuiltonmostotherPHPframeworks.
Laravelalsofocusesdeeplyonsimplicity.It’spossibletousedependencyinjectionandmockingandtheDataMapperpatternandrepositoriesandCommandQueryResponsibilitySegregationandallsortsofothermorecomplexarchitecturalpatternswithLaravel,ifyouwant.Butwhileotherframeworksmightsuggestusingthosetoolsandstructuresoneveryproject,Laravelanditsdocumentationandcommunityleantowardstartingwiththesimplestpossibleimplementation—aglobalfunctionhere,afacadethere,ActiveRecordoverthere.Thisallowsdeveloperstocreatethesimplestpossibleapplicationtosolvefortheirneeds.
AninterestingsourceofhowLaravelisdifferentisthatitscreatoranditscommunityaremoreconnectedtoandinspiredbyRubyandRailsandfunctionalprogramminglanguagesthanbyJava.There’sastrongcurrentinmodernPHPtoleantowardverbosityandcomplexity,embracingthemoreJava-esqueaspectsofPHP.ButLaraveltendstobeontheotherside,embracingexpressive,dynamic,andsimplecodingpracticesandlanguagefeatures.
TheLaravelCommunityIfthisbookisyourfirstexposuretotheLaravelcommunity,youhavesomethingspecialtolookforwardto.OneofthedistinguishingelementsofLaravel,whichhascontributedtoitsgrowthandsuccess,isthewelcoming,teachingcommunitythatsurroundsit.FromJeffreyWay’sLaracastsvideotutorialstoLaravelNewstoSlackandIRCchannels,fromTwitterfriendstobloggerstotheLaraconconferences,Laravelhasarichandvibrantcommunityfulloffolkswho’vebeenaroundsincedayoneandfolkswhoareontheirowndayone.Andthisisn’tanaccident:
FromtheverybeginningofLaravel,I’vehadthisideathatallpeoplewanttofeelliketheyarepartofsomething.It’sanaturalhumaninstincttowanttobelongandbeacceptedintoagroupofotherlike-mindedpeople.So,byinjectingpersonalityintoawebframeworkandbeingreallyactivewiththecommunity,thattypeoffeelingcangrowinthecommunity.TaylorOtwell,ProductandSupportinterview
TaylorunderstoodfromtheearlydaysofLaravelthatasuccessfulopensourceprojectneededtwothings:gooddocumentationandawelcomingcommunity.AndthosetwothingsarenowhallmarksofLaravel.
https://laracasts.com/https://laravel-news.com/
HowItWorksUpuntilnow,everythingI’vesharedherehasbeenentirelyabstract.Whataboutthecode,youask?Let’sdigintoasimpleapplication(Example1-1)soyoucanseewhatworkingwithLaravelday-to-dayisactuallylike.
Example1-1.“Hello,World”inroutes/web.php//File:routes/web.php
Route::get('/',function(){returnGreeting::first()->body;});//File:app/Greeting.php
WhyLaravel?So—whyLaravel?
BecauseLaravelhelpsyoubringyourideastorealitywithnowastedcode,usingmoderncodingstandards,surroundedbyavibrantcommunity,withanempoweringecosystemoftools.
Andbecauseyou,deardeveloper,deservetobehappy.
Chapter2.SettingUpaLaravelDevelopmentEnvironment
PartofPHP’ssuccesshasbeenbecauseit’shardtofindawebserverthatcan’tservePHP.However,modernPHPtoolshavestricterrequirementsthanthoseofthepast.ThebestwaytodevelopforLaravelistoensureaconsistentlocalandremoteserverenvironmentforyourcode,andthankfully,theLaravelecosystemhasafewtoolsforthis.
SystemRequirementsEverythingwe’llcoverinthischapterispossiblewithWindowsmachines,butyou’llneeddozensofpagesofcustominstructionsandcaveats.I’llleavethoseinstructionsandcaveatstoactualWindowsusers,sotheexampleshereandintherestofthebookwillfocusonUnix/Linux/MacOSdevelopers.
WhetheryouchoosetoserveyourwebsitebyinstallingPHPandothertoolsonyourlocalmachine,serveyourdevelopmentenvironmentfromavirtualmachineviaVagrant,orrelyonatoollikeMAMP/WAMP/XAMPP,yourdevelopmentenvironmentwillneedtohaveallofthefollowinginstalledinordertoserveLaravelsites:
PHP>=5.6.4forLaravel5.3orPHP>=5.5.9for5.1and5.2
OpenSSLPHPextension
PDOPHPextension
MbstringPHPextension
TokenizerPHPextension
ComposerWhatevermachineyou’redevelopingonwillneedtohaveComposerinstalledglobally.Ifyou’renotfamiliarwithComposer,it’satoolthat’satthefoundationofmostmodernPHPdevelopment.ComposerisadependencymanagerforPHP,muchlikeNPMforNodeorRubyGemsforRuby.You’llneedComposertoinstallLaravel,updateLaravel,andbringinexternaldependencies.
https://getcomposer.org/
LocalDevelopmentEnvironmentsFormanyprojects,hostingyourdevelopmentenvironmentusingasimplertoolsetwillbeenough.IfyoualreadyhaveMAMPorWAMPorXAMPPinstalledonyoursystem,thatwilllikelybefinetorunLaravel.YoucanalsojustrunLaravelwithPHP’sbuilt-inwebserver,assumingyoursystemPHPistherightversion.
AllyoureallyneedtogetstartedistheabilitytorunPHP.Everythingpastthatisuptoyou.
However,Laravelofferstwotoolsforlocaldevelopment,ValetandHomestead,andwe’llcoverbothbriefly.Ifyou’reunsureofwhichtouse,I’drecommendusingValetandjustskimmingtheHomesteadsection;however,bothtoolsarevaluableandworthunderstanding.
LaravelValetIfyouwanttousePHP’sbuilt-inwebserver,yoursimplestoptionistoserveeverysitefromalocalhostURL.Ifyourunphp-Slocalhost:8000-tpublicfromyourLaravelsite’srootfolder,PHP’sbuilt-inwebserverwillserveyoursiteathttp://localhost:8000/.Youcanalsorunphpartisanserveonceyouhaveyourapplicationsetuptoeasilyspinupanequivalentserver.
Butifyou’reinterestedintyingeachofyoursitestoaspecificdevelopmentdomain,you’llneedtogetcomfortablewithyouroperatingsystem’shostsfileanduseatoollikednsmasq.Let’sinsteadtrysomethingsimpler.
Ifyou’reaMacuser(therearealsounofficialforksforWindowsandLinux),LaravelValettakesawaytheneedtoconnectyourdomainstoyourapplicationfolders.ValetinstallsdnsmasqandaseriesofPHPscriptsthatmakeitpossibletotypelaravelnewmyapp&&openmyapp.devandforittojustwork.You’llneedtoinstallafewtoolsusingHomebrew,whichthedocumentationwillwalkyouthrough,butthestepsfrominitialinstallationtoservingyourappsarefewandsimple.
InstallValet(seethedocsforthelatestinstallationinstruction—it’sunderveryactivedevelopmentatthistimeofwriting),andpointitatoneormoredirectorieswhereyoursiteswilllive.Iranvaletparkfrommy~/Sitesdirectory,whichiswhereIputallofmyunder-developmentapps.Now,youcanjustadd.devtotheendofthedirectorynameandvisititinyourbrowser.
Valetmakesiteasytoserveallfoldersinagivenfolderas“FOLDERNAME.dev”usingvaletpark,toservejustasinglefolderusingvaletlink,toopentheValet-serveddomainforafolderusingvaletopen,toservetheValetsitewithHTTPSusingvaletsecure,andtoopenanngroktunnelsoyoucanshareyoursitewithotherswithvaletshare.
http://bit.ly/2eNPJ5Thttps://laravel.com/docs/valethttps://laravel.com/docs/valet
LaravelHomesteadHomesteadisanothertoolyoumightwanttousetosetupyourlocaldevelopmentenvironment.It’saconfigurationtoolthatsitsontopofVagrantandprovidesapre-configuredvirtualmachineimagethatisperfectlysetupforLaraveldevelopment,andmirrorsthemostcommonproductionenvironmentthatmanyLaravelsitesrunon.
SettingupHomesteadIfyouchoosetouseHomestead,it’sgoingtotakeabitmoreworktosetupthansomethinglikeMAMPorValet.Thebenefitsaremyriad,however:configuredcorrectly,yourlocalenvironmentcanbeincrediblyclosetoyourremoteworkingenvironment;youwon’thavetoworryaboutupdatingyourdependenciesonyourlocalmachine;andyoucanlearnallaboutthestructureofUbuntuserversfromthesafetyofyourlocalmachine.
WHATTOOLSDOHOMESTEADOFFER?
YoucanalwaysupgradetheindividualcomponentsofyourHomesteadvirtualmachine,buthereareafewimportanttoolsHomesteadcomeswithbydefault:
Toruntheserverandservethesite,Ubuntu,PHP,andNginx(awebserversimilartoApache).
Fordatabase/storageandqueues,MySQL,Postgres,Redis,Memcached,andbeanstalkd.
Forbuildstepsandothertools,Node.
InstallingHomestead’sdependenciesFirst,you’llneedtodownloadandinstalleitherVirtualBoxorVMWare.VirtualBoxismostcommonbecauseit’sfree.
Next,downloadandinstallVagrant.
Vagrantisconvenientbecauseitmakesiteasyforyoutocreateanewlocalvirtualmachinefromaprecreated“box,”whichisessentiallyatemplateforavirtualmachine.So,thenextstepistorunvagrantboxaddlaravel/homesteadfromyourterminaltodownloadthebox.
InstallingHomesteadNext,let’sactuallyinstallHomestead.YoucaninstallmultipleinstancesofHomestead(perhapshostingadifferentHomesteadboxperproject),butIpreferasingleHomesteadvirtualmachineforallofmyprojects.Ifyouwantoneperproject,you’llwanttoinstallHomesteadinyourprojectdirectory;checktheHomesteaddocumentationonlineforinstructions.Ifyouwantasinglevirtualmachineforallofyourprojects,installHomesteadinyouruser ’shomedirectoryusingthefollowingcommand:
gitclonehttps://github.com/laravel/homestead.git~/Homestead
https://www.virtualbox.org/wiki/Downloadshttps://www.vagrantup.com/downloads.htmlhttps://laravel.com/docs/5.3/homestead
Now,runtheinitializationscriptfromwhereveryouputtheHomesteaddirectory:
bash~/Homestead/init.sh
ThiswillplaceHomestead’sprimaryconfigurationfile,Homestead.yaml,inanew~/.homesteaddirectory.
ConfiguringHomesteadOpenupHomestead.yamlandconfigureithowyou’dlike.Here’swhatitlookslikeoutofthebox:
ip:"192.168.10.10"memory:2048cpus:1provider:virtualbox
authorize:~/.ssh/id_rsa.pub
keys:-~/.ssh/id_rsa
folders:-map:~/Codeto:/home/vagrant/Code
sites:-map:homestead.appto:/home/vagrant/Code/Laravel/public
databases:-homestead
#blackfire:#-id:foo#token:bar#client-id:foo#client-token:bar
#ports:#-send:50000#to:5000#-send:7777#to:777#protocol:udp
You’llneedtotellityourprovider(likelyvirtualbox),pointittoyourpublicSSHkey(bydefault~/.ssh/id_rsa.pub;ifyoudon’thaveone,GitHubhasagreattutorialoncreatingSSHkeys),mapfoldersandsitestotheirlocalmachineequivalents,andprovisionadatabase.
MappingfoldersinHomesteadallowsyoutoeditfilesonyourlocalmachineandhavethosefilesshowupinyourVagrantboxsotheycanbeserved.Forexample,ifyouhavea~/Sitesdirectorywhereyouputallofyourcode,you’dmapthefoldersinHomesteadbyreplacingthefolderssectioninHomestead.yamlwiththefollowing:
folders:-map:~/Sitesto:/home/vagrant/Sites
http://bit.ly/2e7Auof
You’venowjustcreatedadirectoryinyourHomesteadvirtualmachineat/home/vagrant/Sitesthatwillmirroryourcomputer ’sdirectoryat~/Sites.
TOP-LEVELDOMAINSFORDEVELOPMENTSITESYoucanchooseanyconventionforlocaldevelopmentsites’URLs,but.appand.devarethemostcommon.Homesteadsuggests.app,soifI’mworkingonalocalcopyofsymposiumapp.com,I’lldevelopatsymposiumapp.app.
Now,let’ssetupourfirstexamplewebsite.Let’ssayourlivesiteisgoingtobeprojectName.com.InHomestead.yaml,we’llmapourlocaldevelopmentfoldertoprojectName.app,sowehaveaseparateURLtovisitforlocaldevelopment:
sites:-map:projectName.appto:/home/vagrant/Sites/projectName/public
Asyoucansee,we’remappingtheURLprojectName.apptothevirtualmachinedirectory/home/vagrant/Sites/projectName/public,whichisthepublicfolderwithinourLaravelinstall.We’lllearnmoreaboutthatlater.
Finally,you’regoingtoneedtoteachyourlocalmachinethat,whenyoutrytovisitprojectName.app,itshouldlookatyourcomputer ’slocalIPaddresstoresolveit.MacandLinuxusersshouldedit/etc/hosts,andWindowsusersC:\Windows\System32\drivers\etc\hosts.Addalinetothisfilethatlookslikethis:
192.168.10.10projectName.app
Onceyou’veprovisionedHomestead,yoursitewillbeavailabletobrowse(onyourmachine)athttp://projectName.app/.
CreatingdatabasesinHomesteadJustlikeyoucandefineasiteinHomestead.yaml,youcanalsodefineadatabase.Databasesarealotsimpler,becauseyou’reonlytellingtheprovisionertocreateadatabasewiththatname,nothingelse.Wedothisasfollows:
databases:-projectname
ProvisioningHomesteadThefirsttimeyouactuallyturnonaHomesteadbox,youneedtotellVagranttoinitializeit.NavigatetoyourHomesteaddirectoryandrunvagrantup:
cd~/Homesteadvagrantup
YourHomesteadboxisnowupandrunning;it’smirroringalocalfolder,andit’sservingittoaURLyoucanvisitinanybrowseronyourcomputer.ItalsohascreatedaMySQL
http://projectName.app/
database.Nowthatyouhavethatenvironmentrunning,you’rereadytosetupyourfirstLaravelproject—butfirst,aquicknoteaboutusingHomesteadday-to-day.
UsingHomesteadday-to-dayIt’scommontoleaveyourHomesteadvirtualmachineupandrunningatalltimes,butifyoudon’t,orifyouhaverecentlyrestartedyourcomputer,you’llneedtoknowhowtospintheboxupanddown.
SinceHomesteadisbasedonVagrantcommands,you’lljustusebasicVagrantcommandsformostHomesteadactions.ChangetothedirectorywhereyouinstalledHomestead(usingcd)andthenrunthefollowingcommandsasneeded:
vagrantupspinsuptheHomesteadbox.
vagrantsuspendtakesasnapshotofwheretheboxisandthenshutsitdown;like“hibernating”adesktopmachine.
vagranthaltshutstheentireboxdown;liketurningoffadesktopmachine.
vagrantdestroydeletestheentirebox;likeformattingadesktopmachine.
vagrantprovisionre-runstheprovisionersonthepreexistingbox.
ConnectingtoHomesteaddatabasesfromdesktopapplicationsIfyouuseadesktopapplicationlikeSequelPro,you’lllikelywanttoconnecttoyourHomesteadMySQLdatabasesfromyourhostmachine.Thesesettingswillgetyougoing:
Connectiontype:Standard(non-SSH)
Host:127.0.0.1
Username:homestead
Password:secret
Port:33060
CreatingaNewLaravelProjectTherearetwowaystocreateanewLaravelproject,butbotharerunfromthecommandline.ThefirstoptionistogloballyinstalltheLaravelinstallertool(usingComposer);thesecondistouseComposer ’screate-projectfeature.
YoucanlearnaboutbothoptionsinmoredetailontheInstallationdocumentationpage,butI’drecommendtheLaravelinstallertool.
http://laravel.com/docs/installation
InstallingLaravelwiththeLaravelInstallerToolIfyouhaveComposerinstalledglobally,installingtheLaravelinstallertoolisassimpleasrunningthefollowingcommand:
composerglobalrequire"laravel/installer=~1.1"
OnceyouhavetheLaravelinstallertoolinstalled,spinningupanewLaravelprojectissimple.Justrunthiscommandfromyourcommandline:
laravelnewprojectName
ThiswillcreateanewsubdirectoryofyourcurrentdirectorynamedprojectNameandinstallabareLaravelprojectinit.
InstallingLaravelwithComposer’screate-projectFeatureComposeralsooffersafeaturecalledcreate-projectforcreatingnewprojectswithaparticularskeleton.TousethistooltocreateanewLaravelproject,issuethefollowingcommand:
composercreate-projectlaravel/laravelprojectName--prefer-dist
Justliketheinstallertool,thiswillcreateasubdirectoryofyourcurrentdirectorynamedprojectNamethatcontainsaskeletonLaravelinstall,readyforyoutodevelop.
Laravel’sDirectoryStructureWhenyouopenupadirectorythatcontainsaskeletonLaravelapplication,you’llseethefollowingfilesanddirectories:
app/bootstrap/config/database/public/resources/routes/storage/tests/vendor/.env.env.example.gitattributes.gitignoreartisancomposer.jsoncomposer.lockgulpfile.jspackage.jsonphpunit.xmlreadme.mdserver.php
Let’swalkthroughthemonebyonetogetfamiliar.
TheFoldersTherootdirectorycontainsthefollowingfoldersbydefault:
appiswherethebulkofyouractualapplicationwillgo.Models,controllers,routedefinitions,commands,andyourPHPdomaincodeallgoinhere.
bootstrapcontainsthefilesthattheLaravelframeworkusestobooteverytimeitruns.
configiswherealltheconfigurationfileslive.
databaseiswheredatabasemigrationsandseedslive.
publicisthedirectorytheserverpointstowhenit’sservingthewebsite.Thiscontainsindex.php,whichisthefrontcontrollerthatkicksoffthebootstrappingprocessandroutesallrequestsappropriately.It’salsowhereanypublic-facingfileslikeimages,stylesheets,scripts,ordownloadsgo.
resourcesiswherenon-PHPfilesthatareneededforotherscriptslive.Views,languagefiles,and(optionally)Sass/LESSandsourceJavaScriptfileslivehere.
routesiswherealloftheroutedefinitionslive,bothforHTTProutesand“consoleroutes,”orArtisancommands.
storageiswherecaches,logs,andcompiledsystemfileslive.
testsiswhereunitandintegrationtestslive.
vendoriswhereComposerinstallsitsdependencies.It’sGit-ignored(markedtobeexcludedfromyourversioncontrolsystem),asComposerisexpectedtorunasapartofyourdeployprocessonanyremoteservers.
TheLooseFilesTherootdirectoryalsocontainsthefollowingfiles:
.envand.env.examplearethefilesthatdictatetheenvironmentvariables(variablesthatareexpectedtobedifferentineachenvironmentandarethereforenotcommittedtoversioncontrol)..env.exampleisatemplatethateachenvironmentshouldduplicatetocreateitsown.envfile,whichisGit-ignored.
artisanisthefilethatallowsyoutorunArtisancommands(seeChapter7)fromthecommandline.
.gitignoreand.gitattributesareGitconfigurationfiles.
composer.jsonandcomposer.lockaretheconfigurationfilesforComposer;composer.jsonisuser-editableandcomposer.lockisnot.ThesefilessharesomebasicinformationaboutthisprojectandalsodefineitsPHPdependencies.
gulpfile.jsisthe(optional)configurationfileforElixirandGulp.Thisisforcompilingandprocessingyourfrontendassets.
package.jsonislikecomposer.jsonbutforfrontendassets.
phpunit.xmlisaconfigurationfileforPHPUnit,thetoolLaravelusesfortestingoutofthebox.
readme.mdisaMarkdownfilegivingabasicintroductiontoLaravel.
server.phpisabackupserverthattriestoallowless-capableserverstostillpreviewtheLaravelapplication.
ConfigurationThecoresettingsofyourLaravelapplication—databaseconnection,queueandmailsettings,etc.—liveinfilesintheconfigfolder.Eachofthesefilesreturnsanarray,andeachvalueinthearraywillbeaccessiblebyaconfigkeythatiscomprisedofthefilenameandalldescendantkeys,separatedbydots(.)
So,ifyoucreateafileatconfig/services.phpthatlookslikethis:
//config/services.phpreturn['sparkpost'=>['secret'=>'abcdefg']];
youwillnowhaveaccesstothatconfigvariableusingconfig('services.sparkpost.secret').
Anyconfigurationvariablesthatshouldbedistinctforeachenvironment(andthereforenotcommittedtosourcecontrol)willinsteadliveinyour.envfiles.Let’ssayyouwanttouseadifferentBugsnagAPIkeyforeachenvironment.You’dsettheconfigfiletopullitfrom.env:
//config/services.phpreturn['bugsnag'=>['api_key'=>env('BUGSNAG_API_KEY')]];
Thisenv()helperfunctionpullsavaluefromyour.envfilewiththatsamekey.Sonow,addthatkeytoyour.env(settingsforthisenvironment)and.env.example(templateforallenvironments)files:
BUGSNAG_API_KEY=oinfp9813410942
Your.envfilealreadycontainsquiteafewenvironment-specificvariablesneededbytheframework,likewhichmaildriveryou’llbeusingandwhatyourbasicdatabasesettingsare.
UpandRunningYou’renowupandrunningwithabareLaravelinstall.Rungitinit,committhebarefileswithgitadd.andgitcommit,andyou’rereadytostartcoding.That’sit!Andifyou’reusingValet,youcanrunthefollowingcommandsandinstantlyseeyoursiteliveinyourbrowser:
laravelnewmyProject&&cdmyProject&&valetopen
EverytimeIstartanewproject,thesearethestepsItake:
laravelnewmyProjectcdmyProjectgitinitgitadd.gitcommit-m"Initialcommit"
Ikeepallofmysitesina~/Sitesfolder,whichIhavesetupasmyprimaryValetdirectory,sointhiscaseI’dinstantlyhavemyProject.devaccessibleinmybrowserwithnoaddedwork.Icanedit.envandpointittoaparticulardatabase,addthatdatabaseinmyMySQLapp,andI’mreadytostartcoding.
LAMBOIperformthethissetofstepssooftenthatIcreatedasimpleglobalComposerpackagetodoitforme.It’scalledLambo,andyoucanlearnmoreaboutitonGitHub.
https://github.com/tightenco/lambo
TestingIneverychapterafterthis,the“Testing”sectionattheendofthechapterwillshowyouhowtowritetestsforthefeatureorfeaturesthatwerecovered.Sincethischapterdoesn’tcoveratestablefeature,let’stalktestsquickly.(TolearnmoreaboutwritingandrunningtestsinLaravel,headovertoChapter12.)
Outofthebox,LaravelbringsinPHPUnitasadependencyandisconfiguredtorunthetestsinanyfileinthetestsdirectorywhosenameendswithTest.php(forexample,tests/UserTest.php).
So,thesimplestwaytowritetestsistocreateafileinthetestsdirectorywithanamethatendswithTest.php.Andtheeasiestwaytorunthemistorun./vendor/bin/phpunitfromthecommandline(intheprojectroot).
Ifanytestsrequiredatabaseaccess,besuretorunyourtestsfromthemachinewhereyourdatabaseishosted—soifyou’rehostingyourdatabaseinVagrant,makesuretosshintoyourVagrantboxtorunyourtestsfromthere.Again,youcanlearnaboutthisandmuchmoreinChapter12.
TL;DRSinceLaravelisaPHPframework,it’sverysimpletoserveitlocally.Laravelalsoprovidestwotoolsformanagingyourlocaldevelopment:asimplertoolcalledValetthatusesyourlocalmachinetoprovideyourdependencies,andapreconfiguredVagrantsetupnamedHomestead.Laravelrelieson,andcanbeinstalledby,Composer,andcomesoutoftheboxwithaseriesoffoldersandfilesthatreflectbothitsconventionsanditsrelationshipwithotheropensourcetools.
Chapter3.RoutingandControllers
Theessentialfunctionofanywebapplicationframeworkistotakerequestsfromauseranddeliverresponses,usuallyviaHTTP(S).Thismeansdefininganapplication’sroutesisthefirstandmostimportantprojecttotacklewhenlearningawebframework;withoutroutes,youhavenoabilitytointeractwiththeenduser.
InthischapterwewillexamineroutesinLaravelandshowhowtodefinethem,howtopointthemtothecodetheyshouldexecute,andhowtouseLaravel’sroutingtoolstohandleadiversearrayofroutingneeds.
RouteDefinitionsInaLaravelapplication,youwilldefineyour“web”routesinroutes/web.phpandyour“API”routesinroutes/api.php.Webroutesarethosethatwillbevisitedbyyourendusers;APIroutesarethoseforyourAPI,ifyouhaveone.Fornow,we’llprimarilyfocusontheroutesinroutes/web.php.
NOTEInprojectsrunningversionsofLaravelpriorto5.3,therewillbeonlyoneroutesfile,locatedatapp/Http/routes.php.
Thesimplestwaytodefinearouteistomatchapath(e.g.,/)withaclosure,asseeninExample3-1.
Example3-1.Basicroutedefinition//routes/web.phpRoute::get('/',function(){return'Hello,World!';});
WHAT’SACLOSURE?
ClosuresarePHP’sversionofanonymousfunctions.Aclosureisafunctionthatyoucanpassaroundasanobject,assigntoavariable,passasaparametertootherfunctionsandmethods,orevenserialize.
You’venowdefinedthat,ifanyonevisits/(therootofyourdomain),Laravel’sroutershouldruntheclosuredefinedthereandreturntheresult.Notethatwereturnourcontentanddon’techoorprintit.
AQUICKINTRODUCTIONTOMIDDLEWAREYoumightbewondering,“WhyamIreturning‘Hello,World!’insteadofechoingit?”
Therearequiteafewanswers,butthesimplestisthattherearealotofwrappersaroundLaravel’srequestandresponsecycle,includingsomethingcalledmiddleware.Whenyourrouteclosureorcontrollermethodisdone,it’snottimetosendtheoutputtothebrowseryet;returningthecontentallowsittocontinueflowingthroughtheresponsestackandthemiddlewarebeforeitisreturnedbacktotheuser.
Manysimplewebsitescouldbedefinedentirelywithinthewebroutesfile.WithafewsimpleGETroutescombinedwithsometemplatesasillustratedinExample3-2,youcancanserveaclassicwebsiteeasily.
Example3-2.SamplewebsiteRoute::get('/',function(){returnview('welcome');});
Route::get('about',function(){returnview('about');});
Route::get('products',function(){returnview('products');});
Route::get('services',function(){returnview('services');});
STATICCALLSIfyouhavemuchexperiencedevelopingPHP,youmightbesurprisedtoseestaticcallsontheRouteclass.Thisisnotactuallyastaticmethodperse,butratherservicelocationusingLaravel’sfacades,whichwe’llcoverinChapter11.
Ifyouprefertoavoidfacades,youcanaccomplishthesesamedefinitionslikethis:
$router->get('/',function(){return'Hello,World!';});
HTTPMETHODS
Ifyou’renotfamiliarwiththeideaofHTTPmethods,readoninthischapterformoreinformation,butfornow,justknowthateveryHTTPrequesthasa“verb,”oraction,alongwithit.Laravelallowsyoutodefineyourroutesbasedonwhichverbwasused;themostcommonareGETandPOST,followedbyPUT,DELETE,andPATCH.Eachmethodcommunicatesadifferentthingtotheserver,andtoyourcode,abouttheintentionsofthecaller.
RouteVerbsYoumight’venoticedthatwe’vebeenusingRoute::getinourroutedefinitions.Thismeanswe’retellingLaraveltoonlymatchfortheserouteswhentheHTTPrequestusestheGETaction.Butwhatifit’saformPOST,ormaybesomeJavaScriptsendingPUTorDELETErequests?Thereareafewotheroptionsformethodstocallonaroutedefinition,asillustratedinExample3-3.
Example3-3.RouteverbsRoute::get('/',function(){return'Hello,World!';});
Route::post('/',function(){});
Route::put('/',function(){});
Route::delete('/',function(){});
Route::any('/',function(){});
Route::match(['get','post'],'/',function(){});
RouteHandlingAsyou’veprobablyguessed,passingaclosuretotheroutedefinitionisnottheonlywaytoteachithowtoresolvearoute.Closuresarequickandsimple,butthelargeryourapplicationgets,theclumsieritbecomestoputallofyourroutinglogicinonefile.Additionally,applicationsusingrouteclosurescan’ttakeadvantageofLaravel’sroutecaching(moreonthatlater),whichcanshaveuptohundredsofmillisecondsoffofeachrequest.
Theothercommonoptionistopassacontrollernameandmethodasastringinplaceoftheclosure,asinExample3-4.
Example3-4.RoutescallingcontrollermethodsRoute::get('/','WelcomeController@index');
ThisistellingLaraveltopassrequeststothatpathtotheindex()methodoftheApp\Http\Controllers\WelcomeControllercontroller.Thismethodwillbepassedthesameparametersandtreatedthesamewayasaclosureyoumight’vealternativelyputinitsplace.
RouteParametersIftherouteyou’redefininghasparameters—segmentsintheURLstructurethatarevariable—it’ssimpletodefinetheminyourrouteandpassthemtoyourclosure(seeExample3-5).
Example3-5.RouteparametersRoute::get('users/{id}/friends',function($id){//});
THENAMINGRELATIONSHIPBETWEENROUTEPARAMETERSANDCLOSURE/CONTROLLER METHODPARAMETERS
AsyoucanseeinExample3-5,it’smostcommontousethesamenamesforyourrouteparameters({id})andthemethodparameterstheyinjectintoyourroutedefinition(function($id)).Butisthisnecessary?
Unlessyou’reusingroute/modelbinding,no.Theonlythingthatdefineswhichrouteparametermatcheswithwhichmethodparameteristheirorder(lefttoright),asyoucanseehere:
Route::get('users/{userId}/comments/{commentId}',function($thisIsActuallyTheRouteId,$thisisReallyTheCommentId){//});
Thathavingbeensaid,justbecauseyoucanmakethemdifferentdoesn’tmeanyoushould.Irecommendkeepingthemthesameforthesakeoffuturedevelopers,whocouldgettrippedupbyinconsistentnaming.
Youcanalsomakeyourrouteparametersoptionalbyincludingaquestionmark(?)aftertheparametername,asillustratedinExample3-6.Inthiscase,youshouldalsoprovideadefaultvaluefortheroute’scorrespondingvariable.
Example3-6.OptionalrouteparametersRoute::get('users/{id?}',function($id='fallbackId'){//});
Andyoucanuseregularexpressions(regexes)todefinethatarouteshouldonlymatchifaparametermeetsparticularrequirements,asinExample3-7.
Example3-7.RegularexpressionrouteconstraintsRoute::get('users/{id}',function($id){//})->where('id','[0-9]+');
Route::get('users/{username}',function($username){//})->where('username','[A-Za-z]+');
Route::get('posts/{id}/{slug}',function($id,$slug){//})->where(['id'=>'[0-9]+','slug'=>'[A-Za-z]+']);
Asyou’veprobablyguessed,ifyouvisitapaththatmatchesaroutestring,buttheregexdoesn’tmatchtheparameter,itwon’tbematched.Sinceroutesarematchedtoptobottom,
users/abcwouldskipthefirstclosureinExample3-7,butitwouldbematchedbythesecondclosure,soitwouldgetroutedthere.Ontheotherhand,posts/abc/123wouldn’tmatchanyoftheclosures,soitwouldreturna404NotFounderror.
RouteNamesThesimplestwaytorefertotheserouteselsewhereinyourapplicationisjustbytheirpath.There’saurl()helpertosimplifythatlinkinginyourviews,ifyouneedit;seeExample3-8foranexample.Thehelperwillprefixyourroutewiththefulldomainofyoursite.
Example3-8.URLhelper
DEFININGCUSTOMROUTESINLARAVEL5.1Fluentroutedefinitionsdon’texistinLaravel5.1.You’llneedtoinsteadpassanarraytothesecondparameterofyourroutedefinition;checktheLaraveldocstoseemoreabouthowthisworks.Here’sExample3-9inLaravel5.1:
Route::get('members/{id}',['as'=>'members.show','uses'=>'MembersController@show']);
Inourexample,we’venamedthisroutemembers.show;resourcePlural.actionisacommonconventionwithinLaravelforrouteandviewnames.
ROUTENAMINGCONVENTIONS
Youcannameyourrouteanythingyou’dlike,butthecommonconventionistousethepluraloftheresourcename,thenaperiod,thentheaction.So,herearetheroutesmostcommonforaresourcenamedphoto:
photos.indexphotos.createphotos.storephotos.showphotos.editphotos.updatephotos.destroy
Tolearnmoreabouttheseconventions,see“ResourceControllers”.
Wealsointroducedtheroute()helper.Justlikeurl(),it’sintendedtobeusedinviewstosimplifylinkingtoanamedroute.Iftheroutehasnoparameters,youcansimplypasstheroutename:(route('members.index'))andreceivearoutestringhttp://myapp.com/members/index).Ifithasparameters,passtheminasanarrayasthesecondparameterlikewedidinthisexample.
Ingeneral,Irecommendusingroutenamesinsteadofpathstorefertoyourroutes,andthereforeusingtheroute()helperinsteadoftheurl()helper.Sometimesitcangetabitclumsy—forexample,ifyou’reworkingwithmultiplesubdomains—butitprovidesanincrediblelevelofflexibilitytolaterchangetheapplication’sroutingstructurewithoutmajorpenalty.
PASSINGROUTEPARAMETERSTOTHEROUTE( ) HELPER
Whenyourroutehasparameters(e.g.,users/{id}),youneedtodefinethoseparameterswhenyou’reusingtheroute()helpertogeneratealinktotheroute.
Thereareafewdifferentwaystopasstheseparameters.Let’simaginearoutedefinedasusers/{userId}/comments/{commentId}.IftheuserIDis1andthecommentIDis2,let’slookatafewoptionswehaveavailabletous:
Option1:
route('users.comments.show',[1,2])//http://myapp.com/users/1/comments/2
Option2:
route('users.comments.show',['userId'=>1,'commentId'=>2])//http://myapp.com/users/1/comments/2
Option3:
route('users.comments.show',['commentId'=>2,'userId'=>1])//http://myapp.com/users/1/comments/2
Option4:
route('users.comments.show',['userId'=>1,'commentId'=>2,'opt'=>'a'])//http://myapp.com/users/1/comments/2?opt=a
Asyoucansee,nonkeyedarrayvaluesareassignedinorder;keyedarrayvaluesarematchedwiththerouteparametersmatchingtheirkeys,andanythingleftoverisaddedasaqueryparameter.
RouteGroupsOftenagroupofroutesshareaparticularcharacteristic—acertainauthenticationrequirement,apathprefix,orperhapsacontrollernamespace.Definingthesesharedcharacteristicsagainandagainoneachroutenotonlyseemstediousbutalsocanmuddyuptheshapeofyourroutesfileandobscuresomeofthestructuresofyourapplication.
Routegroupsallowyoutogroupseveralroutestogether,andapplyanysharedconfigurationsettingsoncetotheentiregroup,toreducethisduplication.Additionally,routegroupsarevisualcuestofuturedevelopers(andtoyourownbrain)thattheseroutesaregroupedtogether.
Togrouptwoormoreroutestogether,you“surround”theroutedefinitionswitharoutegroup,asshowninExample3-10.Inreality,you’reactuallypassingaclosuretothegroupdefinition,anddefiningthegroupedrouteswithinthatclosure.
Example3-10.DefiningaroutegroupRoute::group([],function(){Route::get('hello',function(){return'Hello';});Route::get('world',function(){return'World';});});
Bydefault,aroutegroupdoesn’tactuallydoanything.There’snodifferencebetweenthegroupinExample3-10andseparatingasegmentofyourrouteswithcodecomments.Theemptyarraythat’sthefirstparameter,however,allowsyoutopassavarietyofconfigurationsettingsthatwillapplytotheentireroutegroup.
MiddlewareProbablythemostcommonuseforroutegroupsistoapplymiddlewaretoagroupofroutes.We’lllearnmoreaboutmiddlewareinChapter10,but,amongotherthings,they’rewhatLaravelusesforauthenticatingusersandrestrictingguestusersfromusingcertainpartsofasite.
InExample3-11,we’recreatingaroutegrouparoundthedashboardandaccountviewsandapplyingtheauthmiddlewaretoboth.Inthisexample,itmeansusershavetobeloggedintotheapplicationtoviewthedashboardortheaccountpage.
Example3-11.Restrictingagroupofroutestologged-inusersonlyRoute::group(['middleware'=>'auth'],function(){Route::get('dashboard',function(){returnview('dashboard');});Route::get('account',function(){returnview('account');});});
APPLYINGMIDDLEWAREINCONTROLLERSOftenit’sclearerandmoredirecttoattachmiddlewaretoyourroutesinthecontrollerinsteadofattheroutedefinition.Youcandothisbycallingthemiddleware()methodintheconstructorofyourcontroller.Thestringyoupasstothemiddleware()methodisthenameofthemiddleware,andyoucanoptionallychainmodifiermethods(only()andexcept())todefinewhichmethodswillreceivethatmiddleware:
classDashboardControllerextendsController{publicfunction__construct(){$this->middleware('auth');
$this->middleware('admin-auth')->only('admin');
$this->middleware('team-member')->except('admin');}}
Notethat,ifyou’redoingalotof“only”and“except”customizations,that’softenasignthatyoushouldbreakoutanewcontrollerfortheexceptionalroutes.
PathPrefixesIfyouhaveagroupofroutesthatshareasegmentoftheirpath—forexample,ifyoursite’sAPIisprefixedwith/api—youcanuseroutegroupstosimplifythisstructure(seeExample3-12).
Example3-12.PrefixingagroupofroutesRoute::group(['prefix'=>'api'],function(){Route::get('/',function(){//Handlesthepath/api});Route::get('users',function(){//Handlesthepath/api/users});});
Notethateachprefixedgroupalsohasa/routethatrepresentstherootoftheprefix—inExample3-12that’s/api.
SubdomainRoutingSubdomainroutingisthesameasrouteprefixing,butit’sscopedbysubdomaininsteadofrouteprefix.Therearetwoprimaryusesforthis.First,youmaywanttopresentdifferentsectionsoftheapplication(orentirelydifferentapplications)todifferentsubdomains.Example3-13showshowyoucanachievethis.
Example3-13.SubdomainroutingRoute::group(['domain'=>'api.myapp.com'],function(){Route::get('/',function(){//});});
Second,youmightwanttosetpartofthesubdomainasaparameter,asillustratedinExample3-14.Thisismostoftendoneincasesofmultitenancy(thinkSlackorHarvest,whereeachcompanygetsitsownsubdomain,liketighten.slack.co).
Example3-14.ParameterizedsubdomainroutingRoute::group(['domain'=>'{account}.myapp.com'],function(){Route::get('/',function($account){//});Route::get('users/{id}',function($account,$id){//});});
Notethatanyparametersforthegroupgetpassedintothegroupedroutes’methodsasthefirstparameter(s).
NamespacePrefixesWhenyou’regroupingroutesbysubdomainorrouteprefix,it’slikelytheircontrollershaveasimilarPHPnamespace.IntheAPIexample,alloftheAPIroutes’controllersmightbeunderanAPInamespace.Byusingtheroutegroupnamespaceprefix,asshowninExample3-15,youcanavoidlongcontrollerreferencesingroupslike"API/ControllerA@index"and"API/ControllerB@index".
Example3-15.Routegroupnamespaceprefixes//App\Http\Controllers\ControllerARoute::get('/','ControllerA@index');
Route::group(['namespace'=>'API'],function(){//App\Http\Controllers\API\ControllerBRoute::get('api/','ControllerB@index');});
NamePrefixesTheprefixesdon’tstopthere.It’scommonthatroutenameswillreflecttheinheritancechainofpathelements,sousers/comments/5willbeservedbyaroutenamedusers.comments.show.Inthiscase,it’scommontousearoutegrouparoundalloftheroutesthatarebeneaththeusers.commentsresource.
JustlikewecanprefixURLsegmentsandcontrollernamespaces,wecanalsoprefixstringstotheroutename.Withroutegroupnameprefixes,wecandefinethateveryroutewithinthisgroupshouldhaveagivenstringprefixedtoitsname.Inthiscontext,we’reprefixing"users."toeachroutename,then"comments."(seeExample3-16).
Example3-16.RoutegroupnameprefixesRoute::group(['as'=>'users.','prefix'=>'users'],function(){Route::group(['as'=>'comments.','prefix'=>'comments'],function(){//Routenamewillbeusers.comments.showRoute::get('{id}',function(){//})->name('show');});});
ViewsInafewoftherouteclosureswe’velookedatsofar,we’veseensomethingalongthelinesofreturnview('account').What’sgoingonhere?
Ifyou’renotfamiliarwiththeModel–View–Controller(MVC)pattern,views(ortemplates)arefilesthatdescribewhatsomeparticularoutputshouldlooklike.YoumighthaveviewsforJSONorXMLoremails,butthemostcommonviewsinawebframeworkoutputHTML.
InLaravel,therearetwoformatsofviewyoucanuseoutofthebox:plainPHP,orBladetemplates(seeChapter4).Thedifferenceisinthefilename:about.phpwillberenderedwiththePHPengine,andabout.blade.phpwillberenderedwiththeBladeengine.
THREEWAYSTOLOADAVIEW()Therearethreedifferentwaystoreturnaview.Fornow,justconcernyourselfwithview(),butifyoueverseeView::make(),it’sthesamething,andyoucouldalsoinjecttheIlluminate\View\ViewFactoryifyouprefer.
Onceyou’veloadedaview,youhavetheoptiontosimplyreturnit(asinExample3-17),whichwillworkfineiftheviewdoesn’trelyonanyvariablesfromthecontroller.
Example3-17.Simpleview()usageRoute::get('/',function(){returnview('home');});
Thiscodelooksforaviewinresources/views/home.blade.phporresources/views/home.php,andloadsitscontentsandparsesanyinlinePHPorcontrolstructuresuntilyouhavejusttheview’soutput.Onceyoureturnit,it’spassedontotherestoftheresponsestackandeventuallyreturnedtotheuser.
Butwhatifyouneedtopassinvariables?TakealookatExample3-18.
Example3-18.PassingvariablestoviewsRoute::get('tasks',function(){returnview('tasks.index')->with('tasks',Task::all());});
Thisclosureloadstheresources/views/tasks/index.blade.phporresources/views/tasks/index.phpviewandpassesitasinglevariablenamedtasks,whichcontainstheresultoftheTask::all()method.Task::all()isanEloquentdatabasequerywe’lllearnaboutinChapter8.
UsingViewComposerstoShareVariableswithEveryViewSometimesitcanbecomeahassletopassthesamevariablesoverandover.Theremaybeavariablethatyouwantaccessibletoeveryviewinthesite,ortoacertainclassofviewsoracertainincludedsubview—forexample,allviewsrelatedtotasks,ortheheaderpartial.
It’spossibletosharecertainvariableswitheverytemplateorjustcertaintemplates,likeinthefollowingcode:
view()->share('variableName','variableValue');
Tolearnmore,checkout“ViewComposersandServiceInjection”.
ControllersI’vementionedcontrollersafewtimes,butuntilnowmostoftheexampleshaveshownrouteclosures.Ifyou’renotfamiliarwiththeMVCpattern(Figure3-1),controllersareessentiallyclassesthatorganizethelogicofoneormoreroutestogetherinoneplace.Controllerstendtogroupsimilarroutestogether,especiallyifyourapplicationisstructuredalongatraditionallyCRUD-likeformat;inthiscase,acontrollermighthandlealltheactionsthatcanbeperformedonaparticularresource.
Figure3-1.AbasicillustrationofMVC
WHATISCRUD?CRUDstandsforcreate,read,update,delete,whicharethefourprimaryoperationsthatwebapplicationsmostcommonlyprovideonaresource.Forexample,youcancreateanewblogpost,youcanreadthatpost,youcanupdateit,oryoucandeleteit.
Itmaybetemptingtocramalloftheapplication’slogicintothecontrollers,butit’sbettertothinkofcontrollersasthetrafficcopsthatrouteHTTPrequestsaroundyourapplication.Sincethereareotherwaysrequestscancomeintoyourapplication—cronjobs,Artisancommand-linecalls,queuejobs,etc.—it’swisetonotrelyoncontrollersformuchbehavior.Thismeansacontroller ’sprimaryjobistocapturetheintentofanHTTPrequestandpassitontotherestoftheapplication.
So,let’screateacontroller.OneeasywaytodothisiswithanArtisancommand,sofromthecommandlinerunthefollowing:
phpartisanmake:controllerTasksController
ARTISANANDARTISANGENERATORSLaravelcomesbundledwithacommand-linetoolcalledArtisan.Artisancanbeusedtorunmigrations,createusersandotherdatabaserecordsmanually,andperformmanyothermanual,one-timetasks.
Underthemakenamespace,Artisanprovidestoolsforgeneratingskeletonfilesforavarietyofsystemfiles.That’swhatallowsustorunphpartisanmake:controller.
TolearnmoreaboutthisandotherArtisanfeatures,seeChapter7.
ThiswillcreateanewfilenamedTasksController.phpinapp/Http/Controllers,withthecontentsshowninExample3-19.
Example3-19.Defaultgeneratedcontroller
CONTROLLER NAMESPACING
InExample3-21wereferencedacontrollerwiththefullyqualifiedclassnameofApp\Http\Controllers\TasksController,butweonlyusedtheclassname.Thisisn’tbecausewecansimplyreferencecontrollersbytheirclassname.Rather,wecanignoretheApp\Http\Controllers\whenwereferencecontrollers;bydefault,Laravelisconfiguredtolookforcontrollerswithinthatnamespace.
ThismeansthatifyouhaveacontrollerwiththefullyqualifiedclassnameofApp\Http\Controllers\API\ExercisesController,you’dreferenceitinaroutedefinitionasAPI\ExercisesController.
Themostcommonuseofacontrollermethod,then,willbesomethinglikeExample3-22.
Example3-22.Commoncontrollermethodexample//TasksController.php...publicfunctionindex(){returnview('tasks.index')->with('tasks',Task::all());}
Thiscontrollermethodloadstheresources/views/tasks/index.blade.phporresources/views/tasks/index.phpviewandpassesitasinglevariablenamedtasks,whichcontainstheresultoftheTask::all()Eloquentmethod.
GENERATINGRESOURCECONTROLLERSIfyoueverusedphpartisanmake:controllerinLaravelpriorto5.3,youmightbeexpectingittoautogeneratemethodsforallofthebasicresourcerouteslikecreate()andupdate().YoucanbringthisbehaviorbackinLaravel5.3bypassingthe--resourceflagwhenyoucreatethecontroller:
phpartisanmake:controllerTasksController--resource
GettingUserInputThesecondmostcommonactiontoperforminacontrollermethodistotakeinputfromtheuserandactonit.Thatintroducesafewnewconcepts,solet’stakealookatabitofsamplecodeandwalkthroughthenewpieces.
First,let’sbinditquickly;seeExample3-23.
Example3-23.Bindingbasicformactions//routes/web.phpRoute::get('tasks/create','TasksController@create');Route::post('tasks','TasksController@store');
Noticethatwe’rebindingtheGETactionoftasks/create(whichshowstheform)andthePOSTactionoftasks/(whichiswherewePOSTwhenwe’recreatinganewtask).Wecanassumethecreate()methodinourcontrollerjustshowsaform,solet’slookatthestore()methodinExample3-24.
Example3-24.Commonforminputcontrollermethod//TasksController.php...publicfunctionstore(){$task=newTask;$task->title=Input::get('title');$task->description=Input::get('description');$task->save();
returnredirect('tasks');}
ThisexamplemakesuseofEloquentmodelsandtheredirect()functionality,andwe’lltalkaboutthemmorelater,butyoucanseewhatwe’redoinghere:wecreateanewTask,pulldataoutoftheuserinputandsetitonthetask,saveit,andthenredirectbacktothepagethatshowsalltasks.
TherearetwomainwaystogetuserinputfromaPOST:theInputfacade,whichweusedhere,andtheRequestobject,whichwe’lltalkaboutnext.
IMPORTINGFACADESIfyoufollowanyoftheseexamples,whetherincontrollersoranyotherPHPclassthatisnamespaced,youmightfinderrorsshowingthatthefacadecannotbefound.Thisisbecausethey’renotpresentineverynamespace,butratherthey’remadeavailableintherootnamespace.
So,inExample3-24,we’dneedtoimporttheInputfacadeatthetopofthefile.Therearetwowaystodothat:eitherwecanimport\Input,orwecanimportIlluminate\Support\Facades\Input.Forexample:
InjectingDependenciesintoControllersLaravel’sfacadespresentasimpleinterfacetothemostusefulclassesinLaravel’scodebase.Youcangetinformationaboutthecurrentrequestanduserinput,thesession,caches,andmuchmore.
Butifyouprefertoinjectyourdependencies,orifyouwanttouseaservicethatdoesn’thaveafacade,you’llneedtofindsomewaytobringinstancesoftheseclassesintoyourcontroller.
ThisisourfirstexposuretoLaravel’sservicecontainer.Fornow,ifthisisunfamiliar,youcanthinkaboutitasalittlebitofLaravelmagic;or,ifyouwanttoknowmoreabouthowit’sactuallyfunctioning,youcanskipaheadtoChapter11.
Allcontrollermethods(includingtheconstructors)areresolvedoutofLaravel’scontainer,whichmeansanythingyoutypehintthatthecontainerknowshowtoresolvewillbeautomaticallyinjected.
Asaniceexample,whatifyou’dpreferhavinganinstanceoftheRequestobjectinsteadofusingthefacade?JusttypehintIlluminate\Http\Requestinyourmethodparameters,likeinExample3-25.
Example3-25.Controllermethodinjectionviatypehinting//TasksController.php...publicfunctionstore(\Illuminate\Http\Request$request){$task=newTask;$task->title=$request->input('title');$task->description=$request->input('description');$task->save();
returnredirect('tasks');}
So,you’vedefinedaparameterthatmustbepassedintothestore()method.Andsinceyoutypehintedit,andsinceLaravelknowshowtoresolvethatclassname,you’regoingtohavetheRequestobjectreadyforyoutouseinyourmethodwithnoworkonyourpart.Noexplicitbinding,noanythingelse—it’sjustthereasthe$requestvariable.
Bytheway,thisisactuallyhowIandmanyotherLaraveldevelopersprefertogettheuserinput:injectaninstanceoftheRequestandreadtheuserinputfromthere,insteadofrelyingontheInputfacade.
ResourceControllersSometimesnamingthemethodsinyourcontrollerscanbethehardestpartofwritingacontroller.Thankfully,LaravelhassomeconventionsforalloftheroutesofatraditionalREST/CRUDcontroller(calleda“resourcecontroller”inLaravel);additionally,itcomeswithageneratoroutoftheboxandaconvenienceroutedefinitionthatallowsyoutobindanentireresourcecontrolleratonce.
ToseethemethodsthatLaravelexpectsforaresourcecontroller,let’sgenerateanewcontrollerfromthecommandline:
phpartisanmake:controllerMySampleResourceController--resource
Nowopenapp/Http/Controllers/MySampleResourceController.php.You’llseeitcomesprefilledwithquiteafewmethods.Let’swalkoverwhateachrepresents.We’lluseaTaskasanexample.
ThemethodsofLaravel’sresourcecontrollersForeach,youcanseetheHTTPverb,theURL,thecontrollermethodname,andthe“name.”Table3-1showstheHTTPverb,theURL,thecontrollermethodname,andthe“name”foreachofthesedefaultmethods.
Table3-1.ThemethodsofLaravel’sresourcecontrollers
Verb URL Controllermethod Name Description
GET tasks index() tasks.index Showalltasks
GET tasks/create create() tasks.create Showthecreatetaskform
POST tasks store() tasks.store Acceptformsubmissionfromthecreatetaskform
GET tasks/{task} show() tasks.show Showonetask
GET tasks/{task}/edit edit() tasks.edit Editonetask
PUT/PATCH tasks/{task} update() tasks.update Acceptformsubmissionfromtheedittaskform
DELETE tasks/{task} destroy() tasks.destroy Deleteonetask
BindingaresourcecontrollerSo,we’veseenthatthesearetheconventionalroutenamestouseinLaravel,andalsothatit’seasytogeneratearesourcecontrollerwithmethodsforeachofthesedefaultroutes.Thankfully,youdon’thavetogenerateroutesforeachofthesecontrollermethodsbyhand,ifyoudon’twantto.Instead,there’satrickforthat,andit’scalled“resourcecontrollerbinding.”TakealookatExample3-26.
Example3-26.Resourcecontrollerbinding//routes/web.phpRoute::resource('tasks','TasksController');
Thiswillautomaticallybindalloftheroutesforthisresourcetotheappropriatemethodnamesonthespecifiedcontroller.It’llalsonametheseroutesappropriately;forexample,theindex()methodonthetasksresourcecontrollerwillbenamedtasks.index.
ARTISANROUTE:LISTIfyoueverfindyourselfinasituationwhereyou’rewonderingwhatroutesyourcurrentapplicationhasavailable,there’satoolforthat:fromthecommandline,runphpartisanroute:listandyou’llgetalistingofalloftheavailableroutes(seeFigure3-2).
Figure3-2.phpartisanroute:listexample
RouteModelBindingOneofthemostcommonroutingpatternsisthatthefirstlineofanycontrollermethodtriestofindtheresourcewiththegivenID,likeinExample3-27.
Example3-27.GettingaresourceforeachrouteRoute::get('conferences/{id}',function($id){$conference=Conference::findOrFail($id);});
Laravelprovidesafeaturethatsimplifiesthispatterncalled“routemodelbinding.”Thisallowsyoutodefinethataparticularparametername(e.g.,{conference})willindicatetotherouteresolverthatitshouldlookupanEloquentrecordwiththatIDandthenpassitinastheparameterinsteadofjustpassingtheID.
Therearetwokindsofroutemodelbinding:implicitandcustom(orexplicit).
ImplicitRouteModelBindingThesimplestwaytouseroutemodelbindingistonameyourrouteparametersomethinguniquetothatmodel(e.g.,nameit$conferenceinsteadof$id),thentypehintthatparameterintheclosure/controllermethodandusethesamevariablenamethere.It’seasiertoshowthantodescribe,sotakealookatExample3-28.
Example3-28.UsinganexplicitroutemodelbindingRoute::get('conferences/{conference}',function(Conference$conference){returnview('conferences.show')->with('conference',$conference);});
Becausetherouteparameter({conference})isthesameasthemethodparameter($conference),andthemethodparameteristypehintedwithaConferencemodel(Conference$conference),Laravelseesthisasaroutemodelbinding.Everytimethisrouteisvisited,theapplicationwillassumethatwhateverispassedintotheURLinplaceof{conference}isanIDthatshouldbeusedtolookupaConference,andthenthatresultingmodelinstancewillbepassedintoyourclosureorcontrollermethod.
CUSTOMIZINGTHEROUTEKEYFORANELOQUENTMODELAnytimeanEloquentmodelislookedupviaaURLsegment(usuallybecauseofroutemodelbinding),thedefaultcolumnEloquentwilllookitupbyisitsprimarykey(ID).
TochangethecolumnyourEloquentmodelusesforURLlookups,addamethodtoyourmodelnamedgetRouteKeyName():
publicfunctiongetRouteKeyName(){return'slug';}
Now,aURLlikeconferences/{conference}willexpecttogetthesluginsteadoftheID,andwillperformitslookupsaccordingly.
ImplicitroutemodelbindingwasaddedinLaravel5.2,soyouwon’thaveaccesstoitin5.1.
CustomRouteModelBindingTomanuallyconfigureroutemodelbindings,addalineliketheoneinExample3-29totheboot()methodinApp\Providers\RouteServiceProvider.
Example3-29.Addingaroutemodelbindingpublicfunctionboot(Router$router){//Justallowstheparent'sboot()methodtostillrunparent::boot($router);
//Performthebinding$router->model('event',Conference::class);}
You’venowdefinedthatwheneveraroutehasaparameterinitsdefinitionnamed{event},asdemonstratedinExample3-30,therouteresolverwillreturnaninstanceoftheConferenceclasswiththeIDofthatURLparameter.
Example3-30.UsinganexplicitroutemodelbindingRoute::get('events/{event}',function(Conference$event){returnview('events.show')->with('event',$event);});
RouteCachingIfyou’relookingtosqueezeeverymillisecondoutofyourloadtime,youmaywanttotakealookatroutecaching.OneofthepiecesofLaravel’sbootstrapthatcantakeanywherefromafewdozentoafewhundredmillisecondsisparsingtheroutes/*files,androutecachingspeedsupthisprocessdramatically.
Tocacheyourroutesfile,youneedtobeusingallcontrollerandresourceroutes(norouteclosures).Ifyourappisn’tusinganyrouteclosures,youcanrunphpartisanroute:cache,Laravelwillserializetheresultsofyourroutes/*files.Ifyouwanttodeletethecache,runphpartisanroute:clear.
Here’sthedrawback:Laravelwillnowmatchroutesagainstthatcachedfileinsteadofyouractualroutes/*files.Youcanmakeendlesschangestothosefiles,andtheywon’ttakeeffectuntilyourunroute:cacheagain.Thismeansyou’llhavetorecacheeverytimeyoumakeachange,whichintroducesalotofpotentialforconfusion.
Here’swhatIwouldrecommendinstead:sinceGitignorestheroutecachefilebydefaultanyway,consideronlyusingroutecachingonyourproductionserver,andrunthephpartisanroute:cachecommandeverytimeyoudeploynewcode(whetherviaaGitpost-deployhook,aForgedeploycommand,orasapartofwhateverotherdeploysystemyouuse).Thiswayyouwon’thaveconfusinglocaldevelopmentissues,butyourremoteenvironmentwillstillbenefitfromroutecaching.
FormMethodSpoofingSometimes,youneedtomanuallydefinewhichHTTPverbaformshouldsendas.HTMLformsonlyallowforGETorPOST,soifyouwantanyothersortofverb,you’llneedtospecifythatyourself.
AnIntroductiontoHTTPVerbsWe’vetalkedabouttheGETandPOSTHTTPverbsalready.Ifyou’renotfamiliarwithHTTPverbs,theothertwomostcommononesarePUTandDELETE,butthere’salsoHEAD,OPTIONS,PATCH,andtwoothersthatareprettymuchneverusedinnormalwebdevelopment,TRACEandCONNECT.
Here’sthequickrundown:GETrequestsaresourceandHEADasksforaheaders-onlyversionoftheGET,POSTcreatesaresource,PUToverwritesaresourceandPATCHmodifiesaresource,DELETEdeletesaresource,andOPTIONSaskstheserverwhichverbsareallowedatthisURL.
HTTPVerbsinLaravelAswe’veshownalready,youcandefinewhichverbsaroutewillmatchintheroutedefinitionusingRoute::get(),Route::post(),Route::any(),orRoute::match().YoucanalsomatchwithRoute::patch(),Route::put(),andRoute::delete().
ButhowdoesonesendarequestotherthanGETwithawebbrowser?First,themethodattributeinanHTMLformdeterminesitsHTTPverb:ifyourformhasamethodof"GET",itwillsubmitviaqueryparametersandaGETmethod;iftheformhasamethodof"POST",itwillsubmitviathepostbodyandaPOSTmethod.
JavaScriptframeworksmakeiteasytosendotherrequests,likeDELETEandPATCH.ButifyoufindyourselfneedingtosubmitHTMLformsinLaravelwithverbsotherthanGETorPOST,you’llneedtouseformmethodspoofing,whichisspoofingtheHTTPmethodinanHTMLform.
HTTPMethodSpoofinginHTMLFormsToinformLaravelthattheformyou’recurrentlysubmittingshouldbetreatedassomethingotherthanPOST,addahiddenvariablenamed_methodwiththevalueofeither"PUT","PATCH",or"DELETE",andLaravelwillmatchandroutethatformsubmissionasifitwereactuallyarequestwiththatverb.
TheforminExample3-31,sinceit’spassingLaravelthemethodof"DELETE",willmatchroutesdefinedwithRoute::delete()butnotthosewithRoute::post().
Example3-31.Formmethodspoofing
CSRFProtectionIfyou’vetriedtocreateandsubmitaforminaLaravelapplicationalready—includingtheforminExample3-31—you’velikelyrunintothedreadedTokenMismatchException.
Bydefault,allroutesinLaravelexcept“read-only”routes(thoseusingGET,HEAD,orOPTIONS)areprotectedagainstcross-siterequestforgery(CSRF)attacksbyrequiringatoken,intheformofaninputnamed_token,tobepassedalongwitheachrequest.Thistokenisgeneratedatthestartofeverysession,andeverynon–read-onlyroutecomparesthesubmitted_tokenagainstthesessiontoken.
WHATISCSRF?Across-siterequestforgeryiswhenonewebsitepretendstobeanother.Thegoalisforsomeonetohijackyourusers’accesstoyourwebsite,bysubmittingformsfromtheirwebsitetoyourwebsiteviathelogged-inuser’sbrowser.
ThebestwayaroundCSRFattacksistoprotectallinboundroutes—POST,DELETE,etc.—withatoken,whichLaraveldoesoutofthebox.
Youhavetwooptionsforgettingaroundthis.Thefirst,andpreferred,methodistoaddthe_tokeninputtoeachofyoursubmissions.InHTMLforms,that’ssimple;lookatExample3-32.
Example3-32.CSRFtokens
RedirectsSofartheonlythingswe’vereturnedfromacontrollermethodorroutedefinitionhavebeenviews.Butthereareafewotherstructureswecanreturntogivethebrowserinstructionsonhowtobehave.
First,let’scovertheredirect.Therearetwocommonwaystogeneratearedirect;we’llusetheredirectglobalhelperhere,butyoumaypreferthefacade.BothcreateaninstanceofIlluminate\Http\RedirectResponse,performsomeconveniencemethodsonit,andthenreturnit.Youcanalsodothismanually,butyou’llhavetodoalittlemoreworkyourself.TakealookatExample3-34toseeafewwaysyoucanreturnaredirect.
Example3-34.Differentwaystoreturnaredirect//UsingtheglobalhelpertogeneratearedirectresponseRoute::get('redirect-with-helper',function(){returnredirect()->to('login');});
//UsingtheglobalhelpershortcutRoute::get('redirect-with-helper-shortcut',function(){returnredirect('login');});
//UsingthefacadetogeneratearedirectresponseRoute::get('redirect-with-facade',function(){returnRedirect::to('login');});
Notethattheredirect()helperexposesthesamemethodsastheRedirectfacade,butitalsohasashortcut;ifyoupassparametersdirectlytothehelper,insteadofchainingmethodsafterit,it’sashortcuttotheto()redirectmethod.
redirect()->to()Themethodsignaturefortheto()methodforredirectslookslikethis:
functionto($to=null,$status=302,$headers=[],$secure=null)
$toisavalidinternalpath;$statusistheHTTPstatus(defaultingto302FOUND);$headersallowsyoutodefinewhichHTTPheaderstosendalongwithyourredirect;and$secureallowsyoutooverridethedefaultchoiceofhttpversushttps(whichisnormallysetbasedonyourcurrentrequestURL).Example3-35showsanotherexampleofitsuse.
Example3-35.redirect()->to()Route::get('redirect',function(){returnredirect()->to('home');
//orsame,usingtheshortcut:
returnredirect('home');});
redirect()->route()Theroute()methodisthesameastheto()method,butratherthanpointingtoaparticularpath,itpointstoaparticularroutename(seeExample3-36).
Example3-36.redirect()->route()Route::get('redirect',function(){returnredirect()->route('conferences.index');});
Notethat,sincesomeroutenamesrequireparameters,itsparameterorderisalittledifferent.route()hasanoptionalsecondparameterfortherouteparameters:
functionroute($to=null,$parameters=[],$status=302,$headers=[])
So,usingitmightlookalittlelikeExample3-37.
Example3-37.redirect()->route()withparametersRoute::get('redirect',function(){returnredirect()->route('conferences.show',['conference'=>99]);});
redirect()->back()Becauseofsomeofthebuilt-inconveniencesofLaravel’ssessionimplementation,yourapplicationwillalwayshaveknowledgeofwhattheuser ’spreviouslyvisitedpagewas.Thatopensuptheopportunityforaredirect()->()redirect,whichsimplyredirectstheusertowhateverpageshecamefrom.There’salsoaglobalshortcutforthis:back().
OtherRedirectMethodsTheredirectserviceprovidesothermethodsthatarelesscommonlyused,butstillavailable:
home()redirectstoaroutenamedhome.
refresh()redirectstothesamepagetheuseriscurrentlyon.
away()allowsforredirectingtoanexternalURLwithoutthedefaultURLvalidation.
secure()isliketo()withthesecureparametersetto"true".
action()allowsyoutolinktoacontrollerandmethodlikethis:redirect()->action('MyController@myMethod').
guest()isusedinternallybytheauthsystem(discussedinChapter9);whenauservisitsaroutehe’snotauthenticatedfor,thiscapturesthe“intended”routeandthenredirectstheuser(usuallytoaloginpage).
intended()isalsousedinternallybytheauthsystem;afterasuccessfulauthentication,thisgrabsthe“intended”URLstoredbytheguest()methodandredirectstheuserthere.
redirect()->with()Whenyou’reredirectinguserstodifferentpages,youoftenwanttopasscertaindataalongwiththem.Youcouldmanuallyflashthedatatothesession,butLaravelhassomeconveniencemethodstohelpyouwiththat.
Mostcommonly,youcanpassalongeitheranarrayofkeysandvaluesorasinglekeyandvalueusingwith(),likeinExample3-38.
Example3-38.RedirectwithdataRoute::get('redirect-with-key-value',function(){returnredirect('dashboard')->with('error',true);});
Route::get('redirect-with-array',function(){returnredirect('dashboard')->with(['error'=>true,'message'=>'Whoops!']);});
CHAININGMETHODSONREDIRECTSAswithmanyotherfacades,mostcallstotheRedirectfacadecanacceptfluentmethodchains,likethewith()callsinExample3-38.Learnmoreaboutfluencyin“WhatIsaFluentInterface?”.
YoucanalsousewithInput(),asinExample3-39,toredirectwiththeuser ’sforminputflashed;thisismostcommoninthecaseofavalidationerror,whereyouwanttosendtheuserbacktotheformshejustcamefrom.
Example3-39.RedirectwithforminputRoute::get('form',function(){returnview('form');});
Route::post('form',function(){returnredirect('form')->withInput()->with(['error'=>true,'message'=>'Whoops!']);});
TheeasiestwaytogettheflashedinputthatwaspassedwithwithInput()isusingtheold()helper,whichcanbeusedtogetalloldinput(old())orjustthevalueforaparticularkey(old('username'),withthesecondparameterasthedefaultifthereisnooldvalue).You’llcommonlyseethisinviews,whichallowsthisHTMLtobeusedbothonthe“create”andthe“edit”viewforthisform:
THEVALIDATE()SHORTCUTINCONTROLLERMETHODSLikehowExample3-40looks?Ifyou’redefiningyourroutesinacontroller,there’sasimpleandpowerfultoolthatcleansupthatcode.Readmorein“validate()intheControllerUsingValidatesRequests”.
AbortingtheRequestAsidefromreturningviewsandredirects,themostcommonwaytoexitarouteistoabort.Thereareafewgloballyavailablemethods(abort(),abort_if(),andabort_unless()),whichoptionallytakeHTTPstatuscodes,amessage,andaheadersarrayasparameters.
AsExample3-41shows,abort_if()andabort_unless()takeafirstparameterthatisevaluatedforitstruthiness,andperformtheabortdependingontheresult.
Example3-41.403ForbiddenabortsRoute::post('something-you-cant-do',function(Illuminate\Http\Request){abort(403,'Youcannotdothat!');abort_unless($request->has('magicToken'),403);abort_if($request->user()->isBanned,403);});
CustomResponsesThereareafewotheroptionsavailableforustoreturn,solet’sgooverthemostcommonresponsesafterviews,redirects,andaborts.Justlikewithredirects,youcaneitherusetheresponse()helperortheResponsefacadetorunthesemethodson.
response()->make()IfyouwanttocreateanHTTPresponsemanually,justpassyourdataintothefirstparameterofresponse()->make():e.g.,returnresponse()->make('Hello,World!').Onceagain,thesecondparameteristheHTTPstatuscodeandthethirdisyourheaders.
response()->json()and->jsonp()TocreateaJSON-encodedHTTPresponsemanually,passyourJSON-ablecontent(arrays,collections,orwhateverelse)tothejson()method:e.g.,returnresponse()->json(User::all());.It’sjustlikemake(),exceptitjson_encodesyourcontentandsetstheappropriateheaders.
response()->download()and->file()Tosendafilefortheendusertodownload,passeitheranSplFileInfoinstanceorastringfilenametodownload(),withanoptionalsecondparameterofthefilename:e.g.,returnresponse()->download('file501751.pdf','myFile.pdf').
Todisplaythesamefileinthebrowser(ifit’saPDForanimageorsomethingelsethebrowsercanhandle),useresponse()->file()instead,whichtakesthesameparameters.
TestingInsomeothercommunities,theideaofunittestingcontrollermethodsiscommon,butwithinLaravel(andmostofthePHPcommunity),it’smostcommontorelyonapplicationtestingtotestthefunctionalityofroutes.
Forexample,toverifythataPOSTrouteworkscorrectly,wecanwriteatestlikeExample3-42.
Example3-42.WritingasimplePOSTroutetest//AssignmentTest.phppublicfunctiontest_post_creates_new_assignment(){$this->post('/assignments',['title'=>'Mygreatassignment']);
$this->seeInDatabase('assignments',['title'=>'Mygreatassignment']);}
Didwedirectlycallthecontrollermethods?No.Butweensuredthatthegoalofthisroute—toreceiveaPOSTandsaveitsimportantinformationtothedatabase—wasmet.
Youcanalsousesimilarsyntaxtovisitarouteandverifythatcertaintextshowsuponthepage,orthatclickingcertainbuttonsdoescertainthings(seeExample3-43).
Example3-43.WritingasimpleGETroutetest//AssignmentTest.phppublicfunctiontest_list_page_shows_all_assignments(){$assignment=Assignment::create(['title'=>'Mygreatassignment']);
$this->visit('assignments')->dee(['Mygreatassignment']);}
TL;DRLaravel’sroutesaredefinedinroutes/web.phpandroutes/api.php,whereyoucandefinetheexpectedpathforeachroute,whichsegmentsarestaticandwhichareparameters,whichHTTPverbscanaccesstheroute,andhowtoresolveit.Youcanalsoattachmiddlewaretoroutes,groupthem,andgivethemnames.
WhatisreturnedfromtherouteclosureorcontrollermethoddictateshowLaravelrespondstotheuser.Ifit’sastringoraview,it’spresentedtotheuser;ifit’sothersortsofdata,it’sconvertedtoJSONandpresentedtotheuser;andifit’saredirect,itforcesaredirect.
Laravelprovidesaseriesoftoolsandconveniencestosimplifycommonrouting-relatedtasksandstructures.Theseincluderesourcecontrollers,routemodelbinding,andformmethodspoofing.
Chapter4.BladeTemplating
Comparedtomostotherbackendlanguages,PHPactuallyfunctionsrelativelywellasatemplatinglanguage.Butithasitsshortcomings,andit’salsojustuglytobeusing
USINGTWIGWITHLARAVELUnlikemanyotherSymfony-basedframeworks,Laraveldoesn’tuseTwigbydefault.Butifyou’rejustinlovewithTwig,there’saTwigBridgepackagethatmakesiteasytouseTwiginsteadofBlade.
https://github.com/rcrowe/TwigBridge
EchoingDataAsyoucanseeinExample4-1,{{and}}areusedtowrapsectionsofPHPthatyou’dliketoecho.{{$variable}}issimilartoinplainPHP.
It’sdifferentinoneway,however,andyoumight’veguessedthisalready:BladeescapesallechoesbydefaultusingPHP’shtmlentities()toprotectyourusersfrommaliciousscriptinsertion.Thatmeans{{$variable}}isfunctionallyequivalentto.Ifyouwanttoechowithouttheescaping,use{!!and!!}instead.
{{AND}}WHENUSINGAFRONTENDTEMPLATINGFRAMEWORK
Youmight’venoticedthattheechosyntaxforBlade({{}})issimilartotheechosyntaxformanyfrontendframeworks.So,howdoesLaravelknowwhenyou’rewritingBladeversusHandlebars?
Bladewillignoreany{{that’[email protected],itwillparsethefirstofthefollowingexamples,butthesecondwillbeechoedoutdirectly:
//ParsedasBlade;thevalueof$bladeVariableisechoedtotheview{{$bladeVariable}}
//@isremoved,and"{{handlebarsVariable}}"echoedtotheviewdirectly@{{handlebarsVariable}}
ControlStructuresMostofthecontrolstructuresinBladewillbeveryfamiliar.ManydirectlyechothenameandstructureofthesametaginPHP.
Thereareafewconveniencehelpers,butingeneral,thecontrolstructuresjustlookcleanerthantheywouldinPHP.
ConditionalsFirst,let’stakealookatthecontrolstructuresthatallowforlogic.
@ifBlade’s@if($condition)compilesto.@else,@elseif,and@endifalsocompiletotheexactsamesyntaxinPHP.TakealookatExample4-2forsomeexamples.
Example4-2.@if,@else,@elseif,and@endif@if(count($talks)===1)Thereisonetalkatthistimeperiod.@elseif(count($talks)===0)Therearenotalksatthistimeperiod.@elseThereare{{count($talks)}}talksatthistimeperiod.@endif
JustlikewiththenativePHPconditionals,youcanmixandmatchthesehowyouwant.Theydon’thaveanyspeciallogic;there’sliterallyaparserlookingforsomethingwiththeshapeof@if($condition)andreplacingitwiththeappropriatePHPcode.
@unlessand@endunless@unless,ontheotherhand,isanewsyntaxthatdoesn’thaveadirectequivalentinPHP.It’sthedirectinverseof@if.@unless($condition)isthesameas
LoopsNext,let’stakealookattheloops.
@for,@foreach,and@while@for,@foreach,and@whileworkthesameinBladeastheydoinPHP;seeExamples4-4,4-5,and4-6.
Example4-4.@forand@endfor@for($i=0;$i<$talk->slotsCount();$i++)Thenumberis{{$i}}
@endfor
Example4-5.@foreachand@endforeach@foreach($talksas$talk)•{{$talk->title}}({{$talk->length}}minutes)
@endforeach
Example4-6.@whileand@endwhile@while($item=array_pop($items)){{$item->orSomething()}}
@endwhile
@forelse@forelseisa@foreachthatalsoallowsyoutoprograminafallbackiftheobjectyou’reiteratingoverisempty.Wesawitinactionatthestartofthischapter;Example4-7showsanotherexample.
Example4-7.@forelse@forelse($talksas$talk)•{{$talk->title}}({{$talk->length}}minutes)
@emptyNotalksthisday.@endforelse
$LOOPWITHIN@FOREACHAND@FORELSEThe@[email protected]’snotavailableinPHPforeachloops:the$loopvariable.Usedwithina@foreachor@forelseloop,thisvariablewillreturnastdClassobjectwiththefollowingproperties:
index
The0-basedindexofthecurrentitemintheloop;0wouldmean“fi