Download - Laravel 5.0 Documentation
1. Introduction2. Prologue
i. ReleaseNotesi. Laravel5.0ii. Laravel4.2iii. Laravel4.1
ii. UpgradeGuidei. UpgradingTo5.0From4.2ii. UpgradingTo4.2From4.1iii. UpgradingTo4.1.29From<=4.1.xiv. UpgradingTo4.1.26From<=4.1.25v. UpgradingTo4.1From4.0
iii. ContributionGuidei. BugReportsii. CoreDevelopmentDiscussioniii. WhichBranch?iv. SecurityVulnerabilitiesv. CodingStyle
3. Setupi. Installation
i. InstallComposerii. InstallLaraveliii. ServerRequirements
ii. Configurationi. Introductionii. AfterInstallationiii. AccessingConfigurationValuesiv. EnvironmentConfigurationv. ConfigurationCachingvi. MaintenanceModevii. PrettyURLs
iii. Homesteadi. Introductionii. IncludedSoftwareiii. Installation&Setupiv. DailyUsagev. Ports
4. TheBasicsi. Routing
i. BasicRoutingii. CSRFProtectioniii. MethodSpoofingiv. RouteParametersv. NamedRoutesvi. RouteGroupsvii. RouteModelBindingviii. Throwing404Errors
ii. Middlewarei. Introductionii. DefiningMiddlewareiii. RegisteringMiddlewareiv. TerminableMiddleware
TableofContents
iii. Controllersi. Introductionii. BasicControllersiii. ControllerMiddlewareiv. ImplicitControllersv. RESTfulResourceControllersvi. DependencyInjection&Controllersvii. RouteCaching
iv. Requestsi. ObtainingARequestInstanceii. RetrievingInputiii. OldInputiv. Cookiesv. Filesvi. OtherRequestInformation
v. Responsesi. BasicResponsesii. Redirectsiii. OtherResponsesiv. ResponseMacros
vi. Viewsi. BasicUsageii. ViewComposers
5. ArchitectureFoundationsi. ServiceProviders
i. Introductionii. BasicProviderExampleiii. RegisteringProvidersiv. DeferredProviders
ii. ServiceContaineri. Introductionii. BasicUsageiii. BindingInterfacesToImplementationsiv. ContextualBindingv. Taggingvi. PracticalApplicationsvii. ContainerEvents
iii. Contractsi. Introductionii. WhyContracts?iii. ContractReferenceiv. HowToUseContracts
iv. Facadesi. Introductionii. Explanationiii. PracticalUsageiv. CreatingFacadesv. MockingFacadesvi. FacadeClassReference
v. RequestLifecyclei. Introductionii. LifecycleOverviewiii. FocusOnServiceProviders
vi. ApplicationStructurei. Introductionii. TheRootDirectory
iii. TheAppDirectoryiv. NamespacingYourApplication
6. Servicesi. Authentication
i. Introductionii. AuthenticatingUsersiii. RetrievingTheAuthenticatedUseriv. ProtectingRoutesv. HTTPBasicAuthenticationvi. PasswordReminders&Resetvii. SocialAuthentication
ii. Billingi. Introductionii. Configurationiii. SubscribingToAPlaniv. NoCardUpFrontv. SwappingSubscriptionsvi. SubscriptionQuantityvii. CancellingASubscriptionviii. ResumingASubscriptionix. CheckingSubscriptionStatusx. HandlingFailedPaymentsxi. HandlingOtherStripeWebhooksxii. Invoices
iii. Cachei. Configurationii. CacheUsageiii. Increments&Decrementsiv. CacheTagsv. DatabaseCache
iv. Collectionsi. Introductionii. BasicUsage
v. CommandBusi. Introductionii. CreatingCommandsiii. DispatchingCommandsiv. QueuedCommandsv. CommandPipeline
vi. CoreExtensioni. Managers&Factoriesii. Cacheiii. Sessioniv. Authenticationv. IoCBasedExtension
vii. Elixiri. Introductionii. Installation&Setupiii. Usageiv. Gulpv. Extensions
viii. Encryptioni. Introductionii. BasicUsage
ix. Errors&Loggingi. Configuration
ii. HandlingErrorsiii. HTTPExceptionsiv. Logging
x. Eventsi. BasicUsageii. QueuedEventHandlersiii. EventSubscribers
xi. Filesystem/CloudStoragei. Introductionii. Configurationiii. BasicUsage
xii. Hashingi. Introductionii. BasicUsage
xiii. Helpersi. Arraysii. Pathsiii. Stringsiv. URLsv. Miscellaneous
xiv. Localizationi. Introductionii. LanguageFilesiii. BasicUsageiv. Pluralizationv. ValidationLocalizationvi. OverridingPackageLanguageFiles
xv. Maili. Configurationii. BasicUsageiii. EmbeddingInlineAttachmentsiv. QueueingMailv. Mail&LocalDevelopment
xvi. PackageDevelopmenti. Introductionii. Viewsiii. Translationsiv. Configurationv. PublishingFileGroupsvi. Routing
xvii. Paginationi. Configurationii. Usageiii. AppendingToPaginationLinksiv. ConvertingToJSON
xviii. Queuesi. Configurationii. BasicUsageiii. QueueingClosuresiv. RunningTheQueueListenerv. DaemonQueueWorkervi. PushQueuesvii. FailedJobs
xix. Sessioni. Configurationii. SessionUsage
iii. FlashDataiv. DatabaseSessionsv. SessionDrivers
xx. Templatesi. BladeTemplatingii. OtherBladeControlStructuresiii. ExtendingBlade
xxi. UnitTestingi. Introductionii. Defining&RunningTestsiii. TestEnvironmentiv. CallingRoutesFromTestsv. MockingFacadesvi. FrameworkAssertionsvii. HelperMethodsviii. RefreshingTheApplication
xxii. Validationi. BasicUsageii. ControllerValidationiii. FormRequestValidationiv. WorkingWithErrorMessagesv. ErrorMessages&Viewsvi. AvailableValidationRulesvii. ConditionallyAddingRulesviii. CustomErrorMessagesix. CustomValidationRules
7. Databasei. BasicUsage
i. Configurationii. Read/WriteConnectionsiii. RunningQueriesiv. DatabaseTransactionsv. AccessingConnectionsvi. QueryLogging
ii. QueryBuilderi. Introductionii. Selectsiii. Joinsiv. AdvancedWheresv. Aggregatesvi. RawExpressionsvii. Insertsviii. Updatesix. Deletesx. Unionsxi. PessimisticLocking
iii. EloquentORMi. Introductionii. BasicUsageiii. MassAssignmentiv. Insert,Update,Deletev. SoftDeletingvi. Timestampsvii. QueryScopesviii. GlobalScopesix. Relationships
x. QueryingRelationsxi. EagerLoadingxii. InsertingRelatedModelsxiii. TouchingParentTimestampsxiv. WorkingWithPivotTablesxv. Collectionsxvi. Accessors&Mutatorsxvii. DateMutatorsxviii. AttributeCastingxix. ModelEventsxx. ModelObserversxxi. ConvertingToArrays/JSON
iv. SchemaBuilderi. Introductionii. Creating&DroppingTablesiii. AddingColumnsiv. ChangingColumnsv. RenamingColumnsvi. DroppingColumnsvii. CheckingExistenceviii. AddingIndexesix. ForeignKeysx. DroppingIndexesxi. DroppingTimestamps&SoftDeletesxii. StorageEngines
v. Migrations&Seedingi. Introductionii. CreatingMigrationsiii. RunningMigrationsiv. RollingBackMigrationsv. DatabaseSeeding
vi. Redisi. Introductionii. Configurationiii. Usageiv. Pipelining
8. ArtisanCLIi. Overview
i. Introductionii. Usageiii. CallingCommandsOutsideOfCLIiv. SchedulingArtisanCommands
ii. Developmenti. Introductionii. BuildingACommandiii. RegisteringCommands
ReleaseNotesLaravel5.0Laravel4.2Laravel4.1
UpgradeGuideUpgradingTo5.0From4.2UpgradingTo4.2From4.1UpgradingTo4.1.29From<=4.1.xUpgradingTo4.1.26From<=4.1.25UpgradingTo4.1From4.0
ContributionGuideBugReportsCoreDevelopmentDiscussionWhichBranch?SecurityVulnerabilitiesCodingStyle
Prologue
Laravel5.0Laravel4.2Laravel4.1
Laravel5.0introducesafreshapplicationstructuretothedefaultLaravelproject.ThisnewstructureservesasabetterfoundationforbuildingrobustapplicationinLaravel,aswellasembracesnewauto-loadingstandards(PSR-4)throughouttheapplication.First,let'sexaminesomeofthemajorchanges:
Theoldapp/modelsdirectoryhasbeenentirelyremoved.Instead,allofyourcodelivesdirectlywithintheappfolder,and,bydefault,isorganizedtotheAppnamespace.Thisdefaultnamespacecanbequicklychangedusingthenewapp:nameArtisancommand.
Controllers,middleware,andrequests(anewtypeofclassinLaravel5.0)arenowgroupedundertheapp/Httpdirectory,astheyareallclassesrelatedtotheHTTPtransportlayerofyourapplication.Insteadofasingle,flatfileofroutefilters,allmiddlewarearenowbrokenintotheirownclassfiles.
Anewapp/Providersdirectoryreplacestheapp/startfilesfrompreviousversionsofLaravel4.x.Theseserviceprovidersprovidevariousbootstrappingfunctionstoyourapplication,suchaserrorhandling,logging,routeloading,andmore.Ofcourse,youarefreetocreateadditionalserviceprovidersforyourapplication.
Applicationlanguagefilesandviewshavebeenmovedtotheresourcesdirectory.
AllmajorLaravelcomponentsimplementinterfaceswhicharelocatedintheilluminate/contractsrepository.Thisrepositoryhasnoexternaldependencies.Havingaconvenient,centrallylocatedsetofinterfacesyoumayusefordecouplinganddependencyinjectionwillserveasaneasyalternativeoptiontoLaravelFacades.
Formoreinformationoncontracts,consultthefulldocumentation.
Ifyourapplicationismadeupentirelyofcontrollerroutes,youmayutilizethenewroute:cacheArtisancommandtodrasticallyspeeduptheregistrationofyourroutes.Thisisprimarilyusefulonapplicationswith100+routesandwilldrasticallyspeedupthisportionofyourapplication.
InadditiontoLaravel4styleroute"filters",Laravel5nowsupportsHTTPmiddleware,andtheincludedauthenticationandCSRF"filters"havebeenconvertedtomiddleware.Middlewareprovidesasingle,consistentinterfacetoreplacealltypesoffilters,allowingyoutoeasilyinspect,andevenreject,requestsbeforetheyenteryourapplication.
Formoreinformationonmiddleware,checkoutthedocumentation.
Inadditiontotheexistingconstructorinjection,youmaynowtype-hintdependenciesoncontrollermethods.TheIoCcontainerwillautomaticallyinjectthedependencies,eveniftheroutecontainsotherparameters:
ReleaseNotes
Laravel5.0
NewFolderStructure
Contracts
RouteCache
RouteMiddleware
ControllerMethodInjection
publicfunctioncreatePost(Request$request,PostRepository$posts)
{
//
}
Userregistration,authentication,andpasswordresetcontrollersarenowincludedoutofthebox,aswellassimplecorrespondingviews,whicharelocatedatresources/views/auth.Inaddition,a"users"tablemigrationhasbeenincludedwiththeframework.Includingthesesimpleresourcesallowsrapiddevelopmentofapplicationideaswithoutboggingdownonauthenticationboilerplate.Theauthenticationviewsmaybeaccessedontheauth/loginandauth/registerroutes.TheApp\Services\Auth\Registrarserviceisresponsibleforuservalidationandcreation.
Youmaynowdefineeventsasobjectsinsteadofsimplyusingstrings.Forexample,checkoutthefollowingevent:
classPodcastWasPurchased{
public$podcast;
publicfunction__construct(Podcast$podcast)
{
$this->podcast=$podcast;
}
}
Theeventmaybedispatchedlikenormal:
Event::fire(newPodcastWasPurchased($podcast));
Ofcourse,youreventhandlerwillreceivetheeventobjectinsteadofalistofdata:
classReportPodcastPurchase{
publicfunctionhandle(PodcastWasPurchased$event)
{
//
}
}
Formoreinformationonworkingwithevents,checkoutthefulldocumentation.
InadditiontothequeuejobformatsupportedinLaravel4,Laravel5allowsyoutorepresentyourqueuedjobsassimplecommandobjects.Thesecommandsliveintheapp/Commandsdirectory.Here'sasamplecommand:
classPurchasePodcastextendsCommandimplementsSelfHandling,ShouldBeQueued{
useSerializesModels;
protected$user,$podcast;
/**
*Createanewcommandinstance.
*
*@returnvoid
AuthenticationScaffolding
EventObjects
Commands/Queueing
*/
publicfunction__construct(User$user,Podcast$podcast)
{
$this->user=$user;
$this->podcast=$podcast;
}
/**
*Executethecommand.
*
*@returnvoid
*/
publicfunctionhandle()
{
//Handlethelogictopurchasethepodcast...
event(newPodcastWasPurchased($this->user,$this->podcast));
}
}
ThebaseLaravelcontrollerutilizesthenewDispatchesCommandstrait,allowingyoutoeasilydispatchyourcommandsforexecution:
$this->dispatch(newPurchasePodcastCommand($user,$podcast));
Ofcourse,youmayalsousecommandsfortasksthatareexecutedsynchonrously(arenotqueued).Infact,usingcommandsisagreatwaytoencapsulatecomplextasksyourapplicationneedstoperform.Formoreinformation,checkoutthecommandbusdocumentation.
AdatabasequeuedriverisnowincludedinLaravel,providingasimple,localqueuedriverthatrequiresnoextrapackageinstallationbeyondyourdatabasesoftware.
Inthepast,developershavegeneratedaCronentryforeachconsolecommandtheywishedtoschedule.However,thisisaheadache.Yourconsolescheduleisnolongerinsourcecontrol,andyoumustSSHintoyourservertoaddtheCronentries.Let'smakeourliveseasier.TheLaravelcommandschedulerallowsyoutofluentlyandexpressivelydefineyourcommandschedulewithinLaravelitself,andonlyasingleCronentryisneededonyourserver.
Itlookslikethis:
$schedule->command('artisan:command')->dailyAt('15:00');
Ofcourse,checkoutthefulldocumentationtolearnallaboutthescheduler!
ThephpartisantinkercommandnowutilizesPsyshbyJustinHileman,amorerobustREPLforPHP.IfyoulikedBorisinLaravel4,you'regoingtolovePsysh.Evenbetter,itworksonWindows!Togetstarted,justtry:
phpartisantinker
Insteadofavarietyofconfusing,nestedenvironmentconfigurationdirectories,Laravel5nowutilizesDotEnvbyVance
DatabaseQueue
LaravelScheduler
Tinker/Psysh
DotEnv
Lucas.Thislibraryprovidesasupersimplewaytomanageyourenvironmentconfiguration,andmakesenvironmentdetectioninLaravel5abreeze.Formoredetails,checkoutthefullconfigurationdocumentation.
LaravelElixir,byJeffreyWay,providesafluent,expressiveinterfacetocompilingandconcatenatingyourassets.Ifyou'veeverbeenintimidatedbylearningGruntorGulp,fearnomore.ElixirmakesitacinchtogetstartedusingGulptocompileyourLess,Sass,andCoffeeScript.Itcanevenrunyourtestsforyou!
FormoreinformationonElixir,checkoutthefulldocumentation.
LaravelSocialiteisanoptional,Laravel5.0+compatiblepackagethatprovidestotallypainlessauthenticationwithOAuthproviders.Currently,SocialitesupportsFacebook,Twitter,Google,andGitHub.Here'swhatitlookslike:
publicfunctionredirectForAuth()
{
returnSocialize::with('twitter')->redirect();
}
publicfunctiongetUserFromProvider()
{
$user=Socialize::with('twitter')->user();
}
NomorespendinghourswritingOAuthauthenticationflows.Getstartedinminutes!Thefulldocumentationhasallthedetails.
LaravelnowincludesthepowerfulFlysystemfilesystemabstractionlibrary,providingpainfreeintegrationwithlocal,AmazonS3,andRackspacecloudstorage-allwithone,unifiedandelegantAPI!StoringafileinAmazonS3isnowassimpleas:
Storage::put('file.txt','contents');
FormoreinformationontheLaravelFlysystemintegration,consultthefulldocumentation.
Laravel5.0introducesformrequests,whichextendtheIlluminate\Foundation\Http\FormRequestclass.Theserequestobjectscanbecombinedwithcontrollermethodinjectiontoprovideaboiler-platefreemethodofvalidatinguserinput.Let'sdiginandlookatasampleFormRequest:
<?phpnamespaceApp\Http\Requests;
classRegisterRequestextendsFormRequest{
publicfunctionrules()
{
return[
'email'=>'required|email|unique:users',
'password'=>'required|confirmed|min:8',
];
}
publicfunctionauthorize()
{
returntrue;
}
LaravelElixir
LaravelSocialite
FlysystemIntegration
FormRequests
}
Oncetheclasshasbeendefined,wecantype-hintitonourcontrolleraction:
publicfunctionregister(RegisterRequest$request)
{
var_dump($request->input());
}
WhentheLaravelIoCcontaineridentifiesthattheclassitisinjectingisaFormRequestinstance,therequestwillautomaticallybevalidated.Thismeansthatifyourcontrolleractioniscalled,youcansafelyassumetheHTTPrequestinputhasbeenvalidatedaccordingtotherulesyouspecifiedinyourformrequestclass.Evenmore,iftherequestisinvalid,anHTTPredirect,whichyoumaycustomize,willautomaticallybeissued,andtheerrormessageswillbeeitherflashedtothesessionorconvertedtoJSON.Formvalidationhasneverbeenmoresimple.FormoreinformationonFormRequestvalidation,checkoutthedocumentation.
TheLaravel5basecontrollernowincludesaValidatesRequeststrait.Thistraitprovidesasimplevalidatemethodtovalidateincomingrequests.IfFormRequestsarealittletoomuchforyourapplication,checkthisout:
publicfunctioncreatePost(Request$request)
{
$this->validate($request,[
'title'=>'required|max:255',
'body'=>'required',
]);
}
Ifthevalidationfails,anexceptionwillbethrownandtheproperHTTPresponsewillautomaticallybesentbacktothebrowser.Thevalidationerrorswillevenbeflashedtothesession!IftherequestwasanAJAXrequest,LaraveleventakescareofsendingaJSONrepresentationofthevalidationerrorsbacktoyou.
Formoreinformationonthisnewmethod,checkoutthedocumentation.
Tocomplimentthenewdefaultapplicationstructure,newArtisangeneratorcommandshavebeenaddedtotheframework.Seephpartisanlistformoredetails.
Youmaynowcacheallofyourconfigurationinasinglefileusingtheconfig:cachecommand.
Thepopularddhelperfunction,whichdumpsvariabledebuginformation,hasbeenupgradedtousetheamazingSymfonyVarDumper.Thisprovidescolor-codedoutputandevencollapsingofarrays.Justtrythefollowinginyourproject:
dd([1,2,3]);
Thefullchangelistforthisreleasebyrunningthephpartisanchangescommandfroma4.2installation,orbyviewingthe
SimpleControllerRequestValidation
NewGenerators
ConfigurationCache
SymfonyVarDumper
Laravel4.2
changefileonGithub.Thesenotesonlycoverthemajorenhancementsandchangesfortherelease.
Note:Duringthe4.2releasecycle,manysmallbugfixesandenhancementswereincorporatedintothevariousLaravel4.1pointreleases.So,besuretocheckthechangelistforLaravel4.1aswell!
Laravel4.2requiresPHP5.4orgreater.ThisupgradedPHPrequirementallowsustousenewPHPfeaturessuchastraitstoprovidemoreexpressiveinterfacesfortoolslikeLaravelCashier.PHP5.4alsobringssignificantspeedandperformanceimprovementsoverPHP5.3.
LaravelForge,anewwebbasedapplication,providesasimplewaytocreateandmanagePHPserversonthecloudofyourchoice,includingLinode,DigitalOcean,Rackspace,andAmazonEC2.SupportingautomatedNginxconfiguration,SSHkeyaccess,Cronjobautomation,servermonitoringviaNewRelic&Papertrail,"PushToDeploy",Laravelqueueworkerconfiguration,andmore,ForgeprovidesthesimplestandmostaffordablewaytolaunchallofyourLaravelapplications.
ThedefaultLaravel4.2installation'sapp/config/database.phpconfigurationfileisnowconfiguredforForgeusagebydefault,allowingformoreconvenientdeploymentoffreshapplicationsontotheplatform.
MoreinformationaboutLaravelForgecanbefoundontheofficialForgewebsite.
LaravelHomesteadisanofficialVagrantenvironmentfordevelopingrobustLaravelandPHPapplications.Thevastmajorityoftheboxes'provisioningneedsarehandledbeforetheboxispackagedfordistribution,allowingtheboxtobootextremelyquickly.HomesteadincludesNginx1.6,PHP5.6,MySQL,Postgres,Redis,Memcached,Beanstalk,Node,Gulp,Grunt,&Bower.HomesteadincludesasimpleHomestead.yamlconfigurationfileformanagingmultipleLaravelapplicationsonasinglebox.
ThedefaultLaravel4.2installationnowincludesanapp/config/local/database.phpconfigurationfilethatisconfiguredtousetheHomesteaddatabaseoutofthebox,makingLaravelinitialinstallationandconfigurationmoreconvenient.
TheofficialdocumentationhasalsobeenupdatedtoincludeHomesteaddocumentation.
LaravelCashierisasimple,expressivelibraryformanagingsubscriptionbillingwithStripe.WiththeintroductionofLaravel4.2,weareincludingCashierdocumentationalongwiththemainLaraveldocumentation,thoughinstallationofthecomponentitselfisstilloptional.ThisreleaseofCashierbringsnumerousbugfixes,multi-currencysupport,andcompatibilitywiththelatestStripeAPI.
TheArtisanqueue:workcommandnowsupportsa--daemonoptiontostartaworkerin"daemonmode",meaningtheworkerwillcontinuetoprocessjobswithouteverre-bootingtheframework.ThisresultsinasignificantreductioninCPUusageatthecostofaslightlymorecomplexapplicationdeploymentprocess.
Moreinformationaboutdaemonqueueworkerscanbefoundinthequeuedocumentation.
Laravel4.2introducesnewMailgunandMandrillAPIdriversfortheMailfunctions.Formanyapplications,thisprovidesafasterandmorereliablemethodofsendinge-mailsthantheSMTPoptions.ThenewdriversutilizetheGuzzle4HTTPlibrary.
PHP5.4Requirement
LaravelForge
LaravelHomestead
LaravelCashier
DaemonQueueWorkers
MailAPIDrivers
Amuchcleanerarchitecturefor"softdeletes"andother"globalscopes"hasbeenintroducedviaPHP5.4traits.Thisnewarchitectureallowsfortheeasierconstructionofsimilarglobaltraits,andacleanerseparationofconcernswithintheframeworkitself.
MoreinformationonthenewSoftDeletingTraitmaybefoundintheEloquentdocumentation.
ThedefaultLaravel4.2installationnowusessimpletraitsforincludingtheneededpropertiesfortheauthenticationandpasswordreminderuserinterfaces.ThisprovidesamuchcleanerdefaultUsermodelfileoutofthebox.
AnewsimplePaginatemethodwasaddedtothequeryandEloquentbuilderwhichallowsformoreefficientquerieswhenusingsimple"Next"and"Previous"linksinyourpaginationview.
Inproduction,destructivemigrationoperationswillnowaskforconfirmation.Commandsmaybeforcedtorunwithoutanypromptsusingthe--forcecommand.
Thefullchangelistforthisreleasebyrunningthephpartisanchangescommandfroma4.1installation,orbyviewingthechangefileonGithub.Thesenotesonlycoverthemajorenhancementsandchangesfortherelease.
AnentirelynewSSHcomponenthasbeenintroducedwiththisrelease.ThisfeatureallowsyoutoeasilySSHintoremoteserversandruncommands.Tolearnmore,consulttheSSHcomponentdocumentation.
ThenewphpartisantailcommandutilizesthenewSSHcomponent.Formoreinformation,consultthetailcommanddocumentation.
ThephpartisantinkercommandnowutilizestheBorisREPLifyoursystemsupportsit.ThereadlineandpcntlPHPextensionsmustbeinstalledtousethisfeature.Ifyoudonothavetheseextensions,theshellfrom4.0willbeused.
AnewhasManyThroughrelationshiphasbeenaddedtoEloquent.Tolearnhowtouseit,consulttheEloquentdocumentation.
AnewwhereHasmethodhasalsobeenintroducedtoallowretrievingmodelsbasedonrelationshipconstraints.
Automatichandlingofseparateread/writeconnectionsisnowavailablethroughoutthedatabaselayer,includingthequerybuilderandEloquent.Formoreinformation,consultthedocumentation.
SoftDeletingTraits
ConvenientAuth&RemindableTraits
"SimplePaginate"
MigrationConfirmation
Laravel4.1
FullChangeList
NewSSHComponent
BorisInTinker
EloquentImprovements
DatabaseRead/WriteConnections
Queueprioritiesarenowsupportedbypassingacomma-delimitedlisttothequeue:listencommand.
Thequeuefacilitiesnowincludeautomatichandlingoffailedjobswhenusingthenew--triesswitchonqueue:listen.Moreinformationonhandlingfailedjobscanbefoundinthequeuedocumentation.
Cache"sections"havebeensupersededby"tags".Cachetagsallowyoutoassignmultiple"tags"toacacheitem,andflushallitemsassignedtoasingletag.Moreinformationonusingcachetagsmaybefoundinthecachedocumentation.
Thepasswordreminderenginehasbeenchangedtoprovidegreaterdeveloperflexibilitywhenvalidatingpasswords,flashingstatusmessagestothesession,etc.Formoreinformationonusingtheenhancedpasswordreminderengine,consultthedocumentation.
Laravel4.1featuresatotallyre-writtenroutinglayer.TheAPIisthesame;however,registeringroutesisafull100%fastercomparedto4.0.Theentireenginehasbeengreatlysimplified,andthedependencyonSymfonyRoutinghasbeenminimizedtothecompilingofrouteexpressions.
Withthisrelease,we'realsointroducinganentirelynewsessionengine.Similartotheroutingimprovements,thenewsessionlayerisleanerandfaster.WearenolongerusingSymfony's(andthereforePHP's)sessionhandlingfacilities,andareusingacustomsolutionthatissimplerandeasiertomaintain.
IfyouareusingtherenameColumnfunctioninyourmigrations,youwillneedtoaddthedoctrine/dbaldependencytoyourcomposer.jsonfile.ThispackageisnolongerincludedinLaravelbydefault.
QueuePriority
FailedQueueJobHandling
CacheTags
FlexiblePasswordReminders
ImprovedRoutingEngine
ImprovedSessionEngine
DoctrineDBAL
UpgradingTo5.0From4.2UpgradingTo4.2From4.1UpgradingTo4.1.29From<=4.1.xUpgradingTo4.1.26From<=4.1.25UpgradingTo4.1From4.0
TherecommendedmethodofupgradingistocreateanewLaravel5.0installandthentocopyyour4.2site'suniqueapplicationfilesintothenewapplication.Thiswouldincludecontrollers,routes,Eloquentmodels,Artisancommands,assets,andothercodespecifictoyourapplication.
Tostart,installanewLaravel5applicationintoafreshdirectoryinyourlocalenvironment.We'lldiscusseachpieceofthemigrationprocessinfurtherdetailbelow.
Don'tforgettocopyanyadditionalComposerdependenciesintoyour5.0application.Thisincludesthird-partycodesuchasSDKs.
SomeLaravel-specificpackagesmaynotbecompatiblewithLaravel5oninitialrelease.Checkwithyourpackage'smaintainertodeterminetheproperversionofthepackageforLaravel5.OnceyouhaveaddedanyadditionalComposerdependenciesyourapplicationneeds,runcomposerupdate.
Bydefault,Laravel4applicationsdidnotutilizenamespacingwithinyourapplicationcode.So,forexample,allEloquentmodelsandcontrollerssimplylivedinthe"global"namespace.Foraquickermigration,youcansimplyleavetheseclassesintheglobalnamespaceinLaravel5aswell.
Copythenew.env.examplefileto.env,whichisthe5.0equivalentoftheold.env.phpfile.Setanyappropriatevaluesthere,likeyourAPP_ENVandAPP_KEY(yourencryptionkey),yourdatabasecredentials,andyourcacheandsessiondrivers.
Additionally,copyanycustomvaluesyouhadinyourold.env.phpfileandplacetheminboth.env(therealvalueforyourlocalenvironment)and.env.example(asampleinstructionalvalueforotherteammembers).
Formoreinformationonenvironmentconfiguration,viewthefulldocumentation.
Note:Youwillneedtoplacetheappropriate.envfileandvaluesonyourproductionserverbeforedeployingyourLaravel5application.
Laravel5.0nolongerusesapp/config/{environmentName}/directoriestoprovidespecificconfigurationfilesforagivenenvironment.Instead,moveanyconfigurationvaluesthatvarybyenvironmentinto.env,andthenaccesstheminyour
UpgradeGuide
UpgradingTo5.0From4.2
FreshInstall,ThenMigrate
ComposerDependencies&Packages
Namespacing
Configuration
MigratingEnvironmentVariables
ConfigurationFiles
configurationfilesusingenv('key','defaultvalue').Youwillseeexamplesofthisintheconfig/database.phpconfigurationfile.
Settheconfigfilesintheconfig/directorytorepresenteitherthevaluesthatareconsistentacrossallofyourenvironments,orsetthemtouseenv()toloadvaluesthatvarybyenvironment.
Remember,ifyouaddmorekeysto.envfile,addsamplevaluestothe.env.examplefileaswell.Thiswillhelpyourotherteammemberscreatetheirown.envfiles.
Copyandpasteyouroldroutes.phpfileintoyournewapp/Http/routes.php.
Next,moveallofyourcontrollersintotheapp/Http/Controllersdirectory.Sincewearenotgoingtomigratetofullnamespacinginthisguide,addtheapp/Http/Controllersdirectorytotheclassmapdirectiveofyourcomposer.jsonfile.Next,youcanremovethenamespacefromtheabstractapp/Http/Controllers/Controller.phpbaseclass.Verifythatyourmigratedcontrollersareextendingthisbaseclass.
Inyourapp/Providers/RouteServiceProvider.phpfile,setthenamespacepropertytonull.
Copyyourfilterbindingsfromapp/filters.phpandplacethemintotheboot()methodofapp/Providers/RouteServiceProvider.php.AdduseIlluminate\Support\Facades\Route;intheapp/Providers/RouteServiceProvider.phpinordertocontinueusingtheRouteFacade.
YoudonotneedtomoveoveranyofthedefaultLaravel4.0filterssuchasauthandcsrf;they'reallhere,butasmiddleware.Editanyroutesorcontrollersthatreferencetheolddefaultfilters(e.g.['before'=>'auth'])andchangethemtoreferencethenewmiddleware(e.g.['middleware'=>'auth'].)
FiltersarenotremovedinLaravel5.Youcanstillbindanduseyourowncustomfiltersusingbeforeandafter.
Bydefault,CSRFprotectionisenabledonallroutes.Ifyou'dliketodisablethis,oronlymanuallyenableitoncertainroutes,removethislinefromApp\Http\Kernel'smiddlewarearray:
'App\Http\Middleware\VerifyCsrfToken',
Ifyouwanttouseitelsewhere,addthislineto$routeMiddleware:
'csrf'=>'App\Http\Middleware\VerifyCsrfToken',
Nowyoucanaddthemiddlewaretoindividualroutes/controllersusing['middleware'=>'csrf']ontheroute.Formoreinformationonmiddleware,consultthefulldocumentation.
Feelfreetocreateanewapp/ModelsdirectorytohouseyourEloquentmodels.Again,addthisdirectorytotheclassmapdirectiveofyourcomposer.jsonfile.
UpdateanymodelsusingSoftDeletingTraittouseIlluminate\Database\Eloquent\SoftDeletes.
Routes
Controllers
RouteFilters
GlobalCSRF
EloquentModels
Eloquentnolongerprovidestheremembermethodforcachingqueries.YounowareresponsibleforcachingyourqueriesmanuallyusingtheCache::rememberfunction.Formoreinformationoncaching,consultthefulldocumentation.
ToupgradeyourUsermodelforLaravel5'sauthenticationsystem,followtheseinstructions:
Deletethefollowingfromyouruseblock:
useIlluminate\Auth\UserInterface;
useIlluminate\Auth\Reminders\RemindableInterface;
Addthefollowingtoyouruseblock:
useIlluminate\Auth\Authenticatable;
useIlluminate\Auth\Passwords\CanResetPassword;
useIlluminate\Contracts\Auth\AuthenticatableasAuthenticatableContract;
useIlluminate\Contracts\Auth\CanResetPasswordasCanResetPasswordContract;
RemovetheUserInterfaceandRemindableInterfaceinterfaces.
Marktheclassasimplementingthefollowinginterfaces:
implementsAuthenticatableContract,CanResetPasswordContract
Includethefollowingtraitswithintheclassdeclaration:
useAuthenticatable,CanResetPassword;
Ifyouusedthem,removeIlluminate\Auth\Reminders\RemindableTraitandIlluminate\Auth\UserTraitfromyouruseblockandyourclassdeclaration.
ThenameofthetraitandinterfaceusedbyLaravelCashierhaschanged.InsteadofusingBillableTrait,usetheLaravel\Cashier\Billabletrait.And,insteadofLaravel\Cashier\BillableInterfaceimplementtheLaravel\Cashier\Contracts\Billableinterfaceinstead.Noothermethodchangesarerequired.
Moveallofyourcommandclassesfromyouroldapp/commandsdirectorytothenewapp/Console/Commandsdirectory.Next,addtheapp/Console/Commandsdirectorytotheclassmapdirectiveofyourcomposer.jsonfile.
Then,copyyourlistofArtisancommandsfromstart/artisan.phpintothecommandarrayoftheapp/Console/Kernel.phpfile.
DeletethetwomigrationsincludedwithLaravel5.0,sinceyoushouldalreadyhavetheuserstableinyourdatabase.
Moveallofyourmigrationclassesfromtheoldapp/database/migrationsdirectorytothenewdatabase/migrations.Allofyourseedsshouldbemovedfromapp/database/seedstodatabase/seeds.
EloquentCaching
UserAuthenticationModel
CashierUserChanges
ArtisanCommands
DatabaseMigrations&Seeds
IfyouhaveanyIoCbindingsinstart/global.php,movethemalltotheregistermethodoftheapp/Providers/AppServiceProvider.phpfile.YoumayneedtoimporttheAppfacade.
Optionally,youmaybreakthesebindingsupintoseparateserviceprovidersbycategory.
Moveyourviewsfromapp/viewstothenewresources/viewsdirectory.
Forbettersecuritybydefault,Laravel5.0escapesalloutputfromboththe{{}}and{{{}}}Bladedirectives.Anew{!!!!}directivehasbeenintroducedtodisplayraw,unescapedoutput.Themostsecureoptionwhenupgradingyourapplicationistoonlyusethenew{!!!!}directivewhenyouarecertainthatitissafetodisplayrawoutput.
However,ifyoumustusetheoldBladesyntax,addthefollowinglinesatthebottomofAppServiceProvider@register:
\Blade::setRawTags('{{','}}');
\Blade::setContentTags('{{{','}}}');
\Blade::setEscapedContentTags('{{{','}}}');
Thisshouldnotbedonelightly,andmaymakeyourapplicationmorevulnerabletoXSSexploits.Also,commentswith{{--willnolongerwork.
Moveyourlanguagefilesfromapp/langtothenewresources/langdirectory.
Copyyourapplication'spublicassetsfromyour4.2application'spublicdirectorytoyournewapplication'spublicdirectory.Besuretokeepthe5.0versionofindex.php.
Moveyourtestsfromapp/teststothenewtestsdirectory.
Copyinanyotherfilesinyourproject.Forexample,.scrutinizer.yml,bower.jsonandothersimilartoolingconfigurationfiles.
YoumaymoveyourSass,Less,orCoffeeScripttoanylocationyouwish.Theresources/assetsdirectorycouldbeagooddefaultlocation.
Ifyou'reusingFormorHTMLhelpers,youwillseeanerrorstatingclass'Form'notfoundorclass'Html'notfound.Tofixthis,add"illuminate/html":"~5.0"toyourcomposer.jsonfile'srequiresection.
You'llalsoneedtoaddtheFormandHTMLfacadesandserviceprovider.Editconfig/app.php,andaddthislinetothe'providers'array:
GlobalIoCBindings
Views
BladeTagChanges
TranslationFiles
PublicDirectory
Tests
Misc.Files
Form&HTMLHelpers
'Illuminate\Html\HtmlServiceProvider',
Next,addtheselinestothe'aliases'array:
'Form'=>'Illuminate\Html\FormFacade',
'Html'=>'Illuminate\Html\HtmlFacade',
IfyourapplicationcodewasinjectingIlluminate\Cache\CacheManagertogetanon-FacadeversionofLaravel'scache,injectIlluminate\Contracts\Cache\Repositoryinstead.
Replaceanycallsto$paginator->links()with$paginator->render().
Laravel5.0nowrequires"pda/pheanstalk":"~3.0"insteadof"pda/pheanstalk":"~2.1".
TheRemotecomponenthasbeendeprecated.
TheWorkbenchcomponenthasbeendeprecated.
Laravel4.2requiresPHP5.4.0orgreater.
Addanewcipheroptioninyourapp/config/app.phpconfigurationfile.ThevalueofthisoptionshouldbeMCRYPT_RIJNDAEL_256.
'cipher'=>MCRYPT_RIJNDAEL_256
ThissettingmaybeusedtocontrolthedefaultcipherusedbytheLaravelencryptionfacilities.
Note:InLaravel4.2,thedefaultcipherisMCRYPT_RIJNDAEL_128(AES),whichisconsideredtobethemostsecurecipher.ChangingthecipherbacktoMCRYPT_RIJNDAEL_256isrequiredtodecryptcookies/valuesthatwereencryptedinLaravel<=4.1
Ifyouareusingsoftdeletingmodels,thesoftDeletespropertyhasbeenremoved.YoumustnowusetheSoftDeletingTraitlikeso:
CacheManager
Pagination
BeanstalkQueuing
Remote
Workbench
UpgradingTo4.2From4.1
PHP5.4+
EncryptionDefaults
SoftDeletingModelsNowUseTraits
useIlluminate\Database\Eloquent\SoftDeletingTrait;
classUserextendsEloquent{
useSoftDeletingTrait;
}
Youmustalsomanuallyaddthedeleted_atcolumntoyourdatesproperty:
classUserextendsEloquent{
useSoftDeletingTrait;
protected$dates=['deleted_at'];
}
TheAPIforallsoftdeleteoperationsremainsthesame.
Note:TheSoftDeletingTraitcannotbeappliedonabasemodel.Itmustbeusedonanactualmodelclass.
IfyouaredirectlyreferencingtheIlluminate\View\EnvironmentclassorIlluminate\Pagination\Environmentclass,updateyourcodetoreferenceIlluminate\View\FactoryandIlluminate\Pagination\Factoryinstead.Thesetwoclasseshavebeenrenamedtobetterreflecttheirfunction.
IfyouareextendingtheIlluminate\Pagination\Presenterclass,theabstractmethodgetPageLinkWrappersignaturehaschangedtoaddtherelargument:
abstractpublicfunctiongetPageLinkWrapper($url,$page,$rel=null);
IfyouareusingtheIron.ioqueuedriver,youwillneedtoaddanewencryptoptiontoyourqueueconfigurationfile:
'encrypt'=>true
Laravel4.1.29improvesthecolumnquotingforalldatabasedrivers.Thisprotectsyourapplicationfromsomemassassignmentvulnerabilitieswhennotusingthefillablepropertyonmodels.Ifyouareusingthefillablepropertyonyourmodelstoprotectagainstmassassignment,yourapplicationisnotvulnerable.However,ifyouareusingguardedandarepassingausercontrolledarrayintoan"update"or"save"typefunction,youshouldupgradeto4.1.29immediatelyasyourapplicationmaybeatriskofmassassignment.
ToupgradetoLaravel4.1.29,simplycomposerupdate.Nobreakingchangesareintroducedinthisrelease.
Laravel4.1.26introducessecurityimprovementsfor"rememberme"cookies.Beforethisupdate,ifaremembercookiewashijackedbyanothermalicioususer,thecookiewouldremainvalidforalongperiodoftime,evenafterthetrueowneroftheaccountresettheirpassword,loggedout,etc.
View/PaginationEnvironmentRenamed
AdditionalParameterOnPaginationPresenter
Iron.IoQueueEncryption
UpgradingTo4.1.29From<=4.1.x
UpgradingTo4.1.26From<=4.1.25
Thischangerequirestheadditionofanewremember_tokencolumntoyourusers(orequivalent)databasetable.Afterthischange,afreshtokenwillbeassignedtotheusereachtimetheylogintoyourapplication.Thetokenwillalsoberefreshedwhentheuserlogsoutoftheapplication.Theimplicationsofthischangeare:ifa"rememberme"cookieishijacked,simplyloggingoutoftheapplicationwillinvalidatethecookie.
First,addanew,nullableremember_tokenofVARCHAR(100),TEXT,orequivalenttoyouruserstable.
Next,ifyouareusingtheEloquentauthenticationdriver,updateyourUserclasswiththefollowingthreemethods:
publicfunctiongetRememberToken()
{
return$this->remember_token;
}
publicfunctionsetRememberToken($value)
{
$this->remember_token=$value;
}
publicfunctiongetRememberTokenName()
{
return'remember_token';
}
Note:Allexisting"rememberme"sessionswillbeinvalidatedbythischange,soalluserswillbeforcedtore-authenticatewithyourapplication.
TwonewmethodswereaddedtotheIlluminate\Auth\UserProviderInterfaceinterface.Sampleimplementationsmaybefoundinthedefaultdrivers:
publicfunctionretrieveByToken($identifier,$token);
publicfunctionupdateRememberToken(UserInterface$user,$token);
TheIlluminate\Auth\UserInterfacealsoreceivedthethreenewmethodsdescribedinthe"UpgradePath".
ToupgradeyourapplicationtoLaravel4.1,changeyourlaravel/frameworkversionto4.1.*inyourcomposer.jsonfile.
Replaceyourpublic/index.phpfilewiththisfreshcopyfromtherepository.
Replaceyourartisanfilewiththisfreshcopyfromtherepository.
Updateyouraliasesandprovidersarraysinyourapp/config/app.phpconfigurationfile.Theupdatedvaluesforthesearrayscanbefoundinthisfile.Besuretoaddyourcustomandpackageserviceproviders/aliasesbacktothearrays.
Addthenewapp/config/remote.phpfilefromtherepository.
UpgradePath
PackageMaintainers
UpgradingTo4.1From4.0
UpgradingYourComposerDependency
ReplacingFiles
AddingConfigurationFiles&Options
Addthenewexpire_on_closeconfigurationoptiontoyourapp/config/session.phpfile.Thedefaultvalueshouldbefalse.
Addthenewfailedconfigurationsectiontoyourapp/config/queue.phpfile.Herearethedefaultvaluesforthesection:
'failed'=>array(
'database'=>'mysql','table'=>'failed_jobs',
),
(Optional)Updatethepaginationconfigurationoptioninyourapp/config/view.phpfiletopagination::slider-3.
Ifapp/controllers/BaseController.phphasausestatementatthetop,changeuseIlluminate\Routing\Controllers\Controller;touseIlluminate\Routing\Controller;.
Passwordremindershavebeenoverhauledforgreaterflexibility.Youmayexaminethenewstubcontrollerbyrunningthephpartisanauth:reminders-controllerArtisancommand.Youmayalsobrowsetheupdateddocumentationandupdateyourapplicationaccordingly.
Updateyourapp/lang/en/reminders.phplanguagefiletomatchthisupdatedfile.
Forsecurityreasons,URLdomainsmaynolongerbeusedtodetectyourapplicationenvironment.Thesevaluesareeasilyspoofableandallowattackerstomodifytheenvironmentforarequest.Youshouldconvertyourenvironmentdetectiontousemachinehostnames(hostnamecommandonMac,Linux,andWindows).
Laravelnowgeneratesasinglelogfile:app/storage/logs/laravel.log.However,youmaystillconfigurethisbehaviorinyourapp/start/global.phpfile.
Inyourbootstrap/start.phpfile,removethecallto$app->redirectIfTrailingSlash().Thismethodisnolongerneededasthisfunctionalityisnowhandledbythe.htaccessfileincludedwiththeframework.
Next,replaceyourApache.htaccessfilewiththisnewonethathandlestrailingslashes.
ThecurrentrouteisnowaccessedviaRoute::current()insteadofRoute::getCurrentRoute().
Onceyouhavecompletedthechangesabove,youcanrunthecomposerupdatefunctiontoupdateyourcoreapplicationfiles!Ifyoureceiveclassloaderrors,tryrunningtheupdatecommandwiththe--no-scriptsoptionenabledlikeso:composerupdate--no-scripts.
Thewildcardeventlistenersnolongerappendtheeventtoyourhandlerfunctionsparameters.IfyourequirefindingtheeventthatwasfiredyoushoulduseEvent::firing().
ControllerUpdates
PasswordRemindersUpdates
EnvironmentDetectionUpdates
SimplerLogFiles
RemovingRedirectTrailingSlash
CurrentRouteAccess
ComposerUpdate
WildcardEventListeners
BugReportsCoreDevelopmentDiscussionWhichBranch?SecurityVulnerabilitiesCodingStyle
Toencourageactivecollaboration,Laravelstronglyencouragespullrequests,notjustbugreports."Bugreports"mayalsobesentintheformofapullrequestcontainingafailingunittest.
However,ifyoufileabugreport,yourissueshouldcontainatitleandacleardescriptionoftheissue.Youshouldalsoincludeasmuchrelevantinformationaspossibleandacodesamplethatdemonstratestheissue.Thegoalofabugreportistomakeiteasyforyourself-andothers-toreplicatethebuganddevelopafix.
Remember,bugreportsarecreatedinthehopethatotherswiththesameproblemwillbeabletocollaboratewithyouonsolvingit.Donotexpectthatthebugreportwillautomaticallyseeanyactivityorthatotherswilljumptofixit.Creatingabugreportservestohelpyourselfandothersstartonthepathoffixingtheproblem.
TheLaravelsourcecodeismanagedonGithub,andtherearerepositoriesforeachoftheLaravelprojects:
LaravelFrameworkLaravelApplicationLaravelDocumentationLaravelCashierLaravelEnvoyLaravelHomesteadLaravelHomesteadBuildScriptsLaravelWebsiteLaravelArt
Discussionregardingbugs,newfeatures,andimplementationofexistingfeaturestakesplaceinthe#laravel-devIRCchannel(Freenode).TaylorOtwell,themaintainerofLaravel,istypicallypresentinthechannelonweekdaysfrom8am-5pm(UTC-06:00orAmerica/Chicago),andsporadicallypresentinthechannelatothertimes.
The#laravel-devIRCchannelisopentoall.Allarewelcometojointhechanneleithertoparticipateorsimplyobservethediscussions!
Allbugfixesshouldbesenttothelateststablebranch.Bugfixesshouldneverbesenttothemasterbranchunlesstheyfixfeaturesthatexistonlyintheupcomingrelease.
MinorfeaturesthatarefullybackwardscompatiblewiththecurrentLaravelreleasemaybesenttothelateststablebranch.
Majornewfeaturesshouldalwaysbesenttothemasterbranch,whichcontainstheupcomingLaravelrelease.
Ifyouareunsureifyourfeaturequalifiesasamajororminor,pleaseaskTaylorOtwellinthe#laravel-devIRCchannel
ContributionGuide
BugReports
CoreDevelopmentDiscussion
WhichBranch?
(Freenode).
IfyoudiscoverasecurityvulnerabilitywithinLaravel,pleasesendane-mailtoTaylorOtwellattaylorotwell@gmail.com.Allsecurityvulnerabilitieswillbepromptlyaddressed.
LaravelfollowsthePSR-0andPSR-1codingstandards.Inadditiontothesestandards,thefollowingcodingstandardsshouldbefollowed:
Theclassnamespacedeclarationmustbeonthesamelineas<?php.Aclass'opening{mustbeonthesamelineastheclassname.FunctionsandcontrolstructuresmustuseAllmanstylebraces.Indentwithtabs,alignwithspaces.
SecurityVulnerabilities
CodingStyle
InstallationInstallComposerInstallLaravelServerRequirements
ConfigurationIntroductionAfterInstallationAccessingConfigurationValuesEnvironmentConfigurationConfigurationCachingMaintenanceModePrettyURLs
HomesteadIntroductionIncludedSoftwareInstallation&SetupDailyUsagePorts
Setup
InstallComposerInstallLaravelServerRequirements
LaravelutilizesComposertomanageitsdependencies.So,beforeusingLaravel,youwillneedtomakesureyouhaveComposerinstalledonyourmachine.
First,downloadtheLaravelinstallerusingComposer.
composerglobalrequire"laravel/installer=~1.1"
Makesuretoplacethe~/.composer/vendor/bindirectoryinyourPATHsothelaravelexecutablecanbelocatedbyyoursystem.
Onceinstalled,thesimplelaravelnewcommandwillcreateafreshLaravelinstallationinthedirectoryyouspecify.Forinstance,laravelnewblogwouldcreateadirectorynamedblogcontainingafreshLaravelinstallationwithalldependenciesinstalled.ThismethodofinstallationismuchfasterthaninstallingviaComposer:
laravelnewblog
YoumayalsoinstallLaravelbyissuingtheComposercreate-projectcommandinyourterminal:
composercreate-projectlaravel/laravel--prefer-dist
TheLaravelframeworkhasafewsystemrequirements:
PHP>=5.4McryptPHPExtensionOpenSSLPHPExtensionMbstringPHPExtension
AsofPHP5.5,someOSdistributionsmayrequireyoutomanuallyinstallthePHPJSONextension.WhenusingUbuntu,thiscanbedoneviaapt-getinstallphp5-json.
Installation
InstallComposer
InstallLaravel
ViaLaravelInstaller
ViaComposerCreate-Project
ServerRequirements
Configuration
ThefirstthingyoushoulddoafterinstallingLaravelissetyourapplicationkeytoarandomstring.IfyouinstalledLaravelviaComposer,thiskeyhasprobablyalreadybeensetforyoubythekey:generatecommand.
Typically,thisstringshouldbe32characterslong.Thekeycanbesetinthe.envenvironmentfile.Iftheapplicationkeyisnotset,yourusersessionsandotherencrypteddatawillnotbesecure!
Laravelneedsalmostnootherconfigurationoutofthebox.Youarefreetogetstarteddeveloping!However,youmaywishtoreviewtheconfig/app.phpfileanditsdocumentation.Itcontainsseveraloptionssuchastimezoneandlocalethatyoumaywishtochangeaccordingtoyourapplication.
OnceLaravelisinstalled,youshouldalsoconfigureyourlocalenvironment.
Note:Youshouldneverhavetheapp.debugconfigurationoptionsettotrueforaproductionapplication.
Laravelmayrequiresomepermissionstobeconfigured:folderswithinstoragerequirewriteaccessbythewebserver.
Theframeworkshipswithapublic/.htaccessfilethatisusedtoallowURLswithoutindex.php.IfyouuseApachetoserveyourLaravelapplication,besuretoenablethemod_rewritemodule.
Ifthe.htaccessfilethatshipswithLaraveldoesnotworkwithyourApacheinstallation,trythisone:
Options+FollowSymLinks
RewriteEngineOn
RewriteCond%{REQUEST_FILENAME}!-d
RewriteCond%{REQUEST_FILENAME}!-f
RewriteRule^index.php[L]
OnNginx,thefollowingdirectiveinyoursiteconfigurationwillallow"pretty"URLs:
location/{
try_files$uri$uri//index.php?$query_string;
}
Ofcourse,whenusingHomestead,prettyURLswillbeconfiguredautomatically.
Permissions
PrettyURLs
Apache
Nginx
IntroductionAfterInstallationAccessingConfigurationValuesEnvironmentConfigurationConfigurationCachingMaintenanceModePrettyURLs
AlloftheconfigurationfilesfortheLaravelframeworkarestoredintheconfigdirectory.Eachoptionisdocumented,sofeelfreetolookthroughthefilesandgetfamiliarwiththeoptionsavailabletoyou.
AfterinstallingLaravel,youmaywishto"name"yourapplication.Bydefault,theappdirectoryisnamespacedunderApp,andautoloadedbyComposerusingthePSR-4autoloadingstandard.However,youmaychangethenamespacetomatchthenameofyourapplication,whichyoucaneasilydoviatheapp:nameArtisancommand.
Forexample,ifyourapplicationisnamed"Horsefly",youcouldrunthefollowingcommandfromtherootofyourinstallation:
phpartisanapp:nameHorsefly
Renamingyourapplicationisentirelyoptional,andyouarefreetokeeptheAppnamespaceifyouwish.
Laravelneedsverylittleconfigurationoutofthebox.Youarefreetogetstarteddeveloping!However,youmaywishtoreviewtheconfig/app.phpfileanditsdocumentation.Itcontainsseveraloptionssuchastimezoneandlocalethatyoumaywishtochangeaccordingtoyourlocation.
OnceLaravelisinstalled,youshouldalsoconfigureyourlocalenvironment.
Note:Youshouldneverhavetheapp.debugconfigurationoptionsettotrueforaproductionapplication.
Laravelmayrequireonesetofpermissionstobeconfigured:folderswithinstoragerequirewriteaccessbythewebserver.
YoumayeasilyaccessyourconfigurationvaluesusingtheConfigfacade:
$value=Config::get('app.timezone');
Config::set('app.timezone','America/Chicago');
Configuration
Introduction
AfterInstallation
NamingYourApplication
OtherConfiguration
Permissions
AccessingConfigurationValues
Youmayalsousetheconfighelperfunction:
$value=config('app.timezone');
Itisoftenhelpfultohavedifferentconfigurationvaluesbasedontheenvironmenttheapplicationisrunningin.Forexample,youmaywishtouseadifferentcachedriverlocallythanyoudoonyourproductionserver.It'seasyusingenvironmentbasedconfiguration.
Tomakethisacinch,LaravelutilizestheDotEnvPHPlibrarybyVanceLucas.InafreshLaravelinstallation,therootdirectoryofyourapplicationwillcontaina.env.examplefile.IfyouinstallLaravelviaComposer,thisfilewillautomaticallyberenamedto.env.Otherwise,youshouldrenamethefilemanually.
Allofthevariableslistedinthisfilewillbeloadedintothe$_ENVPHPsuper-globalwhenyourapplicationreceivesarequest.Youmayusetheenvhelpertoretrievevaluesfromthesevariables.Infact,ifyoureviewtheLaravelconfigurationfiles,youwillnoticeseveraloftheoptionsalreadyusingthishelper!
Feelfreetomodifyyourenvironmentvariablesasneededforyourownlocalserver,aswellasyourproductionenvironment.However,your.envfileshouldnotbecommittedtoyourapplication'ssourcecontrol,sinceeachdeveloper/serverusingyourapplicationcouldrequireadifferentenvironmentconfiguration.
Ifyouaredevelopingwithateam,youmaywishtocontinueincludinga.env.examplefilewithyourapplication.Byputtingplace-holdervaluesintheexampleconfigurationfile,otherdevelopersonyourteamcanclearlyseewhichenvironmentvariablesareneededtorunyourapplication.
YoumayaccessthecurrentapplicationenvironmentviatheenvironmentmethodontheApplicationinstance:
$environment=$app->environment();
Youmayalsopassargumentstotheenvironmentmethodtocheckiftheenvironmentmatchesagivenvalue:
if($app->environment('local'))
{
//Theenvironmentislocal
}
if($app->environment('local','staging'))
{
//TheenvironmentiseitherlocalORstaging...
}
Toobtainaninstanceoftheapplication,resolvetheIlluminate\Contracts\Foundation\Applicationcontractviatheservicecontainer.Ofcourse,ifyouarewithinaserviceprovider,theapplicationinstanceisavailableviathe$this->appinstancevariable.
AnapplicationinstancemayalsobeaccessedviatheapphelperoftheAppfacade:
$environment=app()->environment();
$environment=App::environment();
EnvironmentConfiguration
AccessingTheCurrentApplicationEnvironment
Togiveyourapplicationalittlespeedboost,youmaycacheallofyourconfigurationfilesintoasinglefileusingtheconfig:cacheArtisancommand.Thiswillcombinealloftheconfigurationoptionsforyourapplicationintoasinglefilewhichcanbeloadedquicklybytheframework.
Youshouldtypicallyruntheconfig:cachecommandaspartofyourdeploymentroutine.
Whenyourapplicationisinmaintenancemode,acustomviewwillbedisplayedforallrequestsintoyourapplication.Thismakesiteasyto"disable"yourapplicationwhileitisupdatingorwhenyouareperformingmaintenance.Amaintenancemodecheckisincludedinthedefaultmiddlewarestackforyourapplication.Iftheapplicationisinmaintenancemode,anHttpExceptionwillbethrownwithastatuscodeof503.
Toenablemaintenancemode,simplyexecutethedownArtisancommand:
phpartisandown
Todisablemaintenancemode,usetheupcommand:
phpartisanup
Thedefaulttemplateformaintenancemoderesponsesislocatedinresources/views/errors/503.blade.php.
Whileyourapplicationisinmaintenancemode,noqueuedjobswillbehandled.Thejobswillcontinuetobehandledasnormaloncetheapplicationisoutofmaintenancemode.
Theframeworkshipswithapublic/.htaccessfilethatisusedtoallowURLswithoutindex.php.IfyouuseApachetoserveyourLaravelapplication,besuretoenablethemod_rewritemodule.
Ifthe.htaccessfilethatshipswithLaraveldoesnotworkwithyourApacheinstallation,trythisone:
Options+FollowSymLinks
RewriteEngineOn
RewriteCond%{REQUEST_FILENAME}!-d
RewriteCond%{REQUEST_FILENAME}!-f
RewriteRule^index.php[L]
OnNginx,thefollowingdirectiveinyoursiteconfigurationwillallow"pretty"URLs:
ConfigurationCaching
MaintenanceMode
MaintenanceModeResponseTemplate
MaintenanceMode&Queues
PrettyURLs
Apache
Nginx
location/{
try_files$uri$uri//index.php?$query_string;
}
Ofcourse,whenusingHomestead,prettyURLswillbeconfiguredautomatically.
IntroductionIncludedSoftwareInstallation&SetupDailyUsagePorts
LaravelstrivestomaketheentirePHPdevelopmentexperiencedelightful,includingyourlocaldevelopmentenvironment.Vagrantprovidesasimple,elegantwaytomanageandprovisionVirtualMachines.
LaravelHomesteadisanofficial,pre-packagedVagrant"box"thatprovidesyouawonderfuldevelopmentenvironmentwithoutrequiringyoutoinstallPHP,HHVM,awebserver,andanyotherserversoftwareonyourlocalmachine.Nomoreworryingaboutmessingupyouroperatingsystem!Vagrantboxesarecompletelydisposable.Ifsomethinggoeswrong,youcandestroyandre-createtheboxinminutes!
HomesteadrunsonanyWindows,Mac,orLinuxsystem,andincludestheNginxwebserver,PHP5.6,MySQL,Postgres,Redis,Memcached,andalloftheothergoodiesyouneedtodevelopamazingLaravelapplications.
Note:IfyouareusingWindows,youmayneedtoenablehardwarevirtualization(VT-x).ItcanusuallybeenabledviayourBIOS.
HomesteadiscurrentlybuiltandtestedusingVagrant1.6.
Ubuntu14.04PHP5.6HHVMNginxMySQLPostgresNode(WithBower,Grunt,andGulp)RedisMemcachedBeanstalkdLaravelEnvoyFabric+HipChatExtension
BeforelaunchingyourHomesteadenvironment,youmustinstallVirtualBoxandVagrant.Bothofthesesoftwarepackagesprovideeasy-to-usevisualinstallersforallpopularoperatingsystems.
OnceVirtualBoxandVagranthavebeeninstalled,youshouldaddthelaravel/homesteadboxtoyourVagrantinstallationusingthefollowingcommandinyourterminal.Itwilltakeafewminutestodownloadthebox,dependingonyourInternet
LaravelHomestead
Introduction
IncludedSoftware
Installation&Setup
InstallingVirtualBox&Vagrant
AddingTheVagrantBox
connectionspeed:
vagrantboxaddlaravel/homestead
Alternatively,ifyoudonotwanttoinstallPHPonyourlocalmachine,youmayinstallHomesteadmanuallybysimplycloningtherepository.ConsidercloningtherepositoryintoaHomesteadfolderwithinyour"home"directory,astheHomesteadboxwillserveasthehosttoallofyourLaravel(andPHP)projects:
gitclonehttps://github.com/laravel/homestead.gitHomestead
OnceyouhaveinstalledtheHomesteadCLItool,runthebashinit.shcommandtocreatetheHomestead.yamlconfigurationfile:
bashinit.sh
TheHomestead.yamlfilewillbeplacedinyour~/.homesteaddirectory.
OncetheboxhasbeenaddedtoyourVagrantinstallation,youarereadytoinstalltheHomesteadCLItoolusingtheComposerglobalcommand:
composerglobalrequire"laravel/homestead=~2.0"
Makesuretoplacethe~/.composer/vendor/bindirectoryinyourPATHsothehomesteadexecutableisfoundwhenyourunthehomesteadcommandinyourterminal.
OnceyouhaveinstalledtheHomesteadCLItool,runtheinitcommandtocreatetheHomestead.yamlconfigurationfile:
homesteadinit
TheHomestead.yamlfilewillbeplacedinthe~/.homesteaddirectory.Ifyou'reusingaMacorLinuxsystem,youmayeditHomestead.yamlfilebyrunningthehomesteadeditcommandinyourterminal:
homesteadedit
Next,youshouldedittheHomestead.yamlfile.Inthisfile,youcanconfigurethepathtoyourpublicSSHkey,aswellasthefoldersyouwishtobesharedbetweenyourmainmachineandtheHomesteadvirtualmachine.
Don'thaveanSSHkey?OnMacandLinux,youcangenerallycreateanSSHkeypairusingthefollowingcommand:
ssh-keygen-trsa-C"you@homestead"
InstallingHomestead
ManuallyViaGit(NoLocalPHP)
WithComposer+PHPTool
SetYourSSHKey
OnWindows,youmayinstallGitandusetheGitBashshellincludedwithGittoissuethecommandabove.Alternatively,youmayusePuTTYandPuTTYgen.
OnceyouhavecreatedaSSHkey,specifythekey'spathintheauthorizepropertyofyourHomestead.yamlfile.
ThefolderspropertyoftheHomestead.yamlfilelistsallofthefoldersyouwishtosharewithyourHomesteadenvironment.Asfileswithinthesefoldersarechanged,theywillbekeptinsyncbetweenyourlocalmachineandtheHomesteadenvironment.Youmayconfigureasmanysharedfoldersasnecessary!
NotfamiliarwithNginx?Noproblem.Thesitespropertyallowsyoutoeasilymapa"domain"toafolderonyourHomesteadenvironment.AsamplesiteconfigurationisincludedintheHomestead.yamlfile.Again,youmayaddasmanysitestoyourHomesteadenvironmentasnecessary.Homesteadcanserveasaconvenient,virtualizedenvironmentforeveryLaravelprojectyouareworkingon!
YoucanmakeanyHomesteadsiteuseHHVMbysettingthehhvmoptiontotrue:
sites:
-map:homestead.app
to:/home/vagrant/Code/Laravel/public
hhvm:true
ToaddBashaliasestoyourHomesteadbox,simplyaddtothealiasesfileintherootofthe~/.homesteaddirectory.
OnceyouhaveeditedtheHomestead.yamltoyourliking,runthevagrantupcommandfromyourHomesteaddirectory.
Vagrantwillbootthevirtualmachine,andconfigureyoursharedfoldersandNginxsitesautomatically!Todestroythemachine,youmayusethevagrantdestroy--forcecommand.
Don'tforgettoaddthe"domains"foryourNginxsitestothehostsfileonyourmachine!ThehostsfilewillredirectyourrequestsforthelocaldomainsintoyourHomesteadenvironment.OnMacandLinux,thisfileislocatedat/etc/hosts.OnWindows,itislocatedatC:\Windows\System32\drivers\etc\hosts.Thelinesyouaddtothisfilewilllooklikethefollowing:
192.168.10.10homestead.app
MakesuretheIPaddresslistedistheoneyousetinyourHomestead.yamlfile.Onceyouhaveaddedthedomaintoyourhostsfile,youcanaccessthesiteviayourwebbrowser!
http://homestead.app
Tolearnhowtoconnecttoyourdatabases,readon!
ConfigureYourSharedFolders
ConfigureYourNginxSites
BashAliases
LaunchTheVagrantBox
DailyUsage
ConnectingViaSSH
ToconnecttoyourHomesteadenvironmentviaSSH,issuethevagrantsshcommandfromyourHomesteaddirectory.
SinceyouwillprobablyneedtoSSHintoyourHomesteadmachinefrequently,considercreatingan"alias"onyourhostmachine:
aliasvm="[email protected]"
Onceyoucreatethisalias,youcansimplyusethe"vm"commandtoSSHintoyourHomesteadmachinefromanywhereonyoursystem.
AhomesteaddatabaseisconfiguredforbothMySQLandPostgresoutofthebox.Forevenmoreconvenience,Laravel'slocaldatabaseconfigurationissettousethisdatabasebydefault.
ToconnecttoyourMySQLorPostgresdatabasefromyourmainmachineviaNavicatorSequelPro,youshouldconnectto127.0.0.1andport33060(MySQL)or54320(Postgres).Theusernameandpasswordforbothdatabasesishomestead/secret.
Note:Youshouldonlyusethesenon-standardportswhenconnectingtothedatabasesfromyourmainmachine.Youwillusethedefault3306and5432portsinyourLaraveldatabaseconfigurationfilesinceLaravelisrunningwithintheVirtualMachine.
OnceyourHomesteadenvironmentisprovisionedandrunning,youmaywanttoaddadditionalNginxsitesforyourLaravelapplications.YoucanrunasmanyLaravelinstallationsasyouwishonasingleHomesteadenvironment.Therearetwowaystodothis:First,youmaysimplyaddthesitestoyourHomestead.yamlfileandthenrunvagrantprovision.
Alternatively,youmayusetheservescriptthatisavailableonyourHomesteadenvironment.Tousetheservescript,SSHintoyourHomesteadenvironmentandrunthefollowingcommand:
servedomain.app/home/vagrant/Code/path/to/public/directory
Note:Afterrunningtheservecommand,donotforgettoaddthenewsitetothehostsfileonyourmainmachine!
ThefollowingportsareforwardedtoyourHomesteadenvironment:
SSH:2222→ForwardsTo22HTTP:8000→ForwardsTo80MySQL:33060→ForwardsTo3306Postgres:54320→ForwardsTo5432
ConnectingToYourDatabases
AddingAdditionalSites
Ports
RoutingBasicRoutingCSRFProtectionMethodSpoofingRouteParametersNamedRoutesRouteGroupsRouteModelBindingThrowing404Errors
MiddlewareIntroductionDefiningMiddlewareRegisteringMiddlewareTerminableMiddleware
ControllersIntroductionBasicControllersControllerMiddlewareImplicitControllersRESTfulResourceControllersDependencyInjection&ControllersRouteCaching
RequestsObtainingARequestInstanceRetrievingInputOldInputCookiesFilesOtherRequestInformation
ResponsesBasicResponsesRedirectsOtherResponsesResponseMacros
ViewsBasicUsageViewComposers
TheBasics
BasicRoutingCSRFProtectionMethodSpoofingRouteParametersNamedRoutesRouteGroupsRouteModelBindingThrowing404Errors
Youwilldefinemostoftheroutesforyourapplicationintheapp/Http/routes.phpfile,whichisloadedbytheApp\Providers\RouteServiceProviderclass.ThemostbasicLaravelroutessimplyacceptaURIandaClosure:
Route::get('/',function()
{
return'HelloWorld';
});
Route::post('foo/bar',function()
{
return'HelloWorld';
});
Route::put('foo/bar',function()
{
//
});
Route::delete('foo/bar',function()
{
//
});
Route::match(['get','post'],'/',function()
{
return'HelloWorld';
});
Route::any('foo',function()
{
return'HelloWorld';
});
Often,youwillneedtogenerateURLstoyourroutes,youmaydosousingtheurlhelper:
HTTPRouting
BasicRouting
BasicGETRoute
OtherBasicRoutesRoute
RegisteringARouteForMultipleVerbs
RegisteringARouteThatRespondsToAnyHTTPVerb
$url=url('foo');
Laravelmakesiteasytoprotectyourapplicationfromcross-siterequestforgeries.Cross-siterequestforgeriesareatypeofmaliciousexploitwherebyunauthorizedcommandsareperformedonbehalfoftheauthenticateduser.
LaravelautomaticallygeneratesaCSRF"token"foreachactiveusersessionmanagedbytheapplication.Thistokenisusedtoverifythattheauthenticateduseristheoneactuallymakingtherequeststotheapplication.
<inputtype="hidden"name="_token"value="<?phpechocsrf_token();?>">
Ofcourse,usingtheBladetemplatingengine:
<inputtype="hidden"name="_token"value="{{csrf_token()}}">
YoudonotneedtomanuallyverifytheCSRFtokenonPOST,PUT,orDELETErequests.TheVerifyCsrfTokenHTTPmiddlewarewillverifytokenintherequestinputmatchesthetokenstoredinthesession.
InadditiontolookingfortheCSRFtokenasa"POST"parameter,themiddlewarewillalsocheckfortheX-XSRF-TOKENrequestheader,whichiscommonlyusedbyJavaScriptframeworks.
HTMLformsdonotsupportPUTorDELETEactions.So,whendefiningPUTorDELETEroutesthatarecalledfromanHTMLform,youwillneedtoaddahidden_methodfieldtotheform.
Thevaluesentwiththe_methodfieldwillbeusedastheHTTPrequestmethod.Forexample:
<formaction="/foo/bar"method="POST">
<inputtype="hidden"name="_method"value="PUT">
<inputtype="hidden"name="_token"value="<?phpechocsrf_token();?>">
</form>
Ofcourse,youcancapturesegmentsoftherequestURIwithinyourroute:
Route::get('user/{id}',function($id)
{
return'User'.$id;
});
CSRFProtection
InsertTheCSRFTokenIntoAForm
MethodSpoofing
RouteParameters
BasicRouteParameter
OptionalRouteParameters
Route::get('user/{name?}',function($name=null)
{
return$name;
});
Route::get('user/{name?}',function($name='John')
{
return$name;
});
Route::get('user/{name}',function($name)
{
//
})
->where('name','[A-Za-z]+');
Route::get('user/{id}',function($id)
{
//
})
->where('id','[0-9]+');
Route::get('user/{id}/{name}',function($id,$name)
{
//
})
->where(['id'=>'[0-9]+','name'=>'[a-z]+'])
Ifyouwouldlikearouteparametertoalwaysbeconstrainedbyagivenregularexpression,youmayusethepatternmethod.YoushoulddefinethesepatternsinthebeforemethodofyourRouteServiceProvider:
$router->pattern('id','[0-9]+');
Oncethepatternhasbeendefined,itisappliedtoallroutesusingthatparameter:
Route::get('user/{id}',function($id)
{
//Onlycalledif{id}isnumeric.
});
Ifyouneedtoaccessarouteparametervalueoutsideofaroute,usetheinputmethod:
if($route->input('id')==1)
{
//
}
OptionalRouteParametersWithDefaultValue
RegularExpressionParameterConstraints
PassingAnArrayOfConstraints
DefiningGlobalPatterns
AccessingARouteParameterValue
YoumayalsoaccessthecurrentrouteparametersviatheIlluminate\Http\Requestinstance.TherequestinstanceforthecurrentrequestmaybeaccessedviatheRequestfacade,orbytype-hintingtheIlluminate\Http\Requestwheredependenciesareinjected:
useIlluminate\Http\Request;
Route::get('user/{id}',function(Request$request,$id)
{
if($request->route('id'))
{
//
}
});
NamedroutesallowyoutoconvenientlygenerateURLsorredirectsforaspecificroute.Youmayspecifyanameforaroutewiththeasarraykey:
Route::get('user/profile',['as'=>'profile',function()
{
//
}]);
Youmayalsospecifyroutenamesforcontrolleractions:
Route::get('user/profile',[
'as'=>'profile','uses'=>'UserController@showProfile'
]);
Now,youmayusetheroute'snamewhengeneratingURLsorredirects:
$url=route('profile');
$redirect=redirect()->route('profile');
ThecurrentRouteNamemethodreturnsthenameoftheroutehandlingthecurrentrequest:
$name=Route::currentRouteName();
Sometimesyoumayneedtoapplyfilterstoagroupofroutes.Insteadofspecifyingthefilteroneachroute,youmayusearoutegroup:
Route::group(['middleware'=>'auth'],function()
{
Route::get('/',function()
{
//HasAuthFilter
});
Route::get('user/profile',function()
{
//HasAuthFilter
NamedRoutes
RouteGroups
});
});
Youmayusethenamespaceparameterwithinyourgrouparraytospecifythenamespaceforallcontrollerswithinthegroup:
Route::group(['namespace'=>'Admin'],function()
{
//
});
Note:Bydefault,theRouteServiceProviderincludesyourroutes.phpfilewithinanamespacegroup,allowingyoutoregistercontrollerrouteswithoutspecifyingthefullnamespace.
Laravelroutesalsohandlewildcardsub-domains,andwillpassyourwildcardparametersfromthedomain:
Route::group(['domain'=>'{account}.myapp.com'],function()
{
Route::get('user/{id}',function($account,$id)
{
//
});
});
Agroupofroutesmaybeprefixedbyusingtheprefixoptionintheattributesarrayofagroup:
Route::group(['prefix'=>'admin'],function()
{
Route::get('user',function()
{
//
});
});
Laravelmodelbindingprovidesaconvenientwaytoinjectclassinstancesintoyourroutes.Forexample,insteadofinjectingauser'sID,youcaninjecttheentireUserclassinstancethatmatchesthegivenID.
First,usetherouter'smodelmethodtospecifytheclassforagivenparameter.YoushoulddefineyourmodelbindingsintheRouteServiceProvider::bootmethod:
publicfunctionboot(Router$router)
{
parent::boot($router);
Sub-DomainRouting
RegisteringSub-DomainRoutes
RoutePrefixing
RouteModelBinding
BindingAParameterToAModel
$router->model('user','App\User');
}
Next,definearoutethatcontainsa{user}parameter:
Route::get('profile/{user}',function(App\User$user)
{
//
});
Sincewehaveboundthe{user}parametertotheApp\Usermodel,aUserinstancewillbeinjectedintotheroute.So,forexample,arequesttoprofile/1willinjecttheUserinstancewhichhasanIDof1.
Note:Ifamatchingmodelinstanceisnotfoundinthedatabase,a404errorwillbethrown.
Ifyouwishtospecifyyourown"notfound"behavior,passaClosureasthethirdargumenttothemodelmethod:
Route::model('user','User',function()
{
thrownewNotFoundHttpException;
});
Ifyouwishtouseyourownresolutionlogic,youshouldusetheRouter::bindmethod.TheClosureyoupasstothebindmethodwillreceivethevalueoftheURIsegment,andshouldreturnaninstanceoftheclassyouwanttobeinjectedintotheroute:
Route::bind('user',function($value)
{
returnUser::where('name',$value)->first();
});
Therearetwowaystomanuallytriggera404errorfromaroute.First,youmayusetheaborthelper:
abort(404);
TheaborthelpersimplythrowsaSymfony\Component\HttpFoundation\Exception\HttpExceptionwiththespecifiedstatuscode.
Secondly,youmaymanuallythrowaninstanceofSymfony\Component\HttpKernel\Exception\NotFoundHttpException.
Moreinformationonhandling404exceptionsandusingcustomresponsesfortheseerrorsmaybefoundintheerrorssectionofthedocumentation.
Throwing404Errors
IntroductionDefiningMiddlewareRegisteringMiddlewareTerminableMiddleware
HTTPmiddlewareprovideaconvenientmechanismforfilteringHTTPrequestsenteringyourapplication.Forexample,Laravelincludesamiddlewarethatverifiestheuserofyourapplicationisauthenticated.Iftheuserisnotauthenticated,themiddlewarewillredirecttheusertotheloginscreen.However,iftheuserisauthenticated,themiddlewarewillallowtherequesttoproceedfurtherintotheapplication.
Ofcourse,middlewarecanbewrittentoperformavarietyoftasksbesidesauthentication.ACORSmiddlewaremightberesponsibleforaddingtheproperheaderstoallresponsesleavingyourapplication.Aloggingmiddlewaremightlogallincomingrequeststoyourapplication.
ThereareseveralmiddlewareincludedintheLaravelframework,includingmiddlewareformaintenance,authentication,CSRFprotection,andmore.Allofthesemiddlewarearelocatedintheapp/Http/Middlewaredirectory.
Tocreateanewmiddleware,usethemake:middlewareArtisancommand:
phpartisanmake:middlewareOldMiddleware
ThiscommandwillplaceanewOldMiddlewareclasswithinyourapp/Http/Middlewaredirectory.Inthismiddleware,wewillonlyallowaccesstotherouteifthesuppliedageisgreaterthan200.Otherwise,wewillredirecttheusersbacktothe"home"URI.
<?phpnamespaceApp\Http\Middleware;
classOldMiddleware{
/**
*Runtherequestfilter.
*
*@param\Illuminate\Http\Request$request
*@param\Closure$next
*@returnmixed
*/
publicfunctionhandle($request,Closure$next)
{
if($request->input('age')<200)
{
returnredirect('home');
}
return$next($request);
}
}
Asyoucansee,ifthegivenageislessthan200,themiddlewarewillreturnanHTTPredirecttotheclient;otherwise,therequestwillbepassedfurtherintotheapplication.Topasstherequestdeeperintotheapplication(allowingthemiddlewareto"pass"),simplycallthe$nextcallbackwiththe$request.
HTTPMiddleware
Introduction
DefiningMiddleware
It'sbesttoenvisionmiddlewareasaseriesof"layers"HTTPrequestsmustpassthroughbeforetheyhityourapplication.Eachlayercanexaminetherequestandevenrejectitentirely.
IfyouwantamiddlewaretoberunduringeveryHTTPrequesttoyourapplication,simplylistthemiddlewareclassinthe$middlewarepropertyofyourapp/Http/Kernel.phpclass.
Ifyouwouldliketoassignmiddlewaretospecificroutes,youshouldfirstassignthemiddlewareashort-handkeyinyourapp/Http/Kernel.phpfile.Bydefault,the$routeMiddlewarepropertyofthisclasscontainsentriesforthemiddlewareincludedwithLaravel.Toaddyourown,simplyappendittothislistandassignitakeyofyourchoosing.
OncethemiddlewarehasbeendefinedintheHTTPkernel,youmayusethemiddlewarekeyintherouteoptionsarray:
Route::get('admin/profile',['middleware'=>'auth',function()
{
//
}]);
SometimesamiddlewaremayneedtodosomeworkaftertheHTTPresponsehasalreadybeensenttothebrowser.Forexample,the"session"middlewareincludedwithLaravelwritesthesessiondatatostorageaftertheresponsehasbeensenttothebrowser.Toaccomplishthis,youmaydefinethemiddlewareas"terminable".
useIlluminate\Contracts\Routing\TerminableMiddleware;
classStartSessionimplementsTerminableMiddleware{
publicfunctionhandle($request,$next)
{
return$next($request);
}
publicfunctionterminate($request,$response)
{
//Storethesessiondata...
}
}
Asyoucansee,inadditiontodefiningahandlemethod,TerminableMiddlewaredefineaterminatemethod.Thismethodreceivesboththerequestandtheresponse.Onceyouhavedefinedaterminablemiddleware,youshouldaddittothelistofglobalmiddlewaresinyourHTTPkernel.
RegisteringMiddleware
GlobalMiddleware
AssigningMiddlewareToRoutes
TerminableMiddleware
IntroductionBasicControllersControllerMiddlewareImplicitControllersRESTfulResourceControllersDependencyInjection&ControllersRouteCaching
Insteadofdefiningallofyourrequesthandlinglogicinasingleroutes.phpfile,youmaywishtoorganizethisbehaviorusingControllerclasses.ControllerscangrouprelatedHTTPrequesthandlinglogicintoaclass.Controllersaretypicallystoredintheapp/Http/Controllersdirectory.
Hereisanexampleofabasiccontrollerclass:
<?phpnamespaceApp\Http\Controllers;
useApp\Http\Controllers\Controller;
classUserControllerextendsController{
/**
*Showtheprofileforthegivenuser.
*
*@paramint$id
*@returnResponse
*/
publicfunctionshowProfile($id)
{
returnview('user.profile',['user'=>User::findOrFail($id)]);
}
}
Wecanroutetothecontrolleractionlikeso:
Route::get('user/{id}','UserController@showProfile');
Note:Allcontrollersshouldextendthebasecontrollerclass.
Itisveryimportanttonotethatwedidnotneedtospecifythefullcontrollernamespace,onlytheportionoftheclassnamethatcomesaftertheApp\Http\Controllersnamespace"root".Bydefault,theRouteServiceProviderwillloadtheroutes.phpfilewithinaroutegroupcontainingtherootcontrollernamespace.
IfyouchoosetonestororganizeyourcontrollersusingPHPnamespacesdeeperintotheApp\Http\Controllersdirectory,simplyusethespecificclassnamerelativetotheApp\Http\Controllersrootnamespace.So,ifyourfullcontrollerclassisApp\Http\Controllers\Photos\AdminController,youwouldregisteraroutelikeso:
HTTPControllers
Introduction
BasicControllers
Controllers&Namespaces
Route::get('foo','Photos\AdminController@method');
LikeClosureroutes,youmayspecifynamesoncontrollerroutes:
Route::get('foo',['uses'=>'FooController@method','as'=>'name']);
TogenerateaURLtoacontrolleraction,usetheactionhelpermethod:
$url=action('App\Http\Controllers\FooController@method');
IfyouwishtogenerateaURLtoacontrolleractionwhileusingonlytheportionoftheclassnamerelativetoyourcontrollernamespace,registertherootcontrollernamespacewiththeURLgenerator:
URL::setRootControllerNamespace('App\Http\Controllers');
$url=action('FooController@method');
YoumayaccessthenameofthecontrolleractionbeingrunusingthecurrentRouteActionmethod:
$action=Route::currentRouteAction();
Middlewaremaybespecifiedoncontrollerrouteslikeso:
Route::get('profile',[
'middleware'=>'auth',
'uses'=>'UserController@showProfile'
]);
Additionally,youmayspecifymiddlewarewithinyourcontroller'sconstructor:
classUserControllerextendsController{
/**
*InstantiateanewUserControllerinstance.
*/
publicfunction__construct()
{
$this->middleware('auth');
$this->middleware('log',['only'=>['fooAction','barAction']]);
$this->middleware('subscribed',['except'=>['fooAction','barAction']]);
}
}
NamingControllerRoutes
URLsToControllerActions
ControllerMiddleware
ImplicitControllers
Laravelallowsyoutoeasilydefineasingleroutetohandleeveryactioninacontroller.First,definetherouteusingtheRoute::controllermethod:
Route::controller('users','UserController');
Thecontrollermethodacceptstwoarguments.ThefirstisthebaseURIthecontrollerhandles,whilethesecondistheclassnameofthecontroller.Next,justaddmethodstoyourcontroller,prefixedwiththeHTTPverbtheyrespondto:
classUserControllerextendsBaseController{
publicfunctiongetIndex()
{
//
}
publicfunctionpostProfile()
{
//
}
publicfunctionanyLogin()
{
//
}
}
TheindexmethodswillrespondtotherootURIhandledbythecontroller,which,inthiscase,isusers.
Ifyourcontrolleractioncontainsmultiplewords,youmayaccesstheactionusing"dash"syntaxintheURI.Forexample,thefollowingcontrolleractiononourUserControllerwouldrespondtotheusers/admin-profileURI:
publicfunctiongetAdminProfile(){}
ResourcecontrollersmakeitpainlesstobuildRESTfulcontrollersaroundresources.Forexample,youmaywishtocreateacontrollerthathandlesHTTPrequestsregarding"photos"storedbyyourapplication.Usingthemake:controllerArtisancommand,wecanquicklycreatesuchacontroller:
phpartisanmake:controllerPhotoController
Next,weregisteraresourcefulroutetothecontroller:
Route::resource('photo','PhotoController');
ThissingleroutedeclarationcreatesmultipleroutestohandleavarietyofRESTfulactionsonthephotoresource.Likewise,thegeneratedcontrollerwillalreadyhavemethodsstubbedforeachoftheseactions,includingnotesinformingyouwhichURIsandverbstheyhandle.
Verb Path Action RouteName
GET /resource index resource.index
RESTfulResourceControllers
ActionsHandledByResourceController
GET /resource/create create resource.create
POST /resource store resource.store
GET /resource/{resource} show resource.show
GET /resource/{resource}/edit edit resource.edit
PUT/PATCH /resource/{resource} update resource.update
DELETE /resource/{resource} destroy resource.destroy
Additionally,youmayspecifyonlyasubsetofactionstohandleontheroute:
Route::resource('photo','PhotoController',
['only'=>['index','show']]);
Route::resource('photo','PhotoController',
['except'=>['create','store','update','destroy']]);
Bydefault,allresourcecontrolleractionshavearoutename;however,youcanoverridethesenamesbypassinganamesarraywithyouroptions:
Route::resource('photo','PhotoController',
['names'=>['create'=>'photo.build']]);
To"nest"resourcecontrollers,use"dot"notationinyourroutedeclaration:
Route::resource('photos.comments','PhotoCommentController');
Thisroutewillregistera"nested"resourcethatmaybeaccessedwithURLslikethefollowing:photos/{photos}/comments/{comments}.
classPhotoCommentControllerextendsController{
/**
*Showthespecifiedphotocomment.
*
*@paramint$photoId
*@paramint$commentId
*@returnResponse
*/
publicfunctionshow($photoId,$commentId)
{
//
}
}
Ifitbecomesnecessarytoaddadditionalroutestoaresourcecontrollerbeyondthedefaultresourceroutes,youshoulddefinethoseroutesbeforeyourcalltoRoute::resource:
Route::get('photos/popular');
CustomizingResourceRoutes
HandlingNestedResourceControllers
AddingAdditionalRoutesToResourceControllers
Route::resource('photos','PhotoController');
TheLaravelservicecontainerisusedtoresolveallLaravelcontrollers.Asaresult,youareabletotype-hintanydependenciesyourcontrollermayneedinitsconstructor:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Routing\Controller;
useApp\Repositories\UserRepository;
classUserControllerextendsController{
/**
*Theuserrepositoryinstance.
*/
protected$users;
/**
*Createanewcontrollerinstance.
*
*@paramUserRepository$users
*@returnvoid
*/
publicfunction__construct(UserRepository$users)
{
$this->users=$users;
}
}
Ofcourse,youmayalsotype-hintanyLaravelcontract.Ifthecontainercanresolveit,youcantype-hintit.
Inadditiontoconstructorinjection,youmayalsotype-hintdependenciesonyourcontroller'smethods.Forexample,let'stype-hinttheRequestinstanceononeofourmethods:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Http\Request;
useIlluminate\Routing\Controller;
classUserControllerextendsController{
/**
*Storeanewuser.
*
*@paramRequest$request
*@returnResponse
*/
publicfunctionstore(Request$request)
{
$name=$request->input('name');
//
}
}
Ifyourcontrollermethodisalsoexpectinginputfromarouteparameter,simplylistyourrouteargumentsafteryourotherdependencies:
DependencyInjection&Controllers
ConstructorInjection
MethodInjection
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Http\Request;
useIlluminate\Routing\Controller;
classUserControllerextendsController{
/**
*Storeanewuser.
*
*@paramRequest$request
*@paramint$id
*@returnResponse
*/
publicfunctionupdate(Request$request,$id)
{
//
}
}
Note:Methodinjectionisfullycompatiblewithmodelbinding.Thecontainerwillintelligentlydeterminewhichargumentsaremodelboundandwhichargumentsshouldbeinjected.
Ifyourapplicationisexclusivelyusingcontrollerroutes,youmaytakeadvantageofLaravel'sroutecache.Usingtheroutecachewilldrasticallydecreasetheamountoftimeittaketoregisterallofyourapplication'sroutes.Insomecases,yourrouteregistrationmayevenbeupto100xfaster!Togeneratearoutecache,justexecutetheroute:cacheArtisancommand:
phpartisanroute:cache
That'sallthereistoit!Yourcachedroutesfilewillnowbeusedinsteadofyourapp/Http/routes.phpfile.Remember,ifyouaddanynewroutesyouwillneedtogenerateafreshroutecache.Becauseofthis,youmaywishtoonlyruntheroute:cachecommandduringyourproject'sdeployment.
Toremovethecachedroutesfilewithoutgeneratinganewcache,usetheroute:clearcommand:
phpartisanroute:clear
RouteCaching
ObtainingARequestInstanceRetrievingInputOldInputCookiesFilesOtherRequestInformation
TheRequestfacadewillgrantyouaccesstothecurrentrequestthatisboundinthecontainer.Forexample:
$name=Request::input('name');
Remember,ifyouareinanamespace,youwillhavetoimporttheRequestfacadeusingauseRequest;statementatthetopofyourclassfile.
ToobtainaninstanceofthecurrentHTTPrequestviadependencyinjection,youshouldtype-hinttheclassonyourcontrollerconstructorormethod.Thecurrentrequestinstancewillautomaticallybeinjectedbytheservicecontainer:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Http\Request;
useIlluminate\Routing\Controller;
classUserControllerextendsController{
/**
*Storeanewuser.
*
*@paramRequest$request
*@returnResponse
*/
publicfunctionstore(Request$request)
{
$name=$request->input('name');
//
}
}
Ifyourcontrollermethodisalsoexpectinginputfromarouteparameter,simplylistyourrouteargumentsafteryourotherdependencies:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Http\Request;
useIlluminate\Routing\Controller;
classUserControllerextendsController{
/**
*Storeanewuser.
*
HTTPRequests
ObtainingARequestInstance
ViaFacade
ViaDependencyInjection
*@paramRequest$request
*@paramint$id
*@returnResponse
*/
publicfunctionupdate(Request$request,$id)
{
//
}
}
Usingafewsimplemethods,youmayaccessalluserinputfromyourIlluminate\Http\Requestinstance.YoudonotneedtoworryabouttheHTTPverbusedfortherequest,asinputisaccessedinthesamewayforallverbs.
$name=Request::input('name');
$name=Request::input('name','Sally');
if(Request::has('name'))
{
//
}
$input=Request::all();
$input=Request::only('username','password');
$input=Request::except('credit_card');
Whenworkingonformswith"array"inputs,youmayusedotnotationtoaccessthearrays:
$input=Request::input('products.0.name');
Laravelalsoallowsyoutokeepinputfromonerequestduringthenextrequest.Forexample,youmayneedtore-populateaformaftercheckingitforvalidationerrors.
RetrievingInput
RetrievingAnInputValue
RetrievingADefaultValueIfTheInputValueIsAbsent
DeterminingIfAnInputValueIsPresent
GettingAllInputForTheRequest
GettingOnlySomeOfTheRequestInput
OldInput
Theflashmethodwillflashthecurrentinputtothesessionsothatitisavailableduringtheuser'snextrequesttotheapplication:
Request::flash();
Request::flashOnly('username','email');
Request::flashExcept('password');
Sinceyouoftenwillwanttoflashinputinassociationwitharedirecttothepreviouspage,youmayeasilychaininputflashingontoaredirect.
returnredirect('form')->withInput();
returnredirect('form')->withInput(Request::except('password'));
Toretrieveflashedinputfromthepreviousrequest,usetheoldmethodontheRequestinstance.
$username=Request::old('username');
IfyouaredisplayingoldinputwithinaBladetemplate,itismoreconvenienttousetheoldhelper:
{{old('username')}}
AllcookiescreatedbytheLaravelframeworkareencryptedandsignedwithanauthenticationcode,meaningtheywillbeconsideredinvalidiftheyhavebeenchangedbytheclient.
$value=Request::cookie('name');
ThecookiehelperservesasasimplefactoryforgeneratingnewSymfony\Component\HttpFoundation\Cookieinstances.ThecookiesmaybeattachedtoaResponseinstanceusingthewithCookiemethod:
$response=newIlluminate\Http\Response('HelloWorld');
$response->withCookie(cookie('name','value',$minutes));
FlashingInputToTheSession
FlashingOnlySomeInputToTheSession
Flash&Redirect
RetrievingOldData
Cookies
RetrievingACookieValue
AttachingANewCookieToAResponse
By"forever",wereallymeanfiveyears.
$response->withCookie(cookie()->forever('name','value'));
$file=Request::file('photo');
if(Request::hasFile('photo'))
{
//
}
TheobjectreturnedbythefilemethodisaninstanceoftheSymfony\Component\HttpFoundation\File\UploadedFileclass,whichextendsthePHPSplFileInfoclassandprovidesavarietyofmethodsforinteractingwiththefile.
if(Request::file('photo')->isValid())
{
//
}
Request::file('photo')->move($destinationPath);
Request::file('photo')->move($destinationPath,$fileName);
ThereareavarietyofothermethodsavailableonUploadedFileinstances.CheckouttheAPIdocumentationfortheclassformoreinformationregardingthesemethods.
TheRequestclassprovidesmanymethodsforexaminingtheHTTPrequestforyourapplicationandextendstheSymfony\Component\HttpFoundation\Requestclass.Herearesomeofthehighlights.
$uri=Request::path();
CreatingACookieThatLastsForever*
Files
RetrievingAnUploadedFile
DeterminingIfAFileWasUploaded
DeterminingIfAnUploadedFileIsValid
MovingAnUploadedFile
OtherFileMethods
OtherRequestInformation
RetrievingTheRequestURI
$method=Request::method();
if(Request::isMethod('post'))
{
//
}
if(Request::is('admin/*'))
{
//
}
$url=Request::url();
RetrievingTheRequestMethod
DeterminingIfTheRequestPathMatchesAPattern
GetTheCurrentRequestURL
BasicResponsesRedirectsOtherResponsesResponseMacros
ThemostbasicresponsefromaLaravelrouteisastring:
Route::get('/',function()
{
return'HelloWorld';
});
However,formostroutesandcontrolleractions,youwillbereturningafullIlluminate\Http\Responseinstanceoraview.ReturningafullResponseinstanceallowsyoucustomizetheresponse'sHTTPstatuscodeandheaders.AResponseinstanceinheritsfromtheSymfony\Component\HttpFoundation\Responseclass,providingavarietyofmethodsforbuildingHTTPresponses:
useIlluminate\Http\Response;
return(newResponse($content,$status))
->header('Content-Type',$value);
Forconvenience,youmayalsousetheresponsehelper:
returnresponse($content,$status)
->header('Content-Type',$value);
Note:ForafulllistofavailableResponsemethods,checkoutitsAPIdocumentationandtheSymfonyAPIdocumentation.
IfyouneedaccesstotheResponseclassmethods,butwanttoreturnaviewastheresponsecontent,youmayusetheviewmethodforconvenience:
returnresponse()->view('hello')->header('Content-Type',$type);
returnresponse($content)->withCookie(cookie('name','value'));
HTTPResponses
BasicResponses
ReturningStringsFromRoutes
CreatingCustomResponses
SendingAViewInAResponse
AttachingCookiesToResponses
KeepinmindthatmostResponsemethodsarechainable,allowingforthefluentbuildingofresponses:
returnresponse()->view('hello')->header('Content-Type',$type)
->withCookie(cookie('name','value'));
RedirectresponsesaretypicallyinstancesoftheIlluminate\Http\RedirectResponseclass,andcontaintheproperheadersneededtoredirecttheusertoanotherURL.
ThereareseveralwaystogenerateaRedirectResponseinstance.Thesimplestmethodistousetheredirecthelpermethod.Whentesting,itisnotcommontomockthecreationofaredirectresponse,sousingthehelpermethodisalmostalwaysacceptable:
returnredirect('user/login');
RedirectingtoanewURLandflashingdatatothesessionaretypicallydoneatthesametime.So,forconvenience,youmaycreateaRedirectResponseinstanceandflashdatatothesessioninasinglemethodchain:
returnredirect('user/login')->with('message','LoginFailed');
Youmaywishtoredirecttheusertotheirpreviouslocation,forexample,afteraformsubmission.Youcandosobyusingthebackmethod:
returnredirect()->back();
returnredirect()->back()->withInput();
Whenyoucalltheredirecthelperwithnoparameters,aninstanceofIlluminate\Routing\Redirectorisreturned,allowingyoutocallanymethodontheRedirectorinstance.Forexample,togenerateaRedirectResponsetoanamedroute,youmayusetheroutemethod:
returnredirect()->route('login');
Ifyourroutehasparameters,youmaypassthemasthesecondargumenttotheroutemethod.
//ForaroutewiththefollowingURI:profile/{id}
MethodChaining
Redirects
ReturningARedirect
ReturningARedirectWithFlashData
RedirectingToThePreviousURL
ReturningARedirectToANamedRoute
ReturningARedirectToANamedRouteWithParameters
returnredirect()->route('profile',[1]);
Ifyouareredirectingtoaroutewithan"ID"parameterthatisbeingpopulatedfromanEloquentmodel,youmaysimplypassthemodelitself.TheIDwillbeextractedautomatically:
returnredirect()->route('profile',[$user]);
//ForaroutewiththefollowingURI:profile/{user}
returnredirect()->route('profile',['user'=>1]);
SimilarlytogeneratingRedirectResponseinstancestonamedroutes,youmayalsogenerateredirectstocontrolleractions:
returnredirect()->action('App\Http\Controllers\HomeController@index');
Note:YoudonotneedtospecifythefullnamespacetothecontrollerifyouhaveregisteredarootcontrollernamespaceviaURL::setRootControllerNamespace.
returnredirect()->action('App\Http\Controllers\UserController@profile',[1]);
returnredirect()->action('App\Http\Controllers\UserController@profile',['user'=>1]);
Theresponsehelpermaybeusedtoconvenientlygenerateothertypesofresponseinstances.Whentheresponsehelperiscalledwithoutarguments,animplementationoftheIlluminate\Contracts\Routing\ResponseFactorycontractisreturned.Thiscontractprovidesseveralhelpfulmethodsforgeneratingresponses.
ThejsonmethodwillautomaticallysettheContent-Typeheadertoapplication/json:
returnresponse()->json(['name'=>'Abigail','state'=>'CA']);
returnresponse()->json(['name'=>'Abigail','state'=>'CA'])
->setCallback($request->input('callback'));
ReturningARedirectToANamedRouteUsingNamedParameters
ReturningARedirectToAControllerAction
ReturningARedirectToAControllerActionWithParameters
ReturningARedirectToAControllerActionUsingNamedParameters
OtherResponses
CreatingAJSONResponse
CreatingAJSONPResponse
returnresponse()->download($pathToFile);
returnresponse()->download($pathToFile,$name,$headers);
Note:SymfonyHttpFoundation,whichmanagesfiledownloads,requiresthefilebeingdownloadedtohaveanASCIIfilename.
Ifyouwouldliketodefineacustomresponsethatyoucanre-useinavarietyofyourroutesandcontrollers,youmayusethemacromethodonanimplementationofIlluminate\Contracts\Routing\ResponseFactory.
Forexample,fromaserviceprovider'sbootmethod:
<?phpnamespaceApp\Providers;
useResponse;
useIlluminate\Support\ServiceProvider;
classResponseMacroServiceProviderextendsServiceProvider{
/**
*Performpost-registrationbootingofservices.
*
*@returnvoid
*/
publicfunctionboot()
{
Response::macro('caps',function($value)
{
returnResponse::make(strtoupper($value));
});
}
}
Themacrofunctionacceptsanameasitsfirstargument,andaClosureasitssecond.Themacro'sClosurewillbeexecutedwhencallingthemacronamefromaResponseFactoryimplementationortheresponsehelper:
returnresponse()->caps('foo');
CreatingAFileDownloadResponse
ResponseMacros
BasicUsageViewComposers
ViewscontaintheHTMLservedbyyourapplication,andserveasaconvenientmethodofseparatingyourcontrolleranddomainlogicfromyourpresentationlogic.Viewsarestoredintheresources/viewsdirectory.
Asimpleviewlookslikethis:
<!--Viewstoredinresources/views/greeting.php-->
<html>
<body>
<h1>Hello,<?phpecho$name;?></h1>
</body>
</html>
Theviewmaybereturnedtothebrowserlikeso:
Route::get('/',function()
{
returnview('greeting',['name'=>'James']);
});
Asyoucansee,thefirstargumentpassedtotheviewhelpercorrespondstothenameoftheviewfileintheresources/viewsdirectory.Thesecondargumentpassedtohelperisanarrayofdatathatshouldbemadeavailabletotheview.
Ofcourse,viewsmayalsobenestedwithinsub-directoriesoftheresources/viewsdirectory.Forexample,ifyourviewisstoredatresources/views/admin/profile.php,itshouldbereturnedlikeso:
returnview('admin.profile',$data);
//Usingconventionalapproach
$view=view('greeting')->with('name','Victoria');
//UsingMagicMethods
$view=view('greeting')->withName('Victoria');
Intheexampleabove,thevariable$nameismadeaccessibletotheviewandcontainsVictoria.
Ifyouwish,youmaypassanarrayofdataasthesecondparametertotheviewhelper:
$view=view('greetings',$data);
Views
BasicUsage
PassingDataToViews
SharingDataWithAllViews
Occasionally,youmayneedtoshareapieceofdatawithallviewsthatarerenderedbyyourapplication.Youhaveseveraloptions:theviewhelper,theIlluminate\Contracts\View\Factorycontract,orawildcardviewcomposer.
Forexample,usingtheviewhelper:
view()->share('data',[1,2,3]);
YoumayalsousetheViewfacade:
View::share('data',[1,2,3]);
Typically,youwouldplacecallstothesharemethodwithinaserviceprovider'sbootmethod.YouarefreetoaddthemtotheAppServiceProviderorgenerateaseparateserviceprovidertohousethem.
Note:Whentheviewhelperiscalledwithoutarguments,itreturnsanimplementationoftheIlluminate\Contracts\View\Factorycontract.
Ifyouneedtodetermineifaviewexists,youmayusetheexistsmethod:
if(view()->exists('emails.customer'))
{
//
}
Ifyouwish,youmaygenerateaviewfromafully-qualifiedfilepath:
returnview()->file($pathToFile,$data);
Viewcomposersarecallbacksorclassmethodsthatarecalledwhenaviewisrendered.Ifyouhavedatathatyouwanttobeboundtoavieweachtimethatviewisrendered,aviewcomposerorganizesthatlogicintoasinglelocation.
Let'sorganizeourviewcomposerswithinaserviceprovider.We'llusetheViewfacadetoaccesstheunderlyingIlluminate\Contracts\View\Factorycontractimplementation:
<?phpnamespaceApp\Providers;
useView;
useIlluminate\Support\ServiceProvider;
classComposerServiceProviderextendsServiceProvider{
/**
*Registerbindingsinthecontainer.
*
*@returnvoid
*/
publicfunctionboot()
{
DeterminingIfAViewExists
ReturningAViewFromAFilePath
ViewComposers
DefiningAViewComposer
//Usingclassbasedcomposers...
View::composer('profile','App\Http\ViewComposers\ProfileComposer');
//UsingClosurebasedcomposers...
View::composer('dashboard',function()
{
});
}
}
Note:Laraveldoesnotincludeadefaultdirectoryforviewcomposers.Youarefreetoorganizethemhoweveryouwish.Forexample,youcouldcreateanApp\Http\Composersdirectory.
Nowthatwehaveregisteredthecomposer,theProfileComposer@composemethodwillbeexecutedeachtimetheprofileviewisbeingrendered.So,let'sdefinethecomposerclass:
<?phpnamespaceApp\Http\Composers;
useIlluminate\Contracts\View\View;
useIlluminate\Users\RepositoryasUserRepository;
classProfileComposer{
/**
*Theuserrepositoryimplementation.
*
*@varUserRepository
*/
protected$users;
/**
*Createanewprofilecomposer.
*
*@paramUserRepository$users
*@returnvoid
*/
publicfunction__construct(UserRepository$users)
{
//Dependenciesautomaticallyresolvedbyservicecontainer...
$this->users=$users;
}
/**
*Binddatatotheview.
*
*@paramView$view
*@returnvoid
*/
publicfunctioncompose(View$view)
{
$view->with('count',$this->users->count());
}
}
Justbeforetheviewisrendered,thecomposer'scomposemethodiscalledwiththeIlluminate\Contracts\View\Viewinstance.Youmayusethewithmethodtobinddatatotheview.
Note:Allviewcomposersareresolvedviatheservicecontainer,soyoumaytype-hintanydependenciesyouneedwithinacomposer'sconstructor.
Thecomposermethodacceptsthe*characterasawildcard,soyoumayattachacomposertoallviewslikeso:
View::composer('*',function()
{
//
WildcardViewComposers
});
Youmayalsoattachaviewcomposertomultipleviewsatonce:
View::composer(['profile','dashboard'],'App\Http\ViewComposers\MyViewComposer');
Youmayusethecomposersmethodtoregisteragroupofcomposersatthesametime:
View::composers([
'App\Http\ViewComposers\AdminComposer'=>['admin.index','admin.profile'],
'App\Http\ViewComposers\UserComposer'=>'user',
'App\Http\ViewComposers\ProductComposer'=>'product'
]);
Viewcreatorsworkalmostexactlylikeviewcomposers;however,theyarefiredimmediatelywhentheviewisinstantiated.Toregisteraviewcreator,usethecreatormethod:
View::creator('profile','App\Http\ViewCreators\ProfileCreator');
AttachingAComposerToMultipleViews
DefiningMultipleComposers
ViewCreators
ServiceProvidersIntroductionBasicProviderExampleRegisteringProvidersDeferredProviders
ServiceContainerIntroductionBasicUsageBindingInterfacesToImplementationsContextualBindingTaggingPracticalApplicationsContainerEvents
ContractsIntroductionWhyContracts?ContractReferenceHowToUseContracts
FacadesIntroductionExplanationPracticalUsageCreatingFacadesMockingFacadesFacadeClassReference
RequestLifecycleIntroductionLifecycleOverviewFocusOnServiceProviders
ApplicationStructureIntroductionTheRootDirectoryTheAppDirectoryNamespacingYourApplication
ArchitectureFoundations
IntroductionBasicProviderExampleRegisteringProvidersDeferredProviders
ServiceprovidersarethecentralplaceofallLaravelapplicationbootstrapping.Yourownapplication,aswellasallofLaravel'scoreservicesarebootstrappedviaserviceproviders.
But,whatdowemeanby"bootstrapped"?Ingeneral,wemeanregisteringthings,includingregisteringservicecontainerbindings,eventlisteners,filters,andevenroutes.Serviceprovidersarethecentralplacetoconfigureyourapplication.
Ifyouopentheconfig/app.phpfileincludedwithLaravel,youwillseeaprovidersarray.Thesearealloftheserviceproviderclassesthatwillbeloadedforyourapplication.Ofcourse,manyofthemare"deferred"providers,meaningtheywillnotbeloadedoneveryrequest,butonlywhentheservicestheyprovideareactuallyneeded.
InthisoverviewyouwilllearnhowtowriteyourownserviceprovidersandregisterthemwithyourLaravelapplication.
AllserviceprovidersextendtheIlluminate\Support\ServiceProviderclass.Thisabstractclassrequiresthatyoudefineatleastonemethodonyourprovider:register.Withintheregistermethod,youshouldonlybindthingsintotheservicecontainer.Youshouldneverattempttoregisteranyeventlisteners,routes,oranyotherpieceoffunctionalitywithintheregistermethod.
TheArtisanCLIcaneasilygenerateanewproviderviathemake:providercommand:
phpartisanmake:providerRiakServiceProvider
Now,let'stakealookatabasicserviceprovider:
<?phpnamespaceApp\Providers;
useRiak\Connection;
useIlluminate\Support\ServiceProvider;
classRiakServiceProviderextendsServiceProvider{
/**
*Registerbindingsinthecontainer.
*
*@returnvoid
*/
publicfunctionregister()
{
$this->app->singleton('Riak\Contracts\Connection',function($app)
{
returnnewConnection($app['config']['riak']);
});
}
}
ServiceProviders
Introduction
BasicProviderExample
TheRegisterMethod
Thisserviceprovideronlydefinesaregistermethod,andusesthatmethodtodefineanimplementationofRiak\Contracts\Connectionintheservicecontainer.Ifyoudon'tunderstandhowtheservicecontainerworks,don'tworry,we'llcoverthatsoon.
ThisclassisnamespacedunderApp\ProviderssincethatisthedefaultlocationforserviceprovidersinLaravel.However,youarefreetochangethisasyouwish.YourserviceprovidersmaybeplacedanywherethatComposercanautoloadthem.
So,whatifweneedtoregisteraneventlistenerwithinourserviceprovider?Thisshouldbedonewithinthebootmethod.Thismethodiscalledafterallotherserviceprovidershavebeenregistered,meaningyouhaveaccesstoallotherservicesthathavebeenregisteredbytheframework.
<?phpnamespaceApp\Providers;
useEvent;
useIlluminate\Support\ServiceProvider;
classEventServiceProviderextendsServiceProvider{
/**
*Performpost-registrationbootingofservices.
*
*@returnvoid
*/
publicfunctionboot()
{
Event::listen('SomeEvent','SomeEventHandler');
}
/**
*Registerbindingsinthecontainer.
*
*@returnvoid
*/
publicfunctionregister()
{
//
}
}
Weareabletotype-hintdependenciesforourbootmethod.Theservicecontainerwillautomaticallyinjectanydependenciesyouneed:
useIlluminate\Contracts\Events\Dispatcher;
publicfunctionboot(Dispatcher$events)
{
$events->listen('SomeEvent','SomeEventHandler');
}
Allserviceprovidersareregisteredintheconfig/app.phpconfigurationfile.Thisfilecontainsaprovidersarraywhereyoucanlistthenamesofyourserviceproviders.Bydefault,asetofLaravelcoreserviceprovidersarelistedinthisarray.TheseprovidersbootstrapthecoreLaravelcomponents,suchasthemailer,queue,cache,andothers.
Toregisteryourprovider,simplyaddittothearray:
'providers'=>[
//OtherServiceProviders
TheBootMethod
RegisteringProviders
'App\Providers\AppServiceProvider',
],
Ifyourproviderisonlyregisteringbindingsintheservicecontainer,youmaychoosetodeferitsregistrationuntiloneoftheregisteredbindingsisactuallyneeded.Deferringtheloadingofsuchaproviderwillimprovetheperformanceofyourapplication,sinceitisnotloadedfromthefilesystemoneveryrequest.
Todefertheloadingofaprovider,setthedeferpropertytotrueanddefineaprovidesmethod.Theprovidesmethodreturnstheservicecontainerbindingsthattheproviderregisters:
<?phpnamespaceApp\Providers;
useRiak\Connection;
useIlluminate\Support\ServiceProvider;
classRiakServiceProviderextendsServiceProvider{
/**
*Indicatesifloadingoftheproviderisdeferred.
*
*@varbool
*/
protected$defer=true;
/**
*Registertheserviceprovider.
*
*@returnvoid
*/
publicfunctionregister()
{
$this->app->singleton('Riak\Contracts\Connection',function($app)
{
returnnewConnection($app['config']['riak']);
});
}
/**
*Gettheservicesprovidedbytheprovider.
*
*@returnarray
*/
publicfunctionprovides()
{
return['Riak\Contracts\Connection'];
}
}
Laravelcompilesandstoresalistofalloftheservicessuppliedbydeferredserviceproviders,alongwiththenameofitsserviceproviderclass.Then,onlywhenyouattempttoresolveoneoftheseservicesdoesLaravelloadtheserviceprovider.
DeferredProviders
IntroductionBasicUsageBindingInterfacesToImplementationsContextualBindingTaggingPracticalApplicationsContainerEvents
TheLaravelservicecontainerisapowerfultoolformanagingclassdependencies.Dependencyinjectionisafancywordthatessentiallymeansthis:classdependenciesare"injected"intotheclassviatheconstructoror,insomecases,"setter"methods.
Let'slookatasimpleexample:
<?phpnamespaceApp\Handlers\Commands;
useApp\User;
useApp\Commands\PurchasePodcast;
useIlluminate\Contracts\Mail\Mailer;
classPurchasePodcastHandler{
/**
*Themailerimplementation.
*/
protected$mailer;
/**
*Createanewinstance.
*
*@paramMailer$mailer
*@returnvoid
*/
publicfunction__construct(Mailer$mailer)
{
$this->mailer=$mailer;
}
/**
*Purchaseapodcast.
*
*@paramPurchasePodcastCommand$command
*@returnvoid
*/
publicfunctionhandle(PurchasePodcastCommand$command)
{
//
}
}
Inthisexample,thePurchasePodcastcommandhandlerneedstosende-mailswhenapodcastispurchased.So,wewillinjectaservicethatisabletosende-mails.Sincetheserviceisinjected,weareabletoeasilyswapitoutwithanotherimplementation.Wearealsoabletoeasily"mock",orcreateadummyimplementationofthemailerwhentestingourapplication.
AdeepunderstandingoftheLaravelservicecontainerisessentialtobuildingapowerful,largeapplication,aswellasforcontributingtotheLaravelcoreitself.
ServiceContainer
Introduction
Almostallofyourservicecontainerbindingswillberegisteredwithinserviceproviders,soalloftheseexampleswilldemonstrateusingthecontainerinthatcontext.However,ifyouneedaninstanceofthecontainerelsewhereinyourapplication,suchasafactory,youmaytype-hinttheIlluminate\Contracts\Container\Containercontractandaninstanceofthecontainerwillbeinjectedforyou.Alternatively,youmayusetheAppfacadetoaccessthecontainer.
Withinaserviceprovider,youalwayshaveaccesstothecontainerviathe$this->appinstancevariable.
Thereareseveralwaystheservicecontainercanregisterdependencies,includingClosurecallbacksandbindinginterfacestoimplementations.First,we'llexploreClosurecallbacks.AClosureresolverisregisteredinthecontainerwithakey(typicallytheclassname)andaClosurethatreturnssomevalue:
$this->app->bind('FooBar',function($app)
{
returnnewFooBar($app['SomethingElse']);
});
Sometimes,youmaywishtobindsomethingintothecontainerthatshouldonlyberesolvedonce,andthesameinstanceshouldbereturnedonsubsequentcallsintothecontainer:
$this->app->singleton('FooBar',function($app)
{
returnnewFooBar($app['SomethingElse']);
});
Youmayalsobindanexistingobjectinstanceintothecontainerusingtheinstancemethod.Thegiveninstancewillalwaysbereturnedonsubsequentcallsintothecontainer:
$fooBar=newFooBar(newSomethingElse);
$this->app->instance('FooBar',$fooBar);
Thereareseveralwaystoresolvesomethingoutofthecontainer.First,youmayusethemakemethod:
$fooBar=$this->app->make('FooBar');
Secondly,youmayuse"arrayaccess"onthecontainer,sinceitimplementsPHP'sArrayAccessinterface:
$fooBar=$this->app['FooBar'];
Lastly,butmostimportantly,youmaysimply"type-hint"thedependencyintheconstructorofaclassthatisresolvedbythe
BasicUsage
Binding
RegisteringABasicResolver
RegisteringASingleton
BindingAnExistingInstanceIntoTheContainer
Resolving
container,includingcontrollers,eventlisteners,queuejobs,filters,andmore.Thecontainerwillautomaticallyinjectthedependencies:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Routing\Controller;
useApp\Users\RepositoryasUserRepository;
classUserControllerextendsController{
/**
*Theuserrepositoryinstance.
*/
protected$users;
/**
*Createanewcontrollerinstance.
*
*@paramUserRepository$users
*@returnvoid
*/
publicfunction__construct(UserRepository$users)
{
$this->users=$users;
}
/**
*ShowtheuserwiththegivenID.
*
*@paramint$id
*@returnResponse
*/
publicfunctionshow($id)
{
//
}
}
Averypowerfulfeaturesoftheservicecontainerisitsabilitytobindaninterfacetoagivenimplementation.Forexample,perhapsourapplicationintegrateswiththePusherwebserviceforsendingandreceivingreal-timeevents.IfweareusingPusher'sPHPSDK,wecouldinjectaninstanceofthePusherclientintoaclass:
<?phpnamespaceApp\Handlers\Commands;
useApp\Commands\CreateOrder;
usePusher\ClientasPusherClient;
classCreateOrderHandler{
/**
*ThePusherSDKclientinstance.
*/
protected$pusher;
/**
*Createaneworderhandlerinstance.
*
*@paramPusherClient$pusher
*@returnvoid
*/
publicfunction__construct(PusherClient$pusher)
{
$this->pusher=$pusher;
}
/**
*Executethegivencommand.
BindingInterfacesToImplementations
InjectingConcreteDependencies
*
*@paramCreateOrder$command
*@returnvoid
*/
publicfunctionexecute(CreateOrder$command)
{
//
}
}
Inthisexample,itisgoodthatweareinjectingtheclassdependencies;however,wearetightlycoupledtothePusherSDK.IfthePusherSDKmethodschangeorwedecidetoswitchtoaneweventserviceentirely,wewillneedtochangeourCreateOrderHandlercode.
Inorderto"insulate"theCreateOrderHandleragainstchangestoeventpushing,wecoulddefineanEventPusherinterfaceandaPusherEventPusherimplementation:
<?phpnamespaceApp\Contracts;
interfaceEventPusher{
/**
*Pushaneweventtoallclients.
*
*@paramstring$event
*@paramarray$data
*@returnvoid
*/
publicfunctionpush($event,array$data);
}
OncewehavecodedourPusherEventPusherimplementationofthisinterface,wecanregisteritwiththeservicecontainerlikeso:
$this->app->bind('App\Contracts\EventPusher','App\Services\PusherEventPusher');
ThistellsthecontainerthatitshouldinjectthePusherEventPusherwhenaclassneedsanimplementationofEventPusher.Nowwecantype-hinttheEventPusherinterfaceinourconstructor:
/**
*Createaneworderhandlerinstance.
*
*@paramEventPusher$pusher
*@returnvoid
*/
publicfunction__construct(EventPusher$pusher)
{
$this->pusher=$pusher;
}
Sometimesyoumayhavetwoclassesthatutilizethesameinterface,butyouwishtoinjectdifferentimplementationsintoeachclass.Forexample,whenoursystemreceivesanewOrder,wemaywanttosendaneventviaPubNubratherthanPusher.Laravelprovidesasimple,fluentinterfacefordefininingthisbehavior:
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
ProgramToAnInterface
ContextualBinding
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
Occasionally,youmayneedtoresolveallofacertain"category"ofbinding.Forexample,perhapsyouarebuildingareportaggregatorthatreceivesanarrayofmanydifferentReportinterfaceimplementations.AfterregisteringtheReportimplementations,youcanassignthematagusingthetagmethod:
$this->app->bind('SpeedReport',function()
{
//
});
$this->app->bind('MemoryReport',function()
{
//
});
$this->app->tag(['SpeedReport','MemoryReport'],'reports');
Oncetheserviceshavebeentagged,youmayeasilyresolvethemallviathetaggedmethod:
$this->app->bind('ReportAggregator',function($app)
{
returnnewReportAggregator($app->tagged('reports'));
});
Laravelprovidesseveralopportunitiestousetheservicecontainertoincreasetheflexibilityandtestabilityofyourapplication.Oneprimaryexampleiswhenresolvingcontrollers.Allcontrollersareresolvedthroughtheservicecontainer,meaningyoucantype-hintdependenciesinacontrollerconstructor,andtheywillautomaticallybeinjected.
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Routing\Controller;
useApp\Repositories\OrderRepository;
classOrdersControllerextendsController{
/**
*Theorderrepositoryinstance.
*/
protected$orders;
/**
*Createacontrollerinstance.
*
*@paramOrderRepository$orders
*@returnvoid
*/
publicfunction__construct(OrderRepository$orders)
{
$this->orders=$orders;
}
/**
*Showalloftheorders.
*
*@returnResponse
*/
publicfunctionindex()
{
$all=$this->orders->all();
Tagging
PracticalApplications
returnview('orders',['all'=>$all]);
}
}
Inthisexample,theOrderRepositoryclasswillautomaticallybeinjectedintothecontroller.Thismeansthata"mock"OrderRepositorymaybeboundintothecontainerwhenunittesting,allowingforpainlessstubbingofdatabaselayerinteraction.
Ofcourse,asmentionedabove,controllersarenottheonlyclassesLaravelresolvesviatheservicecontainer.Youmayalsotype-hintdependenciesonrouteClosures,filters,queuejobs,eventlisteners,andmore.Forexamplesofusingtheservicecontainerinthesecontexts,pleaserefertotheirdocumentation.
Thecontainerfiresaneventeachtimeitresolvesanobject.Youmaylistentothiseventusingtheresolvingmethod:
$this->app->resolving(function($object,$app)
{
//Calledwhencontainerresolvesobjectofanytype...
});
$this->app->resolving(function(FooBar$fooBar,$app)
{
//Calledwhencontainerresolvesobjectsoftype"FooBar"...
});
Theobjectbeingresolvedwillbepassedtothecallback.
OtherExamplesOfContainerUsage
ContainerEvents
RegisteringAResolvingListener
IntroductionWhyContracts?ContractReferenceHowToUseContracts
Laravel'sContractsareasetofinterfacesthatdefinethecoreservicesprovidedbytheframework.Forexample,aQueuecontractdefinesthemethodsneededforqueueingjobs,whiletheMailercontractdefinesthemethodsneededforsendinge-mail.
Eachcontracthasacorrespondingimplementationprovidedbytheframework.Forexample,LaravelprovidesaQueueimplementationwithavarietyofdrivers,andaMailerimplementationthatispoweredbySwiftMailer.
AlloftheLaravelcontractsliveintheirownGitHubrepository.Thisprovidesaquickreferencepointforallavailablecontracts,aswellasasingle,decoupledpackagethatmaybeutilizedbyotherpackagedevelopers.
Youmayhaveseveralquestionsregardingcontracts.Whyuseinterfacesatall?Isn'tusinginterfacesmorecomplicated?
Let'sdistillthereasonsforusinginterfacestothefollowingheadings:loosecouplingandsimplicity.
First,let'sreviewsomecodethatistightlycoupledtoacacheimplementation.Considerthefollowing:
<?phpnamespaceApp\Orders;
classRepository{
/**
*Thecache.
*/
protected$cache;
/**
*Createanewrepositoryinstance.
*
*@param\Package\Cache\Memcached$cache
*@returnvoid
*/
publicfunction__construct(\SomePackage\Cache\Memcached$cache)
{
$this->cache=$cache;
}
/**
*RetrieveanOrderbyID.
*
*@paramint$id
*@returnOrder
*/
publicfunctionfind($id)
{
if($this->cache->has($id))
{
//
}
}
Contracts
Introduction
WhyContracts?
LooseCoupling
}
Inthisclass,thecodeistightlycoupledtoagivencacheimplementation.ItistightlycoupledbecausewearedependingonaconcreteCacheclassfromapackagevendor.IftheAPIofthatpackagechangesourcodemustchangeaswell.
Likewise,ifwewanttoreplaceourunderlyingcachetechnology(Memcached)withanothertechnology(Redis),weagainwillhavetomodifyourrepository.Ourrepositoryshouldnothavesomuchknowledgeregardingwhoisprovidingthemdataorhowtheyareprovidingit.
Insteadofthisapproach,wecanimproveourcodebydependingonasimple,vendoragnosticinterface:
<?phpnamespaceApp\Orders;
useIlluminate\Contracts\Cache\RepositoryasCache;
classRepository{
/**
*Createanewrepositoryinstance.
*
*@paramCache$cache
*@returnvoid
*/
publicfunction__construct(Cache$cache)
{
$this->cache=$cache;
}
}
Nowthecodeisnotcoupledtoanyspecificvendor,orevenLaravel.Sincethecontractspackagecontainsnoimplementationandnodependencies,youmayeasilywriteanalternativeimplementationofanygivencontract,allowingyoutoreplaceyourcacheimplementationwithoutmodifyinganyofyourcacheconsumingcode.
WhenallofLaravel'sservicesareneatlydefinedwithinsimpleinterfaces,itisveryeasytodeterminethefunctionalityofferedbyagivenservice.Thecontractsserveassuccinctdocumentationtotheframework'sfeatures.
Inaddition,whenyoudependonsimpleinterfaces,yourcodeiseasiertounderstandandmaintain.Ratherthantrackingdownwhichmethodsareavailabletoyouwithinalarge,complicatedclass,youcanrefertoasimple,cleaninterface.
ThisisareferencetomostLaravelContracts,aswellastheirLaravel"facade"counterparts:
Contract Laravel4.xFacade
Illuminate\Contracts\Auth\Guard Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache::driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encryption\Encrypter Crypt
Simplicity
ContractReference
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Queue\Factory Queue::driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View
So,howdoyougetanimplementationofacontract?It'sactuallyquitesimple.ManytypesofclassesinLaravelareresolvedthroughtheservicecontainer,includingcontrollers,eventlisteners,filters,queuejobs,andevenrouteClosures.So,togetanimplementationofacontract,youcanjust"type-hint"theinterfaceintheconstructoroftheclassbeingresolved.Forexample,takealookatthiseventhandler:
<?phpnamespaceApp\Handlers\Events;
useApp\User;
useApp\Events\NewUserRegistered;
useIlluminate\Contracts\Redis\Database;
classCacheUserInformation{
/**
*TheRedisdatabaseimplementation.
*/
protected$redis;
/**
*Createaneweventhandlerinstance.
*
*@paramDatabase$redis
*@returnvoid
*/
publicfunction__construct(Database$redis)
{
$this->redis=$redis;
HowToUseContracts
}
/**
*Handletheevent.
*
*@paramNewUserRegistered$event
*@returnvoid
*/
publicfunctionhandle(NewUserRegistered$event)
{
//
}
}
Whentheeventlistenerisresolved,theservicecontainerwillreadthetype-hintsontheconstructoroftheclass,andinjecttheappropriatevalue.Tolearnmoreaboutregisteringthingsintheservicecontainer,checkoutthedocumentation.
IntroductionExplanationPracticalUsageCreatingFacadesMockingFacadesFacadeClassReference
Facadesprovidea"static"interfacetoclassesthatareavailableintheapplication'sIoCcontainer.Laravelshipswithmanyfacades,andyouhaveprobablybeenusingthemwithoutevenknowingit!Laravel"facades"serveas"staticproxies"tounderlyingclassesintheIoCcontainer,providingthebenefitofaterse,expressivesyntaxwhilemaintainingmoretestabilityandflexibilitythantraditionalstaticmethods.
Occasionally,Youmaywishtocreateyourownfacadesforyourapplicationsandpackages,solet'sexploretheconcept,developmentandusageoftheseclasses.
Note:Beforediggingintofacades,itisstronglyrecommendedthatyoubecomeveryfamiliarwiththeLaravelIoCcontainer.
InthecontextofaLaravelapplication,afacadeisaclassthatprovidesaccesstoanobjectfromthecontainer.ThemachinerythatmakesthisworkisintheFacadeclass.Laravel'sfacades,andanycustomfacadesyoucreate,willextendthebaseFacadeclass.
Yourfacadeclassonlyneedstoimplementasinglemethod:getFacadeAccessor.It'sthegetFacadeAccessormethod'sjobtodefinewhattoresolvefromthecontainer.TheFacadebaseclassmakesuseofthe__callStatic()magic-methodtodefercallsfromyourfacadetotheresolvedobject.
So,whenyoumakeafacadecalllikeCache::get,LaravelresolvestheCachemanagerclassoutoftheIoCcontainerandcallsthegetmethodontheclass.Intechnicalterms,LaravelFacadesareaconvenientsyntaxforusingtheLaravelIoCcontainerasaservicelocator.
Intheexamplebelow,acallismadetotheLaravelcachesystem.Byglancingatthiscode,onemightassumethatthestaticmethodgetisbeingcalledontheCacheclass.
$value=Cache::get('key');
However,ifwelookatthatIlluminate\Support\Facades\Cacheclass,you'llseethatthereisnostaticmethodget:
classCacheextendsFacade{
/**
*Gettheregisterednameofthecomponent.
*
*@returnstring
*/
protectedstaticfunctiongetFacadeAccessor(){return'cache';}
Facades
Introduction
Explanation
PracticalUsage
}
TheCacheclassextendsthebaseFacadeclassanddefinesamethodgetFacadeAccessor().Remember,thismethod'sjobistoreturnthenameofanIoCbinding.
WhenauserreferencesanystaticmethodontheCachefacade,LaravelresolvesthecachebindingfromtheIoCcontainerandrunstherequestedmethod(inthiscase,get)againstthatobject.
So,ourCache::getcallcouldbere-writtenlikeso:
$value=$app->make('cache')->get('key');
Remember,ifyouareusingafacadewhenacontrollerthatisnamespaced,youwillneedtoimportthefacadeclassintothenamespace.Allfacadesliveintheglobalnamespace:
<?phpnamespaceApp\Http\Controllers;
useCache;
classPhotosControllerextendsController{
/**
*Getalloftheapplicationphotos.
*
*@returnResponse
*/
publicfunctionindex()
{
$photos=Cache::get('photos');
//
}
}
Creatingafacadeforyourownapplicationorpackageissimple.Youonlyneed3things:
AnIoCbinding.Afacadeclass.Afacadealiasconfiguration.
Let'slookatanexample.Here,wehaveaclassdefinedasPaymentGateway\Payment.
namespacePaymentGateway;
classPayment{
publicfunctionprocess()
{
//
}
}
WeneedtobeabletoresolvethisclassfromtheIoCcontainer.So,let'saddabindingtoaserviceprovider:
ImportingFacades
CreatingFacades
App::bind('payment',function()
{
returnnew\PaymentGateway\Payment;
});
AgreatplacetoregisterthisbindingwouldbetocreateanewserviceprovidernamedPaymentServiceProvider,andaddthisbindingtotheregistermethod.YoucanthenconfigureLaraveltoloadyourserviceproviderfromtheconfig/app.phpconfigurationfile.
Next,wecancreateourownfacadeclass:
useIlluminate\Support\Facades\Facade;
classPaymentextendsFacade{
protectedstaticfunctiongetFacadeAccessor(){return'payment';}
}
Finally,ifwewish,wecanaddanaliasforourfacadetothealiasesarrayintheconfig/app.phpconfigurationfile.Now,wecancalltheprocessmethodonaninstanceofthePaymentclass.
Payment::process();
ClassesinthealiasesarrayarenotavailableinsomeinstancesbecausePHPwillnotattempttoautoloadundefinedtype-hintedclasses.If\ServiceWrapper\ApiTimeoutExceptionisaliasedtoApiTimeoutException,acatch(ApiTimeoutException$e)outsideofthenamespace\ServiceWrapperwillnevercatchtheexception,evenifoneisthrown.Asimilarproblemisfoundinclasseswhichhavetypehintstoaliasedclasses.Theonlyworkaroundistoforegoaliasingandusetheclassesyouwishtotypehintatthetopofeachfilewhichrequiresthem.
Unittestingisanimportantaspectofwhyfacadesworkthewaythattheydo.Infact,testabilityistheprimaryreasonforfacadestoevenexist.Formoreinformation,checkoutthemockingfacadessectionofthedocumentation.
Belowyouwillfindeveryfacadeanditsunderlyingclass.ThisisausefultoolforquicklydiggingintotheAPIdocumentationforagivenfacaderoot.TheIoCbindingkeyisalsoincludedwhereapplicable.
Facade Class IoCBinding
App Illuminate\Foundation\Application app
Artisan Illuminate\Console\Application artisan
Auth Illuminate\Auth\AuthManager auth
Auth(Instance) Illuminate\Auth\Guard
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Cache Illuminate\Cache\Repository cache
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
ANoteOnAuto-LoadingAliases
MockingFacades
FacadeClassReference
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB(Instance) Illuminate\Database\Connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Form Illuminate\Html\FormBuilder form
Hash Illuminate\Hashing\HasherInterface hash
HTML Illuminate\Html\HtmlBuilder html
Input Illuminate\Http\Request request
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\Writer log
Mail Illuminate\Mail\Mailer mailer
Paginator Illuminate\Pagination\Factory paginator
Paginator(Instance) Illuminate\Pagination\Paginator
Password Illuminate\Auth\Passwords\PasswordBroker auth.reminder
Queue Illuminate\Queue\QueueManager queue
Queue(Instance) Illuminate\Queue\QueueInterface
Queue(BaseClass) Illuminate\Queue\Queue
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\Database redis
Request Illuminate\Http\Request request
Response Illuminate\Support\Facades\Response
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Blueprint
Session Illuminate\Session\SessionManager session
Session(Instance) Illuminate\Session\Store
SSH Illuminate\Remote\RemoteManager remote
SSH(Instance) Illuminate\Remote\Connection
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator(Instance) Illuminate\Validation\Validator
View Illuminate\View\Factory view
View(Instance) Illuminate\View\View
IntroductionLifecycleOverviewFocusOnServiceProviders
Whenusinganytoolinthe"realworld",youfeelmoreconfidentifyouunderstandhowthattoolworks.Applicationdevelopmentisnodifferent.Whenyouunderstandhowyourdevelopmenttoolsfunction,youfeelmorecomfortableandconfidentusingthem.
Thegoalofthisdocumentistogiveyouagood,high-leveloverviewofhowtheLaravelframework"works".Bygettingtoknowtheoverallframeworkbetter,everythingfeelsless"magical"andyouwillbemoreconfidentbuildingyourapplications.
Ifyoudon'tunderstandallofthetermsrightaway,don'tloseheart!Justtrytogetabasicgraspofwhatisgoingon,andyourknowledgewillgrowasyouexploreothersectionsofthedocumentation.
TheentrypointforallrequeststoaLaravelapplicationisthepublic/index.phpfile.Allrequestsaredirectedtothisfilebyyourwebserver(Apache/Nginx)configuration.Theindex.phpfiledoesn'tcontainmuchcode.Rather,itissimplyastartingpointforloadingtherestoftheframework.
Theindex.phpfileloadstheComposergeneratedautoloaderdefinition,andthenretrievesaninstanceoftheLaravelapplicationfrombootstrap/app.phpscript.ThefirstactiontakenbyLaravelitselfistocreateaninstanceoftheapplication/servicecontainer.
Next,theincomingrequestissenttoeithertheHTTPkernelortheconsolekernel,dependingonthetypeofrequestthatisenteringtheapplication.Thesetwokernelsserveasthecentrallocationthatallrequestsflowthrough.Fornow,let'sjustfocusontheHTTPkernel,whichislocatedinapp/Http/Kernel.php.
TheHTTPkernelextendstheIlluminate\Foundation\Http\Kernelclass,whichdefinesanarrayofbootstrappersthatwillberunbeforetherequestisexecuted.Thesebootstrappersconfigureerrorhandling,configurelogging,detecttheapplicationenvironment,andperformothertasksthatneedtobedonebeforetherequestisactuallyhandled.
TheHTTPkernelalsodefinesalistofHTTPmiddlewarethatallrequestsmustpassthroughbeforebeinghandledbytheapplication.ThesemiddlewarehandlereadingandwritingtheHTTPsession,determineiftheapplicationisinmaintenancemode,verifyingtheCSRFtoken,andmore.
ThemethodsignaturefortheHTTPkernel'shandlemethodisquitesimple:receiveaRequestandreturnaResponse.ThinkoftheKernelasbeingabigblackboxthatrepresentsyourentireapplication.FeeditHTTPrequestsanditwillreturnHTTPresponses.
OneofthemostimportantKernelbootstrappingactionsisloadingtheserviceprovidersforyourapplication.Alloftheserviceprovidersfortheapplicationareconfiguredintheconfig/app.phpconfigurationfile'sprovidersarray.First,theregistermethodwillbecalledonallproviders,then,onceallprovidershavebeenregistered,thebootmethodwillbe
RequestLifecycle
Introduction
LifecycleOverview
FirstThings
HTTP/ConsoleKernels
ServiceProviders
called.
Oncetheapplicationhasbeenbootstrappedandallserviceprovidershavebeenregistered,theRequestwillbehandedofftotherouterfordispatching.Therouterwilldispatchtherequesttoarouteorcontroller,aswellasrunanyroutespecificmiddleware.
ServiceprovidersaretrulythekeytobootstrappingaLaravelapplication.Theapplicationinstanceiscreated,theserviceprovidersareregistered,andtherequestishandedtothebootstrappedapplication.It'sreallythatsimple!
HavingafirmgraspofhowaLaravelapplicationisbuiltandbootstrappedviaserviceprovidersisveryvaluable.Ofcourse,yourapplication'sdefaultserviceprovidersarestoredintheapp/Providersdirectory.
Bydefault,theAppServiceProviderisfairlyempty.Thisproviderisagreatplacetoaddyourapplication'sownbootstrappingandservicecontainerbindings.Ofcourse,forlargeapplications,youmaywishtocreateseveralserviceproviders,eachwithamoregranulartypeofbootstrapping.
DispatchRequest
FocusOnServiceProviders
IntroductionTheRootDirectoryTheAppDirectoryNamespacingYourApplication
ThedefaultLaravelapplicationstructureisintendedtoprovideagreatstartingpointforbothlargeandsmallapplications.Ofcourse,youarefreetoorganizeyourapplicationhoweveryoulike.Laravelimposesalmostnorestrictionsonwhereanygivenclassislocated-aslongasComposercanautoloadtheclass.
TherootdirectoryofafreshLaravelinstallationcontainsavarietyoffolders:
Theappdirectory,asyoumightexpect,containsthecorecodeofyourapplication.We'llexplorethisfolderinmoredetailsoon.
Thebootstrapfoldercontainsafewfilesthatbootstraptheframeworkandconfigureautoloading.
Theconfigdirectory,asthenameimplies,containsallofyourapplication'sconfigurationfiles.
Thedatabasefoldercontainsyourdatabasemigrationandseeds.
Thepublicdirectorycontainsthefrontcontrollerandyourassets(images,JavaScript,CSS,etc.).
Theresourcesdirectorycontainsyourviews,rawassets(LESS,SASS,CoffeeScript),and"language"files.
ThestoragedirectorycontainscompiledBladetemplates,filebasedsessions,filecaches,andotherfilesgeneratedbytheframework.
Thetestsdirectorycontainsyourautomatedtests.
ThevendordirectorycontainsyourComposerdependencies.
The"meat"ofyourapplicationlivesintheappdirectory.Bydefault,thisdirectoryisnamespacedunderAppandisautoloadedbyComposerusingthePSR-4autoloadingstandard.Youmaychangethisnamespaceusingtheapp:nameArtisancommand.
TheappdirectoryshipswithavarietyofadditionaldirectoriessuchasConsole,Http,andProviders.ThinkoftheConsoleandHttpdirectoriesasprovidinganAPIintothe"core"ofyourapplication.TheHTTPprotocolandCLIarebothmechanismstointeractwithyourapplication,butdonotactuallycontainapplicationlogic.Inotherwords,theyaresimplytwowaysofissuingcommandstoyourapplication.TheConsoledirectorycontainsallofyourArtisancommands,whiletheHttpdirectorycontainsyourcontrollers,filters,andrequests.
TheCommandsdirectory,ofcourse,housesthecommandsforyourapplication.Commandsrepresentjobsthatcanbequeuedbyyourapplication,aswellastasksthatyoucanrunsynchronouslywithinthecurrentrequestlifecycle.
TheEventsdirectory,asyoumightexpect,houseseventclasses.Ofcourse,usingclassestorepresenteventsisnot
ApplicationStructure
Introduction
TheRootDirectory
TheAppDirectory
required;however,ifyouchoosetousethem,thisdirectoryisthedefaultlocationtheywillbecreatedbytheArtisancommandline.
TheHandlersdirectorycontainsthehandlerclassesforbothcommandsandevents.Handlersreceiveacommandoreventandperformlogicinresponsetothatcommandoreventbeingfired.
TheServicesdirectorycontainsvarious"helper"servicesyourapplicationneedstofunction.Forexample,theRegistrarserviceincludedwithLaravelisresponsibleforvalidatingandcreatingnewusersofyourapplication.OtherexamplesmightbeservicestointeractwithexternalAPIs,metricssystems,orevenservicesthataggregatedatafromyourownapplication.
TheExceptionsdirectorycontainsyourapplication'sexceptionhandlerandisalsoagoodplacetostickanyexceptionsthrownbyyourapplication.
Note:ManyoftheclassesintheappdirectorycanbegeneratedbyArtisanviacommands.Toreviewtheavailablecommands,runthephpartisanlistmakecommandinyourterminal.
Asdiscussedabove,thedefaultapplicationnamespaceisApp;however,youmaychangethisnamespacetomatchthenameofyourapplication,whichiseasilydoneviatheapp:nameArtisancommand.Forexample,ifyourapplicationisnamed"SocialNet",youwouldrunthefollowingcommand:
phpartisanapp:nameSocialNet
NamespacingYourApplication
AuthenticationIntroductionAuthenticatingUsersRetrievingTheAuthenticatedUserProtectingRoutesHTTPBasicAuthenticationPasswordReminders&ResetSocialAuthentication
BillingIntroductionConfigurationSubscribingToAPlanNoCardUpFrontSwappingSubscriptionsSubscriptionQuantityCancellingASubscriptionResumingASubscriptionCheckingSubscriptionStatusHandlingFailedPaymentsHandlingOtherStripeWebhooksInvoices
CacheConfigurationCacheUsageIncrements&DecrementsCacheTagsDatabaseCache
CollectionsIntroductionBasicUsage
CommandBusIntroductionCreatingCommandsDispatchingCommandsQueuedCommandsCommandPipeline
CoreExtensionManagers&FactoriesCacheSessionAuthenticationIoCBasedExtension
ElixirIntroductionInstallation&SetupUsageGulpExtensions
EncryptionIntroductionBasicUsage
Errors&Logging
Services
ConfigurationHandlingErrorsHTTPExceptionsLogging
EventsBasicUsageQueuedEventHandlersEventSubscribers
Filesystem/CloudStorageIntroductionConfigurationBasicUsage
HashingIntroductionBasicUsage
HelpersArraysPathsStringsURLsMiscellaneous
LocalizationIntroductionLanguageFilesBasicUsagePluralizationValidationLocalizationOverridingPackageLanguageFiles
MailConfigurationBasicUsageEmbeddingInlineAttachmentsQueueingMailMail&LocalDevelopment
PackageDevelopmentIntroductionViewsTranslationsConfigurationPublishingFileGroupsRouting
PaginationConfigurationUsageAppendingToPaginationLinksConvertingToJSON
QueuesConfigurationBasicUsageQueueingClosuresRunningTheQueueListenerDaemonQueueWorkerPushQueuesFailedJobs
SessionConfiguration
SessionUsageFlashDataDatabaseSessionsSessionDrivers
TemplatesBladeTemplatingOtherBladeControlStructuresExtendingBlade
UnitTestingIntroductionDefining&RunningTestsTestEnvironmentCallingRoutesFromTestsMockingFacadesFrameworkAssertionsHelperMethodsRefreshingTheApplication
ValidationBasicUsageControllerValidationFormRequestValidationWorkingWithErrorMessagesErrorMessages&ViewsAvailableValidationRulesConditionallyAddingRulesCustomErrorMessagesCustomValidationRules
IntroductionAuthenticatingUsersRetrievingTheAuthenticatedUserProtectingRoutesHTTPBasicAuthenticationPasswordReminders&ResetSocialAuthentication
Laravelmakesimplementingauthenticationverysimple.Infact,almosteverythingisconfiguredforyououtofthebox.Theauthenticationconfigurationfileislocatedatconfig/auth.php,whichcontainsseveralwelldocumentedoptionsfortweakingthebehavioroftheauthenticationservices.
Bydefault,LaravelincludesanApp\Usermodelinyourappdirectory.ThismodelmaybeusedwiththedefaultEloquentauthenticationdriver.
Remember:whenbuildingthedatabaseschemaforthismodel,makethepasswordcolumnatleast60characters.Also,beforegettingstarted,makesurethatyourusers(orequivalent)tablecontainsanullable,stringremember_tokencolumnof100characters.Thiscolumnwillbeusedtostoreatokenfor"rememberme"sessionsbeingmaintainedbyyourapplication.Thiscanbedonebyusing$table->rememberToken();inamigration.Ofcourse,Laravel5shipsmigrationsforthesecolumnsoutofthebox!
IfyourapplicationisnotusingEloquent,youmayusethedatabaseauthenticationdriverwhichusestheLaravelquerybuilder.
Laravelshipswithtwoauthenticationrelatedcontrollersoutofthebox.TheAuthControllerhandlesnewuserregistrationand"loggingin",whilethePasswordControllercontainsthelogictohelpexistingusersresettheirforgottenpasswords.
Eachofthesecontrollersusesatraittoincludetheirnecessarymethods.Formanyapplications,youwillnotneedtomodifythesecontrollersatall.Theviewsthatthesecontrollersrenderarelocatedintheresources/views/authdirectory.Youarefreetocustomizetheseviewshoweveryouwish.
Tomodifytheformfieldsthatarerequiredwhenanewuserregisterswithyourapplication,youmaymodifytheApp\Services\Registrarclass.Thisclassisresponsibleforvalidatingandcreatingnewusersofyourapplication.
ThevalidatormethodoftheRegistrarcontainsthevalidationrulesfornewusersoftheapplication,whilethecreatemethodoftheRegistrarisresponsibleforcreatingnewUserrecordsinyourdatabase.Youarefreetomodifyeachofthesemethodsasyouwish.TheRegistrariscalledbytheAuthControllerviathemethodscontainedintheAuthenticatesAndRegistersUserstrait.
IfyouchoosenottousetheprovidedAuthControllerimplementation,youwillneedtomanagetheauthenticationofyourusersusingtheLaravelauthenticationclassesdirectly.Don'tworry,it'sstillacinch!First,let'scheckouttheattemptmethod:
Authentication
Introduction
AuthenticatingUsers
TheUserRegistrar
ManualAuthentication
<?phpnamespaceApp\Http\Controllers;
useAuth;
useIlluminate\Routing\Controller;
classAuthControllerextendsController{
/**
*Handleanauthenticationattempt.
*
*@returnResponse
*/
publicfunctionauthenticate()
{
if(Auth::attempt(['email'=>$email,'password'=>$password]))
{
returnredirect()->intended('dashboard');
}
}
}
Theattemptmethodacceptsanarrayofkey/valuepairsasitsfirstargument.Thepasswordvaluewillbehashed.Theothervaluesinthearraywillbeusedtofindtheuserinyourdatabasetable.So,intheexampleabove,theuserwillberetrievedbythevalueoftheemailcolumn.Iftheuserisfound,thehashedpasswordstoredinthedatabasewillbecomparedwiththehashedpasswordvaluepassedtothemethodviathearray.Ifthetwohashedpasswordsmatch,anewauthenticatedsessionwillbestartedfortheuser.
Theattemptmethodwillreturntrueifauthenticationwassuccessful.Otherwise,falsewillbereturned.
Note:Inthisexample,emailisnotarequiredoption,itismerelyusedasanexample.Youshouldusewhatevercolumnnamecorrespondstoa"username"inyourdatabase.
TheintendedredirectfunctionwillredirecttheusertotheURLtheywereattemptingtoaccessbeforebeingcaughtbytheauthenticationfilter.AfallbackURImaybegiventothismethodincasetheintendeddestinationisnotavailable.
Youalsomayaddextraconditionstotheauthenticationquery:
if(Auth::attempt(['email'=>$email,'password'=>$password,'active'=>1]))
{
//Theuserisactive,notsuspended,andexists.
}
Todetermineiftheuserisalreadyloggedintoyourapplication,youmayusethecheckmethod:
if(Auth::check())
{
//Theuserisloggedin...
}
Ifyouwouldliketoprovide"rememberme"functionalityinyourapplication,youmaypassabooleanvalueasthesecondargumenttotheattemptmethod,whichwillkeeptheuserauthenticatedindefinitely,oruntiltheymanuallylogout.Ofcourse,youruserstablemustincludethestringremember_tokencolumn,whichwillbeusedtostorethe"rememberme"token.
if(Auth::attempt(['email'=>$email,'password'=>$password],$remember))
AuthenticatingAUserWithConditions
DeterminingIfAUserIsAuthenticated
AuthenticatingAUserAnd"Remembering"Them
{
//Theuserisbeingremembered...
}
Ifyouare"remembering"users,youmayusetheviaRemembermethodtodetermineiftheuserwasauthenticatedusingthe"rememberme"cookie:
if(Auth::viaRemember())
{
//
}
TologauserintotheapplicationbytheirID,usetheloginUsingIdmethod:
Auth::loginUsingId(1);
Thevalidatemethodallowsyoutovalidateauser'scredentialswithoutactuallyloggingthemintotheapplication:
if(Auth::validate($credentials))
{
//
}
Youmayalsousetheoncemethodtologauserintotheapplicationforasinglerequest.Nosessionsorcookieswillbeutilized:
if(Auth::once($credentials))
{
//
}
Ifyouneedtologanexistinguserinstanceintoyourapplication,youmaycalltheloginmethodwiththeuserinstance:
Auth::login($user);
Thisisequivalenttologginginauserviacredentialsusingtheattemptmethod.
Auth::logout();
Ofcourse,ifyouareusingthebuilt-inLaravelauthenticationcontrollers,acontrollermethodthathandlesloggingusersoutoftheapplicationisprovidedoutofthebox.
AuthenticatingUsersByID
ValidatingUserCredentialsWithoutLogin
LoggingAUserInForASingleRequest
ManuallyLoggingInAUser
LoggingAUserOutOfTheApplication
Whentheattemptmethodiscalled,theauth.attempteventwillbefired.Iftheauthenticationattemptissuccessfulandtheuserisloggedin,theauth.logineventwillbefiredaswell.
Onceauserisauthenticated,thereareseveralwaystoobtainaninstanceoftheUser.
First,youmayaccesstheuserfromtheAuthfacade:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Routing\Controller;
classProfileControllerextendsController{
/**
*Updatetheuser'sprofile.
*
*@returnResponse
*/
publicfunctionupdateProfile()
{
if(Auth::user())
{
//Auth::user()returnsaninstanceoftheauthenticateduser...
}
}
}
Second,youmayaccesstheauthenticateduserviaanIlluminate\Http\Requestinstance:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Http\Request;
useIlluminate\Routing\Controller;
classProfileControllerextendsController{
/**
*Updatetheuser'sprofile.
*
*@returnResponse
*/
publicfunctionupdateProfile(Request$request)
{
if($request->user())
{
//$request->user()returnsaninstanceoftheauthenticateduser...
}
}
}
Thirdly,youmaytype-hinttheIlluminate\Contracts\Auth\Authenticatablecontract.Thistype-hintmaybeaddedtoacontrollerconstructor,controllermethod,oranyotherconstructorofaclassresolvedbytheservicecontainer:
<?phpnamespaceApp\Http\Controllers;
useIlluminate\Routing\Controller;
useIlluminate\Contracts\Auth\Authenticatable;
classProfileControllerextendsController{
/**
*Updatetheuser'sprofile.
AuthenticationEvents
RetrievingTheAuthenticatedUser
*
*@returnResponse
*/
publicfunctionupdateProfile(Authenticatable$user)
{
//$userisaninstanceoftheauthenticateduser...
}
}
Routemiddlewarecanbeusedtoallowonlyauthenticateduserstoaccessagivenroute.Laravelprovidestheauthmiddlewarebydefault,anditisdefinedinapp\Http\Middleware\Authenticate.php.Allyouneedtodoisattachittoaroutedefinition:
//WithARouteClosure...
Route::get('profile',['middleware'=>'auth',function()
{
//Onlyauthenticatedusersmayenter...
}]);
//WithAController...
Route::get('profile',['middleware'=>'auth','uses'=>'ProfileController@show']);
HTTPBasicAuthenticationprovidesaquickwaytoauthenticateusersofyourapplicationwithoutsettingupadedicated"login"page.Togetstarted,attachtheauth.basicmiddlewaretoyourroute:
Route::get('profile',['middleware'=>'auth.basic',function()
{
//Onlyauthenticatedusersmayenter...
}]);
Bydefault,thebasicmiddlewarewillusetheemailcolumnontheuserrecordasthe"username".
YoumayalsouseHTTPBasicAuthenticationwithoutsettingauseridentifiercookieinthesession,whichisparticularlyusefulforAPIauthentication.Todoso,defineamiddlewarethatcallstheonceBasicmethod:
publicfunctionhandle($request,Closure$next)
{
returnAuth::onceBasic()?:$next($request);
}
IfyouareusingPHPFastCGI,HTTPBasicauthenticationmaynotworkcorrectlyoutofthebox.Thefollowinglinesshouldbeaddedtoyour.htaccessfile:
RewriteCond%{HTTP:Authorization}^(.+)$
RewriteRule.*-[E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
ProtectingRoutes
HTTPBasicAuthentication
ProtectingARouteWithHTTPBasic
SettingUpAStatelessHTTPBasicFilter
Mostwebapplicationsprovideawayforuserstoresettheirforgottenpasswords.Ratherthanforcingyoutore-implementthisoneachapplication,Laravelprovidesconvenientmethodsforsendingpasswordremindersandperformingpasswordresets.
Togetstarted,verifythatyourUsermodelimplementstheIlluminate\Contracts\Auth\CanResetPasswordcontract.Ofcourse,theUsermodelincludedwiththeframeworkalreadyimplementsthisinterface,andusestheIlluminate\Auth\Passwords\CanResetPasswordtraittoincludethemethodsneededtoimplementtheinterface.
Next,atablemustbecreatedtostorethepasswordresettokens.ThemigrationforthistableisincludedwithLaraveloutofthebox,andresidesinthedatabase/migrationsdirectory.Soallyouneedtodoismigrate:
phpartisanmigrate
LaravelalsoincludesanAuth\PasswordControllerthatcontainsthelogicnecessarytoresetuserpasswords.We'veevenprovidedviewstogetyoustarted!Theviewsarelocatedintheresources/views/authdirectory.Youarefreetomodifytheseviewsasyouwishtosuityourownapplication'sdesign.
Youruserwillreceiveane-mailwithalinkthatpointstothegetResetmethodofthePasswordController.Thismethodwillrenderthepasswordresetformandallowuserstoresettheirpasswords.Afterthepasswordisreset,theuserwillautomaticallybeloggedintotheapplicationandredirectedto/home.Youcancustomizethepost-resetredirectlocationbydefiningaredirectTopropertyonthePasswordController:
protected$redirectTo='/dashboard';
Note:Bydefault,passwordresettokensexpireafteronehour.Youmaychangethisviathereminder.expireoptionofyourconfig/auth.phpfile.
Inadditiontotypical,formbasedauthentication,Laravelalsoprovidesasimple,convenientwaytoauthenticatewithOAuthprovidersusingLaravelSocialite.SocialitecurrentlysupportsauthenticationwithFacebook,Twitter,Google,andGitHub.
TogetstartedwithSocialite,includethepackageinyourcomposer.jsonfile:
"laravel/socialite":"~2.0"
Next,registertheLaravel\Socialite\SocialiteServiceProviderinyourconfig/app.phpconfigurationfile.Youmayalsoregisterafacade:
'Socialize'=>'Laravel\Socialite\Facades\Socialite',
PasswordReminders&Reset
Model&Table
GeneratingTheReminderTableMigration
PasswordReminderController
SocialAuthentication
YouwillneedtoaddcredentialsfortheOAuthservicesyourapplicationutilizes.Thesecredentialsshouldbeplacedinyourconfig/services.phpconfigurationfile,andshouldusethekeyfacebook,twitter,google,orgithub,dependingontheprovidersyourapplicationrequires.Forexample:
'github'=>[
'client_id'=>'your-github-app-id',
'client_secret'=>'your-github-app-secret',
'redirect'=>'http://your-callback-url',
],
Next,youarereadytoauthenticateusers!Youwillneedtworoutes:oneforredirectingtheusertotheOAuthprovider,andanotherforreceivingthecallbackfromtheproviderafterauthentication.Here'sanexampleusingtheSocializefacade:
publicfunctionredirectToProvider()
{
returnSocialize::with('github')->redirect();
}
publicfunctionhandleProviderCallback()
{
$user=Socialize::with('github')->user();
//$user->token;
}
TheredirectmethodtakescareofsendingtheusertotheOAuthprovider,whiletheusermethodwillreadtheincomingrequestandretrievetheuser'sinformationfromtheprovider.Beforeredirectingtheuser,youmayalsoset"scopes"ontherequest:
returnSocialize::with('github')->scopes(['scope1','scope2'])->redirect();
Onceyouhaveauserinstance,youcangrabafewmoredetailsabouttheuser:
$user=Socialize::with('github')->user();
//OAuthTwoProviders
$token=$user->token;
//OAuthOneProviders
$token=$user->token;
$tokenSecret=$user->tokenSecret;
//AllProviders
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
RetrievingUserDetails
IntroductionConfigurationSubscribingToAPlanNoCardUpFrontSwappingSubscriptionsSubscriptionQuantityCancellingASubscriptionResumingASubscriptionCheckingSubscriptionStatusHandlingFailedPaymentsHandlingOtherStripeWebhooksInvoices
LaravelCashierprovidesanexpressive,fluentinterfacetoStripe'ssubscriptionbillingservices.Ithandlesalmostalloftheboilerplatesubscriptionbillingcodeyouaredreadingwriting.Inadditiontobasicsubscriptionmanagement,Cashiercanhandlecoupons,swappingsubscription,subscription"quantities",cancellationgraceperiods,andevengenerateinvoicePDFs.
First,addtheCashierpackagetoyourcomposer.jsonfile:
"laravel/cashier":"~3.0"
Next,registertheLaravel\Cashier\CashierServiceProviderinyourappconfigurationfile.
BeforeusingCashier,we'llneedtoaddseveralcolumnstoyourdatabase.Don'tworry,youcanusethecashier:tableArtisancommandtocreateamigrationtoaddthenecessarycolumn.Forexample,toaddthecolumntotheuserstableusephpartisancashier:tableusers.Oncethemigrationhasbeencreated,simplyrunthemigratecommand.
Next,addtheBillabletraitandappropriatedatemutatorstoyourmodeldefinition:
useLaravel\Cashier\Billable;
useLaravel\Cashier\Contracts\BillableasBillableContract;
classUserextendsEloquentimplementsBillableContract{
useBillable;
protected$dates=['trial_ends_at','subscription_ends_at'];
}
LaravelCashier
Introduction
Configuration
Composer
ServiceProvider
Migration
ModelSetup
Finally,setyourStripekeyinoneofyourbootstrapfilesorserviceproviders,suchastheAppServiceProvider:
User::setStripeKey('stripe-key');
Onceyouhaveamodelinstance,youcaneasilysubscribethatusertoagivenStripeplan:
$user=User::find(1);
$user->subscription('monthly')->create($creditCardToken);
Ifyouwouldliketoapplyacouponwhencreatingthesubscription,youmayusethewithCouponmethod:
$user->subscription('monthly')
->withCoupon('code')
->create($creditCardToken);
ThesubscriptionmethodwillautomaticallycreatetheStripesubscription,aswellasupdateyourdatabasewithStripecustomerIDandotherrelevantbillinginformation.IfyourplanhasatrialconfiguredinStripe,thetrialenddatewillalsoautomaticallybesetontheuserrecord.
IfyourplanhasatrialperiodthatisnotconfiguredinStripe,youmustsetthetrialenddatemanuallyaftersubscribing:
$user->trial_ends_at=Carbon::now()->addDays(14);
$user->save();
Ifyouwouldliketospecifyadditionalcustomerdetails,youmaydosobypassingthemassecondargumenttothecreatemethod:
$user->subscription('monthly')->create($creditCardToken,[
'email'=>$email,'description'=>'OurFirstCustomer'
]);
TolearnmoreabouttheadditionalfieldssupportedbyStripe,checkoutStripe'sdocumentationoncustomercreation.
Ifyourapplicationoffersafree-trialwithnocredit-cardupfront,setthecardUpFrontpropertyonyourmodeltofalse:
protected$cardUpFront=false;
Onaccountcreation,besuretosetthetrialenddateonthemodel:
StripeKey
SubscribingToAPlan
SpecifyingAdditionalUserDetails
NoCardUpFront
$user->trial_ends_at=Carbon::now()->addDays(14);
$user->save();
Toswapausertoanewsubscription,usetheswapmethod:
$user->subscription('premium')->swap();
Iftheuserisontrial,thetrialwillbemaintainedasnormal.Also,ifa"quantity"existsforthesubscription,thatquantitywillalsobemaintained.
Sometimessubscriptionsareaffectedby"quantity".Forexample,yourapplicationmightcharge$10permonthperuseronanaccount.Toeasilyincrementordecrementyoursubscriptionquantity,usetheincrementanddecrementmethods:
$user=User::find(1);
$user->subscription()->increment();
//Addfivetothesubscription'scurrentquantity...
$user->subscription()->increment(5);
$user->subscription->decrement();
//Subtractfivetothesubscription'scurrentquantity...
$user->subscription()->decrement(5);
Cancellingasubscriptionisawalkinthepark:
$user->subscription()->cancel();
Whenasubscriptioniscancelled,Cashierwillautomaticallysetthesubscription_ends_atcolumnonyourdatabase.Thiscolumnisusedtoknowwhenthesubscribedmethodshouldbeginreturningfalse.Forexample,ifacustomercancelsasubscriptiononMarch1st,butthesubscriptionwasnotscheduledtoenduntilMarch5th,thesubscribedmethodwillcontinuetoreturntrueuntilMarch5th.
Ifauserhascancelledtheirsubscriptionandyouwishtoresumeit,usetheresumemethod:
$user->subscription('monthly')->resume($creditCardToken);
Iftheusercancelsasubscriptionandthenresumesthatsubscriptionbeforethesubscriptionhasfullyexpired,theywillnotbebilledimmediately.Theirsubscriptionwillsimplybere-activated,andtheywillbebilledontheoriginalbillingcycle.
SwappingSubscriptions
SubscriptionQuantity
CancellingASubscription
ResumingASubscription
CheckingSubscriptionStatus
Toverifythatauserissubscribedtoyourapplication,usethesubscribedcommand:
if($user->subscribed())
{
//
}
Thesubscribedmethodmakesagreatcandidateforaroutemiddleware:
publicfunctionhandle($request,Closure$next)
{
if($request->user()&&!$request->user()->subscribed())
{
returnredirect('billing');
}
return$next($request);
}
Youmayalsodetermineiftheuserisstillwithintheirtrialperiod(ifapplicable)usingtheonTrialmethod:
if($user->onTrial())
{
//
}
Todetermineiftheuserwasonceanactivesubscriber,buthascancelledtheirsubscription,youmayusethecancelledmethod:
if($user->cancelled())
{
//
}
Youmayalsodetermineifauserhascancelledtheirsubscription,butarestillontheir"graceperiod"untilthesubscriptionfullyexpires.Forexample,ifausercancelsasubscriptiononMarch5ththatwasscheduledtoendonMarch10th,theuserisontheir"graceperiod"untilMarch10th.Notethatthesubscribedmethodstillreturnstrueduringthistime.
if($user->onGracePeriod())
{
//
}
TheeverSubscribedmethodmaybeusedtodetermineiftheuserhaseversubscribedtoaplaninyourapplication:
if($user->everSubscribed())
{
//
}
TheonPlanmethodmaybeusedtodetermineiftheuserissubscribedtoagivenplanbasedonitsID:
if($user->onPlan('monthly'))
{
//
}
Whatifacustomer'screditcardexpires?Noworries-CashierincludesaWebhookcontrollerthatcaneasilycancelthecustomer'ssubscriptionforyou.Justpointaroutetothecontroller:
Route::post('stripe/webhook','Laravel\Cashier\WebhookController@handleWebhook');
That'sit!Failedpaymentswillbecapturedandhandledbythecontroller.Thecontrollerwillcancelthecustomer'ssubscriptionafterthreefailedpaymentattempts.Thestripe/webhookURIinthisexampleisjustforexample.YouwillneedtoconfiguretheURIinyourStripesettings.
IfyouhaveadditionalStripewebhookeventsyouwouldliketohandle,simplyextendtheWebhookcontroller.YourmethodnamesshouldcorrespondtoCashier'sexpectedconvention,specifically,methodsshouldbeprefixedwithhandleandthenameoftheStripewebhookyouwishtohandle.Forexample,ifyouwishtohandletheinvoice.payment_succeededwebhook,youshouldaddahandleInvoicePaymentSucceededmethodtothecontroller.
classWebhookControllerextendsLaravel\Cashier\WebhookController{
publicfunctionhandleInvoicePaymentSucceeded($payload)
{
//HandleTheEvent
}
}
Note:Inadditiontoupdatingthesubscriptioninformationinyourdatabase,theWebhookcontrollerwillalsocancelthesubscriptionviatheStripeAPI.
Youcaneasilyretrieveanarrayofauser'sinvoicesusingtheinvoicesmethod:
$invoices=$user->invoices();
Whenlistingtheinvoicesforthecustomer,youmayusethesehelpermethodstodisplaytherelevantinvoiceinformation:
{{$invoice->id}}
{{$invoice->dateString()}}
{{$invoice->dollars()}}
UsethedownloadInvoicemethodtogenerateaPDFdownloadoftheinvoice.Yes,it'sreallythiseasy:
return$user->downloadInvoice($invoice->id,[
'vendor'=>'YourCompany',
'product'=>'YourProduct',
]);
HandlingFailedPayments
HandlingOtherStripeWebhooks
Invoices
ConfigurationCacheUsageIncrements&DecrementsCacheTagsDatabaseCache
LaravelprovidesaunifiedAPIforvariouscachingsystems.Thecacheconfigurationislocatedatconfig/cache.php.Inthisfileyoumayspecifywhichcachedriveryouwouldlikeusedbydefaultthroughoutyourapplication.LaravelsupportspopularcachingbackendslikeMemcachedandRedisoutofthebox.
Thecacheconfigurationfilealsocontainsvariousotheroptions,whicharedocumentedwithinthefile,somakesuretoreadovertheseoptions.Bydefault,Laravelisconfiguredtousethefilecachedriver,whichstorestheserialized,cachedobjectsinthefilesystem.Forlargerapplications,itisrecommendedthatyouuseanin-memorycachesuchasMemcachedorAPC.Youmayevenconfiguremultiplecacheconfigurationsforthesamedriver.
BeforeusingaRediscachewithLaravel,youwillneedtoinstallthepredis/predispackage(~1.0)viaComposer.
Cache::put('key','value',$minutes);
$expiresAt=Carbon::now()->addMinutes(10);
Cache::put('key','value',$expiresAt);
Cache::add('key','value',$minutes);
Theaddmethodwillreturntrueiftheitemisactuallyaddedtothecache.Otherwise,themethodwillreturnfalse.
if(Cache::has('key'))
{
//
}
Cache
Configuration
CacheUsage
StoringAnItemInTheCache
UsingCarbonObjectsToSetExpireTime
StoringAnItemInTheCacheIfItDoesn'tExist
CheckingForExistenceInCache
RetrievingAnItemFromTheCache
$value=Cache::get('key');
$value=Cache::get('key','default');
$value=Cache::get('key',function(){return'default';});
Cache::forever('key','value');
Sometimesyoumaywishtoretrieveanitemfromthecache,butalsostoreadefaultvalueiftherequesteditemdoesn'texist.YoumaydothisusingtheCache::remembermethod:
$value=Cache::remember('users',$minutes,function()
{
returnDB::table('users')->get();
});
Youmayalsocombinetherememberandforevermethods:
$value=Cache::rememberForever('users',function()
{
returnDB::table('users')->get();
});
Notethatallitemsstoredinthecacheareserialized,soyouarefreetostoreanytypeofdata.
Ifyouneedtoretrieveanitemfromthecacheandthendeleteit,youmayusethepullmethod:
$value=Cache::pull('key');
Cache::forget('key');
Alldriversexceptfileanddatabasesupporttheincrementanddecrementoperations:
Cache::increment('key');
Cache::increment('key',$amount);
RetrievingAnItemOrReturningADefaultValue
StoringAnItemInTheCachePermanently
PullingAnItemFromTheCache
RemovingAnItemFromTheCache
Increments&Decrements
IncrementingAValue
Cache::decrement('key');
Cache::decrement('key',$amount);
Note:Cachetagsarenotsupportedwhenusingthefileordatabasecachedrivers.Furthermore,whenusingmultipletagswithcachesthatarestored"forever",performancewillbebestwithadriversuchasmemcached,whichautomaticallypurgesstalerecords.
Cachetagsallowyoutotagrelateditemsinthecache,andthenflushallcachestaggedwithagivenname.Toaccessataggedcache,usethetagsmethod.
Youmaystoreataggedcachebypassinginanorderedlistoftagnamesasarguments,orasanorderedarrayoftagnames:
Cache::tags('people','authors')->put('John',$john,$minutes);
Cache::tags(array('people','artists'))->put('Anne',$anne,$minutes);
Youmayuseanycachestoragemethodincombinationwithtags,includingremember,forever,andrememberForever.Youmayalsoaccesscacheditemsfromthetaggedcache,aswellasusetheothercachemethodssuchasincrementanddecrement.
Toaccessataggedcache,passthesameorderedlistoftagsusedtosaveit.
$anne=Cache::tags('people','artists')->get('Anne');
$john=Cache::tags(array('people','authors'))->get('John');
Youmayflushallitemstaggedwithanameorlistofnames.Forexample,thisstatementwouldremoveallcachestaggedwitheitherpeople,authors,orboth.So,both"Anne"and"John"wouldberemovedfromthecache:
Cache::tags('people','authors')->flush();
Incontrast,thisstatementwouldremoveonlycachestaggedwithauthors,so"John"wouldberemoved,butnot"Anne".
Cache::tags('authors')->flush();
Whenusingthedatabasecachedriver,youwillneedtosetupatabletocontainthecacheitems.You'llfindanexampleSchemadeclarationforthetablebelow:
DecrementingAValue
CacheTags
AccessingATaggedCache
AccessingItemsInATaggedCache
DatabaseCache
Schema::create('cache',function($table)
{
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
IntroductionBasicUsage
TheIlluminate\Support\Collectionclassprovidesafluent,convenientwrapperforworkingwitharraysofdata.Forexample,checkoutthefollowingcode.We'llusethecollecthelpertocreateanewcollectioninstancefromthearray:
$collection=collect(['taylor','abigail',null])->map(function($name)
{
returnstrtoupper($name);
})
->reject(function($name)
{
returnis_null($value);
});
Asyoucansee,theCollectionclassallowsyoutochainitsmethodstoperformfluentmappingandreducingoftheunderlyingarray.Ingeneral,everyCollectionmethodreturnsanentirelynewCollectioninstance.Todiginfurther,keepreading!
Asmentionedabove,thecollecthelperwillreturnanewIlluminate\Support\Collectioninstanceforthegivenarray.YoumayalsousethemakecommandontheCollectionclass:
$collection=collect([1,2,3]);
$collection=Collection::make([1,2,3]);
Ofcourse,collectionsofEloquentobjectsarealwaysreturnedasCollectioninstances;however,youshouldfeelfreetousetheCollectionclasswhereveritisconvenientforyourapplication.
Insteadoflistingallofthemethods(therearealot)theCollectionmakesavailable,checkouttheAPIdocumentationfortheclass!
Collections
Introduction
BasicUsage
CreatingCollections
ExploreTheCollection
IntroductionCreatingCommandsDispatchingCommandsQueuedCommandsCommandPipeline
TheLaravelcommandbusprovidesaconvenientmethodofencapsulatingtasksyourapplicationneedstoperformintosimple,easytounderstand"commands".Tohelpusunderstandthepurposeofcommands,let'spretendwearebuildinganapplicationthatallowsuserstopurchasepodcasts.
Whenauserpurchasesapodcast,thereareavarietyofthingsthatneedtohappen.Forexample,wemayneedtochargetheuser'screditcard,addarecordtoourdatabasethatrepresentsthepurchase,andsendaconfirmatione-mailofthepurchase.Perhapswealsoneedtoperformsomekindofvalidationastowhethertheuserisallowedtopurchasepodcasts.
Wecouldputallofthislogicinsideacontrollermethod;however,thishasseveraldisadvantages.ThefirstdisadvantageisthatourcontrollerprobablyhandlesseveralotherincomingHTTPactions,andincludingcomplicatedlogicineachcontrollermethodwillsoonbloatourcontrollerandmakeithardertoread.Secondly,itisdifficulttore-usethepurchasepodcastlogicoutsideofthecontrollercontext.Thirdly,itismoredifficulttounit-testthecommandaswemustalsogenerateastubHTTPrequestandmakeafullrequesttotheapplicationtotestthepurchasepodcastlogic.
Insteadofputtingthislogicinthecontroller,wemaychoosetoencapsulateitwithina"command"object,suchasaPurchasePodcastcommand.
TheArtisanCLIcangeneratenewcommandclassesusingthemake:commandcommand:
phpartisanmake:commandPurchasePodcast
Thenewlygeneratedclasswillbeplacedintheapp/Commandsdirectory.Bydefault,thecommandcontainstwomethods:theconstructorandthehandlemethod.Ofcourse,theconstructorallowsyoutopassanyrelevantobjectstothecommand,whilethehandlemethodexecutesthecommand.Forexample:
classPurchasePodcastextendsCommandimplementsSelfHandling{
protected$user,$podcast;
/**
*Createanewcommandinstance.
*
*@returnvoid
*/
publicfunction__construct(User$user,Podcast$podcast)
{
$this->user=$user;
$this->podcast=$podcast;
}
/**
*Executethecommand.
*
*@returnvoid
CommandBus
Introduction
CreatingCommands
*/
publicfunctionhandle()
{
//Handlethelogictopurchasethepodcast...
event(newPodcastWasPurchased($this->user,$this->podcast));
}
}
Thehandlemethodmayalsotype-hintdependencies,andtheywillbeautomaticallyinjectedbytheIoCcontainer.Forexample:
/**
*Executethecommand.
*
*@returnvoid
*/
publicfunctionhandle(BillingGateway$billing)
{
//Handlethelogictopurchasethepodcast...
}
So,oncewehavecreatedacommand,howdowedispatchit?Ofcourse,wecouldcallthehandlemethoddirectly;however,dispatchingthecommandthroughtheLaravel"commandbus"hasseveraladvantageswhichwewilldiscusslater.
Ifyouglanceatyourapplication'sbasecontroller,youwillseetheDispatchesCommandstrait.Thistraitallowsustocallthedispatchmethodfromanyofourcontrollers.Forexample:
publicfunctionpurchasePodcast($podcastId)
{
$this->dispatch(
newPurchasePodcast(Auth::user(),Podcast::findOrFail($podcastId))
);
}
ThecommandbuswilltakecareofexecutingthecommandandcallingtheIoCcontainertoinjectanyneededdependenciesintothehandlemethod.
YoumayaddtheIlluminate\Foundation\Bus\DispatchesCommandstraittoanyclassyouwish.Ifyouwouldliketoreceiveacommandbusinstancethroughtheconstructorofanyofyourclasses,youmaytype-hinttheIlluminate\Contracts\Bus\Dispatcherinterface.Finally,youmayalsousetheBusfacadetoquicklydispatchcommands:
Bus::dispatch(
newPurchasePodcast(Auth::user(),Podcast::findOrFail($podcastId))
);
ItisverycommontomapHTTPrequestvariablesintocommands.So,insteadofforcingyoutodothismanuallyforeachrequest,Laravelprovidessomehelpermethodstomakeitacinch.Let'stakealookatthedispatchFrommethodavailableontheDispatchesCommandstrait:
$this->dispatchFrom('Command\Class\Name',$request);
DispatchingCommands
MappingCommandPropertiesFromRequests
Thismethodwillexaminetheconstructorofthecommandclassitisgiven,andthenextractvariablesfromtheHTTPrequest(oranyotherArrayAccessobject)tofilltheneededconstructorparametersofthecommand.So,ifourcommandclassacceptsafirstNamevariableinitsconstructor,thecommandbuswillattempttopullthefirstNameparameterfromtheHTTPrequest.
YoumayalsopassanarrayasthethirdargumenttothedispatchFrommethod.Thisarraywillbeusedtofillanyconstructorparametersthatarenotavailableontherequest:
$this->dispatchFrom('Command\Class\Name',$request,[
'firstName'=>'Taylor',
]);
Thecommandbusisnotjustforsynchronousjobsthatrunduringthecurrentrequestcycle,butalsoservesastheprimarywaytobuildqueuedjobsinLaravel.So,howdoweinstructcommandbustoqueueourjobforbackgroundprocessinginsteadofrunningitsynchronously?It'seasy.Firstly,whengeneratinganewcommand,justaddthe--queuedflagtothecommand:
phpartisanmake:commandPurchasePodcast--queued
Asyouwillsee,thisaddsafewmorefeaturestothecommand,namelytheIlluminate\Contracts\Queue\ShouldBeQueuedinterfaceandtheSerializesModelstrait.Theseinstructthecommandbustoqueuethecommand,aswellasgracefullyserializeanddeserializeanyEloquentmodelsyourcommandstoresasproperties.
Ifyouwouldliketoconvertanexistingcommandintoaqueuedcommand,simplyimplementtheIlluminate\Contracts\Queue\ShouldBeQueuedinterfaceontheclassmanually.Itcontainsnomethods,andmerelyservesasa"markerinterface"forthedispatcher.
Then,justwriteyourcommandnormally.Whenyoudispatchittothebusthatbuswillautomaticallyqueuethecommandforbackgroundprocessing.Itdoesn'tgetanyeasierthanthat.
Formoreinformationoninteractingwithqueuedcommands,viewthefullqueuedocumentation.
Beforeacommandisdispatchedtoahandler,youmaypassitthroughotherclassesina"pipeline".CommandpipesworkjustlikeHTTPmiddleware,exceptforyourcommands!Forexample,acommandpipecouldwraptheentirecommandoperationwithinadatabasetransaction,orsimplylogitsexecution.
Toaddapipetoyourbus,callthepipeThroughmethodofthedispatcherfromyourApp\Providers\BusServiceProvider::bootmethod:
$dispatcher->pipeThrough(['UseDatabaseTransactions','LogCommand']);
Acommandpipeisdefinedwithahandlemethod,justlikeamiddleware:
classUseDatabaseTransactions{
publicfunctionhandle($command,$next)
{
returnDB::transaction(function()use($command,$next)
{
return$next($command);
QueuedCommands
CommandPipeline
}
}
}
CommandpipeclassesareresolvedthroughtheIoCcontainer,sofeelfreetotype-hintanydependenciesyouneedwithintheirconstructors.
YoumayevendefineaClosureasacommandpipe:
$dispatcher->pipeThrough([function($command,$next)
{
returnDB::transaction(function()use($command,$next)
{
return$next($command);
}
}]);
Managers&FactoriesCacheSessionAuthenticationIoCBasedExtension
LaravelhasseveralManagerclassesthatmanagethecreationofdriver-basedcomponents.Theseincludethecache,session,authentication,andqueuecomponents.Themanagerclassisresponsibleforcreatingaparticulardriverimplementationbasedontheapplication'sconfiguration.Forexample,theCacheManagerclasscancreateAPC,Memcached,File,andvariousotherimplementationsofcachedrivers.
Eachofthesemanagersincludesanextendmethodwhichmaybeusedtoeasilyinjectnewdriverresolutionfunctionalityintothemanager.We'llcovereachofthesemanagersbelow,withexamplesofhowtoinjectcustomdriversupportintoeachofthem.
Note:TakeamomenttoexplorethevariousManagerclassesthatshipwithLaravel,suchastheCacheManagerandSessionManager.ReadingthroughtheseclasseswillgiveyouamorethoroughunderstandingofhowLaravelworksunderthehood.AllmanagerclassesextendtheIlluminate\Support\Managerbaseclass,whichprovidessomehelpful,commonfunctionalityforeachmanager.
ToextendtheLaravelcachefacility,wewillusetheextendmethodontheCacheManager,whichisusedtobindacustomdriverresolvertothemanager,andiscommonacrossallmanagerclasses.Forexample,toregisteranewcachedrivernamed"mongo",wewoulddothefollowing:
Cache::extend('mongo',function($app)
{
returnCache::repository(newMongoStore);
});
Thefirstargumentpassedtotheextendmethodisthenameofthedriver.Thiswillcorrespondtoyourdriveroptionintheconfig/cache.phpconfigurationfile.ThesecondargumentisaClosurethatshouldreturnanIlluminate\Cache\Repositoryinstance.TheClosurewillbepassedan$appinstance,whichisaninstanceofIlluminate\Foundation\ApplicationandanIoCcontainer.
ThecalltoCache::extendcouldbedoneinthebootmethodofthedefaultApp\Providers\AppServiceProviderthatshipswithfreshLaravelapplications,oryoumaycreateyourownserviceprovidertohousetheextension-justdon'tforgettoregistertheproviderintheconfig/app.phpproviderarray.
Tocreateourcustomcachedriver,wefirstneedtoimplementtheIlluminate\Contracts\Cache\Storecontract.So,ourMongoDBcacheimplementationwouldlooksomethinglikethis:
classMongoStoreimplementsIlluminate\Contracts\Cache\Store{
publicfunctionget($key){}
publicfunctionput($key,$value,$minutes){}
publicfunctionincrement($key,$value=1){}
publicfunctiondecrement($key,$value=1){}
publicfunctionforever($key,$value){}
publicfunctionforget($key){}
ExtendingTheFramework
Managers&Factories
Cache
publicfunctionflush(){}
}
WejustneedtoimplementeachofthesemethodsusingaMongoDBconnection.Onceourimplementationiscomplete,wecanfinishourcustomdriverregistration:
Cache::extend('mongo',function($app)
{
returnCache::repository(newMongoStore);
});
Ifyou'rewonderingwheretoputyourcustomcachedrivercode,considermakingitavailableonPackagist!Or,youcouldcreateanExtensionsnamespacewithinyourappdirectory.However,keepinmindthatLaraveldoesnothavearigidapplicationstructureandyouarefreetoorganizeyourapplicationaccordingtoyourpreferences.
ExtendingLaravelwithacustomsessiondriverisjustaseasyasextendingthecachesystem.Again,wewillusetheextendmethodtoregisterourcustomcode:
Session::extend('mongo',function($app)
{
//ReturnimplementationofSessionHandlerInterface
});
YoushouldplaceyoursessionextensioncodeinthebootmethodofyourAppServiceProvider.
NotethatourcustomsessiondrivershouldimplementtheSessionHandlerInterface.Thisinterfacecontainsjustafewsimplemethodsweneedtoimplement.AstubbedMongoDBimplementationwouldlooksomethinglikethis:
classMongoHandlerimplementsSessionHandlerInterface{
publicfunctionopen($savePath,$sessionName){}
publicfunctionclose(){}
publicfunctionread($sessionId){}
publicfunctionwrite($sessionId,$data){}
publicfunctiondestroy($sessionId){}
publicfunctiongc($lifetime){}
}
SincethesemethodsarenotasreadilyunderstandableasthecacheStoreInterface,let'squicklycoverwhateachofthemethodsdo:
Theopenmethodwouldtypicallybeusedinfilebasedsessionstoresystems.SinceLaravelshipswithafilesessiondriver,youwillalmostneverneedtoputanythinginthismethod.Youcanleaveitasanemptystub.Itissimplyafactofpoorinterfacedesign(whichwe'lldiscusslater)thatPHPrequiresustoimplementthismethod.Theclosemethod,liketheopenmethod,canalsousuallybedisregarded.Formostdrivers,itisnotneeded.Thereadmethodshouldreturnthestringversionofthesessiondataassociatedwiththegiven$sessionId.Thereisnoneedtodoanyserializationorotherencodingwhenretrievingorstoringsessiondatainyourdriver,asLaravelwillperformtheserializationforyou.Thewritemethodshouldwritethegiven$datastringassociatedwiththe$sessionIdtosomepersistentstorage
Session
WhereToExtendTheSession
WritingTheSessionExtension
system,suchasMongoDB,Dynamo,etc.Thedestroymethodshouldremovethedataassociatedwiththe$sessionIdfrompersistentstorage.Thegcmethodshoulddestroyallsessiondatathatisolderthanthegiven$lifetime,whichisaUNIXtimestamp.Forself-expiringsystemslikeMemcachedandRedis,thismethodmaybeleftempty.
OncetheSessionHandlerInterfacehasbeenimplemented,wearereadytoregisteritwiththeSessionmanager:
Session::extend('mongo',function($app)
{
returnnewMongoHandler;
});
Oncethesessiondriverhasbeenregistered,wemayusethemongodriverinourconfig/session.phpconfigurationfile.
Note:Remember,ifyouwriteacustomsessionhandler,shareitonPackagist!
Authenticationmaybeextendedthesamewayasthecacheandsessionfacilities.Again,wewillusetheextendmethodwehavebecomefamiliarwith:
Auth::extend('riak',function($app)
{
//ReturnimplementationofIlluminate\Contracts\Auth\UserProvider
});
TheUserProviderimplementationsareonlyresponsibleforfetchingaIlluminate\Contracts\Auth\Authenticatableimplementationoutofapersistentstoragesystem,suchasMySQL,Riak,etc.ThesetwointerfacesallowtheLaravelauthenticationmechanismstocontinuefunctioningregardlessofhowtheuserdataisstoredorwhattypeofclassisusedtorepresentit.
Let'stakealookattheUserProvidercontract:
interfaceUserProvider{
publicfunctionretrieveById($identifier);
publicfunctionretrieveByToken($identifier,$token);
publicfunctionupdateRememberToken(Authenticatable$user,$token);
publicfunctionretrieveByCredentials(array$credentials);
publicfunctionvalidateCredentials(Authenticatable$user,array$credentials);
}
TheretrieveByIdfunctiontypicallyreceivesanumerickeyrepresentingtheuser,suchasanauto-incrementingIDfromaMySQLdatabase.TheAuthenticatableimplementationmatchingtheIDshouldberetrievedandreturnedbythemethod.
TheretrieveByTokenfunctionretrievesauserbytheirunique$identifierand"rememberme"$token,storedinafieldremember_token.Aswithwithpreviousmethod,theAuthenticatableimplementationshouldbereturned.
TheupdateRememberTokenmethodupdatesthe$userfieldremember_tokenwiththenew$token.Thenewtokencanbeeitherafreshtoken,assignedonsuccessfull"rememberme"loginattempt,oranullwhenuserisloggedout.
TheretrieveByCredentialsmethodreceivesthearrayofcredentialspassedtotheAuth::attemptmethodwhenattemptingtosignintoanapplication.Themethodshouldthen"query"theunderlyingpersistentstoragefortheusermatchingthosecredentials.Typically,thismethodwillrunaquerywitha"where"conditionon$credentials['username'].Thismethodshouldnotattempttodoanypasswordvalidationorauthentication.
Authentication
ThevalidateCredentialsmethodshouldcomparethegiven$userwiththe$credentialstoauthenticatetheuser.Forexample,thismethodmightcomparethe$user->getAuthPassword()stringtoaHash::makeof$credentials['password'].
NowthatwehaveexploredeachofthemethodsontheUserProvider,let'stakealookattheAuthenticatable.Remember,theprovidershouldreturnimplementationsofthisinterfacefromtheretrieveByIdandretrieveByCredentialsmethods:
interfaceAuthenticatable{
publicfunctiongetAuthIdentifier();
publicfunctiongetAuthPassword();
publicfunctiongetRememberToken();
publicfunctionsetRememberToken($value);
publicfunctiongetRememberTokenName();
}
Thisinterfaceissimple.ThegetAuthIdentifiermethodshouldreturnthe"primarykey"oftheuser.InaMySQLback-end,again,thiswouldbetheauto-incrementingprimarykey.ThegetAuthPasswordshouldreturntheuser'shashedpassword.ThisinterfaceallowstheauthenticationsystemtoworkwithanyUserclass,regardlessofwhatORMorstorageabstractionlayeryouareusing.Bydefault,LaravelincludesaUserclassintheappdirectorywhichimplementsthisinterface,soyoumayconsultthisclassforanimplementationexample.
Finally,oncewehaveimplementedtheUserProvider,wearereadytoregisterourextensionwiththeAuthfacade:
Auth::extend('riak',function($app)
{
returnnewRiakUserProvider($app['riak.connection']);
});
Afteryouhaveregisteredthedriverwiththeextendmethod,youswitchtothenewdriverinyourconfig/auth.phpconfigurationfile.
AlmosteveryserviceproviderincludedwiththeLaravelframeworkbindsobjectsintotheIoCcontainer.Youcanfindalistofyourapplication'sserviceprovidersintheconfig/app.phpconfigurationfile.Asyouhavetime,youshouldskimthrougheachoftheseprovider'ssourcecode.Bydoingso,youwillgainamuchbetterunderstandingofwhateachprovideraddstotheframework,aswellaswhatkeysareusedtobindvariousservicesintotheIoCcontainer.
Forexample,theHashServiceProviderbindsahashkeyintotheIoCcontainer,whichresolvesintoaIlluminate\Hashing\BcryptHasherinstance.YoucaneasilyextendandoverridethisclasswithinyourownapplicationbyoverridingthisIoCbinding.Forexample:
<?phpnamespaceApp\Providers;
classSnappyHashProviderextends\Illuminate\Hashing\HashServiceProvider{
publicfunctionboot()
{
$this->app->bindShared('hash',function()
{
returnnew\Snappy\Hashing\ScryptHasher;
});
parent::boot();
}
}
NotethatthisclassextendstheHashServiceProvider,notthedefaultServiceProviderbaseclass.Onceyouhave
IoCBasedExtension
extendedtheserviceprovider,swapouttheHashServiceProviderinyourconfig/app.phpconfigurationfilewiththenameofyourextendedprovider.
Thisisthegeneralmethodofextendinganycoreclassthatisboundinthecontainer.Essentiallyeverycoreclassisboundinthecontainerinthisfashion,andcanbeoverridden.Again,readingthroughtheincludedframeworkserviceproviderswillfamiliarizeyouwithwherevariousclassesareboundintothecontainer,andwhatkeystheyareboundby.ThisisagreatwaytolearnmoreabouthowLaravelisputtogether.
IntroductionInstallation&SetupUsageGulpExtensions
LaravelElixirprovidesaclean,fluentAPIfordefiningbasicGulptasksforyourLaravelapplication.ElixirsupportsseveralcommonCSSandJavaScriptpre-processors,andeventestingtools.
Ifyou'veeverbeenconfusedabouthowtogetstartedwithGulpandassetcompilation,youwillloveLaravelElixir!
BeforetriggeringElixir,youmustfirstensurethatNode.jsisinstalledonyourmachine.
node-v
Bydefault,LaravelHomesteadincludeseverythingyouneed;however,ifyouaren'tusingVagrant,thenyoucaneasilyinstallNodebyvisitingtheirdownloadpage.Don'tworry,it'squickandeasy!
Next,you'llwanttopullinGulpasaglobalNPMpackagelikeso:
npminstall--globalgulp
TheonlyremainingstepistoinstallElixir!WithanewinstallofLaravel,you'llfindapackage.jsonfileintheroot.Thinkofthislikeyourcomposer.jsonfile,exceptitdefinesNodedependenciesinsteadofPHP.Youmayinstallthedependenciesitreferencesbyrunning:
npminstall
Nowthatyou'veinstalledElixir,you'llbecompilingandconcatenatinginnotime!
elixir(function(mix){
mix.less("app.less");
LaravelElixir
Introduction
Installation&Setup
InstallingNode
Gulp
LaravelElixir
Usage
CompileLess
});
Intheexampleabove,ElixirassumesthatyourLessfilesarestoredinresources/assets/less.
elixir(function(mix){
mix.sass("app.sass");
});
ThisassumesthatyourSassfilesarestoredinresources/assets/sass.
elixir(function(mix){
mix.coffee();
});
ThisassumesthatyourCoffeeScriptfilesarestoredinresources/assets/coffee.
elixir(function(mix){
mix.less()
.coffee();
});
elixir(function(mix){
mix.phpUnit();
});
elixir(function(mix){
mix.phpSpec();
});
elixir(function(mix){
mix.styles([
"normalize.css",
"main.css"
]);
});
Pathspassedtothismethodarerelativetotheresources/cssdirectory.
elixir(function(mix){
CompileSass
CompileCoffeeScript
CompileAllLessandCoffeeScript
TriggerPHPUnitTests
TriggerPHPSpecTests
CombineStylesheets
CombineStylesheetsandSavetoaCustomDirectory
mix.styles([
"normalize.css",
"main.css"
],'public/build/css/everything.css');
});
elixir(function(mix){
mix.styles([
"normalize.css",
"main.css"
],'public/build/css/everything.css','public/css');
});
Thethirdargumenttoboththestylesandscriptsmethodsdeterminestherelativedirectoryforallpathspassedtothemethods.
elixir(function(mix){
mix.stylesIn("public/css");
});
elixir(function(mix){
mix.scripts([
"jquery.js",
"app.js"
]);
});
Again,thisassumesallpathsarerelativetotheresources/jsdirectory.
elixir(function(mix){
mix.scriptsIn("public/js/some/directory");
});
elixir(function(mix){
mix.scripts(['jquery.js','main.js'],'public/js/main.js')
.scripts(['forum.js','threads.js'],'public/js/forum.js');
});
elixir(function(mix){
mix.version("css/all.css");
});
Thiswillappendauniquehashtothefilename,allowingforcache-busting.Forexample,thegeneratedfilenamewilllook
CombineStylesheetsFromACustomBaseDirectory
CombineAllStylesinaDirectory
CombineScripts
CombineAllScriptsinaDirectory
CombineMultipleSetsofScripts
Version/HashAFile
somethinglike:all-16d570a7.css.
Withinyourviews,youmayusetheelixir()functiontoloadtheappropriatelyhashedasset.Here'sanexample:
<linkrel="stylesheet"href="{{elixir("css/all.css")}}">
Behindthescenes,theelixir()functionwilldeterminethenameofthehashedfilethatshouldbeincluded.Don'tyoufeeltheweightliftingoffyourshouldersalready?
elixir(function(mix){
mix.copy('vendor/foo/bar.css','public/css/bar.css');
});
elixir(function(mix){
mix.copy('vendor/package/views','resources/views');
});
Ofcourse,youmaychainalmostallofElixir'smethodstogethertobuildyourrecipe:
elixir(function(mix){
mix.less("app.less")
.coffee()
.phpUnit()
.version("css/bootstrap.css");
});
Nowthatyou'vetoldElixirwhichtaskstoexecute,youonlyneedtotriggerGulpfromthecommandline.
gulp
gulpwatch
gulptdd
Note:Alltaskswillassumeadevelopmentenvironment,andwillexcludeminification.Forproduction,usegulp--
CopyaFiletoaNewLocation
CopyanEntireDirectorytoaNewLocation
MethodChaining
Gulp
ExecuteAllRegisteredTasksOnce
WatchAssetsForChanges
WatchTestsAndPHPClassesforChanges
production.
YoucanevencreateyourownGulptasks,andhookthemintoElixir.ImaginethatyouwanttoaddafuntaskthatusestheTerminaltoverballynotifyyouwithsomemessage.Here'swhatthatmightlooklike:
vargulp=require("gulp");
varshell=require("gulp-shell");
varelixir=require("laravel-elixir");
elixir.extend("message",function(message){
gulp.task("say",function(){
gulp.src("").pipe(shell("say"+message));
});
returnthis.queueTask("say");
});
NoticethatweextendElixir'sAPIbypassingthekeythatwewillusewithinourGulpfile,aswellasacallbackfunctionthatwillcreatetheGulptask.
Ifyouwantyourcustomtasktobemonitored,thenregisterawatcheraswell.
this.registerWatcher("message","**/*.php");
Thislinesdesignatesthatwhenanyfilethatmatchestheregex,**/*.phpismodified,wewanttotriggerthemessagetask.
That'sit!YoumayeitherplacethisatthetopofyourGulpfile,orinsteadextractittoacustomtasksfile.Ifyouchoosethelatterapproach,simplyrequireitintoyourGulpfile,likeso:
require("./custom-tasks")
You'redone!Now,youcanmixitin.
elixir(function(mix){
mix.message("Tea,EarlGrey,Hot");
});
Withthisaddition,eachtimeyoutriggerGulp,Picardwillrequestsometea.
Extensions
IntroductionBasicUsage
LaravelprovidesfacilitiesforstrongAESencryptionviatheMcryptPHPextension.
$encrypted=Crypt::encrypt('secret');
Note:Besuretoseta16,24,or32characterrandomstringinthekeyoptionoftheconfig/app.phpfile.Otherwise,encryptedvalueswillnotbesecure.
$decrypted=Crypt::decrypt($encryptedValue);
Youmayalsosetthecipherandmodeusedbytheencrypter:
Crypt::setMode('ctr');
Crypt::setCipher($cipher);
Encryption
Introduction
BasicUsage
EncryptingAValue
DecryptingAValue
SettingTheCipher&Mode
ConfigurationHandlingErrorsHTTPExceptionsLogging
TheloggingfacilitiesforyourapplicationareconfiguredintheIlluminate\Foundation\Bootstrap\ConfigureLoggingbootstrapperclass.Thisclassutilizesthelogconfigurationoptionfromyourconfig/app.phpconfigurationfile.
Bydefault,theloggerisconfiguredtousedailylogfiles;however,youmaycustomizethisbehaviorasneeded.SinceLaravelusesthepopularMonologlogginglibrary,youcantakeadvantageofthevarietyofhandlersthatMonologoffers.
Forexample,ifyouwishtouseasinglelogfileinsteadofdailyfiles,youcanmakethefollowingchangetoyourconfig/app.phpconfigurationfile:
'log'=>'single'
Outofthebox,Laravelsupportedsingle,daily,andsyslogloggingmodes.However,youarefreetocustomizetheloggingforyourapplicationasyouwishbyoverridingtheConfigureLoggingbootstrapperclass.
Theamountoferrordetailyourapplicationdisplaysthroughthebrowseriscontrolledbytheapp.debugconfigurationoptioninyourconfig/app.phpconfigurationfile.Bydefault,thisconfigurationoptionissettorespecttheAPP_DEBUGenvironmentvariable,whichisstoredinyour.envfile.
Forlocaldevelopment,youshouldsettheAPP_DEBUGenvironmentvariabletotrue.Inyourproductionenvironment,thisvalueshouldalwaysbefalse.
AllexceptionsarehandledbytheApp\Exceptions\Handlerclass.Thisclasscontainstwomethods:reportandrender.
ThereportmethodisusedtologexceptionsorsendthemtoanexternalservicelikeBugSnag.Bydefault,thereportmethodsimplypassestheexceptiontothebaseimplementationontheparentclasswheretheexceptionislogged.However,youarefreetologexceptionshoweveryouwish.Ifyouneedtoreportdifferenttypesofexceptionsindifferentways,youmayusethePHPinstanceofcomparisonoperator:
/**
*Reportorloganexception.
*
*ThisisagreatspottosendexceptionstoSentry,Bugsnag,etc.
*
*@param\Exception$e
*@returnvoid
*/
publicfunctionreport(Exception$e)
{
if($einstanceofCustomException)
{
//
}
Errors&Logging
Configuration
ErrorDetail
HandlingErrors
returnparent::report($e);
}
TherendermethodisresponsibleforconvertingtheexceptionintoanHTTPresponsethatshouldbesentbacktothebrowser.Bydefault,theexceptionispassedtothebaseclasswhichgeneratesaresponseforyou.However,youarefreetochecktheexceptiontypeorreturnyourowncustomresponse.
ThedontReportpropertyoftheexceptionhandlercontainsanarrayofexceptiontypesthatwillnotbelogged.Bydefault,exceptionsresultingfrom404errorsarenotwrittentoyourlogfiles.Youmayaddotherexceptiontypestothisarrayasneeded.
SomeexceptionsdescribeHTTPerrorcodesfromtheserver.Forexample,thismaybea"pagenotfound"error(404),an"unauthorizederror"(401)orevenadevelopergenerated500error.Inordertoreturnsucharesponse,usethefollowing:
abort(404);
Optionally,youmayprovidearesponse:
abort(403,'Unauthorizedaction.');
Thismethodmaybeusedatanytimeduringtherequest'slifecycle.
Toreturnacustomviewforall404errors,createaresources/views/errors/404.blade.phpfile.Thisviewwillbeservedonall404errorsgeneratedbyyourapplication.
TheLaravelloggingfacilitiesprovideasimplelayerontopofthepowerfulMonologlibrary.Bydefault,Laravelisconfiguredtocreatedailylogfilesforyourapplicationwhicharestoredinthestorage/logsdirectory.Youmaywriteinformationtotheloglikeso:
Log::info('Thisissomeusefulinformation.');
Log::warning('Somethingcouldbegoingwrong.');
Log::error('Somethingisreallygoingwrong.');
TheloggerprovidesthesevenlogginglevelsdefinedinRFC5424:debug,info,notice,warning,error,critical,andalert.
Anarrayofcontextualdatamayalsobepassedtothelogmethods:
Log::info('Logmessage',['context'=>'Otherhelpfulinformation']);
Monologhasavarietyofadditionalhandlersyoumayuseforlogging.Ifneeded,youmayaccesstheunderlyingMonologinstancebeingusedbyLaravel:
HTTPExceptions
Custom404ErrorPage
Logging
$monolog=Log::getMonolog();
Youmayalsoregisteraneventtocatchallmessagespassedtothelog:
Log::listen(function($level,$message,$context)
{
//
});
RegisteringALogEventListener
BasicUsageQueuedEventHandlersEventSubscribers
TheLaraveleventfacilitiesprovidesasimpleobserverimplementation,allowingyoutosubscribeandlistenforeventsinyourapplication.Eventclassesaretypicallystoredintheapp/Eventsdirectory,whiletheirhandlersarestoredinapp/Handlers/Events.
YoucangenerateaneweventclassusingtheArtisanCLItool:
phpartisanmake:eventPodcastWasPurchased
TheEventServiceProviderincludedwithyourLaravelapplicationprovidesaconvenientplacetoregisteralleventhandlers.Thelistenpropertycontainsanarrayofallevents(keys)andtheirhandlers(values).Ofcourse,youmayaddasmanyeventstothisarrayasyourapplicationrequires.Forexample,let'saddourPodcastWasPurchasedevent:
/**
*Theeventhandlermappingsfortheapplication.
*
*@vararray
*/
protected$listen=[
'App\Events\PodcastWasPurchased'=>[
'App\Handlers\Events\EmailPurchaseConfirmation@handle',
],
];
Togenerateahandlerforanevent,usethehandler:eventArtisanCLIcommand:
phpartisanhandler:eventEmailPurchaseConfirmation--event=PodcastWasPurchased
Ofcourse,manuallyrunningthemake:eventandhandler:eventcommandseachtimeyouneedahandleroreventiscumbersome.Instead,simplyaddhandlersandeventstoyourEventServiceProviderandusetheevent:generatecommand.ThiscommandwillgenerateanyeventsorhandlersthatarelistedinyourEventServiceProvider:
phpartisanevent:generate
NowwearereadytofireoureventusingtheEventfacade:
$response=Event::fire(newPodcastWasPurchased($podcast));
Thefiremethodreturnsanarrayofresponsesthatyoucanusetocontrolwhathappensnextinyourapplication.
Events
BasicUsage
SubscribingToAnEvent
FiringAnEvent
Youmayalsousetheeventhelpertofireanevent:
event(newPodcastWasPurchased($podcast));
Youcanevenlistentoeventswithoutcreatingaseparatehandlerclassatall.Forexample,inthebootmethodofyourEventServiceProvider,youcoulddothefollowing:
Event::listen('App\Events\PodcastWasPurchased',function($event)
{
//Handletheevent...
});
Sometimes,youmaywishtostopthepropagationofaneventtootherlisteners.Youmaydosousingbyreturningfalsefromyourhandler:
Event::listen('App\Events\PodcastWasPurchased',function($event)
{
//Handletheevent...
returnfalse;
});
Needtoqueueaneventhandler?Itcouldn'tbeanyeasier.Whengeneratingthehandler,simplyusethe--queuedflag:
phpartisanhandler:eventSendPurchaseConfirmation--event=PodcastWasPurchased--queued
ThiswillgenerateahandlerclassthatimplementstheIlluminate\Contracts\Queue\ShouldBeQueuedinterface.That'sit!Nowwhenthishandleriscalledforanevent,itwillbequeuedautomaticallybytheeventdispatcher.
Ifnoexceptionsarethrownwhenthehandlerisexecutedbythequeue,thequeuedjobwillbedeletedautomaticallyafterithasprocessed.Ifyouneedtoaccessthequeuedjob'sdeleteandreleasemethodsmanually,youmaydoso.TheIlluminate\Queue\InteractsWithQueuetrait,whichisincludedbydefaultonqueuedhandlers,givesyouaccesstothesemethods:
publicfunctionhandle(PodcastWasPurchased$event)
{
if(true)
{
$this->release(30);
}
}
Ifyouhaveanexistinghandlerthatyouwouldliketoconverttoaqueuedhandler,simplyaddtheShouldBeQueuedinterfacetotheclassmanually.
ClosureListeners
StoppingThePropagationOfAnEvent
QueuedEventHandlers
EventSubscribers
Eventsubscribersareclassesthatmaysubscribetomultipleeventsfromwithintheclassitself.Subscribersshoulddefineasubscribemethod,whichwillbepassedaneventdispatcherinstance:
classUserEventHandler{
/**
*Handleuserloginevents.
*/
publicfunctiononUserLogin($event)
{
//
}
/**
*Handleuserlogoutevents.
*/
publicfunctiononUserLogout($event)
{
//
}
/**
*Registerthelistenersforthesubscriber.
*
*@paramIlluminate\Events\Dispatcher$events
*@returnarray
*/
publicfunctionsubscribe($events)
{
$events->listen('App\Events\UserLoggedIn','UserEventHandler@onUserLogin');
$events->listen('App\Events\UserLoggedOut','UserEventHandler@onUserLogout');
}
}
Oncethesubscriberhasbeendefined,itmayberegisteredwiththeEventclass.
$subscriber=newUserEventHandler;
Event::subscribe($subscriber);
YoumayalsousetheLaravelIoCcontainertoresolveyoursubscriber.Todoso,simplypassthenameofyoursubscribertothesubscribemethod:
Event::subscribe('UserEventHandler');
DefiningAnEventSubscriber
RegisteringAnEventSubscriber
IntroductionConfigurationBasicUsage
LaravelprovidesawonderfulfilesystemabstractionthankstotheFlysystemPHPpackagebyFrankdeJonge.TheLaravelFlysystemintegrationprovidessimpletousedriversforworkingwithlocalfilesystems,AmazonS3,andRackspaceCloudStorage.Evenbetter,it'samazinglysimpletoswitchbetweenthesestorageoptionsastheAPIremainsthesameforeachsystem!
Thefilesystemconfigurationfileislocatedatconfig/filesystems.php.Withinthisfileyoumayconfigureallofyour"disks".Eachdiskrepresentsaparticularstoragedriverandstoragelocation.Exampleconfigurationsforeachsupporteddriverisincludedintheconfigurationfile.So,simplymodifytheconfigurationtoreflectyourstoragepreferencesandcredentials!
BeforeusingtheS3orRackspacedrivers,youwillneedtoinstalltheappropriatepackageviaComposer:
AmazonS3:league/flysystem-aws-s3-v2~1.0Rackspace:league/flysystem-rackspace~1.0
Ofcourse,youmayconfigureasmanydisksasyoulike,andmayevenhavemultipledisksthatusethesamedriver.
Whenusingthelocaldriver,notethatallfileoperationsarerelativetotherootdirectorydefinedinyourconfigurationfile.Bydefault,thisvalueissettothestorage/appdirectory.Therefore,thefollowingmethodwouldstoreafileinstorage/app/file.txt:
Storage::disk('local')->put('file.txt','Contents');
TheStoragefacademaybeusedtointeractwithanyofyourconfigureddisks.Alternatively,youmaytype-hinttheIlluminate\Contracts\Filesystem\FactorycontractonanyclassthatisresolvedviatheIoCcontainer.
$disk=Storage::disk('s3');
$disk=Storage::disk('local');
$exists=Storage::disk('s3')->exists('file.jpg');
Filesystem/CloudStorage
Introduction
Configuration
BasicUsage
RetrievingAParticularDisk
DeterminingIfAFileExists
CallingMethodsOnTheDefaultDisk
if(Storage::exists('file.jpg'))
{
//
}
$contents=Storage::get('file.jpg');
Storage::put('file.jpg',$contents);
Storage::prepend('file.log','PrependedText');
Storage::append('file.log','AppendedText');
Storage::delete('file.jpg');
Storage::delete(['file1.jpg','file2.jpg']);
Storage::copy('old/file1.jpg','new/file1.jpg');
Storage::move('old/file1.jpg','new/file1.jpg');
$size=Storage::size('file1.jpg');
$time=Storage::lastModified('file1.jpg');
RetrievingAFile'sContents
SettingAFile'sContents
PrependToAFile
AppendToAFile
DeleteAFile
CopyAFileToANewLocation
MoveAFileToANewLocation
GetFileSize
GetTheLastModificationTime(UNIX)
GetAllFilesWithinADirectory
$files=Storage::files($directory);
//Recursive...
$files=Storage::allFiles($directory);
$directories=Storage::directories($directory);
//Recursive...
$directories=Storage::allDirectories($directory);
Storage::makeDirectory($directory);
Storage::deleteDirectory($directory);
GetAllDirectoriesWithinADirectory
CreateADirectory
DeleteADirectory
IntroductionBasicUsage
TheLaravelHashfacadeprovidessecureBcrypthashingforstoringuserpasswords.IfyouareusingtheAuthControllercontrollerthatisincludedwithyourLaravelapplication,itwillbetakecareofverifyingtheBcryptpasswordagainsttheun-hashedversionprovidedbytheuser.
Likewise,theuserRegistrarservicethatshipswithLaravelmakestheproperbcryptfunctioncalltohashstoredpasswords.
$password=Hash::make('secret');
Youmayalsousethebcrypthelperfunction:
$password=bcrypt('secret');
if(Hash::check('secret',$hashedPassword))
{
//Thepasswordsmatch...
}
if(Hash::needsRehash($hashed))
{
$hashed=Hash::make('secret');
}
Hashing
Introduction
BasicUsage
HashingAPasswordUsingBcrypt
VerifyingAPasswordAgainstAHash
CheckingIfAPasswordNeedsToBeRehashed
ArraysPathsStringsURLsMiscellaneous
Thearray_addfunctionaddsagivenkey/valuepairtothearrayifthegivenkeydoesn'talreadyexistinthearray.
$array=array('foo'=>'bar');
$array=array_add($array,'key','value');
Thearray_dividefunctionreturnstwoarrays,onecontainingthekeys,andtheothercontainingthevaluesoftheoriginalarray.
$array=array('foo'=>'bar');
list($keys,$values)=array_divide($array);
Thearray_dotfunctionflattensamulti-dimensionalarrayintoasinglelevelarraythatuses"dot"notationtoindicatedepth.
$array=array('foo'=>array('bar'=>'baz'));
$array=array_dot($array);
//array('foo.bar'=>'baz');
Thearray_exceptmethodremovesthegivenkey/valuepairsfromthearray.
$array=array_except($array,array('keys','to','remove'));
Thearray_fetchmethodreturnsaflattenedarraycontainingtheselectednestedelement.
$array=array(
array('developer'=>array('name'=>'Taylor')),
array('developer'=>array('name'=>'Dayle')),
);
HelperFunctions
Arrays
array_add
array_divide
array_dot
array_except
array_fetch
$array=array_fetch($array,'developer.name');
//array('Taylor','Dayle');
Thearray_firstmethodreturnsthefirstelementofanarraypassingagiventruthtest.
$array=array(100,200,300);
$value=array_first($array,function($key,$value)
{
return$value>=150;
});
Adefaultvaluemayalsobepassedasthethirdparameter:
$value=array_first($array,$callback,$default);
Thearray_lastmethodreturnsthelastelementofanarraypassingagiventruthtest.
$array=array(350,400,500,300,200,100);
$value=array_last($array,function($key,$value)
{
return$value>350;
});
//500
Adefaultvaluemayalsobepassedasthethirdparameter:
$value=array_last($array,$callback,$default);
Thearray_flattenmethodwillflattenamulti-dimensionalarrayintoasinglelevel.
$array=array('name'=>'Joe','languages'=>array('PHP','Ruby'));
$array=array_flatten($array);
//array('Joe','PHP','Ruby');
Thearray_forgetmethodwillremoveagivenkey/valuepairfromadeeplynestedarrayusing"dot"notation.
$array=array('names'=>array('joe'=>array('programmer')));
array_forget($array,'names.joe');
array_first
array_last
array_flatten
array_forget
array_get
Thearray_getmethodwillretrieveagivenvaluefromadeeplynestedarrayusing"dot"notation.
$array=array('names'=>array('joe'=>array('programmer')));
$value=array_get($array,'names.joe');
$value=array_get($array,'names.john','default');
Note:Wantsomethinglikearray_getbutforobjectsinstead?Useobject_get.
Thearray_onlymethodwillreturnonlythespecifiedkey/valuepairsfromthearray.
$array=array('name'=>'Joe','age'=>27,'votes'=>1);
$array=array_only($array,array('name','votes'));
Thearray_pluckmethodwillpluckalistofthegivenkey/valuepairsfromthearray.
$array=array(array('name'=>'Taylor'),array('name'=>'Dayle'));
$array=array_pluck($array,'name');
//array('Taylor','Dayle');
Thearray_pullmethodwillreturnagivenkey/valuepairfromthearray,aswellasremoveit.
$array=array('name'=>'Taylor','age'=>27);
$name=array_pull($array,'name');
Thearray_setmethodwillsetavaluewithinadeeplynestedarrayusing"dot"notation.
$array=array('names'=>array('programmer'=>'Joe'));
array_set($array,'names.editor','Taylor');
Thearray_sortmethodsortsthearraybytheresultsofthegivenClosure.
$array=array(
array('name'=>'Jill'),
array('name'=>'Barry'),
);
$array=array_values(array_sort($array,function($value)
{
return$value['name'];
}));
array_only
array_pluck
array_pull
array_set
array_sort
FilterthearrayusingthegivenClosure.
$array=array(100,'200',300,'400',500);
$array=array_where($array,function($key,$value)
{
returnis_string($value);
});
//Array([1]=>200[3]=>400)
Returnthefirstelementinthearray.UsefulformethodchaininginPHP5.3.x.
$first=head($this->returnsArray('foo'));
Returnthelastelementinthearray.Usefulformethodchaining.
$last=last($this->returnsArray('foo'));
Getthefullyqualifiedpathtotheappdirectory.
$path=app_path();
Getthefullyqualifiedpathtotherootoftheapplicationinstall.
Getthefullyqualifiedpathtothepublicdirectory.
Getthefullyqualifiedpathtothestoragedirectory.
ConvertthegivenstringtocamelCase.
array_where
head
last
Paths
app_path
base_path
public_path
storage_path
Strings
camel_case
$camel=camel_case('foo_bar');
//fooBar
Gettheclassnameofthegivenclass,withoutanynamespacenames.
$class=class_basename('Foo\Bar\Baz');
//Baz
Runhtmlentitiesoverthegivenstring,withUTF-8support.
$entities=e('<html>foo</html>');
Determineifthegivenhaystackendswithagivenneedle.
$value=ends_with('Thisismyname','name');
Convertthegivenstringtosnake_case.
$snake=snake_case('fooBar');
//foo_bar
Limitthenumberofcharactersinastring.
str_limit($value,$limit=100,$end='...')
Example:
$value=str_limit('ThePHPframeworkforwebartisans.',7);
//ThePHP...
Determineifthegivenhaystackbeginswiththegivenneedle.
$value=starts_with('Thisismyname','This');
class_basename
e
ends_with
snake_case
str_limit
starts_with
Determineifthegivenhaystackcontainsthegivenneedle.
$value=str_contains('Thisismyname','my');
Addasingleinstanceofthegivenneedletothehaystack.Removeanyextrainstances.
$string=str_finish('this/string','/');
//this/string/
Determineifagivenstringmatchesagivenpattern.Asterisksmaybeusedtoindicatewildcards.
$value=str_is('foo*','foobar');
Convertastringtoitspluralform(Englishonly).
$plural=str_plural('car');
Generatearandomstringofthegivenlength.
$string=str_random(40);
Convertastringtoitssingularform(Englishonly).
$singular=str_singular('cars');
GenerateaURLfriendly"slug"fromagivenstring.
str_slug($title,$separator);
Example:
$title=str_slug("Laravel5Framework","-");
str_contains
str_finish
str_is
str_plural
str_random
str_singular
str_slug
//laravel-5-framework
ConvertthegivenstringtoStudlyCase.
$value=studly_case('foo_bar');
//FooBar
Translateagivenlanguageline.AliasofLang::get.
$value=trans('validation.required'):
Translateagivenlanguagelinewithinflection.AliasofLang::choice.
$value=trans_choice('foo.bar',$count);
GenerateaURLforagivencontrolleraction.
$url=action('HomeController@getIndex',$params);
GenerateaURLforagivennamedroute.
$url=route('routeName',$params);
GenerateaURLforanasset.
$url=asset('img/photo.jpg');
GenerateaHTMLlinktothegivenURL.
echolink_to('foo/bar',$title,$attributes=array(),$secure=null);
studly_case
trans
trans_choice
URLs
action
route
asset
link_to
GenerateaHTMLlinktothegivenasset.
echolink_to_asset('foo/bar.zip',$title,$attributes=array(),$secure=null);
GenerateaHTMLlinktothegivenroute.
echolink_to_route('route.name',$title,$parameters=array(),$attributes=array());
GenerateaHTMLlinktothegivencontrolleraction.
echolink_to_action('HomeController@getIndex',$title,$parameters=array(),$attributes=array());
GenerateaHTMLlinktothegivenassetusingHTTPS.
echosecure_asset('foo/bar.zip',$title,$attributes=array());
GenerateafullyqualifiedURLtoagivenpathusingHTTPS.
echosecure_url('foo/bar',$parameters=array());
GenerateafullyqualifiedURLtothegivenpath.
echourl('foo/bar',$parameters=array(),$secure=null);
GetthevalueofthecurrentCSRFtoken.
$token=csrf_token();
link_to_asset
link_to_route
link_to_action
secure_asset
secure_url
url
Miscellaneous
csrf_token
dd
Dumpthegivenvariableandendexecutionofthescript.
dd($value);
IfthegivenvalueisaClosure,returnthevaluereturnedbytheClosure.Otherwise,returnthevalue.
$value=value(function(){return'bar';});
Returnthegivenobject.UsefulformethodchainingconstructorsinPHP5.3.x.
$value=with(newFoo)->doWork();
value
with
IntroductionLanguageFilesBasicUsagePluralizationValidationLocalizationOverridingPackageLanguageFiles
TheLaravelLangfacadeprovidesaconvenientwayofretrievingstringsinvariouslanguages,allowingyoutoeasilysupportmultiplelanguageswithinyourapplication.
Languagestringsarestoredinfileswithintheresources/langdirectory.Withinthisdirectorythereshouldbeasubdirectoryforeachlanguagesupportedbytheapplication.
/resources
/lang
/en
messages.php
/es
messages.php
Languagefilessimplyreturnanarrayofkeyedstrings.Forexample:
<?php
returnarray(
'welcome'=>'Welcometoourapplication'
);
Thedefaultlanguageforyourapplicationisstoredintheconfig/app.phpconfigurationfile.YoumaychangetheactivelanguageatanytimeusingtheApp::setLocalemethod:
App::setLocale('es');
Youmayalsoconfigurea"fallbacklanguage",whichwillbeusedwhentheactivelanguagedoesnotcontainagivenlanguageline.Likethedefaultlanguage,thefallbacklanguageisalsoconfiguredintheconfig/app.phpconfigurationfile:
'fallback_locale'=>'en',
Localization
Introduction
LanguageFiles
ExampleLanguageFile
ChangingTheDefaultLanguageAtRuntime
SettingTheFallbackLanguage
echoLang::get('messages.welcome');
Thefirstsegmentofthestringpassedtothegetmethodisthenameofthelanguagefile,andthesecondisthenameofthelinethatshouldberetrieved.
Note:Ifalanguagelinedoesnotexist,thekeywillbereturnedbythegetmethod.
Youmayalsousethetranshelperfunction,whichisanaliasfortheLang::getmethod.
echotrans('messages.welcome');
Youmayalsodefineplace-holdersinyourlanguagelines:
'welcome'=>'Welcome,:name',
Then,passasecondargumentofreplacementstotheLang::getmethod:
echoLang::get('messages.welcome',array('name'=>'Dayle'));
if(Lang::has('messages.welcome'))
{
//
}
Pluralizationisacomplexproblem,asdifferentlanguageshaveavarietyofcomplexrulesforpluralization.Youmayeasilymanagethisinyourlanguagefiles.Byusinga"pipe"character,youmayseparatethesingularandpluralformsofastring:
'apples'=>'Thereisoneapple|Therearemanyapples',
YoumaythenusetheLang::choicemethodtoretrievetheline:
echoLang::choice('messages.apples',10);
Youmayalsosupplyalocaleargumenttospecifythelanguage.Forexample,ifyouwanttousetheRussian(ru)language:
echoLang::choice('товар|товара|товаров',$count,array(),'ru');
BasicUsage
RetrievingLinesFromALanguageFile
MakingReplacementsInLines
DetermineIfALanguageFileContainsALine
Pluralization
SincetheLaraveltranslatorispoweredbytheSymfonyTranslationcomponent,youmayalsocreatemoreexplicitpluralizationruleseasily:
'apples'=>'{0}Therearenone|[1,19]Therearesome|[20,Inf]Therearemany',
Forlocalizationforvalidationerrorsandmessages,takealookatthedocumentationonValidation.
Manypackagesshipwiththeirownlanguagelines.Insteadofhackingthepackage'scorefilestotweaktheselines,youmayoverridethembyplacingfilesintheresources/lang/packages/{locale}/{package}directory.So,forexample,ifyouneedtooverridetheEnglishlanguagelinesinmessages.phpforapackagenamedskyrim/hearthfire,youwouldplacealanguagefileat:resources/lang/packages/en/hearthfire/messages.php.Inthisfileyouwoulddefineonlythelanguagelinesyouwishtooverride.Anylanguagelinesyoudon'toverridewillstillbeloadedfromthepackage'slanguagefiles.
Validation
OverridingPackageLanguageFiles
ConfigurationBasicUsageEmbeddingInlineAttachmentsQueueingMailMail&LocalDevelopment
Laravelprovidesaclean,simpleAPIoverthepopularSwiftMailerlibrary.Themailconfigurationfileisconfig/mail.php,andcontainsoptionsallowingyoutochangeyourSMTPhost,port,andcredentials,aswellassetaglobalfromaddressforallmessagesdeliveredbythelibrary.YoumayuseanySMTPserveryouwish.IfyouwishtousethePHPmailfunctiontosendmail,youmaychangethedrivertomailintheconfigurationfile.Asendmaildriverisalsoavailable.
LaravelalsoincludesdriversfortheMailgunandMandrillHTTPAPIs.TheseAPIsareoftensimplerandquickerthantheSMTPservers.BothofthesedriversrequirethattheGuzzle4HTTPlibrarybeinstalledintoyourapplication.YoucanaddGuzzle4toyourprojectbyaddingthefollowinglinetoyourcomposer.jsonfile:
"guzzlehttp/guzzle":"~4.0"
TousetheMailgundriver,setthedriveroptiontomailguninyourconfig/mail.phpconfigurationfile.Next,createanconfig/services.phpconfigurationfileifonedoesnotalreadyexistforyourproject.Verifythatitcontainsthefollowingoptions:
'mailgun'=>array(
'domain'=>'your-mailgun-domain',
'secret'=>'your-mailgun-key',
),
TousetheMandrilldriver,setthedriveroptiontomandrillinyourconfig/mail.phpconfigurationfile.Next,createanconfig/services.phpconfigurationfileifonedoesnotalreadyexistforyourproject.Verifythatitcontainsthefollowingoptions:
'mandrill'=>array(
'secret'=>'your-mandrill-key',
),
Ifthedriveroptionofyourconfig/mail.phpconfigurationfileissettolog,alle-mailswillbewrittentoyourlogfiles,andwillnotactuallybesenttoanyoftherecipients.Thisisprimarilyusefulforquick,localdebuggingandcontentverification.
Configuration
APIDrivers
MailgunDriver
MandrillDriver
LogDriver
BasicUsage
TheMail::sendmethodmaybeusedtosendane-mailmessage:
Mail::send('emails.welcome',array('key'=>'value'),function($message)
{
$message->to('[email protected]','JohnSmith')->subject('Welcome!');
});
Thefirstargumentpassedtothesendmethodisthenameoftheviewthatshouldbeusedasthee-mailbody.Thesecondisthedatatobepassedtotheview,oftenasanassociativearraywherethedataitemsareavailabletotheviewby$key.ThethirdisaClosureallowingyoutospecifyvariousoptionsonthee-mailmessage.
Note:A$messagevariableisalwayspassedtoe-mailviews,andallowstheinlineembeddingofattachments.So,itisbesttoavoidpassingamessagevariableinyourviewpayload.
YoumayalsospecifyaplaintextviewtouseinadditiontoanHTMLview:
Mail::send(array('html.view','text.view'),$data,$callback);
Or,youmayspecifyonlyonetypeofviewusingthehtmlortextkeys:
Mail::send(array('text'=>'view'),$data,$callback);
Youmayspecifyotheroptionsonthee-mailmessagesuchasanycarboncopiesorattachmentsaswell:
Mail::send('emails.welcome',$data,function($message)
{
$message->from('[email protected]','Laravel');
$message->to('[email protected]')->cc('[email protected]');
$message->attach($pathToFile);
});
Whenattachingfilestoamessage,youmayalsospecifyaMIMEtypeand/oradisplayname:
$message->attach($pathToFile,array('as'=>$display,'mime'=>$mime));
Ifyoujustneedtoe-mailasimplestringinsteadofanentireview,usetherawmethod:
Mail::raw('Texttoe-mail',function($message)
{
$message->from('[email protected]','Laravel');
$message->to('[email protected]')->cc('[email protected]');
});
Note:ThemessageinstancepassedtoaMail::sendClosureextendstheSwiftMailermessageclass,allowingyoutocallanymethodonthatclasstobuildyoure-mailmessages.
Embeddinginlineimagesintoyoure-mailsistypicallycumbersome;however,Laravelprovidesaconvenientwaytoattachimagestoyoure-mailsandretrievingtheappropriateCID.
EmbeddingInlineAttachments
<body>
Hereisanimage:
<imgsrc="<?phpecho$message->embed($pathToFile);?>">
</body>
<body>
Hereisanimagefromrawdata:
<imgsrc="<?phpecho$message->embedData($data,$name);?>">
</body>
Notethatthe$messagevariableisalwayspassedtoe-mailviewsbytheMailfacade.
Sincesendinge-mailmessagescandrasticallylengthentheresponsetimeofyourapplication,manydeveloperschoosetoqueuee-mailmessagesforbackgroundsending.Laravelmakesthiseasyusingitsbuilt-inunifiedqueueAPI.Toqueueamailmessage,simplyusethequeuemethodontheMailfacade:
Mail::queue('emails.welcome',$data,function($message)
{
$message->to('[email protected]','JohnSmith')->subject('Welcome!');
});
Youmayalsospecifythenumberofsecondsyouwishtodelaythesendingofthemailmessageusingthelatermethod:
Mail::later(5,'emails.welcome',$data,function($message)
{
$message->to('[email protected]','JohnSmith')->subject('Welcome!');
});
Ifyouwishtospecifyaspecificqueueor"tube"onwhichtopushthemessage,youmaydosousingthequeueOnandlaterOnmethods:
Mail::queueOn('queue-name','emails.welcome',$data,function($message)
{
$message->to('[email protected]','JohnSmith')->subject('Welcome!');
});
Whendevelopinganapplicationthatsendse-mail,it'susuallydesirabletodisablethesendingofmessagesfromyourlocalordevelopmentenvironment.Todoso,youmayeithercalltheMail::pretendmethod,orsetthepretendoptionintheconfig/mail.phpconfigurationfiletotrue.Whenthemailerisinpretendmode,messageswillbewrittentoyourapplication'slogfilesinsteadofbeingsenttotherecipient.
Ifyouwouldliketoactuallyviewtheteste-mails,considerusingaservicelikeMailTrap.
EmbeddingAnImageInAnE-MailView
EmbeddingRawDataInAnE-MailView
QueueingMail
QueueingAMailMessage
Mail&LocalDevelopment
IntroductionViewsTranslationsConfigurationPublishingFileGroupsRouting
PackagesaretheprimarywayofaddingfunctionalitytoLaravel.PackagesmightbeanythingfromagreatwaytoworkwithdateslikeCarbon,oranentireBDDtestingframeworklikeBehat.
Ofcourse,therearedifferenttypesofpackages.Somepackagesarestand-alone,meaningtheyworkwithanyframework,notjustLaravel.BothCarbonandBehatareexamplesofstand-alonepackages.AnyofthesepackagesmaybeusedwithLaravelbysimplyrequestingtheminyourcomposer.jsonfile.
Ontheotherhand,otherpackagesarespecificallyintendedforusewithLaravel.Thesepackagesmayhaveroutes,controllers,views,andconfigurationspecificallyintendedtoenhanceaLaravelapplication.ThisguideprimarilycoversthedevelopmentofthosethatareLaravelspecific.
AllLaravelpackagesaredistributedviaPackagistandComposer,solearningaboutthesewonderfulPHPpackagedistributiontoolsisessential.
Yourpackage'sinternalstructureisentirelyuptoyou;however,typicallyeachpackagewillcontainoneormoreserviceproviders.TheserviceprovidercontainsanyIoCbindings,aswellasinstructionsastowherepackageconfiguration,views,andtranslationfilesarelocated.
Packageviewsaretypicallyreferencedusingadouble-colon"namespace"syntax:
returnview('package::view.name');
AllyouneedtodoistellLaravelwheretheviewsforagivennamespacearelocated.Forexample,ifyourpackageisnamed"courier",youmightaddthefollowingtoyourserviceprovider'sbootmethod:
publicfunctionboot()
{
$this->loadViewsFrom(__DIR__.'/path/to/views','courier');
}
Nowyoumayloadyourpackageviewsusingthefollowingsyntax:
returnview('courier::view.name');
WhenyouusetheloadViewsFrommethod,Laravelactuallyregisterstwolocationsforyourviews:oneintheapplication'sresources/views/vendordirectoryandoneinthedirectoryyouspecify.So,usingourcourierexample:whenrequestinga
PackageDevelopment
Introduction
Views
Views
packageview,Laravelwillfirstcheckifacustomversionoftheviewhasbeenprovidedbythedeveloperinresources/views/vendor/courier.Then,iftheviewhasnotbeencustomized,LaravelwillsearchthepackageviewdirectoryyouspecifiedinyourcalltoloadViewsFrom.Thismakesiteasyforend-userstocustomize/overrideyourpackage'sviews.
Topublishyourpackage'sviewstotheresources/views/vendordirectory,youshouldusethepublishesmethodfromthebootmethodofyourserviceprovider:
publicfunctionboot()
{
$this->loadViewsFrom(__DIR__.'/path/to/views','courier');
$this->publishes([
__DIR__.'/path/to/views'=>base_path('resources/views/vendor/courier'),
]);
}
Now,whenusersofyourpackageexecuteLaravel'svendor:publishcommand,yourviewsdirectorywillbecopiedtothespecifiedlocation.
Ifyouwouldliketooverwriteexistingfiles,usethe--forceswitch:
phpartisanvendor:publish--force
Note:Youmayusethepublishesmethodtopublishanytypeoffiletoanylocationyouwish.
Packagetranslationfilesaretypicallyreferencedusingadouble-colonsyntax:
returntrans('package::file.line');
AllyouneedtodoistellLaravelwherethetranslationsforagivennamespacearelocated.Forexample,ifyourpackageisnamed"courier",youmightaddthefollowingtoyourserviceprovider'sbootmethod:
publicfunctionboot()
{
$this->loadTranslationsFrom(__DIR__.'/path/to/translations','courier');
}
Notethatwithinyourtranslationsfolder,youwouldhavefurtherdirectoriesforeachlanguage,suchasen,es,ru,etc.
Nowyoumayloadyourpackagetranslationsusingthefollowingsyntax:
returntrans('courier::file.line');
Typically,youwillwanttopublishyourpackage'sconfigurationfiletotheapplication'sownconfigdirectory.Thiswillallowusersofyourpackagetoeasilyoverrideyourdefaultconfigurationoptions.
Topublishaconfigurationfile,justusethepublishesmethodfromthebootmethodofyourserviceprovider:
PublishingViews
Translations
Configuration
$this->publishes([
__DIR__.'/path/to/config/courier.php'=>config_path('courier.php'),
]);
Now,whenusersofyourpackageexecuteLaravel'svendor:publishcommand,yourfilewillbecopiedtothespecifiedlocation.Ofcourse,onceyourconfigurationhasbeenpublished,itcanbeaccessedlikeanyotherconfigurationfile:
$value=config('courier.option');
Youmayalsochoosetomergeyourownpackageconfigurationfilewiththeapplication'scopy.Thisallowsyouruserstoincludeonlytheoptionstheyactuallywanttooverrideinthepublishedcopyoftheconfiguration.Tomergetheconfigurations,usethemergeConfigFrommethodwithinyourserviceprovider'sregistermethod:
$this->mergeConfigFrom(
__DIR__.'/path/to/config/courier.php','courier'
);
Youmaywanttopublishgroupsoffilesseparately.Forinstance,youmightwantyouruserstobeabletopublishyourpackage'sconfigurationfilesandassetfilesseparately.Youcandothisby'tagging'them:
//Publishaconfigfile
$this->publishes([
__DIR__.'/../config/package.php',config_path('package.php')
],'config');
//Publishyourmigrations
$this->publishes([
__DIR__.'/../database/migrations/'=>base_path('/database/migrations')
],'migrations');
Youcanthenpublishthesefilesseparatelybyreferencingtheirtaglikeso:
phpartisanvendor:publish--provider="Vendor\Providers\PackageServiceProvider"--tag="config"
Toloadaroutesfileforyourpackage,simplyincludeitfromwithinyourserviceprovider'sbootmethod.
publicfunctionboot()
{
include__DIR__.'/../../routes.php';
}
Note:Ifyourpackageisusingcontrollers,youwillneedtomakesuretheyareproperlyconfiguredinyourcomposer.jsonfile'sauto-loadsection.
PublishingFileGroups
Routing
IncludingARoutesFileFromAServiceProvider
ConfigurationUsageAppendingToPaginationLinksConvertingToJSON
Inotherframeworks,paginationcanbeverypainful.Laravelmakesitabreeze.Laravelcangenerateanintelligent"range"oflinksbasedonthecurrentpage.ThegeneratedHTMLiscompatiblewiththeBootstrapCSSframework.
Thereareseveralwaystopaginateitems.ThesimplestisbyusingthepaginatemethodonthequerybuilderoranEloquentmodel.
$users=DB::table('users')->paginate(15);
Note:Currently,paginationoperationsthatuseagroupBystatementcannotbeexecutedefficientlybyLaravel.IfyouneedtouseagroupBywithapaginatedresultset,itisrecommendedthatyouquerythedatabaseandcreateapaginatormanually.
Sometimesyoumaywishtocreateapaginationinstancemanually,passingitanarrayofitems.YoumaydosobycreatingeitheranIlluminate\Pagination\PaginatororIlluminate\Pagination\LengthAwarePaginatorinstance,dependingonyourneeds.
YoumayalsopaginateEloquentmodels:
$allUsers=User::paginate(15);
$someUsers=User::where('votes','>',100)->paginate(15);
Theargumentpassedtothepaginatemethodisthenumberofitemsyouwishtodisplayperpage.Onceyouhaveretrievedtheresults,youmaydisplaythemonyourview,andcreatethepaginationlinksusingtherendermethod:
<divclass="container">
<?phpforeach($usersas$user):?>
<?phpecho$user->name;?>
<?phpendforeach;?>
</div>
<?phpecho$users->render();?>
Thisisallittakestocreateapaginationsystem!Notethatwedidnothavetoinformtheframeworkofthecurrentpage.Laravelwilldeterminethisforyouautomatically.
Pagination
Configuration
Usage
PaginatingDatabaseResults
CreatingAPaginatorManually
PaginatingAnEloquentModel
Youmayalsoaccessadditionalpaginationinformationviathefollowingmethods:
currentPage
lastPage
perPage
total
count
Ifyouareonlyshowing"Next"and"Previous"linksinyourpaginationview,youhavetheoptionofusingthesimplePaginatemethodtoperformamoreefficientquery.Thisisusefulforlargerdatasetswhenyoudonotrequirethedisplayofexactpagenumbersonyourview:
$someUsers=User::where('votes','>',100)->simplePaginate(15);
YoumayalsocustomizetheURIusedbythepaginatorviathesetPathmethod:
$users=User::paginate();
$users->setPath('custom/url');
TheexampleabovewillcreateURLslikethefollowing:http://example.com/custom/url?page=2
YoucanaddtothequerystringofpaginationlinksusingtheappendsmethodonthePaginator:
<?phpecho$users->appends(['sort'=>'votes'])->render();?>
ThiswillgenerateURLsthatlooksomethinglikethis:
http://example.com/something?page=2&sort=votes
Ifyouwishtoappenda"hashfragment"tothepaginator'sURLs,youmayusethefragmentmethod:
<?phpecho$users->fragment('foo')->render();?>
ThismethodcallwillgenerateURLsthatlooksomethinglikethis:
http://example.com/something?page=2#foo
ThePaginatorclassimplementstheIlluminate\Contracts\Support\JsonableInterfacecontractandexposesthetoJsonmethod.YoumayalsoconvertaPaginatorinstancetoJSONbyreturningitfromaroute.TheJSON'dformoftheinstancewillincludesome"meta"informationsuchastotal,current_page,andlast_page.Theinstance'sdatawillbeavailable
"SimplePagination"
CustomizingThePaginatorURI
AppendingToPaginationLinks
ConvertingToJSON
viathedatakeyintheJSONarray.
ConfigurationBasicUsageQueueingClosuresRunningTheQueueListenerDaemonQueueWorkerPushQueuesFailedJobs
TheLaravelQueuecomponentprovidesaunifiedAPIacrossavarietyofdifferentqueueservices.Queuesallowyoutodefertheprocessingofatimeconsumingtask,suchassendingane-mail,untilalatertime,thusdrasticallyspeedingupthewebrequeststoyourapplication.
Thequeueconfigurationfileisstoredinconfig/queue.php.Inthisfileyouwillfindconnectionconfigurationsforeachofthequeuedriversthatareincludedwiththeframework,whichincludesadatabase,Beanstalkd,IronMQ,AmazonSQS,Redis,null,andsynchronous(forlocaluse)driver.Thenullqueuedriversimplydiscardsqueuedjobssotheyareneverrun.
Inordertousethedatabasequeuedriver,youwillneedadatabasetabletoholdthejobs.Togenerateamigrationtocreatethistable,runthequeue:tableArtisancommand:
phpartisanqueue:table
Thefollowingdependenciesareneededforthelistedqueuedrivers:
AmazonSQS:aws/aws-sdk-phpBeanstalkd:pda/pheanstalk~3.0IronMQ:iron-io/iron_mqRedis:predis/predis~1.0
AllofthequeueablejobsforyourapplicationarestoredintheApp\Commandsdirectory.YoumaygenerateanewqueuedcommandusingtheArtisanCLI:
phpartisanmake:commandSendEmail--queued
Topushanewjobontothequeue,usetheQueue::pushmethod:
Queue::push(newSendEmail($message));
Queues
Configuration
QueueDatabaseTable
OtherQueueDependencies
BasicUsage
PushingAJobOntoTheQueue
Note:Inthisexample,weareusingtheQueuefacadedirectly;however,typicallyyouwoulddispatchqueuedcommandviatheCommandBus.WewillcontinuetousetheQueuefacadethroughoutthispage;however,familiarizewiththecommandbusaswell,sinceitisusedtodispatchbothqueuedandsynchronouscommandsforyourapplication.
Bydefault,themake:commandArtisancommandgeneratesa"self-handling"command,meaningahandlemethodisaddedtothecommanditself.Thismethodwillbecalledwhenthejobisexecutedbythequeue.Youmaytype-hintanydependenciesyouneedonthehandlemethodandtheIoCcontainerwillautomaticallyinjectthem:
publicfunctionhandle(UserRepository$users)
{
//
}
Ifyouwouldlikeyourcommandtohaveaseparatehandlerclass,youshouldaddthe--handlerflagtothemake:commandcommand:
phpartisanmake:commandSendEmail--queued--handler
ThegeneratedhandlerwillbeplacedinApp\Handlers\CommandsandwillberesolvedoutoftheIoCcontainer.
Youmayalsospecifythequeue/tubeajobshouldbesentto:
Queue::pushOn('emails',newSendEmail($message));
Ifyouneedtopassthesamedatatoseveralqueuejobs,youmayusetheQueue::bulkmethod:
Queue::bulk(array(newSendEmail($message),newAnotherCommand));
Sometimesyoumaywishtodelaytheexecutionofaqueuedjob.Forinstance,youmaywishtoqueueajobthatsendsacustomerane-mail15minutesaftersign-up.YoucanaccomplishthisusingtheQueue::latermethod:
$date=Carbon::now()->addMinutes(15);
Queue::later($date,newSendEmail($message));
Inthisexample,we'reusingtheCarbondatelibrarytospecifythedelaywewishtoassigntothejob.Alternatively,youmaypassthenumberofsecondsyouwishtodelayasaninteger.
Note:TheAmazonSQSservicehasadelaylimitof900seconds(15minutes).
IfyourqueuedjobacceptsanEloquentmodelinitsconstructor,onlytheidentifierforthemodelwillbeserializedontothequeue.Whenthejobisactuallyhandled,thequeuesystemwillautomaticallyre-retrievethefullmodelinstancefromthedatabase.It'salltotallytransparenttoyourapplicationandpreventsissuesthatcanarisefromserializingfullEloquent
SpecifyingTheQueue/TubeForAJob
PassingTheSamePayloadToMultipleJobs
DelayingTheExecutionOfAJob
QueuesAndEloquentModels
modelinstances.
Onceyouhaveprocessedajob,itmustbedeletedfromthequeue.Ifnoexceptionisthrownduringtheexecutionofyourjob,thiswillbedoneautomatically.
Ifyouwouldliketodeleteorreleasethejobmanually,theIlluminate\Queue\InteractsWithQueuetraitprovidesaccesstothequeuejobreleaseanddeletemethods.Thereleasemethodacceptsasinglevalue:thenumberofsecondsyouwishtowaituntilthejobismadeavailableagain.
publicfunctionhandle(SendEmail$command)
{
if(true)
{
$this->release(30);
}
}
IFanexceptionisthrownwhilethejobisbeingprocessed,itwillautomaticallybereleasedbackontothequeuesoitmaybeattemptedagain.Thejobwillcontinuetobereleaseduntilithasbeenattemptedthemaximumnumberoftimesallowedbyyourapplication.Thenumberofmaximumattemptsisdefinedbythe--triesswitchusedonthequeue:listenorqueue:workArtisancommands.
Ifanexceptionoccurswhilethejobisbeingprocessed,itwillautomaticallybereleasedbackontothequeue.Youmaycheckthenumberofattemptsthathavebeenmadetorunthejobusingtheattemptsmethod:
if($this->attempts()>3)
{
//
}
Note:Yourcommand/handlermustusetheIlluminate\Queue\InteractsWithQueuetraitinordertocallthismethod.
YoumayalsopushaClosureontothequeue.Thisisveryconvenientforquick,simpletasksthatneedtobequeued:
Queue::push(function($job)use($id)
{
Account::delete($id);
$job->delete();
});
Note:InsteadofmakingobjectsavailabletoqueuedClosuresviatheusedirective,considerpassingprimarykeysandre-pullingtheassociatedmodelsfromwithinyourqueuejob.Thisoftenavoidsunexpectedserializationbehavior.
WhenusingIron.iopushqueues,youshouldtakeextraprecautionqueueingClosures.Theend-pointthatreceivesyourqueuemessagesshouldcheckforatokentoverifythattherequestisactuallyfromIron.io.Forexample,yourpushqueueend-pointshouldbesomethinglike:https://yourapp.com/queue/receive?token=SecretToken.Youmaythencheckthevalue
DeletingAProcessedJob
ReleasingAJobBackOntoTheQueue
CheckingTheNumberOfRunAttempts
QueueingClosures
PushingAClosureOntoTheQueue
ofthesecrettokeninyourapplicationbeforemarshallingthequeuerequest.
LaravelincludesanArtisantaskthatwillrunnewjobsastheyarepushedontothequeue.Youmayrunthistaskusingthequeue:listencommand:
phpartisanqueue:listen
Youmayalsospecifywhichqueueconnectionthelistenershouldutilize:
phpartisanqueue:listenconnection
Notethatoncethistaskhasstarted,itwillcontinuetorununtilitismanuallystopped.YoumayuseaprocessmonitorsuchasSupervisortoensurethatthequeuelistenerdoesnotstoprunning.
Youmaypassacomma-delimitedlistofqueueconnectionstothelistencommandtosetqueuepriorities:
phpartisanqueue:listen--queue=high,low
Inthisexample,jobsonthehigh-connectionwillalwaysbeprocessedbeforemovingontojobsfromthelow-connection.
Youmayalsosetthelengthoftime(inseconds)eachjobshouldbeallowedtorun:
phpartisanqueue:listen--timeout=60
Inaddition,youmayspecifythenumberofsecondstowaitbeforepollingfornewjobs:
phpartisanqueue:listen--sleep=5
Notethatthequeueonly"sleeps"ifnojobsareonthequeue.Ifmorejobsareavailable,thequeuewillcontinuetoworkthemwithoutsleeping.
Toprocessonlythefirstjobonthequeue,youmayusethequeue:workcommand:
phpartisanqueue:work
Thequeue:workalsoincludesa--daemonoptionforforcingthequeueworkertocontinueprocessingjobswithouteverre-
RunningTheQueueListener
StartingTheQueueListener
SpecifyingTheJobTimeoutParameter
SpecifyingQueueSleepDuration
ProcessingTheFirstJobOnTheQueue
DaemonQueueWorker
bootingtheframework.ThisresultsinasignificantreductionofCPUusagewhencomparedtothequeue:listencommand,butattheaddedcomplexityofneedingtodrainthequeuesofcurrentlyexecutingjobsduringyourdeployments.
Tostartaqueueworkerindaemonmode,usethe--daemonflag:
phpartisanqueue:workconnection--daemon
phpartisanqueue:workconnection--daemon--sleep=3
phpartisanqueue:workconnection--daemon--sleep=3--tries=3
Asyoucansee,thequeue:workcommandsupportsmostofthesameoptionsavailabletoqueue:listen.Youmayusethephpartisanhelpqueue:workcommandtoviewalloftheavailableoptions.
Thesimplestwaytodeployanapplicationusingdaemonqueueworkersistoputtheapplicationinmaintenancemodeatthebeginningofyourdeployment.Thiscanbedoneusingthephpartisandowncommand.Oncetheapplicationisinmaintenancemode,Laravelwillnotacceptanynewjobsoffofthequeue,butwillcontinuetoprocessexistingjobs.
Theeasiestwaytorestartyourworkersistoincludethefollowingcommandinyourdeploymentscript:
phpartisanqueue:restart
Thiscommandwillinstructallqueueworkerstorestartaftertheyfinishprocessingtheircurrentjob.
Note:Thiscommandreliesonthecachesystemtoscheduletherestart.Bydefault,APCudoesnotworkforCLIcommands.IfyouareusingAPCu,addapc.enable_cli=1toyourAPCuconfiguration.
Daemonqueueworkersdonotrestarttheframeworkbeforeprocessingeachjob.Therefore,youshouldbecarefultofreeanyheavyresourcesbeforeyourjobfinishes.Forexample,ifyouaredoingimagemanipulationwiththeGDlibrary,youshouldfreethememorywithimagedestroywhenyouaredone.
Similarly,yourdatabaseconnectionmaydisconnectwhenbeingusedbylong-runningdaemon.YoumayusetheDB::reconnectmethodtoensureyouhaveafreshconnection.
PushqueuesallowyoutoutilizethepowerfulLaravel4queuefacilitieswithoutrunninganydaemonsorbackgroundlisteners.Currently,pushqueuesareonlysupportedbytheIron.iodriver.Beforegettingstarted,createanIron.ioaccount,andaddyourIroncredentialstotheconfig/queue.phpconfigurationfile.
Next,youmayusethequeue:subscribeArtisancommandtoregisteraURLend-pointthatwillreceivenewlypushedqueuejobs:
phpartisanqueue:subscribequeue_namehttp://foo.com/queue/receive
Now,whenyoulogintoyourIrondashboard,youwillseeyournewpushqueue,aswellasthesubscribedURL.YoumaysubscribeasmanyURLsasyouwishtoagivenqueue.Next,createarouteforyourqueue/receiveend-pointandreturntheresponsefromtheQueue::marshalmethod:
DeployingWithDaemonQueueWorkers
CodingForDaemonQueueWorkers
PushQueues
RegisteringAPushQueueSubscriber
Route::post('queue/receive',function()
{
returnQueue::marshal();
});
Themarshalmethodwilltakecareoffiringthecorrectjobhandlerclass.Tofirejobsontothepushqueue,justusethesameQueue::pushmethodusedforconventionalqueues.
Sincethingsdon'talwaysgoasplanned,sometimesyourqueuedjobswillfail.Don'tworry,ithappenstothebestofus!Laravelincludesaconvenientwaytospecifythemaximumnumberoftimesajobshouldbeattempted.Afterajobhasexceededthisamountofattempts,itwillbeinsertedintoafailed_jobstable.Thefailedjobstablenamecanbeconfiguredviatheconfig/queue.phpconfigurationfile.
Tocreateamigrationforthefailed_jobstable,youmayusethequeue:failed-tablecommand:
phpartisanqueue:failed-table
Youcanspecifythemaximumnumberoftimesajobshouldbeattemptedusingthe--triesswitchonthequeue:listencommand:
phpartisanqueue:listenconnection-name--tries=3
Ifyouwouldliketoregisteraneventthatwillbecalledwhenaqueuejobfails,youmayusetheQueue::failingmethod.Thiseventisagreatopportunitytonotifyyourteamviae-mailorHipChat.
Queue::failing(function($connection,$job,$data)
{
//
});
Youmayalsodefineafailedmethoddirectlyonaqueuejobclass,allowingyoutoperformjobspecificactionswhenafailureoccurs:
publicfunctionfailed()
{
//Calledwhenthejobisfailing...
}
Toviewallofyourfailedjobs,youmayusethequeue:failedArtisancommand:
phpartisanqueue:failed
Thequeue:failedcommandwilllistthejobID,connection,queue,andfailuretime.ThejobIDmaybeusedtoretrythefailedjob.Forinstance,toretryafailedjobthathasanIDof5,thefollowingcommandshouldbeissued:
phpartisanqueue:retry5
FailedJobs
RetryingFailedJobs
Ifyouwouldliketodeleteafailedjob,youmayusethequeue:forgetcommand:
phpartisanqueue:forget5
Todeleteallofyourfailedjobs,youmayusethequeue:flushcommand:
phpartisanqueue:flush
ConfigurationSessionUsageFlashDataDatabaseSessionsSessionDrivers
SinceHTTPdrivenapplicationsarestateless,sessionsprovideawaytostoreinformationabouttheuseracrossrequests.Laravelshipswithavarietyofsessionback-endsavailableforusethroughaclean,unifiedAPI.Supportforpopularback-endssuchasMemcached,Redis,anddatabasesisincludedoutofthebox.
Thesessionconfigurationisstoredinconfig/session.php.Besuretoreviewthewelldocumentedoptionsavailabletoyouinthisfile.Bydefault,Laravelisconfiguredtousethefilesessiondriver,whichwillworkwellforthemajorityofapplications.
BeforeusingRedissessionswithLaravel,youwillneedtoinstallthepredis/predispackage(~1.0)viaComposer.
Note:Ifyouneedallstoredsessiondatatobeencrypted,settheencryptconfigurationoptiontotrue.
TheLaravelframeworkusestheflashsessionkeyinternally,soyoushouldnotaddanitemtothesessionbythatname.
Session::put('key','value');
Session::push('user.teams','developers');
$value=Session::get('key');
$value=Session::get('key','default');
$value=Session::get('key',function(){return'default';});
Session
Configuration
ReservedKeys
SessionUsage
StoringAnItemInTheSession
PushAValueOntoAnArraySessionValue
RetrievingAnItemFromTheSession
RetrievingAnItemOrReturningADefaultValue
RetrievingAnItemAndForgettingIt
$value=Session::pull('key','default');
$data=Session::all();
if(Session::has('users'))
{
//
}
Session::forget('key');
Session::flush();
Session::regenerate();
Sometimesyoumaywishtostoreitemsinthesessiononlyforthenextrequest.YoumaydosousingtheSession::flashmethod:
Session::flash('key','value');
Session::reflash();
Session::keep(array('username','email'));
Whenusingthedatabasesessiondriver,youwillneedtosetupatabletocontainthesessionitems.BelowisanexampleSchemadeclarationforthetable:
RetrievingAllDataFromTheSession
DeterminingIfAnItemExistsInTheSession
RemovingAnItemFromTheSession
RemovingAllItemsFromTheSession
RegeneratingTheSessionID
FlashData
ReflashingTheCurrentFlashDataForAnotherRequest
ReflashingOnlyASubsetOfFlashData
DatabaseSessions
Schema::create('sessions',function($table)
{
$table->string('id')->unique();
$table->text('payload');
$table->integer('last_activity');
});
Ofcourse,youmayusethesession:tableArtisancommandtogeneratethismigrationforyou!
phpartisansession:table
composerdump-autoload
phpartisanmigrate
Thesession"driver"defineswheresessiondatawillbestoredforeachrequest.Laravelshipswithseveralgreatdriversoutofthebox:
file-sessionswillbestoredinapp/storage/sessions.cookie-sessionswillbestoredinsecure,encryptedcookies.database-sessionswillbestoredinadatabaseusedbyyourapplication.memcached/redis-sessionswillbestoredinoneofthesefast,cachedbasedstores.array-sessionswillbestoredinasimplePHParrayandwillnotbepersistedacrossrequests.
Note:Thearraydriveristypicallyusedforrunningunittests,sonosessiondatawillbepersisted.
SessionDrivers
BladeTemplatingOtherBladeControlStructuresExtendingBlade
Bladeisasimple,yetpowerfultemplatingengineprovidedwithLaravel.Unlikecontrollerlayouts,Bladeisdrivenbytemplateinheritanceandsections.AllBladetemplatesshouldusethe.blade.phpextension.
<!--Storedinresources/views/layouts/master.blade.php-->
<html>
<body>
@section('sidebar')
Thisisthemastersidebar.
@show
<divclass="container">
@yield('content')
</div>
</body>
</html>
@extends('layouts.master')
@section('sidebar')
@@parent
<p>Thisisappendedtothemastersidebar.</p>
@stop
@section('content')
<p>Thisismybodycontent.</p>
@stop
NotethatviewswhichextendaBladelayoutsimplyoverridesectionsfromthelayout.Contentofthelayoutcanbeincludedinachildviewusingthe@@parentdirectiveinasection,allowingyoutoappendtothecontentsofalayoutsectionsuchasasidebarorfooter.
Sometimes,suchaswhenyouarenotsureifasectionhasbeendefined,youmaywishtopassadefaultvaluetothe@yielddirective.Youmaypassthedefaultvalueasthesecondargument:
@yield('section','DefaultContent')
Hello,{{$name}}.
Templates
BladeTemplating
DefiningABladeLayout
UsingABladeLayout
OtherBladeControlStructures
EchoingData
ThecurrentUNIXtimestampis{{time()}}.
Sometimesyoumaywishtoechoavariable,butyouaren'tsureifthevariablehasbeenset.Basically,youwanttodothis:
{{isset($name)?$name:'Default'}}
However,insteadofwritingaternarystatement,Bladeallowsyoutousethefollowingconvenientshort-cut:
{{$nameor'Default'}}
Ifyouneedtodisplayastringthatiswrappedincurlybraces,youmayescapetheBladebehaviorbyprefixingyourtextwithan@symbol:
@{{ThiswillnotbeprocessedbyBlade}}
Ifyoudon'twantthedatatobeescaped,youmayusethefollowingsyntax:
Hello,{!!$name!!}.
Note:Beverycarefulwhenechoingcontentthatissuppliedbyusersofyourapplication.AlwaysusethedoublecurlybracesyntaxtoescapeanyHTMLentitiesinthecontent.
@if(count($records)===1)
Ihaveonerecord!
@elseif(count($records)>1)
Ihavemultiplerecords!
@else
Idon'thaveanyrecords!
@endif
@unless(Auth::check())
Youarenotsignedin.
@endunless
@for($i=0;$i<10;$i++)
Thecurrentvalueis{{$i}}
@endfor
@foreach($usersas$user)
<p>Thisisuser{{$user->id}}</p>
@endforeach
@forelse($usersas$user)
<li>{{$user->name}}</li>
@empty
<p>Nousers</p>
@endforelse
EchoingDataAfterCheckingForExistence
DisplayingRawTextWithCurlyBraces
IfStatements
Loops
@while(true)
<p>I'mloopingforever.</p>
@endwhile
@include('view.name')
Youmayalsopassanarrayofdatatotheincludedview:
@include('view.name',['some'=>'data'])
Tooverwriteasectionentirely,youmayusetheoverwritestatement:
@extends('list.item.container')
@section('list.item.content')
<p>Thisisanitemoftype{{$item->type}}</p>
@overwrite
@lang('language.line')
@choice('language.line',1)
{{--ThiscommentwillnotbeintherenderedHTML--}}
Bladeevenallowsyoutodefineyourowncustomcontrolstructures.WhenaBladefileiscompiled,eachcustomextensioniscalledwiththeviewcontents,allowingyoutodoanythingfromsimplestr_replacemanipulationstomorecomplexregularexpressions.
TheBladecompilercomeswiththehelpermethodscreateMatcherandcreatePlainMatcher,whichgeneratetheexpressionyouneedtobuildyourowncustomdirectives.
ThecreatePlainMatchermethodisusedfordirectiveswithnoargumentslike@endifand@stop,whilecreateMatcherisusedfordirectiveswitharguments.
Thefollowingexamplecreatesa@datetime($var)directivewhichsimplycalls->format()on$var:
Blade::extend(function($view,$compiler)
{
$pattern=$compiler->createMatcher('datetime');
returnpreg_replace($pattern,'$1<?phpecho$2->format(\'m/d/YH:i\');?>',$view);
});
IncludingSub-Views
OverwritingSections
DisplayingLanguageLines
Comments
ExtendingBlade
IntroductionDefining&RunningTestsTestEnvironmentCallingRoutesFromTestsMockingFacadesFrameworkAssertionsHelperMethodsRefreshingTheApplication
Laravelisbuiltwithunittestinginmind.Infact,supportfortestingwithPHPUnitisincludedoutofthebox,andaphpunit.xmlfileisalreadysetupforyourapplication.
Anexampletestfileisprovidedinthetestsdirectory.AfterinstallinganewLaravelapplication,simplyrunphpunitonthecommandlinetorunyourtests.
Tocreateatestcase,simplycreateanewtestfileinthetestsdirectory.ThetestclassshouldextendTestCase.YoumaythendefinetestmethodsasyounormallywouldwhenusingPHPUnit.
classFooTestextendsTestCase{
publicfunctiontestSomethingIsTrue()
{
$this->assertTrue(true);
}
}
Youmayrunallofthetestsforyourapplicationbyexecutingthephpunitcommandfromyourterminal.
Note:IfyoudefineyourownsetUpmethod,besuretocallparent::setUp.
Whenrunningunittests,Laravelwillautomaticallysettheconfigurationenvironmenttotesting.Also,Laravelincludesconfigurationfilesforsessionandcacheinthetestenvironment.Bothofthesedriversaresettoarraywhileinthetestenvironment,meaningnosessionorcachedatawillbepersistedwhiletesting.Youarefreetocreateothertestingenvironmentconfigurationsasnecessary.
Thetestingenvironmentvariablesmaybeconfiguredinthephpunit.xmlfile.
Testing
Introduction
Defining&RunningTests
AnExampleTestClass
TestEnvironment
CallingRoutesFromTests
CallingARouteFromATest
Youmayeasilycalloneofyourroutesforatestusingthecallmethod:
$response=$this->call('GET','user/profile');
$response=$this->call($method,$uri,$parameters,$files,$server,$content);
YoumaytheninspecttheIlluminate\Http\Responseobject:
$this->assertEquals('HelloWorld',$response->getContent());
Youmayalsocallacontrollerfromatest:
$response=$this->action('GET','HomeController@index');
$response=$this->action('GET','UserController@profile',array('user'=>1));
Note:Youdonotneedtospecifythefullcontrollernamespacewhenusingtheactionmethod.OnlyspecifytheportionoftheclassnamethatfollowstheApp\Http\Controllersnamespace.
ThegetContentmethodwillreturntheevaluatedstringcontentsoftheresponse.IfyourroutereturnsaView,youmayaccessitusingtheoriginalproperty:
$view=$response->original;
$this->assertEquals('John',$view['name']);
TocallaHTTPSroute,youmayusethecallSecuremethod:
$response=$this->callSecure('GET','foo/bar');
Whentesting,youmayoftenwanttomockacalltoaLaravelstaticfacade.Forexample,considerthefollowingcontrolleraction:
publicfunctiongetIndex()
{
Event::fire('foo',['name'=>'Dayle']);
return'Alldone!';
}
WecanmockthecalltotheEventclassbyusingtheshouldReceivemethodonthefacade,whichwillreturnaninstanceofaMockerymock.
publicfunctiontestGetIndex()
{
Event::shouldReceive('fire')->once()->with('foo',['name'=>'Dayle']);
CallingAControllerFromATest
MockingFacades
MockingAFacade
$this->call('GET','/');
}
Note:YoushouldnotmocktheRequestfacade.Instead,passtheinputyoudesireintothecallmethodwhenrunningyourtest.
Laravelshipswithseveralassertmethodstomaketestingalittleeasier:
publicfunctiontestMethod()
{
$this->call('GET','/');
$this->assertResponseOk();
}
$this->assertResponseStatus(403);
$this->assertRedirectedTo('foo');
$this->assertRedirectedToRoute('route.name');
$this->assertRedirectedToAction('Controller@method');
publicfunctiontestMethod()
{
$this->call('GET','/');
$this->assertViewHas('name');
$this->assertViewHas('age',$value);
}
publicfunctiontestMethod()
{
$this->call('GET','/');
$this->assertSessionHas('name');
$this->assertSessionHas('age',$value);
}
publicfunctiontestMethod()
{
FrameworkAssertions
AssertingResponsesAreOK
AssertingResponseStatuses
AssertingResponsesAreRedirects
AssertingAViewHasSomeData
AssertingTheSessionHasSomeData
AssertingTheSessionHasErrors
$this->call('GET','/');
$this->assertSessionHasErrors();
//Assertingthesessionhaserrorsforagivenkey...
$this->assertSessionHasErrors('name');
//Assertingthesessionhaserrorsforseveralkeys...
$this->assertSessionHasErrors(array('name','age'));
}
publicfunctiontestMethod()
{
$this->call('GET','/');
$this->assertHasOldInput();
}
TheTestCaseclasscontainsseveralhelpermethodstomaketestingyourapplicationeasier.
$this->session(['foo'=>'bar']);
$this->flushSession();
Youmaysetthecurrentlyauthenticateduserusingthebemethod:
$user=newUser(array('name'=>'John'));
$this->be($user);
Youmayre-seedyourdatabasefromatestusingtheseedmethod:
$this->seed();
$this->seed($connection);
Moreinformationoncreatingseedsmaybefoundinthemigrationsandseedingsectionofthedocumentation.
Asyoumayalreadyknow,youcanaccessyourLaravelApplication/IoCContainervia$this->appfromanytestmethod.ThisApplicationinstanceisrefreshedforeachtestclass.IfyouwishtomanuallyforcetheApplicationtoberefreshedforagivenmethod,youmayusetherefreshApplicationmethodfromyourtestmethod.Thiswillresetanyextrabindings,suchasmocks,thathavebeenplacedintheIoCcontainersincethetestcasestartedrunning.
AssertingOldInputHasSomeData
HelperMethods
SettingAndFlushingSessionsFromTests
SettingTheCurrentlyAuthenticatedUser
Re-SeedingDatabaseFromTests
RefreshingTheApplication
BasicUsageControllerValidationFormRequestValidationWorkingWithErrorMessagesErrorMessages&ViewsAvailableValidationRulesConditionallyAddingRulesCustomErrorMessagesCustomValidationRules
Laravelshipswithasimple,convenientfacilityforvalidatingdataandretrievingvalidationerrormessagesviatheValidationclass.
$validator=Validator::make(
array('name'=>'Dayle'),
array('name'=>'required|min:5')
);
Thefirstargumentpassedtothemakemethodisthedataundervalidation.Thesecondargumentisthevalidationrulesthatshouldbeappliedtothedata.
Multiplerulesmaybedelimitedusingeithera"pipe"character,orasseparateelementsofanarray.
$validator=Validator::make(
array('name'=>'Dayle'),
array('name'=>array('required','min:5'))
);
$validator=Validator::make(
array(
'name'=>'Dayle',
'password'=>'lamepassword',
'email'=>'[email protected]'
),
array(
'name'=>'required',
'password'=>'required|min:8',
'email'=>'required|email|unique:users'
)
);
OnceaValidatorinstancehasbeencreated,thefails(orpasses)methodmaybeusedtoperformthevalidation.
if($validator->fails())
{
Validation
BasicUsage
BasicValidationExample
UsingArraysToSpecifyRules
ValidatingMultipleFields
//Thegivendatadidnotpassvalidation
}
Ifvalidationhasfailed,youmayretrievetheerrormessagesfromthevalidator.
$messages=$validator->messages();
Youmayalsoaccessanarrayofthefailedvalidationrules,withoutmessages.Todoso,usethefailedmethod:
$failed=$validator->failed();
TheValidatorclassprovidesseveralrulesforvalidatingfiles,suchassize,mimes,andothers.Whenvalidatingfiles,youmaysimplypassthemintothevalidatorwithyourotherdata.
Thevalidatoralsoallowsyoutoattachcallbackstoberunaftervalidationiscompleted.Thisallowsyoutoeasilyperformfurthervalidation,andevenaddmoreerrormessagestothemessagecollection.Togetstarted,usetheaftermethodonavalidatorinstance:
$validator=Validator::make(...);
$validator->after(function($validator)
{
if($this->somethingElseIsInvalid())
{
$validator->errors()->add('field','Somethingiswrongwiththisfield!');
}
});
if($validator->fails())
{
//
}
Youmayaddasmanyaftercallbackstoavalidatorasneeded.
Ofcourse,manuallycreatingandcheckingaValidatorinstanceeachtimeyoudovalidationisaheadache.Don'tworry,youhaveotheroptions!ThebaseApp\Http\Controllers\ControllerclassincludedwithLaravelusesaValidatesRequeststrait.Thistraitprovidesasingle,convenientmethodforvalidatingincomingHTTPrequests.Here'swhatitlookslike:
/**
*Storetheincomingblogpost.
*
*@paramRequest$request
*@returnResponse
*/
publicfunctionstore(Request$request)
{
$this->validate($request,[
'title'=>'required|unique|max:255',
'body'=>'required',
]);
//
}
ValidatingFiles
AfterValidationHook
ControllerValidation
Ifvalidationpasses,yourcodewillkeepexecutingnormally.However,ifvalidationfails,anIlluminate\Contracts\Validation\ValidationExceptionwillbethrown.Thisexceptionisautomaticallycaughtandaredirectisgeneratedtotheuser'spreviouslocation.Thevalidationerrorsareevenautomaticallyflashedtothesession!
IftheincomingrequestwasanAJAXrequest,noredirectwillbegenerated.Instead,anHTTPresponsewitha422statuscodewillbereturnedtothebrowsercontainingaJSONrepresentationofthevalidationerrors.
Forexample,hereistheequivalentcodewrittenmanually:
/**
*Storetheincomingblogpost.
*
*@paramRequest$request
*@returnResponse
*/
publicfunctionstore(Request$request)
{
$v=Validator::make($request->all(),[
'title'=>'required|unique|max:255',
'body'=>'required',
]);
if($v->fails())
{
returnredirect()->back()->withErrors($v->errors());
}
//
}
Ifyouwishtocustomizetheformatofthevalidationerrorsthatareflashedtothesessionwhenvalidationfails,overridetheformatValidationErrorsonyourbasecontroller.Don'tforgettoimporttheIlluminate\Validation\Validatorclassatthetopofthefile:
/**
*{@inheritdoc}
*/
protectedfunctionformatValidationErrors(Validator$validator)
{
return$validator->errors()->all();
}
Formorecomplexvalidationscenarios,youmaywishtocreatea"formrequest".Formrequestsarecustomrequestclassesthatcontainvalidationlogic.Tocreateaformrequestclass,usethemake:requestArtisanCLIcommand:
phpartisanmake:requestStoreBlogPostRequest
Thegeneratedclasswillbeplacedintheapp/Http/Requestsdirectory.Let'saddafewvalidationrulestotherulesmethod:
/**
*Getthevalidationrulesthatapplytotherequest.
*
*@returnarray
*/
publicfunctionrules()
CustomizingTheFlashedErrorFormat
FormRequestValidation
{
return[
'title'=>'required|unique|max:255',
'body'=>'required',
];
}
So,howarethevalidationrulesexecuted?Allyouneedtodoistype-hinttherequestonyourcontrollermethod:
/**
*Storetheincomingblogpost.
*
*@paramStoreBlogPostRequest$request
*@returnResponse
*/
publicfunctionstore(StoreBlogPostRequest$request)
{
//Theincomingrequestisvalid...
}
Theincomingformrequestisvalidatedbeforethecontrollermethodiscalled,meaningyoudonotneedtoclutteryourcontrollerwithanyvalidationlogic.Ithasalreadybeenvalidated!
Ifvalidationfails,aredirectresponsewillbegeneratedtosendtheuserbacktotheirpreviouslocation.Theerrorswillalsobeflashedtothesessionsotheyareavailablefordisplay.IftherequestwasanAJAXrequest,aHTTPresponsewitha422statuscodewillbereturnedtotheuserincludingaJSONrepresentationofthevalidationerrors.
Theformrequestclassalsocontainsanauthorizemethod.Withinthismethod,youmaycheckiftheauthenticateduseractuallyhastheauthoritytoupdateagivenresource.Forexample,ifauserisattemptingtoupdateablogpostcomment,dotheyactuallyownthatcomment?Forexample:
/**
*Determineiftheuserisauthorizedtomakethisrequest.
*
*@returnbool
*/
publicfunctionauthorize()
{
$commentId=$this->route('comment');
returnComment::where('id',$commentId)
->where('user_id',Auth::id())->exists();
}
Notethecalltotheroutemethodintheexampleabove.ThismethodgrantsyouaccesstotheURIparametersdefinedontheroutebeingcalled,suchasthe{comment}parameterintheexamplebelow:
Route::post('comment/{comment}');
Iftheauthorizemethodreturnsfalse,aHTTPresponsewitha403statuscodewillautomaticallybereturnedandyourcontrollermethodwillnotexecute.
Ifyouplantohaveauthorizationlogicinanotherpartofyourapplication,simplyreturntruefromtheauthorizemethod:
/**
*Determineiftheuserisauthorizedtomakethisrequest.
*
*@returnbool
*/
publicfunctionauthorize()
AuthorizingFormRequests
{
returntrue;
}
Ifyouwishtocustomizetheformatofthevalidationerrorsthatareflashedtothesessionwhenvalidationfails,overridetheformatValidationErrorsonyourbaserequest(App\Http\Requests\Request).Don'tforgettoimporttheIlluminate\Validation\Validatorclassatthetopofthefile:
/**
*{@inheritdoc}
*/
protectedfunctionformatErrors(Validator$validator)
{
return$validator->errors()->all();
}
AftercallingthemessagesmethodonaValidatorinstance,youwillreceiveaMessageBaginstance,whichhasavarietyofconvenientmethodsforworkingwitherrormessages.
echo$messages->first('email');
foreach($messages->get('email')as$message)
{
//
}
foreach($messages->all()as$message)
{
//
}
if($messages->has('email'))
{
//
}
echo$messages->first('email','<p>:message</p>');
CustomizingTheFlashedErrorFormat
WorkingWithErrorMessages
RetrievingTheFirstErrorMessageForAField
RetrievingAllErrorMessagesForAField
RetrievingAllErrorMessagesForAllFields
DeterminingIfMessagesExistForAField
RetrievingAnErrorMessageWithAFormat
Note:Bydefault,messagesareformattedusingBootstrapcompatiblesyntax.
foreach($messages->all('<li>:message</li>')as$message)
{
//
}
Onceyouhaveperformedvalidation,youwillneedaneasywaytogettheerrormessagesbacktoyourviews.ThisisconvenientlyhandledbyLaravel.Considerthefollowingroutesasanexample:
Route::get('register',function()
{
returnView::make('user.register');
});
Route::post('register',function()
{
$rules=array(...);
$validator=Validator::make(Input::all(),$rules);
if($validator->fails())
{
returnredirect('register')->withErrors($validator);
}
});
Notethatwhenvalidationfails,wepasstheValidatorinstancetotheRedirectusingthewithErrorsmethod.Thismethodwillflashtheerrormessagestothesessionsothattheyareavailableonthenextrequest.
However,noticethatwedonothavetoexplicitlybindtheerrormessagestotheviewinourGETroute.ThisisbecauseLaravelwillalwayscheckforerrorsinthesessiondata,andautomaticallybindthemtotheviewiftheyareavailable.So,itisimportanttonotethatan$errorsvariablewillalwaysbeavailableinallofyourviews,oneveryrequest,allowingyoutoconvenientlyassumethe$errorsvariableisalwaysdefinedandcanbesafelyused.The$errorsvariablewillbeaninstanceofMessageBag.
So,afterredirection,youmayutilizetheautomaticallybound$errorsvariableinyourview:
<?phpecho$errors->first('email');?>
Ifyouhavemultipleformsonasinglepage,youmaywishtonametheMessageBagoferrors.Thiswillallowyoutoretrievetheerrormessagesforaspecificform.SimplypassanameasthesecondargumenttowithErrors:
returnredirect('register')->withErrors($validator,'login');
YoumaythenaccessthenamedMessageBaginstancefromthe$errorsvariable:
<?phpecho$errors->login->first('email');?>
RetrievingAllErrorMessagesWithAFormat
ErrorMessages&Views
NamedErrorBags
Belowisalistofallavailablevalidationrulesandtheirfunction:
AcceptedActiveURLAfter(Date)AlphaAlphaDashAlphaNumericArrayBefore(Date)BetweenBooleanConfirmedDateDateFormatDifferentDigitsDigitsBetweenE-MailExists(Database)Image(File)InIntegerIPAddressMaxMIMETypesMinNotInNumericRegularExpressionRequiredRequiredIfRequiredWithRequiredWithAllRequiredWithoutRequiredWithoutAllSameSizeStringTimezoneUnique(Database)URL
Thefieldundervalidationmustbeyes,on,or1.Thisisusefulforvalidating"TermsofService"acceptance.
ThefieldundervalidationmustbeavalidURLaccordingtothecheckdnsrrPHPfunction.
Thefieldundervalidationmustbeavalueafteragivendate.ThedateswillbepassedintothePHPstrtotimefunction.
AvailableValidationRules
accepted
active_url
after:date
Thefieldundervalidationmustbeentirelyalphabeticcharacters.
Thefieldundervalidationmayhavealpha-numericcharacters,aswellasdashesandunderscores.
Thefieldundervalidationmustbeentirelyalpha-numericcharacters.
Thefieldundervalidationmustbeoftypearray.
Thefieldundervalidationmustbeavalueprecedingthegivendate.ThedateswillbepassedintothePHPstrtotimefunction.
Thefieldundervalidationmusthaveasizebetweenthegivenminandmax.Strings,numerics,andfilesareevaluatedinthesamefashionasthesizerule.
Thefieldundervalidationmustbeabletobecastasaboolean.Acceptedinputaretrue,false,1,0,"1"and"0".
Thefieldundervalidationmusthaveamatchingfieldoffoo_confirmation.Forexample,ifthefieldundervalidationispassword,amatchingpassword_confirmationfieldmustbepresentintheinput.
ThefieldundervalidationmustbeavaliddateaccordingtothestrtotimePHPfunction.
Thefieldundervalidationmustmatchtheformatdefinedaccordingtothedate_parse_from_formatPHPfunction.
Thegivenfieldmustbedifferentthanthefieldundervalidation.
Thefieldundervalidationmustbenumericandmusthaveanexactlengthofvalue.
Thefieldundervalidationmusthavealengthbetweenthegivenminandmax.
alpha
alpha_dash
alpha_num
array
before:date
between:min,max
boolean
confirmed
date
dateformat:_format
different:field
digits:value
digitsbetween:_min,max
Thefieldundervalidationmustbeformattedasane-mailaddress.
Thefieldundervalidationmustexistonagivendatabasetable.
'state'=>'exists:states'
'state'=>'exists:states,abbreviation'
Youmayalsospecifymoreconditionsthatwillbeaddedas"where"clausestothequery:
'email'=>'exists:staff,email,account_id,1'
PassingNULLasa"where"clausevaluewilladdacheckforaNULLdatabasevalue:
'email'=>'exists:staff,email,deleted_at,NULL'
Thefileundervalidationmustbeanimage(jpeg,png,bmp,gif,orsvg)
Thefieldundervalidationmustbeincludedinthegivenlistofvalues.
Thefieldundervalidationmusthaveanintegervalue.
ThefieldundervalidationmustbeformattedasanIPaddress.
Thefieldundervalidationmustbelessthanorequaltoamaximumvalue.Strings,numerics,andfilesareevaluatedinthesamefashionasthesizerule.
ThefileundervalidationmusthaveaMIMEtypecorrespondingtooneofthelistedextensions.
'photo'=>'mimes:jpeg,bmp,png'
exists:table,column
BasicUsageOfExistsRule
SpecifyingACustomColumnName
image
in:foo,bar,...
integer
ip
max:value
mimes:foo,bar,...
BasicUsageOfMIMERule
Thefieldundervalidationmusthaveaminimumvalue.Strings,numerics,andfilesareevaluatedinthesamefashionasthesizerule.
Thefieldundervalidationmustnotbeincludedinthegivenlistofvalues.
Thefieldundervalidationmusthaveanumericvalue.
Thefieldundervalidationmustmatchthegivenregularexpression.
Note:Whenusingtheregexpattern,itmaybenecessarytospecifyrulesinanarrayinsteadofusingpipedelimiters,especiallyiftheregularexpressioncontainsapipecharacter.
Thefieldundervalidationmustbepresentintheinputdata.
Thefieldundervalidationmustbepresentifthefieldfieldisequaltoanyvalue.
Thefieldundervalidationmustbepresentonlyifanyoftheotherspecifiedfieldsarepresent.
Thefieldundervalidationmustbepresentonlyifalloftheotherspecifiedfieldsarepresent.
Thefieldundervalidationmustbepresentonlywhenanyoftheotherspecifiedfieldsarenotpresent.
Thefieldundervalidationmustbepresentonlywhenalloftheotherspecifiedfieldsarenotpresent.
Thegivenfieldmustmatchthefieldundervalidation.
Thefieldundervalidationmusthaveasizematchingthegivenvalue.Forstringdata,valuecorrespondstothenumberofcharacters.Fornumericdata,valuecorrespondstoagivenintegervalue.Forfiles,sizecorrespondstothefilesizeinkilobytes.
Thefieldundervalidationmustbeastringtype.
min:value
notin:_foo,bar,...
numeric
regex:pattern
required
requiredif:_field,value,...
requiredwith:_foo,bar,...
requiredwith_all:_foo,bar,...
requiredwithout:_foo,bar,...
requiredwithout_all:_foo,bar,...
same:field
size:value
string:value
Thefieldundervalidationmustbeavalidtimezoneidentifieraccordingtothetimezone_identifiers_listPHPfunction.
Thefieldundervalidationmustbeuniqueonagivendatabasetable.Ifthecolumnoptionisnotspecified,thefieldnamewillbeused.
'email'=>'unique:users'
'email'=>'unique:users,email_address'
'email'=>'unique:users,email_address,10'
Youmayalsospecifymoreconditionsthatwillbeaddedas"where"clausestothequery:
'email'=>'unique:users,email_address,NULL,id,account_id,1'
Intheruleabove,onlyrowswithanaccount_idof1wouldbeincludedintheuniquecheck.
ThefieldundervalidationmustbeformattedasanURL.
Note:ThisfunctionusesPHP'sfilter_varmethod.
Insomesituations,youmaywishtorunvalidationchecksagainstafieldonlyifthatfieldispresentintheinputarray.Toquicklyaccomplishthis,addthesometimesruletoyourrulelist:
$v=Validator::make($data,array(
'email'=>'sometimes|required|email',
));
Intheexampleabove,theemailfieldwillonlybevalidatedifitispresentinthe$dataarray.
Sometimesyoumaywishtorequireagivenfieldonlyifanotherfieldhasagreatervaluethan100.Oryoumayneedtwofieldstohaveagivenvalueonlywhenanotherfieldispresent.Addingthesevalidationrulesdoesn'thavetobeapain.
timezone
unique:table,column,except,idColumn
BasicUsageOfUniqueRule
SpecifyingACustomColumnName
ForcingAUniqueRuleToIgnoreAGivenID
AddingAdditionalWhereClauses
url
ConditionallyAddingRules
ComplexConditionalValidation
First,createaValidatorinstancewithyourstaticrulesthatneverchange:
$v=Validator::make($data,array(
'email'=>'required|email',
'games'=>'required|numeric',
));
Let'sassumeourwebapplicationisforgamecollectors.Ifagamecollectorregisterswithourapplicationandtheyownmorethan100games,wewantthemtoexplainwhytheyownsomanygames.Forexample,perhapstheyrunagamere-sellshop,ormaybetheyjustenjoycollecting.Toconditionallyaddthisrequirement,wecanusethesometimesmethodontheValidatorinstance.
$v->sometimes('reason','required|max:500',function($input)
{
return$input->games>=100;
});
Thefirstargumentpassedtothesometimesmethodisthenameofthefieldweareconditionallyvalidating.Thesecondargumentistheruleswewanttoadd.IftheClosurepassedasthethirdargumentreturnstrue,theruleswillbeadded.Thismethodmakesitabreezetobuildcomplexconditionalvalidations.Youmayevenaddconditionalvalidationsforseveralfieldsatonce:
$v->sometimes(array('reason','cost'),'required',function($input)
{
return$input->games>=100;
});
Note:The$inputparameterpassedtoyourClosurewillbeaninstanceofIlluminate\Support\Fluentandmaybeusedasanobjecttoaccessyourinputandfiles.
Ifneeded,youmayusecustomerrormessagesforvalidationinsteadofthedefaults.Thereareseveralwaystospecifycustommessages.
$messages=array(
'required'=>'The:attributefieldisrequired.',
);
$validator=Validator::make($input,$rules,$messages);
Note:The:attributeplace-holderwillbereplacedbytheactualnameofthefieldundervalidation.Youmayalsoutilizeotherplace-holdersinvalidationmessages.
$messages=array(
'same'=>'The:attributeand:othermustmatch.',
'size'=>'The:attributemustbeexactly:size.',
'between'=>'The:attributemustbebetween:min-:max.',
'in'=>'The:attributemustbeoneofthefollowingtypes::values',
);
CustomErrorMessages
PassingCustomMessagesIntoValidator
OtherValidationPlace-Holders
Sometimesyoumaywishtospecifyacustomerrormessagesonlyforaspecificfield:
$messages=array(
'email.required'=>'Weneedtoknowyoure-mailaddress!',
);
Insomecases,youmaywishtospecifyyourcustommessagesinalanguagefileinsteadofpassingthemdirectlytotheValidator.Todoso,addyourmessagestocustomarrayintheresources/lang/xx/validation.phplanguagefile.
'custom'=>array(
'email'=>array(
'required'=>'Weneedtoknowyoure-mailaddress!',
),
),
Laravelprovidesavarietyofhelpfulvalidationrules;however,youmaywishtospecifysomeofyourown.OnemethodofregisteringcustomvalidationrulesisusingtheValidator::extendmethod:
Validator::extend('foo',function($attribute,$value,$parameters)
{
return$value=='foo';
});
ThecustomvalidatorClosurereceivesthreearguments:thenameofthe$attributebeingvalidated,the$valueoftheattribute,andanarrayof$parameterspassedtotherule.
YoumayalsopassaclassandmethodtotheextendmethodinsteadofaClosure:
Validator::extend('foo','FooValidator@validate');
Notethatyouwillalsoneedtodefineanerrormessageforyourcustomrules.Youcandosoeitherusinganinlinecustommessagearrayorbyaddinganentryinthevalidationlanguagefile.
InsteadofusingClosurecallbackstoextendtheValidator,youmayalsoextendtheValidatorclassitself.Todoso,writeaValidatorclassthatextendsIlluminate\Validation\Validator.Youmayaddvalidationmethodstotheclassbyprefixingthemwithvalidate:
<?php
classCustomValidatorextendsIlluminate\Validation\Validator{
publicfunctionvalidateFoo($attribute,$value,$parameters)
{
return$value=='foo';
}
SpecifyingACustomMessageForAGivenAttribute
SpecifyingCustomMessagesInLanguageFiles
CustomValidationRules
RegisteringACustomValidationRule
ExtendingTheValidatorClass
}
Next,youneedtoregisteryourcustomValidatorextension:
Validator::resolver(function($translator,$data,$rules,$messages)
{
returnnewCustomValidator($translator,$data,$rules,$messages);
});
Whencreatingacustomvalidationrule,youmaysometimesneedtodefinecustomplace-holderreplacementsforerrormessages.YoumaydosobycreatingacustomValidatorasdescribedabove,andaddingareplaceXXXfunctiontothevalidator.
protectedfunctionreplaceFoo($message,$attribute,$rule,$parameters)
{
returnstr_replace(':foo',$parameters[0],$message);
}
Ifyouwouldliketoaddacustommessage"replacer"withoutextendingtheValidatorclass,youmayusetheValidator::replacermethod:
Validator::replacer('rule',function($message,$attribute,$rule,$parameters)
{
//
});
RegisteringACustomValidatorResolver
BasicUsageConfigurationRead/WriteConnectionsRunningQueriesDatabaseTransactionsAccessingConnectionsQueryLogging
QueryBuilderIntroductionSelectsJoinsAdvancedWheresAggregatesRawExpressionsInsertsUpdatesDeletesUnionsPessimisticLocking
EloquentORMIntroductionBasicUsageMassAssignmentInsert,Update,DeleteSoftDeletingTimestampsQueryScopesGlobalScopesRelationshipsQueryingRelationsEagerLoadingInsertingRelatedModelsTouchingParentTimestampsWorkingWithPivotTablesCollectionsAccessors&MutatorsDateMutatorsAttributeCastingModelEventsModelObserversConvertingToArrays/JSON
SchemaBuilderIntroductionCreating&DroppingTablesAddingColumnsChangingColumnsRenamingColumnsDroppingColumnsCheckingExistenceAddingIndexesForeignKeysDroppingIndexes
Database
DroppingTimestamps&SoftDeletesStorageEngines
Migrations&SeedingIntroductionCreatingMigrationsRunningMigrationsRollingBackMigrationsDatabaseSeeding
RedisIntroductionConfigurationUsagePipelining
ConfigurationRead/WriteConnectionsRunningQueriesDatabaseTransactionsAccessingConnectionsQueryLogging
Laravelmakesconnectingwithdatabasesandrunningqueriesextremelysimple.Thedatabaseconfigurationfileisconfig/database.php.Inthisfileyoumaydefineallofyourdatabaseconnections,aswellasspecifywhichconnectionshouldbeusedbydefault.Examplesforallofthesupporteddatabasesystemsareprovidedinthisfile.
CurrentlyLaravelsupportsfourdatabasesystems:MySQL,Postgres,SQLite,andSQLServer.
SometimesyoumaywishtouseonedatabaseconnectionforSELECTstatements,andanotherforINSERT,UPDATE,andDELETEstatements.Laravelmakesthisabreeze,andtheproperconnectionswillalwaysbeusedwhetheryouareusingrawqueries,thequerybuilder,ortheEloquentORM.
Toseehowread/writeconnectionsshouldbeconfigured,let'slookatthisexample:
'mysql'=>[
'read'=>[
'host'=>'192.168.1.1',
],
'write'=>[
'host'=>'196.168.1.2'
],
'driver'=>'mysql',
'database'=>'database',
'username'=>'root',
'password'=>'',
'charset'=>'utf8',
'collation'=>'utf8_unicode_ci',
'prefix'=>'',
],
Notethattwokeyshavebeenaddedtotheconfigurationarray:readandwrite.Bothofthesekeyshavearrayvaluescontainingasinglekey:host.Therestofthedatabaseoptionsforthereadandwriteconnectionswillbemergedfromthemainmysqlarray.So,weonlyneedtoplaceitemsinthereadandwritearraysifwewishtooverridethevaluesinthemainarray.So,inthiscase,192.168.1.1willbeusedasthe"read"connection,while192.168.1.2willbeusedasthe"write"connection.Thedatabasecredentials,prefix,characterset,andallotheroptionsinthemainmysqlarraywillbesharedacrossbothconnections.
Onceyouhaveconfiguredyourdatabaseconnection,youmayrunqueriesusingtheDBfacade.
$results=DB::select('select*fromuserswhereid=?',[1]);
BasicDatabaseUsage
Configuration
Read/WriteConnections
RunningQueries
RunningASelectQuery
Theselectmethodwillalwaysreturnanarrayofresults.
DB::insert('insertintousers(id,name)values(?,?)',[1,'Dayle']);
DB::update('updateuserssetvotes=100wherename=?',['John']);
DB::delete('deletefromusers');
Note:Theupdateanddeletestatementsreturnthenumberofrowsaffectedbytheoperation.
DB::statement('droptableusers');
YoumaylistenforqueryeventsusingtheDB::listenmethod:
DB::listen(function($sql,$bindings,$time)
{
//
});
Torunasetofoperationswithinadatabasetransaction,youmayusethetransactionmethod:
DB::transaction(function()
{
DB::table('users')->update(['votes'=>1]);
DB::table('posts')->delete();
});
Note:Anyexceptionthrownwithinthetransactionclosurewillcausethetransactiontoberolledbackautomatically.
Sometimesyoumayneedtobeginatransactionyourself:
DB::beginTransaction();
Youcanrollbackatransactionviatherollbackmethod:
RunningAnInsertStatement
RunningAnUpdateStatement
RunningADeleteStatement
RunningAGeneralStatement
ListeningForQueryEvents
DatabaseTransactions
DB::rollback();
Lastly,youcancommitatransactionviathecommitmethod:
DB::commit();
Whenusingmultipleconnections,youmayaccessthemviatheDB::connectionmethod:
$users=DB::connection('foo')->select(...);
Youmayalsoaccesstheraw,underlyingPDOinstance:
$pdo=DB::connection()->getPdo();
Sometimesyoumayneedtoreconnecttoagivendatabase:
DB::reconnect('foo');
IfyouneedtodisconnectfromthegivendatabaseduetoexceedingtheunderlyingPDOinstance'smax_connectionslimit,usethedisconnectmethod:
DB::disconnect('foo');
Bydefault,Laravelkeepsaloginmemoryofallqueriesthathavebeenrunforthecurrentrequest.However,insomecases,suchaswheninsertingalargenumberofrows,thiscancausetheapplicationtouseexcessmemory.Todisablethelog,youmayusethedisableQueryLogmethod:
DB::connection()->disableQueryLog();
Togetanarrayoftheexecutedqueries,youmayusethegetQueryLogmethod:
$queries=DB::getQueryLog();
AccessingConnections
QueryLogging
IntroductionSelectsJoinsAdvancedWheresAggregatesRawExpressionsInsertsUpdatesDeletesUnionsPessimisticLocking
Thedatabasequerybuilderprovidesaconvenient,fluentinterfacetocreatingandrunningdatabasequeries.Itcanbeusedtoperformmostdatabaseoperationsinyourapplication,andworksonallsupporteddatabasesystems.
Note:TheLaravelquerybuilderusesPDOparameterbindingthroughouttoprotectyourapplicationagainstSQLinjectionattacks.Thereisnoneedtocleanstringsbeingpassedasbindings.
$users=DB::table('users')->get();
foreach($usersas$user)
{
var_dump($user->name);
}
DB::table('users')->chunk(100,function($users)
{
foreach($usersas$user)
{
//
}
});
YoumaystopfurtherchunksfrombeingprocessedbyreturningfalsefromtheClosure:
DB::table('users')->chunk(100,function($users)
{
//
returnfalse;
});
QueryBuilder
Introduction
Selects
RetrievingAllRowsFromATable
ChunkingResultsFromATable
RetrievingASingleRowFromATable
$user=DB::table('users')->where('name','John')->first();
var_dump($user->name);
$name=DB::table('users')->where('name','John')->pluck('name');
$roles=DB::table('roles')->lists('title');
Thismethodwillreturnanarrayofroletitles.Youmayalsospecifyacustomkeycolumnforthereturnedarray:
$roles=DB::table('roles')->lists('title','name');
$users=DB::table('users')->select('name','email')->get();
$users=DB::table('users')->distinct()->get();
$users=DB::table('users')->select('nameasuser_name')->get();
$query=DB::table('users')->select('name');
$users=$query->addSelect('age')->get();
$users=DB::table('users')->where('votes','>',100)->get();
$users=DB::table('users')
->where('votes','>',100)
->orWhere('name','John')
->get();
$users=DB::table('users')
->whereBetween('votes',array(1,100))->get();
RetrievingASingleColumnFromARow
RetrievingAListOfColumnValues
SpecifyingASelectClause
AddingASelectClauseToAnExistingQuery
UsingWhereOperators
OrStatements
UsingWhereBetween
UsingWhereNotBetween
$users=DB::table('users')
->whereNotBetween('votes',array(1,100))->get();
$users=DB::table('users')
->whereIn('id',array(1,2,3))->get();
$users=DB::table('users')
->whereNotIn('id',array(1,2,3))->get();
$users=DB::table('users')
->whereNull('updated_at')->get();
$users=DB::table('users')
->orderBy('name','desc')
->groupBy('count')
->having('count','>',100)
->get();
$users=DB::table('users')->skip(10)->take(5)->get();
Thequerybuildermayalsobeusedtowritejoinstatements.Takealookatthefollowingexamples:
DB::table('users')
->join('contacts','users.id','=','contacts.user_id')
->join('orders','users.id','=','orders.user_id')
->select('users.id','contacts.phone','orders.price')
->get();
DB::table('users')
->leftJoin('posts','users.id','=','posts.user_id')
->get();
Youmayalsospecifymoreadvancedjoinclauses:
DB::table('users')
->join('contacts',function($join)
{
$join->on('users.id','=','contacts.user_id')->orOn(...);
})
UsingWhereInWithAnArray
UsingWhereNullToFindRecordsWithUnsetValues
OrderBy,GroupBy,AndHaving
Offset&Limit
Joins
BasicJoinStatement
LeftJoinStatement
->get();
Ifyouwouldliketousea"where"styleclauseonyourjoins,youmayusethewhereandorWheremethodsonajoin.Insteadofcomparingtwocolumns,thesemethodswillcomparethecolumnagainstavalue:
DB::table('users')
->join('contacts',function($join)
{
$join->on('users.id','=','contacts.user_id')
->where('contacts.user_id','>',5);
})
->get();
Sometimesyoumayneedtocreatemoreadvancedwhereclausessuchas"whereexists"ornestedparametergroupings.TheLaravelquerybuildercanhandletheseaswell:
DB::table('users')
->where('name','=','John')
->orWhere(function($query)
{
$query->where('votes','>',100)
->where('title','<>','Admin');
})
->get();
ThequeryabovewillproducethefollowingSQL:
select*fromuserswherename='John'or(votes>100andtitle<>'Admin')
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id=users.id');
})
->get();
ThequeryabovewillproducethefollowingSQL:
select*fromusers
whereexists(
select1fromorderswhereorders.user_id=users.id
)
Thequerybuilderalsoprovidesavarietyofaggregatemethods,suchascount,max,min,avg,andsum.
AdvancedWheres
ParameterGrouping
ExistsStatements
Aggregates
$users=DB::table('users')->count();
$price=DB::table('orders')->max('price');
$price=DB::table('orders')->min('price');
$price=DB::table('orders')->avg('price');
$total=DB::table('users')->sum('votes');
Sometimesyoumayneedtousearawexpressioninaquery.Theseexpressionswillbeinjectedintothequeryasstrings,sobecarefulnottocreateanySQLinjectionpoints!Tocreatearawexpression,youmayusetheDB::rawmethod:
$users=DB::table('users')
->select(DB::raw('count(*)asuser_count,status'))
->where('status','<>',1)
->groupBy('status')
->get();
DB::table('users')->insert(
array('email'=>'[email protected]','votes'=>0)
);
Ifthetablehasanauto-incrementingid,useinsertGetIdtoinsertarecordandretrievetheid:
$id=DB::table('users')->insertGetId(
array('email'=>'[email protected]','votes'=>0)
);
Note:WhenusingPostgreSQLtheinsertGetIdmethodexpectstheauto-incrementingcolumntobenamed"id".
DB::table('users')->insert(array(
array('email'=>'[email protected]','votes'=>0),
array('email'=>'[email protected]','votes'=>0),
));
UsingAggregateMethods
RawExpressions
UsingARawExpression
Inserts
InsertingRecordsIntoATable
InsertingRecordsIntoATableWithAnAuto-IncrementingID
InsertingMultipleRecordsIntoATable
Updates
UpdatingRecordsInATable
DB::table('users')
->where('id',1)
->update(array('votes'=>1));
DB::table('users')->increment('votes');
DB::table('users')->increment('votes',5);
DB::table('users')->decrement('votes');
DB::table('users')->decrement('votes',5);
Youmayalsospecifyadditionalcolumnstoupdate:
DB::table('users')->increment('votes',1,array('name'=>'John'));
DB::table('users')->where('votes','<',100)->delete();
DB::table('users')->delete();
DB::table('users')->truncate();
Thequerybuilderalsoprovidesaquickwayto"union"twoqueriestogether:
$first=DB::table('users')->whereNull('first_name');
$users=DB::table('users')->whereNull('last_name')->union($first)->get();
TheunionAllmethodisalsoavailable,andhasthesamemethodsignatureasunion.
Thequerybuilderincludesafewfunctionstohelpyoudo"pessimisticlocking"onyourSELECTstatements.
ToruntheSELECTstatementwitha"sharedlock",youmayusethesharedLockmethodonaquery:
Incrementingordecrementingavalueofacolumn
Deletes
DeletingRecordsInATable
DeletingAllRecordsFromATable
TruncatingATable
Unions
PessimisticLocking
DB::table('users')->where('votes','>',100)->sharedLock()->get();
To"lockforupdate"onaSELECTstatement,youmayusethelockForUpdatemethodonaquery:
DB::table('users')->where('votes','>',100)->lockForUpdate()->get();
IntroductionBasicUsageMassAssignmentInsert,Update,DeleteSoftDeletingTimestampsQueryScopesGlobalScopesRelationshipsQueryingRelationsEagerLoadingInsertingRelatedModelsTouchingParentTimestampsWorkingWithPivotTablesCollectionsAccessors&MutatorsDateMutatorsAttributeCastingModelEventsModelObserversConvertingToArrays/JSON
TheEloquentORMincludedwithLaravelprovidesabeautiful,simpleActiveRecordimplementationforworkingwithyourdatabase.Eachdatabasetablehasacorresponding"Model"whichisusedtointeractwiththattable.
Beforegettingstarted,besuretoconfigureadatabaseconnectioninconfig/database.php.
Togetstarted,createanEloquentmodel.Modelstypicallyliveintheappdirectory,butyouarefreetoplacethemanywherethatcanbeauto-loadedaccordingtoyourcomposer.jsonfile.AllEloquentmodelsextendIlluminate\Database\Eloquent\Model.
classUserextendsModel{}
YoumayalsogenerateEloquentmodelsusingthemake:modelcommand:
phpartisanmake:modelUser
NotethatwedidnottellEloquentwhichtabletouseforourUsermodel.Thelower-case,pluralnameoftheclasswillbeusedasthetablenameunlessanothernameisexplicitlyspecified.So,inthiscase,EloquentwillassumetheUsermodelstoresrecordsintheuserstable.Youmayspecifyacustomtablebydefiningatablepropertyonyourmodel:
classUserextendsModel{
EloquentORM
Introduction
BasicUsage
DefiningAnEloquentModel
protected$table='my_users';
}
Note:Eloquentwillalsoassumethateachtablehasaprimarykeycolumnnamedid.YoumaydefineaprimaryKeypropertytooverridethisconvention.Likewise,youmaydefineaconnectionpropertytooverridethenameofthedatabaseconnectionthatshouldbeusedwhenutilizingthemodel.
Onceamodelisdefined,youarereadytostartretrievingandcreatingrecordsinyourtable.Notethatyouwillneedtoplaceupdated_atandcreated_atcolumnsonyourtablebydefault.Ifyoudonotwishtohavethesecolumnsautomaticallymaintained,setthe$timestampspropertyonyourmodeltofalse.
$users=User::all();
$user=User::find(1);
var_dump($user->name);
Note:AllmethodsavailableonthequerybuilderarealsoavailablewhenqueryingEloquentmodels.
Sometimesyoumaywishtothrowanexceptionifamodelisnotfound,allowingyoutocatchtheexceptionsusinganApp::errorhandleranddisplaya404page.
$model=User::findOrFail(1);
$model=User::where('votes','>',100)->firstOrFail();
Toregistertheerrorhandler,listenfortheModelNotFoundException
useIlluminate\Database\Eloquent\ModelNotFoundException;
App::error(function(ModelNotFoundException$e)
{
returnResponse::make('NotFound',404);
});
$users=User::where('votes','>',100)->take(10)->get();
foreach($usersas$user)
{
var_dump($user->name);
}
Ofcourse,youmayalsousethequerybuilderaggregatefunctions.
RetrievingAllModels
RetrievingARecordByPrimaryKey
RetrievingAModelByPrimaryKeyOrThrowAnException
QueryingUsingEloquentModels
EloquentAggregates
$count=User::where('votes','>',100)->count();
Ifyouareunabletogeneratethequeryyouneedviathefluentinterface,feelfreetousewhereRaw:
$users=User::whereRaw('age>?andvotes=100',array(25))->get();
Ifyouneedtoprocessalot(thousands)ofEloquentrecords,usingthechunkcommandwillallowyoutodowithouteatingallofyourRAM:
User::chunk(200,function($users)
{
foreach($usersas$user)
{
//
}
});
Thefirstargumentpassedtothemethodisthenumberofrecordsyouwishtoreceiveper"chunk".TheClosurepassedasthesecondargumentwillbecalledforeachchunkthatispulledfromthedatabase.
YoumayalsospecifywhichdatabaseconnectionshouldbeusedwhenrunninganEloquentquery.Simplyusetheonmethod:
$user=User::on('connection-name')->find(1);
Ifyouareusingread/writeconnections,youmayforcethequerytousethe"write"connectionwiththefollowingmethod:
$user=User::onWriteConnection()->find(1);
Whencreatinganewmodel,youpassanarrayofattributestothemodelconstructor.Theseattributesarethenassignedtothemodelviamass-assignment.Thisisconvenient;however,canbeaserioussecurityconcernwhenblindlypassinguserinputintoamodel.Ifuserinputisblindlypassedintoamodel,theuserisfreetomodifyanyandallofthemodel'sattributes.Forthisreason,allEloquentmodelsprotectagainstmass-assignmentbydefault.
Togetstarted,setthefillableorguardedpropertiesonyourmodel.
Thefillablepropertyspecifieswhichattributesshouldbemass-assignable.Thiscanbesetattheclassorinstancelevel.
classUserextendsModel{
protected$fillable=array('first_name','last_name','email');
}
ChunkingResults
SpecifyingTheQueryConnection
MassAssignment
DefiningFillableAttributesOnAModel
Inthisexample,onlythethreelistedattributeswillbemass-assignable.
Theinverseoffillableisguarded,andservesasa"black-list"insteadofa"white-list":
classUserextendsModel{
protected$guarded=array('id','password');
}
Note:Whenusingguarded,youshouldstillneverpassInput::get()oranyrawarrayofusercontrolledinputintoasaveorupdatemethod,asanycolumnthatisnotguardedmaybeupdated.
Intheexampleabove,theidandpasswordattributesmaynotbemassassigned.Allotherattributeswillbemassassignable.Youmayalsoblockallattributesfrommassassignmentusingtheguardproperty:
protected$guarded=array('*');
Tocreateanewrecordinthedatabasefromamodel,simplycreateanewmodelinstanceandcallthesavemethod.
$user=newUser;
$user->name='John';
$user->save();
Note:Typically,yourEloquentmodelswillhaveauto-incrementingkeys.However,ifyouwishtospecifyyourownkeys,settheincrementingpropertyonyourmodeltofalse.
Youmayalsousethecreatemethodtosaveanewmodelinasingleline.Theinsertedmodelinstancewillbereturnedtoyoufromthemethod.However,beforedoingso,youwillneedtospecifyeitherafillableorguardedattributeonthemodel,asallEloquentmodelsprotectagainstmass-assignment.
Aftersavingorcreatinganewmodelthatusesauto-incrementingIDs,youmayretrievetheIDbyaccessingtheobject'sidattribute:
$insertedId=$user->id;
classUserextendsModel{
protected$guarded=array('id','account_id');
}
DefiningGuardedAttributesOnAModel
BlockingAllAttributesFromMassAssignment
Insert,Update,Delete
SavingANewModel
SettingTheGuardedAttributesOnTheModel
//Createanewuserinthedatabase...
$user=User::create(array('name'=>'John'));
//Retrievetheuserbytheattributes,orcreateitifitdoesn'texist...
$user=User::firstOrCreate(array('name'=>'John'));
//Retrievetheuserbytheattributes,orinstantiateanewinstance...
$user=User::firstOrNew(array('name'=>'John'));
Toupdateamodel,youmayretrieveit,changeanattribute,andusethesavemethod:
$user=User::find(1);
$user->email='[email protected]';
$user->save();
Sometimesyoumaywishtosavenotonlyamodel,butalsoallofitsrelationships.Todoso,youmayusethepushmethod:
$user->push();
Youmayalsorunupdatesasqueriesagainstasetofmodels:
$affectedRows=User::where('votes','>',100)->update(array('status'=>2));
Note:NomodeleventsarefiredwhenupdatingasetofmodelsviatheEloquentquerybuilder.
Todeleteamodel,simplycallthedeletemethodontheinstance:
$user=User::find(1);
$user->delete();
User::destroy(1);
User::destroy(array(1,2,3));
User::destroy(1,2,3);
Ofcourse,youmayalsorunadeletequeryonasetofmodels:
$affectedRows=User::where('votes','>',100)->delete();
UsingTheModelCreateMethod
UpdatingARetrievedModel
SavingAModelAndRelationships
DeletingAnExistingModel
DeletingAnExistingModelByKey
Ifyouwishtosimplyupdatethetimestampsonamodel,youmayusethetouchmethod:
$user->touch();
Whensoftdeletingamodel,itisnotactuallyremovedfromyourdatabase.Instead,adeleted_attimestampissetontherecord.Toenablesoftdeletesforamodel,applytheSoftDeletestothemodel:
useIlluminate\Database\Eloquent\SoftDeletes;
classUserextendsModel{
useSoftDeletes;
protected$dates=['deleted_at'];
}
Toaddadeleted_atcolumntoyourtable,youmayusethesoftDeletesmethodfromamigration:
$table->softDeletes();
Now,whenyoucallthedeletemethodonthemodel,thedeleted_atcolumnwillbesettothecurrenttimestamp.Whenqueryingamodelthatusessoftdeletes,the"deleted"modelswillnotbeincludedinqueryresults.
Toforcesoftdeletedmodelstoappearinaresultset,usethewithTrashedmethodonthequery:
$users=User::withTrashed()->where('account_id',1)->get();
ThewithTrashedmethodmaybeusedonadefinedrelationship:
$user->posts()->withTrashed()->get();
Ifyouwishtoonlyreceivesoftdeletedmodelsinyourresults,youmayusetheonlyTrashedmethod:
$users=User::onlyTrashed()->where('account_id',1)->get();
Torestoreasoftdeletedmodelintoanactivestate,usetherestoremethod:
$user->restore();
Youmayalsousetherestoremethodonaquery:
User::withTrashed()->where('account_id',1)->restore();
UpdatingOnlyTheModel'sTimestamps
SoftDeleting
ForcingSoftDeletedModelsIntoResults
LikewithwithTrashed,therestoremethodmayalsobeusedonrelationships:
$user->posts()->restore();
Ifyouwishtotrulyremoveamodelfromthedatabase,youmayusetheforceDeletemethod:
$user->forceDelete();
TheforceDeletemethodalsoworksonrelationships:
$user->posts()->forceDelete();
Todetermineifagivenmodelinstancehasbeensoftdeleted,youmayusethetrashedmethod:
if($user->trashed())
{
//
}
Bydefault,Eloquentwillmaintainthecreated_atandupdated_atcolumnsonyourdatabasetableautomatically.SimplyaddthesetimestampcolumnstoyourtableandEloquentwilltakecareoftherest.IfyoudonotwishforEloquenttomaintainthesecolumns,addthefollowingpropertytoyourmodel:
classUserextendsModel{
protected$table='users';
public$timestamps=false;
}
Ifyouwishtocustomizetheformatofyourtimestamps,youmayoverridethegetDateFormatmethodinyourmodel:
classUserextendsModel{
protectedfunctiongetDateFormat()
{
return'U';
}
}
Timestamps
DisablingAutoTimestamps
ProvidingACustomTimestampFormat
QueryScopes
DefiningAQueryScope
Scopesallowyoutoeasilyre-usequerylogicinyourmodels.Todefineascope,simplyprefixamodelmethodwithscope:
classUserextendsModel{
publicfunctionscopePopular($query)
{
return$query->where('votes','>',100);
}
publicfunctionscopeWomen($query)
{
return$query->whereGender('W');
}
}
$users=User::popular()->women()->orderBy('created_at')->get();
Sometimesyoumaywishtodefineascopethatacceptsparameters.Justaddyourparameterstoyourscopefunction:
classUserextendsModel{
publicfunctionscopeOfType($query,$type)
{
return$query->whereType($type);
}
}
Thenpasstheparameterintothescopecall:
$users=User::ofType('member')->get();
Sometimesyoumaywishtodefineascopethatappliestoallqueriesperformedonamodel.Inessence,thisishowEloquent'sown"softdelete"featureworks.GlobalscopesaredefinedusingacombinationofPHPtraitsandanimplementationofIlluminate\Database\Eloquent\ScopeInterface.
First,let'sdefineatrait.Forthisexample,we'llusetheSoftDeletesthatshipswithLaravel:
traitSoftDeletes{
/**
*Bootthesoftdeletingtraitforamodel.
*
*@returnvoid
*/
publicstaticfunctionbootSoftDeletes()
{
static::addGlobalScope(newSoftDeletingScope);
}
}
UtilizingAQueryScope
DynamicScopes
GlobalScopes
IfanEloquentmodelusesatraitthathasamethodmatchingthebootNameOfTraitnamingconvention,thattraitmethodwillbecalledwhentheEloquentmodelisbooted,givingyouanopportunitytoregisteraglobalscope,ordoanythingelseyouwant.AscopemustimplementScopeInterface,whichspecifiestwomethods:applyandremove.
TheapplymethodreceivesanIlluminate\Database\Eloquent\Builderquerybuilderobject,andisresponsibleforaddinganyadditionalwhereclausesthatthescopewishestoadd.TheremovemethodalsoreceivesaBuilderobjectandisresponsibleforreversingtheactiontakenbyapply.Inotherwords,removeshouldremovethewhereclause(oranyotherclause)thatwasadded.So,forourSoftDeletingScope,themethodslooksomethinglikethis:
/**
*ApplythescopetoagivenEloquentquerybuilder.
*
*@param\Illuminate\Database\Eloquent\Builder$builder
*@returnvoid
*/
publicfunctionapply(Builder$builder)
{
$model=$builder->getModel();
$builder->whereNull($model->getQualifiedDeletedAtColumn());
}
/**
*RemovethescopefromthegivenEloquentquerybuilder.
*
*@param\Illuminate\Database\Eloquent\Builder$builder
*@returnvoid
*/
publicfunctionremove(Builder$builder)
{
$column=$builder->getModel()->getQualifiedDeletedAtColumn();
$query=$builder->getQuery();
foreach((array)$query->wheresas$key=>$where)
{
//Ifthewhereclauseisasoftdeletedateconstraint,wewillremoveitfrom
//thequeryandresetthekeysonthewheres.Thisallowsthisdeveloperto
//includedeletedmodelinarelationshipresultsetthatislazyloaded.
if($this->isSoftDeleteConstraint($where,$column))
{
unset($query->wheres[$key]);
$query->wheres=array_values($query->wheres);
}
}
}
Ofcourse,yourdatabasetablesareprobablyrelatedtooneanother.Forexample,ablogpostmayhavemanycomments,oranordercouldberelatedtotheuserwhoplacedit.Eloquentmakesmanagingandworkingwiththeserelationshipseasy.Laravelsupportsmanytypesofrelationships:
OneToOneOneToManyManyToManyHasManyThroughPolymorphicRelationsManyToManyPolymorphicRelations
Aone-to-onerelationshipisaverybasicrelation.Forexample,aUsermodelmighthaveonePhone.Wecandefinethis
Relationships
OneToOne
DefiningAOneToOneRelation
relationinEloquent:
classUserextendsModel{
publicfunctionphone()
{
return$this->hasOne('App\Phone');
}
}
ThefirstargumentpassedtothehasOnemethodisthenameoftherelatedmodel.Oncetherelationshipisdefined,wemayretrieveitusingEloquent'sdynamicproperties:
$phone=User::find(1)->phone;
TheSQLperformedbythisstatementwillbeasfollows:
select*fromuserswhereid=1
select*fromphoneswhereuser_id=1
TakenotethatEloquentassumestheforeignkeyoftherelationshipbasedonthemodelname.Inthiscase,Phonemodelisassumedtouseauser_idforeignkey.Ifyouwishtooverridethisconvention,youmaypassasecondargumenttothehasOnemethod.Furthermore,youmaypassathirdargumenttothemethodtospecifywhichlocalcolumnthatshouldbeusedfortheassociation:
return$this->hasOne('App\Phone','foreign_key');
return$this->hasOne('App\Phone','foreign_key','local_key');
TodefinetheinverseoftherelationshiponthePhonemodel,weusethebelongsTomethod:
classPhoneextendsModel{
publicfunctionuser()
{
return$this->belongsTo('App\User');
}
}
Intheexampleabove,Eloquentwilllookforauser_idcolumnonthephonestable.Ifyouwouldliketodefineadifferentforeignkeycolumn,youmaypassitasthesecondargumenttothebelongsTomethod:
classPhoneextendsModel{
publicfunctionuser()
{
return$this->belongsTo('App\User','local_key');
}
}
Additionally,youpassathirdparameterwhichspecifiesthenameoftheassociatedcolumnontheparenttable:
DefiningTheInverseOfARelation
classPhoneextendsModel{
publicfunctionuser()
{
return$this->belongsTo('App\User','local_key','parent_key');
}
}
Anexampleofaone-to-manyrelationisablogpostthat"hasmany"comments.Wecanmodelthisrelationlikeso:
classPostextendsModel{
publicfunctioncomments()
{
return$this->hasMany('App\Comment');
}
}
Nowwecanaccessthepost'scommentsthroughthedynamicproperty:
$comments=Post::find(1)->comments;
Ifyouneedtoaddfurtherconstraintstowhichcommentsareretrieved,youmaycallthecommentsmethodandcontinuechainingconditions:
$comments=Post::find(1)->comments()->where('title','=','foo')->first();
Again,youmayoverridetheconventionalforeignkeybypassingasecondargumenttothehasManymethod.And,likethehasOnerelation,thelocalcolumnmayalsobespecified:
return$this->hasMany('App\Comment','foreign_key');
return$this->hasMany('App\Comment','foreign_key','local_key');
TodefinetheinverseoftherelationshipontheCommentmodel,weusethebelongsTomethod:
classCommentextendsModel{
publicfunctionpost()
{
return$this->belongsTo('App\Post');
}
}
Many-to-manyrelationsareamorecomplicatedrelationshiptype.Anexampleofsucharelationshipisauserwithmanyroles,wheretherolesarealsosharedbyotherusers.Forexample,manyusersmayhavetheroleof"Admin".Threedatabasetablesareneededforthisrelationship:users,roles,androle_user.Therole_usertableisderivedfromthe
OneToMany
DefiningTheInverseOfARelation
ManyToMany
alphabeticalorderoftherelatedmodelnames,andshouldhaveuser_idandrole_idcolumns.
Wecandefineamany-to-manyrelationusingthebelongsToManymethod:
classUserextendsModel{
publicfunctionroles()
{
return$this->belongsToMany('App\Role');
}
}
Now,wecanretrievetherolesthroughtheUsermodel:
$roles=User::find(1)->roles;
Ifyouwouldliketouseanunconventionaltablenameforyourpivottable,youmaypassitasthesecondargumenttothebelongsToManymethod:
return$this->belongsToMany('App\Role','user_roles');
Youmayalsooverridetheconventionalassociatedkeys:
return$this->belongsToMany('App\Role','user_roles','user_id','foo_id');
Ofcourse,youmayalsodefinetheinverseoftherelationshipontheRolemodel:
classRoleextendsModel{
publicfunctionusers()
{
return$this->belongsToMany('App\User');
}
}
The"hasmanythrough"relationprovidesaconvenientshort-cutforaccessingdistantrelationsviaanintermediaterelation.Forexample,aCountrymodelmighthavemanyPostthroughaUsermodel.Thetablesforthisrelationshipwouldlooklikethis:
countries
id-integer
name-string
users
id-integer
country_id-integer
name-string
posts
id-integer
user_id-integer
title-string
Eventhoughthepoststabledoesnotcontainacountry_idcolumn,thehasManyThroughrelationwillallowustoaccessa
HasManyThrough
country'spostsvia$country->posts.Let'sdefinetherelationship:
classCountryextendsModel{
publicfunctionposts()
{
return$this->hasManyThrough('App\Post','User');
}
}
Ifyouwouldliketomanuallyspecifythekeysoftherelationship,youmaypassthemasthethirdandfourthargumentstothemethod:
classCountryextendsModel{
publicfunctionposts()
{
return$this->hasManyThrough('App\Post','User','country_id','user_id');
}
}
Polymorphicrelationsallowamodeltobelongtomorethanoneothermodel,onasingleassociation.Forexample,youmighthaveaphotomodelthatbelongstoeitherastaffmodeloranordermodel.Wewoulddefinethisrelationlikeso:
classPhotoextendsModel{
publicfunctionimageable()
{
return$this->morphTo();
}
}
classStaffextendsModel{
publicfunctionphotos()
{
return$this->morphMany('App\Photo','imageable');
}
}
classOrderextendsModel{
publicfunctionphotos()
{
return$this->morphMany('App\Photo','imageable');
}
}
Now,wecanretrievethephotosforeitherastaffmemberoranorder:
$staff=Staff::find(1);
foreach($staff->photosas$photo)
{
//
}
PolymorphicRelations
RetrievingAPolymorphicRelation
However,thetrue"polymorphic"magiciswhenyouaccessthestaffororderfromthePhotomodel:
$photo=Photo::find(1);
$imageable=$photo->imageable;
TheimageablerelationonthePhotomodelwillreturneitheraStafforOrderinstance,dependingonwhichtypeofmodelownsthephoto.
Tohelpunderstandhowthisworks,let'sexplorethedatabasestructureforapolymorphicrelation:
staff
id-integer
name-string
orders
id-integer
price-integer
photos
id-integer
path-string
imageable_id-integer
imageable_type-string
Thekeyfieldstonoticeherearetheimageable_idandimageable_typeonthephotostable.TheIDwillcontaintheIDvalueof,inthisexample,theowningstaffororder,whilethetypewillcontaintheclassnameoftheowningmodel.ThisiswhatallowstheORMtodeterminewhichtypeofowningmodeltoreturnwhenaccessingtheimageablerelation.
Inadditiontotraditionalpolymorphicrelations,youmayalsospecifymany-to-manypolymorphicrelations.Forexample,ablogPostandVideomodelcouldshareapolymorphicrelationtoaTagmodel.First,let'sexaminethetablestructure:
posts
id-integer
name-string
videos
id-integer
name-string
tags
id-integer
name-string
taggables
tag_id-integer
taggable_id-integer
taggable_type-string
Next,we'rereadytosetuptherelationshipsonthemodel.ThePostandVideomodelwillbothhaveamorphToManyrelationshipviaatagsmethod:
classPostextendsModel{
RetrievingTheOwnerOfAPolymorphicRelation
PolymorphicRelationTableStructure
ManyToManyPolymorphicRelations
PolymorphicManyToManyRelationTableStructure
publicfunctiontags()
{
return$this->morphToMany('App\Tag','taggable');
}
}
TheTagmodelmaydefineamethodforeachofitsrelationships:
classTagextendsModel{
publicfunctionposts()
{
return$this->morphedByMany('App\Post','taggable');
}
publicfunctionvideos()
{
return$this->morphedByMany('App\Video','taggable');
}
}
Whenaccessingtherecordsforamodel,youmaywishtolimityourresultsbasedontheexistenceofarelationship.Forexample,youwishtopullallblogpoststhathaveatleastonecomment.Todoso,youmayusethehasmethod:
$posts=Post::has('comments')->get();
Youmayalsospecifyanoperatorandacount:
$posts=Post::has('comments','>=',3)->get();
Nestedhasstatementsmayalsobeconstructedusing"dot"notation:
$posts=Post::has('comments.votes')->get();
Ifyouneedevenmorepower,youmayusethewhereHasandorWhereHasmethodstoput"where"conditionsonyourhasqueries:
$posts=Post::whereHas('comments',function($q)
{
$q->where('content','like','foo%');
})->get();
Eloquentallowsyoutoaccessyourrelationsviadynamicproperties.Eloquentwillautomaticallyloadtherelationshipforyou,andisevensmartenoughtoknowwhethertocalltheget(forone-to-manyrelationships)orfirst(forone-to-onerelationships)method.Itwillthenbeaccessibleviaadynamicpropertybythesamenameastherelation.Forexample,withthefollowingmodel$phone:
QueryingRelations
QueryingRelationsWhenSelecting
DynamicProperties
classPhoneextendsModel{
publicfunctionuser()
{
return$this->belongsTo('App\User');
}
}
$phone=Phone::find(1);
Insteadofechoingtheuser'semaillikethis:
echo$phone->user()->first()->email;
Itmaybeshortenedtosimply:
echo$phone->user->email;
Note:RelationshipsthatreturnmanyresultswillreturnaninstanceoftheIlluminate\Database\Eloquent\Collectionclass.
EagerloadingexiststoalleviatetheN+1queryproblem.Forexample,consideraBookmodelthatisrelatedtoAuthor.Therelationshipisdefinedlikeso:
classBookextendsModel{
publicfunctionauthor()
{
return$this->belongsTo('App\Author');
}
}
Now,considerthefollowingcode:
foreach(Book::all()as$book)
{
echo$book->author->name;
}
Thisloopwillexecute1querytoretrieveallofthebooksonthetable,thenanotherqueryforeachbooktoretrievetheauthor.So,ifwehave25books,thisloopwouldrun26queries.
Thankfully,wecanuseeagerloadingtodrasticallyreducethenumberofqueries.Therelationshipsthatshouldbeeagerloadedmaybespecifiedviathewithmethod:
foreach(Book::with('author')->get()as$book)
{
echo$book->author->name;
}
Intheloopabove,onlytwoquerieswillbeexecuted:
EagerLoading
select*frombooks
select*fromauthorswhereidin(1,2,3,4,5,...)
Wiseuseofeagerloadingcandrasticallyincreasetheperformanceofyourapplication.
Ofcourse,youmayeagerloadmultiplerelationshipsatonetime:
$books=Book::with('author','publisher')->get();
Youmayeveneagerloadnestedrelationships:
$books=Book::with('author.contacts')->get();
Intheexampleabove,theauthorrelationshipwillbeeagerloaded,andtheauthor'scontactsrelationwillalsobeloaded.
Sometimesyoumaywishtoeagerloadarelationship,butalsospecifyaconditionfortheeagerload.Here'sanexample:
$users=User::with(array('posts'=>function($query)
{
$query->where('title','like','%first%');
}))->get();
Inthisexample,we'reeagerloadingtheuser'sposts,butonlyifthepost'stitlecolumncontainstheword"first".
Ofcourse,eagerloadingClosuresaren'tlimitedto"constraints".Youmayalsoapplyorders:
$users=User::with(array('posts'=>function($query)
{
$query->orderBy('created_at','desc');
}))->get();
Itisalsopossibletoeagerlyloadrelatedmodelsdirectlyfromanalreadyexistingmodelcollection.Thismaybeusefulwhendynamicallydecidingwhethertoloadrelatedmodelsornot,orincombinationwithcaching.
$books=Book::all();
$books->load('author','publisher');
Youwilloftenneedtoinsertnewrelatedmodels.Forexample,youmaywishtoinsertanewcommentforapost.Insteadofmanuallysettingthepost_idforeignkeyonthemodel,youmayinsertthenewcommentfromitsparentPostmodeldirectly:
EagerLoadConstraints
LazyEagerLoading
InsertingRelatedModels
AttachingARelatedModel
$comment=newComment(array('message'=>'Anewcomment.'));
$post=Post::find(1);
$comment=$post->comments()->save($comment);
Inthisexample,thepost_idfieldwillautomaticallybesetontheinsertedcomment.
Ifyouneedtosavemultiplerelatedmodels:
$comments=array(
newComment(array('message'=>'Anewcomment.')),
newComment(array('message'=>'Anothercomment.')),
newComment(array('message'=>'Thelatestcomment.'))
);
$post=Post::find(1);
$post->comments()->saveMany($comments);
WhenupdatingabelongsTorelationship,youmayusetheassociatemethod.Thismethodwillsettheforeignkeyonthechildmodel:
$account=Account::find(10);
$user->account()->associate($account);
$user->save();
Youmayalsoinsertrelatedmodelswhenworkingwithmany-to-manyrelations.Let'scontinueusingourUserandRolemodelsasexamples.Wecaneasilyattachnewrolestoauserusingtheattachmethod:
$user=User::find(1);
$user->roles()->attach(1);
Youmayalsopassanarrayofattributesthatshouldbestoredonthepivottablefortherelation:
$user->roles()->attach(1,array('expires'=>$expires));
Ofcourse,theoppositeofattachisdetach:
$user->roles()->detach(1);
BothattachanddetachalsotakearraysofIDsasinput:
$user=User::find(1);
$user->roles()->detach([1,2,3]);
AssociatingModels(BelongsTo)
InsertingRelatedModels(ManyToMany)
AttachingManyToManyModels
$user->roles()->attach([1=>['attribute1'=>'value1'],2,3]);
Youmayalsousethesyncmethodtoattachrelatedmodels.ThesyncmethodacceptsanarrayofIDstoplaceonthepivottable.Afterthisoperationiscomplete,onlytheIDsinthearraywillbeontheintermediatetableforthemodel:
$user->roles()->sync(array(1,2,3));
YoumayalsoassociateotherpivottablevalueswiththegivenIDs:
$user->roles()->sync(array(1=>array('expires'=>true)));
Sometimesyoumaywishtocreateanewrelatedmodelandattachitinasinglecommand.Forthisoperation,youmayusethesavemethod:
$role=newRole(array('name'=>'Editor'));
User::find(1)->roles()->save($role);
Inthisexample,thenewRolemodelwillbesavedandattachedtotheusermodel.Youmayalsopassanarrayofattributestoplaceonthejoiningtableforthisoperation:
User::find(1)->roles()->save($role,array('expires'=>$expires));
WhenamodelbelongsToanothermodel,suchasaCommentwhichbelongstoaPost,itisoftenhelpfultoupdatetheparent'stimestampwhenthechildmodelisupdated.Forexample,whenaCommentmodelisupdated,youmaywanttoautomaticallytouchtheupdated_attimestampoftheowningPost.Eloquentmakesiteasy.Justaddatouchespropertycontainingthenamesoftherelationshipstothechildmodel:
classCommentextendsModel{
protected$touches=array('post');
publicfunctionpost()
{
return$this->belongsTo('App\Post');
}
}
Now,whenyouupdateaComment,theowningPostwillhaveitsupdated_atcolumnupdated:
$comment=Comment::find(1);
$comment->text='Edittothiscomment!';
$comment->save();
UsingSyncToAttachManyToManyModels
AddingPivotDataWhenSyncing
TouchingParentTimestamps
Asyouhavealreadylearned,workingwithmany-to-manyrelationsrequiresthepresenceofanintermediatetable.Eloquentprovidessomeveryhelpfulwaysofinteractingwiththistable.Forexample,let'sassumeourUserobjecthasmanyRoleobjectsthatitisrelatedto.Afteraccessingthisrelationship,wemayaccessthepivottableonthemodels:
$user=User::find(1);
foreach($user->rolesas$role)
{
echo$role->pivot->created_at;
}
NoticethateachRolemodelweretrieveisautomaticallyassignedapivotattribute.Thisattributecontainsamodelrepresentingtheintermediatetable,andmaybeusedasanyotherEloquentmodel.
Bydefault,onlythekeyswillbepresentonthepivotobject.Ifyourpivottablecontainsextraattributes,youmustspecifythemwhendefiningtherelationship:
return$this->belongsToMany('App\Role')->withPivot('foo','bar');
NowthefooandbarattributeswillbeaccessibleonourpivotobjectfortheRolemodel.
Ifyouwantyourpivottabletohaveautomaticallymaintainedcreated_atandupdated_attimestamps,usethewithTimestampsmethodontherelationshipdefinition:
return$this->belongsToMany('App\Role')->withTimestamps();
Todeleteallrecordsonthepivottableforamodel,youmayusethedetachmethod:
User::find(1)->roles()->detach();
Notethatthisoperationdoesnotdeleterecordsfromtherolestable,butonlyfromthepivottable.
Sometimesyoumayneedtoupdateyourpivottable,butnotdetachit.IfyouwishtoupdateyourpivottableinplaceyoumayuseupdateExistingPivotmethodlikeso:
User::find(1)->roles()->updateExistingPivot($roleId,$attributes);
LaravelalsoallowsyoutodefineacustomPivotmodel.Todefineacustommodel,firstcreateyourown"Base"modelclassthatextendsEloquent.InyourotherEloquentmodels,extendthiscustombasemodelinsteadofthedefaultEloquentbase.Inyourbasemodel,addthefollowingfunctionthatreturnsaninstanceofyourcustomPivotmodel:
publicfunctionnewPivot(Model$parent,array$attributes,$table,$exists)
{
returnnewYourCustomPivot($parent,$attributes,$table,$exists);
WorkingWithPivotTables
DeletingRecordsOnAPivotTable
UpdatingARecordOnAPivotTable
DefiningACustomPivotModel
}
Allmulti-resultsetsreturnedbyEloquent,eitherviathegetmethodorarelationship,willreturnacollectionobject.ThisobjectimplementstheIteratorAggregatePHPinterfacesoitcanbeiteratedoverlikeanarray.However,thisobjectalsohasavarietyofotherhelpfulmethodsforworkingwithresultsets.
Forexample,wemaydetermineifaresultsetcontainsagivenprimarykeyusingthecontainsmethod:
$roles=User::find(1)->roles;
if($roles->contains(2))
{
//
}
CollectionsmayalsobeconvertedtoanarrayorJSON:
$roles=User::find(1)->roles->toArray();
$roles=User::find(1)->roles->toJson();
Ifacollectioniscasttoastring,itwillbereturnedasJSON:
$roles=(string)User::find(1)->roles;
Eloquentcollectionsalsocontainafewhelpfulmethodsforloopingandfilteringtheitemstheycontain:
$roles=$user->roles->each(function($role)
{
//
});
Whenfilteringcollections,thecallbackprovidedwillbeusedascallbackforarray_filter.
$users=$users->filter(function($user)
{
return$user->isAdmin();
});
Note:WhenfilteringacollectionandconvertingittoJSON,trycallingthevaluesfunctionfirsttoresetthearray'skeys.
$roles=User::find(1)->roles;
Collections
CheckingIfACollectionContainsAKey
IteratingCollections
FilteringCollections
ApplyingACallbackToEachCollectionObject
$roles->each(function($role)
{
//
});
$roles=$roles->sortBy(function($role)
{
return$role->created_at;
});
$roles=$roles->sortBy('created_at');
Sometimes,youmaywishtoreturnacustomCollectionobjectwithyourownaddedmethods.YoumayspecifythisonyourEloquentmodelbyoverridingthenewCollectionmethod:
classUserextendsModel{
publicfunctionnewCollection(array$models=array())
{
returnnewCustomCollection($models);
}
}
Eloquentprovidesaconvenientwaytotransformyourmodelattributeswhengettingorsettingthem.SimplydefineagetFooAttributemethodonyourmodeltodeclareanaccessor.Keepinmindthatthemethodsshouldfollowcamel-casing,eventhoughyourdatabasecolumnsaresnake-case:
classUserextendsModel{
publicfunctiongetFirstNameAttribute($value)
{
returnucfirst($value);
}
}
Intheexampleabove,thefirst_namecolumnhasanaccessor.Notethatthevalueoftheattributeispassedtotheaccessor.
Mutatorsaredeclaredinasimilarfashion:
classUserextendsModel{
SortingACollectionByAValue
SortingACollectionByAValue
ReturningACustomCollectionType
Accessors&Mutators
DefiningAnAccessor
DefiningAMutator
publicfunctionsetFirstNameAttribute($value)
{
$this->attributes['first_name']=strtolower($value);
}
}
Bydefault,Eloquentwillconvertthecreated_atandupdated_atcolumnstoinstancesofCarbon,whichprovidesanassortmentofhelpfulmethods,andextendsthenativePHPDateTimeclass.
Youmaycustomizewhichfieldsareautomaticallymutated,andevencompletelydisablethismutation,byoverridingthegetDatesmethodofthemodel:
publicfunctiongetDates()
{
returnarray('created_at');
}
Whenacolumnisconsideredadate,youmaysetitsvaluetoaUNIXtimestamp,datestring(Y-m-d),date-timestring,andofcourseaDateTime/Carboninstance.
Tototallydisabledatemutations,simplyreturnanemptyarrayfromthegetDatesmethod:
publicfunctiongetDates()
{
returnarray();
}
Ifyouhavesomeattributesthatyouwanttoalwaysconverttoanotherdata-type,youmayaddtheattributetothecastspropertyofyourmodel.Otherwise,youwillhavetodefineamutatorforeachoftheattributes,whichcanbetimeconsuming.Hereisanexampleofusingthecastsproperty:
/**
*Theattributesthatshouldbecastedtonativetypes.
*
*@vararray
*/
protected$casts=[
'is_admin'=>'boolean',
];
Nowtheis_adminattributewillalwaysbecasttoabooleanwhenyouaccessit,eveniftheunderlyingvalueisstoredinthedatabaseasaninteger.Othersupportedcasttypesare:integer,real,float,double,string,boolean,andarray.
ThearraycastisparticularlyusefulforworkingwithcolumnsthatarestoredasserializedJSON.Forexample,ifyourdatabasehasaTEXTtypefieldthatcontainsserializedJSON,addingthearraycasttothatattributewillautomaticallydeserializetheattributetoaPHParraywhenyouaccessitonyourEloquentmodel:
/**
*Theattributesthatshouldbecastedtonativetypes.
*
*@vararray
DateMutators
AttributeCasting
*/
protected$casts=[
'options'=>'array',
];
Now,whenyouutilizetheEloquentmodel:
$user=User::find(1);
//$optionsisanarray...
$options=$user->options;
//optionsisautomaticallyserializedbacktoJSON...
$user->options=['foo'=>'bar'];
Eloquentmodelsfireseveralevents,allowingyoutohookintovariouspointsinthemodel'slifecycleusingthefollowingmethods:creating,created,updating,updated,saving,saved,deleting,deleted,restoring,restored.
Wheneveranewitemissavedforthefirsttime,thecreatingandcreatedeventswillfire.Ifanitemisnotnewandthesavemethodiscalled,theupdating/updatedeventswillfire.Inbothcases,thesaving/savedeventswillfire.
Iffalseisreturnedfromthecreating,updating,saving,ordeletingevents,theactionwillbecancelled:
User::creating(function($user)
{
if(!$user->isValid())returnfalse;
});
YourEventServiceProviderservesasaconvenientplacetoregisteryourmodeleventbindings.Forexample:
/**
*Registeranyothereventsforyourapplication.
*
*@param\Illuminate\Contracts\Events\Dispatcher$events
*@returnvoid
*/
publicfunctionboot(DispatcherContract$events)
{
parent::boot($events);
User::creating(function($user)
{
//
});
}
Toconsolidatethehandlingofmodelevents,youmayregisteramodelobserver.Anobserverclassmayhavemethodsthatcorrespondtothevariousmodelevents.Forexample,creating,updating,savingmethodsmaybeonanobserver,inadditiontoanyothermodeleventname.
So,forexample,amodelobservermightlooklikethis:
ModelEvents
CancellingSaveOperationsViaEvents
WhereToRegisterEventListeners
ModelObservers
classUserObserver{
publicfunctionsaving($model)
{
//
}
publicfunctionsaved($model)
{
//
}
}
Youmayregisteranobserverinstanceusingtheobservemethod:
User::observe(newUserObserver);
WhenbuildingJSONAPIs,youmayoftenneedtoconvertyourmodelsandrelationshipstoarraysorJSON.So,Eloquentincludesmethodsfordoingso.Toconvertamodelanditsloadedrelationshiptoanarray,youmayusethetoArraymethod:
$user=User::with('roles')->first();
return$user->toArray();
Notethatentirecollectionsofmodelsmayalsobeconvertedtoarrays:
returnUser::all()->toArray();
ToconvertamodeltoJSON,youmayusethetoJsonmethod:
returnUser::find(1)->toJson();
Notethatwhenamodelorcollectioniscasttoastring,itwillbeconvertedtoJSON,meaningyoucanreturnEloquentobjectsdirectlyfromyourapplication'sroutes!
Route::get('users',function()
{
returnUser::all();
});
Sometimesyoumaywishtolimittheattributesthatareincludedinyourmodel'sarrayorJSONform,suchaspasswords.
ConvertingToArrays/JSON
ConvertingAModelToAnArray
ConvertingAModelToJSON
ReturningAModelFromARoute
HidingAttributesFromArrayOrJSONConversion
Todoso,addahiddenpropertydefinitiontoyourmodel:
classUserextendsModel{
protected$hidden=array('password');
}
Note:Whenhidingrelationships,usetherelationship'smethodname,notthedynamicaccessorname.
Alternatively,youmayusethevisiblepropertytodefineawhite-list:
protected$visible=array('first_name','last_name');
Occasionally,youmayneedtoaddarrayattributesthatdonothaveacorrespondingcolumninyourdatabase.Todoso,simplydefineanaccessorforthevalue:
publicfunctiongetIsAdminAttribute()
{
return$this->attributes['admin']=='yes';
}
Onceyouhavecreatedtheaccessor,justaddthevaluetotheappendspropertyonthemodel:
protected$appends=array('is_admin');
Oncetheattributehasbeenaddedtotheappendslist,itwillbeincludedinboththemodel'sarrayandJSONforms.Attributesintheappendsarrayrespectthevisibleandhiddenconfigurationonthemodel.
IntroductionCreating&DroppingTablesAddingColumnsChangingColumnsRenamingColumnsDroppingColumnsCheckingExistenceAddingIndexesForeignKeysDroppingIndexesDroppingTimestamps&SoftDeletesStorageEngines
TheLaravelSchemaclassprovidesadatabaseagnosticwayofmanipulatingtables.ItworkswellwithallofthedatabasessupportedbyLaravel,andhasaunifiedAPIacrossallofthesesystems.
Tocreateanewdatabasetable,theSchema::createmethodisused:
Schema::create('users',function($table)
{
$table->increments('id');
});
Thefirstargumentpassedtothecreatemethodisthenameofthetable,andthesecondisaClosurewhichwillreceiveaBlueprintobjectwhichmaybeusedtodefinethenewtable.
Torenameanexistingdatabasetable,therenamemethodmaybeused:
Schema::rename($from,$to);
Tospecifywhichconnectiontheschemaoperationshouldtakeplaceon,usetheSchema::connectionmethod:
Schema::connection('foo')->create('users',function($table)
{
$table->increments('id');
});
Todropatable,youmayusetheSchema::dropmethod:
Schema::drop('users');
Schema::dropIfExists('users');
SchemaBuilder
Introduction
Creating&DroppingTables
AddingColumns
Toupdateanexistingtable,wewillusetheSchema::tablemethod:
Schema::table('users',function($table)
{
$table->string('email');
});
Thetablebuildercontainsavarietyofcolumntypesthatyoumayusewhenbuildingyourtables:
Command Description
$table->bigIncrements('id'); IncrementingIDusinga"biginteger"equivalent.
$table->bigInteger('votes'); BIGINTequivalenttothetable
$table->binary('data'); BLOBequivalenttothetable
$table->boolean('confirmed'); BOOLEANequivalenttothetable
$table->char('name',4); CHARequivalentwithalength
$table->date('created_at'); DATEequivalenttothetable
$table->dateTime('created_at'); DATETIMEequivalenttothetable
$table->decimal('amount',5,2); DECIMALequivalentwithaprecisionandscale
$table->double('column',15,8);DOUBLEequivalentwithprecision,15digitsintotaland8afterthedecimalpoint
$table->enum('choices',array('foo',
'bar'));ENUMequivalenttothetable
$table->float('amount'); FLOATequivalenttothetable
$table->increments('id'); IncrementingIDtothetable(primarykey).
$table->integer('votes'); INTEGERequivalenttothetable
$table->json('options'); JSONequivalenttothetable
$table->longText('description'); LONGTEXTequivalenttothetable
$table->mediumInteger('numbers'); MEDIUMINTequivalenttothetable
$table->mediumText('description'); MEDIUMTEXTequivalenttothetable
$table->morphs('taggable'); AddsINTEGERtaggable_idandSTRINGtaggable_type
$table->nullableTimestamps(); Sameastimestamps(),exceptallowsNULLs
$table->smallInteger('votes'); SMALLINTequivalenttothetable
$table->tinyInteger('numbers'); TINYINTequivalenttothetable
$table->softDeletes(); Addsdeleted_atcolumnforsoftdeletes
$table->string('email'); VARCHARequivalentcolumn
$table->string('name',100); VARCHARequivalentwithalength
$table->text('description'); TEXTequivalenttothetable
$table->time('sunrise'); TIMEequivalenttothetable
$table->timestamp('added_on'); TIMESTAMPequivalenttothetable
$table->timestamps(); Addscreated_atandupdated_atcolumns
$table->rememberToken(); Addsremember_tokenasVARCHAR(100)NULL
->nullable() DesignatethatthecolumnallowsNULLvalues
->default($value) Declareadefaultvalueforacolumn
->unsigned() SetINTEGERtoUNSIGNED
IfyouareusingtheMySQLdatabase,youmayusetheaftermethodtospecifytheorderofcolumns:
$table->string('name')->after('email');
Sometimesyoumayneedtomodifyanexistingcolumn.Forexample,youmaywishtoincreasethesizeofastringcolumn.Thechangemethodmakesiteasy!Forexample,let'sincreasethesizeofthenamecolumnfrom25to50:
Schema::table('users',function($table)
{
$table->string('name',50)->change();
});
Wecouldalsomodifyacolumntobenullable:
Schema::table('users',function($table)
{
$table->string('name',50)->nullable()->change();
});
Torenameacolumn,youmayusetherenameColumnmethodontheSchemabuilder.Beforerenamingacolumn,besuretoaddthedoctrine/dbaldependencytoyourcomposer.jsonfile.
Schema::table('users',function($table)
{
$table->renameColumn('from','to');
});
Note:Renamingenumcolumntypesisnotsupported.
Todropacolumn,youmayusethedropColumnmethodontheSchemabuilder.Beforedroppingacolumn,besuretoaddthedoctrine/dbaldependencytoyourcomposer.jsonfile.
Schema::table('users',function($table)
{
$table->dropColumn('votes');
});
UsingAfterOnMySQL
ChangingColumns
RenamingColumns
DroppingColumns
DroppingAColumnFromADatabaseTable
DroppingMultipleColumnsFromADatabaseTable
Schema::table('users',function($table)
{
$table->dropColumn(array('votes','avatar','location'));
});
YoumayeasilycheckfortheexistenceofatableorcolumnusingthehasTableandhasColumnmethods:
if(Schema::hasTable('users'))
{
//
}
if(Schema::hasColumn('users','email'))
{
//
}
Theschemabuildersupportsseveraltypesofindexes.Therearetwowaystoaddthem.First,youmayfluentlydefinethemonacolumndefinition,oryoumayaddthemseparately:
$table->string('email')->unique();
Or,youmaychoosetoaddtheindexesonseparatelines.Belowisalistofallavailableindextypes:
Command Description
$table->primary('id'); Addingaprimarykey
$table->primary(array('first','last')); Addingcompositekeys
$table->unique('email'); Addingauniqueindex
$table->index('state'); Addingabasicindex
Laravelalsoprovidessupportforaddingforeignkeyconstraintstoyourtables:
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
Inthisexample,wearestatingthattheuser_idcolumnreferencestheidcolumnontheuserstable.Makesuretocreatetheforeignkeycolumnfirst!
Youmayalsospecifyoptionsforthe"ondelete"and"onupdate"actionsoftheconstraint:
CheckingExistence
CheckingForExistenceOfTable
CheckingForExistenceOfColumns
AddingIndexes
ForeignKeys
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
Todropaforeignkey,youmayusethedropForeignmethod.Asimilarnamingconventionisusedforforeignkeysasisusedforotherindexes:
$table->dropForeign('posts_user_id_foreign');
Note:Whencreatingaforeignkeythatreferencesanincrementinginteger,remembertoalwaysmaketheforeignkeycolumnunsigned.
Todropanindexyoumustspecifytheindex'sname.Laravelassignsareasonablenametotheindexesbydefault.Simplyconcatenatethetablename,thenamesofthecolumnintheindex,andtheindextype.Herearesomeexamples:
Command Description
$table->dropPrimary('users_id_primary'); Droppingaprimarykeyfromthe"users"table
$table->dropUnique('users_email_unique'); Droppingauniqueindexfromthe"users"table
$table->dropIndex('geo_state_index'); Droppingabasicindexfromthe"geo"table
Todropthetimestamps,nullableTimestampsorsoftDeletescolumntypes,youmayusethefollowingmethods:
Command Description
$table->dropTimestamps(); Droppingthecreated_atandupdated_atcolumnsfromthetable
$table->dropSoftDeletes(); Droppingdeleted_atcolumnfromthetable
Tosetthestorageengineforatable,settheenginepropertyontheschemabuilder:
Schema::create('users',function($table)
{
$table->engine='InnoDB';
$table->string('email');
});
DroppingIndexes
DroppingTimestamps&SoftDeletes
StorageEngines
IntroductionCreatingMigrationsRunningMigrationsRollingBackMigrationsDatabaseSeeding
Migrationsareatypeofversioncontrolforyourdatabase.Theyallowateamtomodifythedatabaseschemaandstayuptodateonthecurrentschemastate.MigrationsaretypicallypairedwiththeSchemaBuildertoeasilymanageyourapplication'sschema.
Tocreateamigration,youmayusethemake:migrationcommandontheArtisanCLI:
phpartisanmake:migrationcreate_users_table
Themigrationwillbeplacedinyourdatabase/migrationsfolder,andwillcontainatimestampwhichallowstheframeworktodeterminetheorderofthemigrations.
The--tableand--createoptionsmayalsobeusedtoindicatethenameofthetable,andwhetherthemigrationwillbecreatinganewtable:
phpartisanmake:migrationadd_votes_to_user_table--table=users
phpartisanmake:migrationcreate_users_table--create=users
phpartisanmigrate
Note:Ifyoureceivea"classnotfound"errorwhenrunningmigrations,tryrunningthecomposerdump-autoloadcommand.
Somemigrationoperationsaredestructive,meaningtheymaycauseyoutolosedata.Inordertoprotectyoufromrunningthesecommandsagainstyourproductiondatabase,youwillpromptedforconfirmationbeforethesecommandsareexecuted.Toforcethecommandstorunwithoutaprompt,usethe--forceflag:
phpartisanmigrate--force
Migrations&Seeding
Introduction
CreatingMigrations
RunningMigrations
RunningAllOutstandingMigrations
ForcingMigrationsInProduction
phpartisanmigrate:rollback
phpartisanmigrate:reset
phpartisanmigrate:refresh
phpartisanmigrate:refresh--seed
Laravelalsoincludesasimplewaytoseedyourdatabasewithtestdatausingseedclasses.Allseedclassesarestoredindatabase/seeds.Seedclassesmayhaveanynameyouwish,butprobablyshouldfollowsomesensibleconvention,suchasUserTableSeeder,etc.Bydefault,aDatabaseSeederclassisdefinedforyou.Fromthisclass,youmayusethecallmethodtorunotherseedclasses,allowingyoutocontroltheseedingorder.
classDatabaseSeederextendsSeeder{
publicfunctionrun()
{
$this->call('UserTableSeeder');
$this->command->info('Usertableseeded!');
}
}
classUserTableSeederextendsSeeder{
publicfunctionrun()
{
DB::table('users')->delete();
User::create(array('email'=>'[email protected]'));
}
}
Toseedyourdatabase,youmayusethedb:seedcommandontheArtisanCLI:
phpartisandb:seed
Bydefault,thedb:seedcommandrunstheDatabaseSeederclass,whichmaybeusedtocallotherseedclasses.However,youmayusethe--classoptiontospecifyaspecificseederclasstorunindividually:
phpartisandb:seed--class=UserTableSeeder
RollingBackMigrations
RollbackTheLastMigrationOperation
Rollbackallmigrations
Rollbackallmigrationsandrunthemallagain
DatabaseSeeding
ExampleDatabaseSeedClass
Youmayalsoseedyourdatabaseusingthemigrate:refreshcommand,whichwillalsorollbackandre-runallofyourmigrations:
phpartisanmigrate:refresh--seed
IntroductionConfigurationUsagePipelining
Redisisanopensource,advancedkey-valuestore.Itisoftenreferredtoasadatastructureserversincekeyscancontainstrings,hashes,lists,sets,andsortedsets.
BeforeusingRediswithLaravel,youwillneedtoinstallthepredis/predispackage(~1.0)viaComposer.
Note:IfyouhavetheRedisPHPextensioninstalledviaPECL,youwillneedtorenamethealiasforRedisinyourconfig/app.phpfile.
TheRedisconfigurationforyourapplicationisstoredintheconfig/database.phpfile.Withinthisfile,youwillseearedisarraycontainingtheRedisserversusedbyyourapplication:
'redis'=>[
'cluster'=>true,
'default'=>['host'=>'127.0.0.1','port'=>6379],
],
Thedefaultserverconfigurationshouldsufficefordevelopment.However,youarefreetomodifythisarraybasedonyourenvironment.SimplygiveeachRedisserveraname,andspecifythehostandportusedbytheserver.
TheclusteroptionwilltelltheLaravelRedisclienttoperformclient-sideshardingacrossyourRedisnodes,allowingyoutopoolnodesandcreatealargeamountofavailableRAM.However,notethatclient-sideshardingdoesnothandlefailover;therefore,isprimarilysuitedforcacheddatathatisavailablefromanotherprimarydatastore.
IfyourRedisserverrequiresauthentication,youmaysupplyapasswordbyaddingapasswordkey/valuepairtoyourRedisserverconfigurationarray.
YoumaygetaRedisinstancebycallingtheRedis::connectionmethod:
$redis=Redis::connection();
ThiswillgiveyouaninstanceofthedefaultRedisserver.Ifyouarenotusingserverclustering,youmaypasstheservernametotheconnectionmethodtogetaspecificserverasdefinedinyourRedisconfiguration:
$redis=Redis::connection('other');
Redis
Introduction
Configuration
Usage
OnceyouhaveaninstanceoftheRedisclient,wemayissueanyoftheRediscommandstotheinstance.LaravelusesmagicmethodstopassthecommandstotheRedisserver:
$redis->set('name','Taylor');
$name=$redis->get('name');
$values=$redis->lrange('names',5,10);
Noticetheargumentstothecommandaresimplypassedintothemagicmethod.Ofcourse,youarenotrequiredtousethemagicmethods,youmayalsopasscommandstotheserverusingthecommandmethod:
$values=$redis->command('lrange',array(5,10));
Whenyouaresimplyexecutingcommandsagainstthedefaultconnection,justusestaticmagicmethodsontheRedisclass:
Redis::set('name','Taylor');
$name=Redis::get('name');
$values=Redis::lrange('names',5,10);
Note:RediscacheandsessiondriversareincludedwithLaravel.
Pipeliningshouldbeusedwhenyouneedtosendmanycommandstotheserverinoneoperation.Togetstarted,usethepipelinecommand:
Redis::pipeline(function($pipe)
{
for($i=0;$i<1000;$i++)
{
$pipe->set("key:$i",$i);
}
});
Pipelining
PipingManyCommandsToYourServers
OverviewIntroductionUsageCallingCommandsOutsideOfCLISchedulingArtisanCommands
DevelopmentIntroductionBuildingACommandRegisteringCommands
ArtisanCLI
IntroductionUsageCallingCommandsOutsideOfCLISchedulingArtisanCommands
Artisanisthenameofthecommand-lineinterfaceincludedwithLaravel.Itprovidesanumberofhelpfulcommandsforyourusewhiledevelopingyourapplication.ItisdrivenbythepowerfulSymfonyConsolecomponent.
ToviewalistofallavailableArtisancommands,youmayusethelistcommand:
phpartisanlist
Everycommandalsoincludesa"help"screenwhichdisplaysanddescribesthecommand'savailableargumentsandoptions.Toviewahelpscreen,simplyprecedethenameofthecommandwithhelp:
phpartisanhelpmigrate
Youmayspecifytheconfigurationenvironmentthatshouldbeusedwhilerunningacommandusingthe--envswitch:
phpartisanmigrate--env=local
YoumayalsoviewthecurrentversionofyourLaravelinstallationusingthe--versionoption:
phpartisan--version
SometimesyoumaywishtoexecuteanArtisancommandoutsideoftheCLI.Forexample,youmaywishtofireanArtisancommandfromanHTTProute.JustusetheArtisanfacade:
Route::get('/foo',function()
{
$exitCode=Artisan::call('command:name',['--option'=>'foo']);
ArtisanCLI
Introduction
Usage
ListingAllAvailableCommands
ViewingTheHelpScreenForACommand
SpecifyingTheConfigurationEnvironment
DisplayingYourCurrentLaravelVersion
CallingCommandsOutsideOfCLI
//
});
YoumayevenqueueArtisancommandssotheyareprocessedinthebackgroundbyyourqueueworkers:
Route::get('/foo',function()
{
Artisan::queue('command:name',['--option'=>'foo']);
//
});
Inthepast,developershavegeneratedaCronentryforeachconsolecommandtheywishedtoschedule.However,thisisaheadache.Yourconsolescheduleisnolongerinsourcecontrol,andyoumustSSHintoyourservertoaddtheCronentries.Let'smakeourliveseasier.TheLaravelcommandschedulerallowsyoutofluentlyandexpressivelydefineyourcommandschedulewithinLaravelitself,andonlyasingleCronentryisneededonyourserver.
Yourcommandscheduleisstoredintheapp/Console/Kernel.phpfile.Withinthisclassyouwillseeaschedulemethod.Tohelpyougetstarted,asimpleexampleisincludedwiththemethod.YouarefreetoaddasmanyscheduledjobsasyouwishtotheScheduleobject.TheonlyCronentryyouneedtoaddtoyourserveristhis:
*****php/path/to/artisanschedule:run1>>/dev/null2>&1
ThisCronwillcalltheLaravelcommandschedulereveryminute.Then,Laravelevaluatesyourscheduledjobsandrunsthejobsthataredue.Itcouldn'tbeeasier!
Let'slookatafewmoreschedulingexamples:
$schedule->call(function()
{
//Dosometask...
})->hourly();
$schedule->exec('composerself-update')->daily();
$schedule->command('foo')->cron('*****');
$schedule->command('foo')->everyFiveMinutes();
SchedulingArtisanCommands
MoreSchedulingExamples
SchedulingClosures
SchedulingTerminalCommands
ManualCronExpression
FrequentJobs
$schedule->command('foo')->everyTenMinutes();
$schedule->command('foo')->everyThirtyMinutes();
$schedule->command('foo')->daily();
$schedule->command('foo')->dailyAt('15:00');
$schedule->command('foo')->twiceDaily();
$schedule->command('foo')->weekdays();
$schedule->command('foo')->weekly();
//Scheduleweeklyjobforspecificday(0-6)andtime...
$schedule->command('foo')->weeklyOn(1,'8:00');
$schedule->command('foo')->monthly();
$schedule->command('foo')->monthly()->environments('production');
$schedule->command('foo')->monthly()->evenInMaintenanceMode();
$schedule->command('foo')->monthly()->when(function()
{
returntrue;
});
DailyJobs
DailyJobsAtASpecificTime(24HourTime)
TwiceDailyJobs
JobThatRunsEveryWeekday
WeeklyJobs
MonthlyJobs
LimitTheEnvironmentTheJobsShouldRunIn
IndicateTheJobShouldRunEvenWhenApplicationIsInMaintenanceMode
OnlyAllowJobToRunWhenCallbackIsTrue
IntroductionBuildingACommandRegisteringCommands
InadditiontothecommandsprovidedwithArtisan,youmayalsobuildyourowncustomcommandsforworkingwithyourapplication.Youmaystoreyourcustomcommandsintheapp/Console/Commandsdirectory;however,youarefreetochooseyourownstoragelocationaslongasyourcommandscanbeautoloadedbasedonyourcomposer.jsonsettings.
Tocreateanewcommand,youmayusethemake:consoleArtisancommand,whichwillgenerateacommandstubtohelpyougetstarted:
phpartisanmake:consoleFooCommand
Thecommandabovewouldgenerateaclassatapp/Console/FooCommand.php.
Whencreatingthecommand,the--commandoptionmaybeusedtoassigntheterminalcommandname:
phpartisanmake:consoleAssignUsers--command=users:assign
Onceyourcommandisgenerated,youshouldfilloutthenameanddescriptionpropertiesoftheclass,whichwillbeusedwhendisplayingyourcommandonthelistscreen.
Thefiremethodwillbecalledwhenyourcommandisexecuted.Youmayplaceanycommandlogicinthismethod.
ThegetArgumentsandgetOptionsmethodsarewhereyoumaydefineanyargumentsoroptionsyourcommandreceives.Bothofthesemethodsreturnanarrayofcommands,whicharedescribedbyalistofarrayoptions.
Whendefiningarguments,thearraydefinitionvaluesrepresentthefollowing:
array($name,$mode,$description,$defaultValue)
Theargumentmodemaybeanyofthefollowing:InputArgument::REQUIREDorInputArgument::OPTIONAL.
Whendefiningoptions,thearraydefinitionvaluesrepresentthefollowing:
ArtisanDevelopment
Introduction
BuildingACommand
GeneratingTheClass
GenerateANewCommandClass
WritingTheCommand
Arguments&Options
array($name,$shortcut,$mode,$description,$defaultValue)
Foroptions,theargumentmodemaybe:InputOption::VALUE_REQUIRED,InputOption::VALUE_OPTIONAL,InputOption::VALUE_IS_ARRAY,InputOption::VALUE_NONE.
TheVALUE_IS_ARRAYmodeindicatesthattheswitchmaybeusedmultipletimeswhencallingthecommand:
phpartisanfoo--option=bar--option=baz
TheVALUE_NONEoptionindicatesthattheoptionissimplyusedasa"switch":
phpartisanfoo--option
Whileyourcommandisexecuting,youwillobviouslyneedtoaccessthevaluesfortheargumentsandoptionsacceptedbyyourapplication.Todoso,youmayusetheargumentandoptionmethods:
$value=$this->argument('name');
$arguments=$this->argument();
$value=$this->option('name');
$options=$this->option();
Tosendoutputtotheconsole,youmayusetheinfo,comment,questionanderrormethods.EachofthesemethodswillusetheappropriateANSIcolorsfortheirpurpose.
$this->info('Displaythisonthescreen');
$this->error('Somethingwentwrong!');
RetrievingInput
RetrievingTheValueOfACommandArgument
RetrievingAllArguments
RetrievingTheValueOfACommandOption
RetrievingAllOptions
WritingOutput
SendingInformationToTheConsole
SendingAnErrorMessageToTheConsole
Youmayalsousetheaskandconfirmmethodstoprompttheuserforinput:
$name=$this->ask('Whatisyourname?');
$password=$this->secret('Whatisthepassword?');
if($this->confirm('Doyouwishtocontinue?[yes|no]'))
{
//
}
Youmayalsospecifyadefaultvaluetotheconfirmmethod,whichshouldbetrueorfalse:
$this->confirm($question,true);
Sometimesyoumaywishtocallothercommandsfromyourcommand.Youmaydosousingthecallmethod:
$this->call('command:name',['argument'=>'foo','--option'=>'bar']);
Onceyourcommandisfinished,youneedtoregisteritwithArtisansoitwillbeavailableforuse.Thisistypicallydoneintheapp/Console/Kernel.phpfile.Withinthisfile,youwillfindalistofcommandsinthecommandsproperty.Toregisteryourcommand,simplyaddittothislist.WhenArtisanboots,allthecommandslistedinthispropertywillberesolvedbytheIoCcontainerandregisteredwithArtisan.
AskingQuestions
AskingTheUserForInput
AskingTheUserForSecretInput
AskingTheUserForConfirmation
CallingOtherCommands
RegisteringCommands
RegisteringAnArtisanCommand