How to work with Google Spreadsheets in PHP

I had the pleasure of writing a guest post at Twilio’s blog this week, focusing on how to read, insert, update, and delete data in Google Spreadsheets using PHP. It’s not Laravel-specific, but throwing in a service provider would simplify the sample code up quite a bit. Check it out!

Have you ever needed to pull some data from a Google Spreadsheet? My default in the past would be to export the data and upload it to the app directly, but it turns out it’s not very difficult to read directly from Google Spreadsheets using the Google Drive API.

Twilio – Google Spreadsheets and PHP

Removing all Vue dependencies from Laravel

The recent versions of Laravel have come with some very minor Vue dependencies out of the box. They’re easy to remove, but you may have not actually tried that yet, or you might be worried you’re going to leave something sitting there. So, here’s a quick tip on how to remove all Vue dependencies in a new Laravel install in a few easy steps.

1. Install Laravel

laravel new my-react-project
cd my-react-project

2. Drop Vue from package.json

Here’s what the devDependencies section of the default package.json looks right now:

{
“devDependencies”: {
“axios”: “^0.15.3”,
“bootstrap-sass”: “^3.3.7”,
“cross-env”: “^3.2.3”,
“jquery”: “^3.1.1”,
“laravel-mix”: “^0.8.3”,
“lodash”: “^4.17.4”,
“vue”: “^2.1.10”
}
}

You’ll definitely want to drop this entry:

“vue”: “^2.1.10”

If you want, you can also drop Axios (a fantastic, framework-agnostic, HTTP client) and Lodash (a simple JS library providing collection support and other convenient tools augmenting JS’s somewhat sparse API).

You can drop jQuery and Bootstrap-sass, if you won’t be using them, and if you’re not a Windows user you can drop cross-env.

Note: if you drop the cross-env dependency, you also have to remove the string “cross-env ” from the beginning of each of the scripts lines (e.g. cross-env NODE_ENV=… becomes NODE_ENV=…).

So, if you wanted a brand new project that uses Mix but no other dependencies, here’s what your package.json would look like:

{
“private”: true,
“scripts”: {
“dev”: “NODE_ENV=development node_modules/webpack/bin/webpack.js –progress –hide-modules –config=node_modules/laravel-mix/setup/webpack.config.js”,
“watch”: “NODE_ENV=development node_modules/webpack/bin/webpack.js –watch –progress –hide-modules –config=node_modules/laravel-mix/setup/webpack.config.js”,
“watch-poll”: “NODE_ENV=development node_modules/webpack/bin/webpack.js –watch –watch-poll –progress –hide-modules –config=node_modules/laravel-mix/setup/webpack.config.js”,
“hot”: “NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js –inline –hot –config=node_modules/laravel-mix/setup/webpack.config.js”,
“production”: “NODE_ENV=production node_modules/webpack/bin/webpack.js –progress –hide-modules –config=node_modules/laravel-mix/setup/webpack.config.js”
},
“devDependencies”: {
“laravel-mix”: “^0.8.3”
}
}

Once you modify your package.json file, if you’re using Yarn, you’ll want to update your yarn.lock file:

yarn upgrade

3. Drop the bootstrap and the sample component

In resources/assets/js/app.js, our default script requires a bootstrap and sets up a sample Vue component. Here’s what it looks like right now (with comments removed):

require(‘./bootstrap’);

Vue.component(‘example’, require(‘./components/Example.vue’));

const app = new Vue({
el: ‘#app’
});

If you are dropping all the other dependencies as well (Axios, jQuery, Lodash, etc.) you can just delete all the code in app.js, and delete the bootstrap (resources/assets/js/bootstrap.js) and the sample Vue component (resources/assets/js/components/Example.vue).

If you’re planning to keep all the non-Vue components, you’ll want to delete the Vue lines of app.js, and then modify the bootstrap. Open resources/assets/js/bootstrap.js and drop this line: window.Vue = require(‘vue’);.

Conclusion

That’s it! You’ve wiped all the Vue out of the app and optionally all the other dependencies.

In case you’re like me and want all the other dependencies but just not Vue some times, here’s a short task list for that:

Delete Vue from package.json

Delete the Vue.component(… line and the const app = new Vue({ block from resources/assets/js/app.js

Delete window.Vue = require(‘vue’); from resources/assets/js/bootstrap.js

Delete the resources/assets/js/components directory

How to set up your Laravel application for zero-downtime (Envoyer/Capistrano) deploys

If you’ve ever worked with Capistrano or Envoyer, you’ve probably seen a directory structure in your webroot that looks something like this:

root root 4096 Mar 29 18:44 .
root root 4096 Mar 28 14:15 ..
root root 47 Mar 29 14:54 current -> ./releases/1490824249
root root 4096 Mar 29 14:50 releases

Where you’re expecting to see your webroot containing your Git repository, instead it’s this weird structure. What gives?

A brief introduction to Capistrano-style zero-downtime deploys

The reason you’re getting zero-downtime deploy from these tools is because the entire deploy process—clone, composer install, etc.—doesn’t happen in the directory that is currently serving your site. Instead, each new release gets its own separate “release” directory, all while your site is still being served from its current “release” directory.

– current -> ./releases/1490802721 * apache/nginx serves from this directory
– releases
– 1490802133 (the new release you’re building right now)
– 1490802721 (latest complete release)
– 1490803081 (a little bit older release)
– 1490824249 (an even older release)

All of these release directories are just subdirectories of releases. Each directory here represents one of your deploys, and each directory individually has everything needed to serve your site. Your web server points to yourproject/current/public and therefore the “currently served” release is just that which has a symlink pointed at it from yourproject/current.

So, once the build process is complete for each new release, your deploy tool will delete the current symlink and create a new current symlink that points to your latest release. Boom. Now that release is live.

Caveats

In general, Laravel is no different from any other project in that this style of deployment works great. In fact, a tool provided by Taylor Otwell, Envoyer, is predicated around this release style.

However, every tool has a different set of caveats around how to handle them well in zero-downtime settings. Here’s why:

There are always some things that you want to persist between releases. Most of it lives in databases and caches, which is fine—nothing’s wiping your database on every deploy. But some isn’t. Take the storage folder; do you want to wipe that every time you push a new release? Naw. What about the .env file? Definitely naw. So there are a few quick tricks.

How to set up your deploy for Laravel

Remember: If you use Envoyer, this is all handled for you. But if you don’t, here’s what to do.

Clone your release into a new release folder. This should be handled by your deploy tool.
composer install -o –no-interaction
php artisan migrate –no-interaction –force

(optional, if you don’t commit your built scripts) npm install (or yarn) and either gulp –production (Elixir) or npm run production (Mix)

rm -rf storage && ln -s ../../storage ./
(Delete the storage directory and symlink it to a storage folder in the parent)

ln -s ../../.env ./
(Symlink the .env file to a .env file in the parent)
php artisan route:cache
php artisan config:cache
Update the current symlink to your new release. This should be handled by your deploy tool.

php artisan queue:restart
(Restart the queue.)

This is all you need to do on every deploy. As you can tell, you’ll end up with a root directory that looks a bit more like this:

root root 4096 Mar 29 18:44 .
root root 4096 Mar 28 14:15 ..
root root 1033 Mar 29 18:44 .env
root root 47 Mar 29 14:54 current -> ./releases/1490824249
root root 4096 Mar 29 14:50 releases
root root 4096 Mar 29 14:51 storage

And, of course, you’ll need to create the .env file and the storage directory and subdirectories before you run your build script for the first time.

But that’s it! You’re now ready to go! Get deploying!

Postscript

Looking for a list of steps to take on every deploy, regardless of whether or not it’s Capistrano?

composer install -o –no-interactions
php artisan migrate –no-interaction –force
yarn && npm run production
php artisan route:cache
php artisan config:cache
php artisan queue:restart

What happens to Laravel if Taylor Otwell disappears?

After we talked a bit about enterprise apps on the Laravel Podcast the other day , a few folks in the Laravel community have been talking about what makes a tool enterprise-ready.
I have a lot of thoughts about support plans, SLAs, and other such features of “enterprise-readiness”, but I’ll save those for a later date. Today, let’s talk about the easiest-to-dismiss concern: What happens if Taylor disappears suddenly?

This question brings up the point that, unlike a framework backed by a company, a framework backed by an individual relies on that individual’s desire and ability to keep the project running. What happens if Taylor decides he wants to retire and be a goat farmer?

I’d like to share a few points in response to this concern.

Note: I also recorded a Five-Minute Geek Show about this back in 2015.

There is a plan

Most simply, I think the majority of people with this concern have never stopped to just look whether this has been considered. It has. For a long time.

Taylor even shared his answer on Reddit about a year ago:

If anything ever happens to Taylor, Jeffrey Way of Laracasts will take over. Jeffrey has been here since almost the beginning, has access to everything he needs to keep the products and the framework running, and is a great developer and teacher with a vision for the framework.

Laravel, LLC

Many folks have also said that what they really want is a company instead of a person.

Well, here ya go: Taylor may be the primary creator and maintainer of Laravel, the open source framework, but the ecosystem of tools around Laravel is managed by Laravel, LLC, a company with an owner (Taylor) and an employee (Mohamed Said). If Taylor ever disappears, the company still exists. It still has a flow of revenue and an employee to run it.

Sure, the company doesn’t have 500 employees, but it is also not just tied to Taylor’s personal social security number and brain. There are systems and structures in place, already.

See: CodeIgniter

Let’s say there weren’t a plan, and Taylor did disappear. Let’s say Laravel, LLC and Mohamed didn’t exist. Let’s say the formal plan for Jeffrey to take over weren’t already in place.

If, in that non-existent circumstance, Taylor disappeared, Laravel Forge and Envoyer and Spark would be effectively end-of-lifed.

… and, just like when EllisLab completely dropped the ball on CodeIgniter for many years, the community of contributors and users of the framework would continue to develop it, adding new features. If necessary, frameworks would fork off of Laravel and at least one would start as a near-mirror. Laravel itself would get security updates and bug fixes by the massive community of people who submit pull requests to the framework every day.

Tighten etc.

I can’t specifically speak for other consultancies who use Laravel, but Tighten has already committed time, effort, and finances to support the ongoing development of Laravel. This wouldn’t stop if Taylor disappeared. Ideologically, we want the work to move forward and would do what we could to support the work and the community of Laravel.

But for those of you who may pooh pooh our ideological goals, there are also pragmatic reasons for us to actively work for the good of Laravel. We love the tool. There’s a reason it’s the tool we pick for the majority of our projects: it’s a fantastic tool and a fantastic ecosystem. We make money using Laravel. We have no interest in it going away and we’re committed to seeing it succeed.

And on and on…

There’s plenty more, and I hope to find some time to write more posts about other aspects of Laravel’s enterprise readiness or non-readiness. But this is the simplest, easiest to address, so I hope we can stop bringing it up and call this handled. Good? Good.

Elsewhere: A brief introduction to Progressive Web Apps

Over on the Tighten blog I wrote up an extensive introduction to Progressive Web Apps. Later in the series I’ll actually teach you how to create your own. Check it out!

Within the last year or two I’ve watched references to service workers and PWAs, or Progressive Web Apps, go from never-heard-of-them to every-other-tweet. So! Let’s go learn. What is a PWA? What’s their history, purpose, and value? Why do we care?

Tighten Blog: A Brief Introduction to Progressive Web Apps, or PWAs

What packages do you install on every Laravel application you create?

In preparation for my upcoming talk at Laracon 2017, which I’m titling “Custom Laravel,” I asked a quick question on Twitter to my followers:

Laravel devs: what are the packages you install on *every* app?

— Matt Stauffer (@stauffermatt) July 14, 2017

I wanted to know for my talk, but I was also just curious for my own purposes. Are there any packages I should check out that everyone else already knows about?

Here’s what I found, in order of the number of recommendations I received:

Nearly unanimous support ❤️❤️❤️❤️

Dang, y’all love these packages.

Laravel Debugbar
Makes it simple to add the PHP Debugbar, customized and colored for Laravel, to your applications. Dive deep into your call stack, views, database queries, etc.

Laravel IDE Helper
Teach your IDE (PHPStorm; I doubt any other IDEs reference it, but I’m not sure) how to handle autocompletion and docblocks for Laravel.

LaravelCollective HTML
Laravel’s form and HTML generators, archived by the Laravel Collective. Most beloved because of form model binding.

Well-loved packages ❤️❤️❤️

They don’t necessarily work on every app, but these still came very highly recommended.

Fractal or Laravel-Fractal (for making APIs)

Intervention Image (for modifying and creating images)

Laravel Dusk (for browser-based testing)

Doctrine DBAL (for better database modifications)

Received a few recommendations ❤️❤️

These had two or three recommendations—enough to pique my interest, but clearly not globally installed.

Appstract Opcache
Laravel-Backup
Yajra Datatables
PHPSpec
PHP CodeSniffer
PHPMD
Whoops
Laravel 5 Repositories
Laracasts Flash
Exception handlers (Bugsnag/Rollbar/Sentry)

Just one recommendation ❤️

It’s hard to just ignore someone who went to the effort to compose a tweet. Here you go, folks. Only one recommendation for each of these; but someone, somewhere, wanted to recommend it.

Laravel Permission
Clockwork
Laravel Tinker Tools
Codeception
Laravel DOM-PDF
Laravel Excel
Deployer
LaravelCS
PHPCPD
Laravel Tail
Laravel 5 log Viewer
Health Monitor
Laravel Decomposer

Note: I ignored a few recommendations that were extremely context-specific (Mongo) or which were recommended by the package author. 🙂

Skeletons

A few folks instead pointed to publicly available app skeletons, each of which has their own unique set of packages and customizations:

Sebastiaan Luca – Skeleton
Rappasoft Laravel 5 Boilerplate
Spatie Laravel Skeleton

At Tighten, we currently don’t use a skeleton, but I do have some cool news to share at Laracon that will show how easy it is to do some of this same work, even without a skeleton.

… Elsewhere

There’s another post Eric Barnes linked me to where Mike Erickson asked people their one favorite package—similar to this question, but not quite the same. Check it out: What is the one package you install in all Laravel projects?

It looks like they found the same thing as I did: Debugbar and IDE helper are the winners in our community. If you haven’t checked them out, be sure to do so!

Outro

Did I miss any absolutely vital packages here? Let me know on Twitter.

Lambo “config” and “after” scripts for even better quick Laravel app creation

If you’re not familiar with Lambo, it’s a command-line tool I built to quickly spin up a new Laravel application and take some of the most common steps you may want to at the beginning of each project. Check out our writeup on the Tighten blog if you want to learn more.

The itch

I use Lambo all the time. I create a lot of apps, yes, but I also write and teach about Laravel a lot. Before Lambo, I would hack my examples and tests into a pre-existing app to make sure things worked the way I wanted. With Lambo, I now just spin up a quick new Laravel install every time I need to test anything. I love Lambo.

I love the customization flags you can pass into Lambo. “I want to open the code in Sublime Text, the site in Chrome, and I want to run npm install afterward.” Cool.

But the switches are hard to remember; and, honestly, it’s harder to remember to even type them. lambo MyApplication -e subl -q imconfused -zztop… more often than not I type lambo MyApplication and then two seconds later yell “crap” and CMD-c and try to re-do it with the right flags. At that point, Lambo’s still faster than not-Lambo, but it’s starting to bother me.

And, of course, there are still some common tasks that you could never perform with Lambo—for example, installing your use-on-every-app packages.

Introducing the config file

So, I made an issue. I had some discussion with folks who take a look at Lambo’s issues, and we came up with the idea of a config file that lets you set your defaults.

Thanks to @_cpb, you can create a config file (which lives in ~/.lambo/config) that’s a .env-style set of key/value pairs. Each key represents one of the variables that is toggled by one of the command-line flags. This way, you do’t have to remember to always set your code editor; just set it once in config and it sticks.

Just upgrade to the latest (composer global update tightenco/lambo) and then create a config file (lambo make-config). Here’s mine:

#!/usr/bin/env bash

PROJECTPATH=”.”
MESSAGE=”Initial commit.”
DEVELOP=false
AUTH=false
NODE=true
CODEEDITOR=subl
BROWSER=””
LINK=false

Edit that file and its flags will be passed to every new application you create with Lambo.

Introducing the after file

That covers you for remembering the config flags. But what about other operations you take every time you spin up a site?

We have you covered for that, too. Once again, I opened up an issue, we had some conversation, and a different contributer @quickliketurtle wrote the actual code. You can now create an after script (~/.lambo/after), a shell script that runs after Lambo’s normal processes, and you can define literally anything you want in there.

Here’s what mine looks like:

#!/usr/bin/env bash

# Install additional composer dependencies
echo “Installing Composer Dependencies”
composer require barryvdh/laravel-debugbar

# Copy standard files from ~/.lambo/includes into every new project
echo “Copying Include Files”
cp -R ~/.lambo/includes/ $PROJECTPATH

# Add a git commit after given modifications
echo “Committing after modifications to Git”
git add .
git commit -am “Initialize Composer dependencies and additional files.”

Just like with the config file, upgrade Lambo (composer global update tightenco/lambo) and then create an after file (lambo make-after). Edit that file and it will run every time after Lambo runs.

I put a nitpick.json file in that includes/ directory so my Nitpick config is set up right on every project I start.

Now it’s easier than ever to use Lambo to spin up the perfect Laravel application, every time.

Introducing Laravel Horizon – a Dashboard for your Queues

At Laracon 2017, today, Taylor introduced the latest package in the Laravel world. Like Cashier, Scout, and Passport before it, Horizon is an open-source package that you can bring into your apps but isn’t distributed with the core.

Update: After I wrote this post, Taylor also released an intro post on Medium covering a lot of these topics from the official angle.

What is Horizon?

Horizon is a package for configuring and understanding your queues. It provides you control, insight, and analytics into the number of queues and queue workers you have, your failed jobs, and your job throughput. Horizon makes it easy to configure your queues and see how they’re doing.

Code-based configuration

Using code-based configuration, just like you’re used to with any other Laravel apps and components, you can tell Horizon how many supervisors to run and for each define which connection they’ll use, which queues they should operate on, which mechanism to use for balancing the work, and the maximum number of processes they can spin up.

Horizon makes it easy to define all of these settings uniquely for each environment.

<?php

// horizon config file
[
// …,
‘environments’ =>
‘production’ => [
‘supervisor-1’ => [
‘connection’ => ‘redis’,
‘queue’ => [‘default’],
‘balance’ => ‘simple’,
‘processes’ => 10,
‘tries’ => 3
]
],

‘local’ => [
‘supervisor-1’ => [
‘connection’ => ‘redis’,
‘queue’ => [‘default’, ‘notifications’],
‘balance’ => ‘simple’,
‘processes’ => 20,
‘tries’ => 3,
‘min-processes’ => 5, // optional config
]
]

// …

‘waits’ => [‘redis:default’ => 5] // If I read this syntax correctly, sets how long to wait before consider queue “backed up”
];

Commands

There are a few commands you can pass to Horizon. Here are those Taylor shared:

php artisan horizon:pause # pause but not stop worker
php artisan horizon:continue # resume after pause
php artisan horizon:terminate # gracefully stop during deploy process
php artisan horizon:snapshot # take a metrics snapshot; cron as often as you want

High-level analytics

Horizon provides you with a few key metrics on your entire queue:

Jobs per minute
Jobs in the past hour
Failed jobs in the past hour
Queue worker status
Total processes
Max wait time for your jobs
Max run time for your jobs
Max throughput for your jobs

It’ll also show you a list of the supervisors you have running, how many processes they’re supervising, which queues they’re operating on, and whether they’re a balancing supervisor.

Job- and queue- specific analytics

Horizon provides throughput-over-time and runtime-over-time graphs for each of your individual queued jobs.

Note: This also works for anything else that’s queued. Event listeners, notifications, queued mail, etc.

Tags and Monitoring

Horizon makes it simple to “tag” your queued jobs and to monitor for given tags, giving you even better insight into certain classes of jobs or certain users.

To tag a job, add it to the tags() method on the job:

class MyJob
{
// …
public function tags()
{
return [‘videos’, ‘video:’ . $this->video->id];
}
}

Then later you can go to the tag monitoring and choose to pull just specific tags; e.g. customer emails having trouble with Invoice 14; you can monitor Invoice:14 tag and just watch it for a bit to see what’s happening, failing, etc.

If you don’t provide a tags method, Laravel will auto-tag jobs by the Eloquent model Ids; if you have a “Video” eloquent model attached to your job with the ID of 4, your job will automatically get the tag AppVideo:4 applied to it.

Recent jobs

Horizon keeps track of the most recent queued jobs and shows all of the important information you might want to know about each: which queue they ran on, which tags they had, when they were queued, how long they took to run, and whether or not they succeeded.

Failed jobs

For each failing job, Horizon tracks the stack trace and all of the relevant data, making it easy to understand the reason for the failure. You can also choose to retry a failed job after resolving whatever caused it to fail.

If you retry a job, you can see all of the additional tries after the first to see how they did (or didn’t) change.

Even if you’re not monitoring a tag, you can search the “Failed Jobs” list for any tags—allowing you to debug after the fact.

Failed jobs are retained for seven days (configurable) and the ability to search their tags is retained for 48 hours. All of this metadaa is stored directly in Redis.

Queue balancing strategies

You may have noticed that one of the options in the configuration is “balance”, which is set to “simple” in each of the given examples. Queue balancing describes strategies to handle how Horizon splits resources between two queues.

simple splits the processes between the two, regardless of the workload

auto auto-balances your queue workers based on the number of remaining jobs and average wait time on each queue

Notifications

Horizon can send SMS or Slack messages to notify the app owner if the wait is getting long on a queue.

// AppServiceProvider
Horizon::routeSlackNotificationsTo(‘slack endpoint’);
Horizon::routeSmsNotificationsTo(‘phone number’);

“Long” is defined via a “waits” configuration setting.

Authentication

On first installation, dashboard is local-only.

You can also choose who has access to it:

// AppServiceProvider
// Choose who can see the dashboard
Horizon::auth(function ($request) {
return true;
});

Conclusion

I’m looking forward to diving into Horizon as soon as I can get my hands on it, and I’ll be sure to write up anything I haven’t covered here. But as someone who runs quite a few projects that rely on queues, I’m very much looking forward to adding Horizon to everything.

New Laravel 5.5 Features: Recap from Laracon US 2017

Timeline: releasing August-ish; around Eu

Frontend presets

php artisan preset react; default React components

php artisan preset none; axis & blank Sass

New routing options

Route::view(‘/welcome’, ‘welcome’) returns welcome view

Works with route caching!

Route::redirect(‘home’, ‘dashboard’) returns redirect to another URI

Blade::if

Simple creation of conditional Blade directives
e.g. Blade::if(‘public’, function () { return app()->context()->isPublic(); });

Generates: @public / @endpublic

Renderable mailable

Return a mailable from a route to preview it

Route::get(‘preview’, function () {
return MyMailable;
});

Renderable Exceptions

report() method on exceptions define how to report it

render() method on exceptions define how to render it

class MyException extends Exception
{
public function report()
{
// send wherever
}

public function render()
{
return view(‘error-or-whatever’);
}
}

Responsable interface

Implement Responsable interface; class must provide toResponse() method which shows how to convert this object to a response

class Thing implements Responsable
{
public function toResponse()
{
return ‘This is a great response! ‘ . $this->id;
}
}

One-off Notifications

(a.k.a. Anonymous notifications)

// Easy way to notify people who aren’t in your system as Notifiable
Notification::route(‘mail’, ‘[email protected]’)
->notify(new AppNotificationsNotifyThingHappened);

Validation improvements

Return validated data from $this->validate()

Custom validation “rule” classes; php artisan make:rule

passes() returns boolean; receives name and value

message() returns error message if needed

Use:

$this->validate([
‘myfield’ => [
‘string’,
‘required’,
new AppRulesMyValidationRule
]
);

TrustedProxy package brought internally

If you have a proxy in front of your app like a CloudFlare proxy or something else that provides the SSL which then at your proxy, Laravel currently cannot correctly detect that it’s an HTTP request. It’s getting requests from port 80 instead of port 443.

TrustProxies Middleware, extending Fideloper’s TrustedProxy, teaches the system how to trust the proxy that their forwarded headers (including those identifying that it’s SSL) are trustworthy.

$proxies property on the middleware allows you to define which proxies are trusted.

Migrate:fresh

Ignores the down migrations and just wipes the whole database before re-uping.

New database migration trait

Previously we used DatabaseMigrations and DatabaseTransactions; new combined way of doing it
Inspired by Adam Wathan (of course); migrates once at the start of your tests and then runs every test after that with transactions
Benefit: We don’t have to remember to migrate every time (solved by DatabaseMigrations) but it’s faster because we’re not re-migrating every time (solved by DatabaseTransactions); now both in one world
New trait: named RefreshDatabase

// Usage
class MyTest extends TestCase
{
use RefreshDatabase;
}

WithoutExceptionHandling middleware

If doing integration testing, in the past, exceptions would just get swallowed in your tests.
Disabling exception handling allows exceptions to bubble up to PHPUnit so you can see what’s going wrong
Avoids integration calls failing silently and being only fixable via log tailing

Dusk improvements

Headless by default—faster and doesn’t pop up a browser every time

Package auto-discovery

Inspired/originally created by Dries Vints of Laravel.io
No longer have to register your service provider in the config/app.php provider array; now, set a block in each package’s composer.json that teaches Laravel to discover it without any manual work

php artisan package:discover runs the discovery process
“Most of the time I install a package I just do composer require packagename and then I’m good to go. Don’t have to do anything else”

Vendor:publish menu

Nice readout of all the packages and tags you could pick instead of having to manually pass in providers every time

Auto-registered console commands

No longer have to put commands in the app/Console/Kernel.php commands array
Instead, Laravel looks for all classes that are commands every time you try to run a command and finds it for you

Job chaining

Dispatch a job and then queue up other jobs to be queued up after that one is completed

dispatch((new AppJobsPerformTask)->chain([
new AppJobsAnotherTask,
new AppJobsFinalTask($post)
]));

Better missing model handling in jobs

If you have a job that’s referencing a model and that model disappears before the job is handled, the job will fail out instantly if the model does not exist
Previously it would try and try forever
If you set $deleteWhenMissingModels to true it just deletes itself without even failing

Introducing Laravel’s tap, “higher order” tap, and collection tap

If you follow Adam Wathan at all, you’ve seen him use his favorite function, tap(), dozens of times in his videos. But what does it actually do?

tap() was introduced in Laravel 5.3 and got some power boosts in 5.4. Let’s take a look at what it is and what it does.

Defining tap()

function tap($value, $callback)
{
$callback($value);

return $value;
}

That’s what the tap() function originally looked like—it’s gotten a few small improvements since then, but let’s start at the basics.

It’s really simple, right? So why is everyone so excited?

Let’s look at what it does: Take a value, pass that value into some form of callback, and then return the value.

An example using tap()

Here’s what it looks like to refactor something to use tap().

First, let’s take a common pattern:

public function generateUseAndReturnThing($input)
{
$thing = $this->thingFromInput($input);

$this->doActionToThing($thing);

return $thing;
}

We take some input, make a thing from it, perform some actions with that thing, and then finally return the thing that we generated.

So, remember, tap() takes a value, acts on it, and then returns it. That means we can identify a potential place to use tap() here; we’re acting on a value ($thing) and then returning that same value.

That’s our key to watch out for. Consider that a code smell that hints at a potential use for tap() usage: using temporary variables just for the sake of returning later.

So, let’s make this use tap() instead.

public function generateUseAndReturnThing($input)
{
return tap($this->thingFromInput($input), function ($thing) {
$this->doActionToThing($thing);
});
}

Let’s walk through what we’ve changed here.

First, we are no longer assigning the output of $this->thingFromInput($input) to a temporary variable; we’re instead passing it directly as the “value” to tap().

Second, we know the “value” (that is, the first parameter you send to tap()) is provided as a parameter to our callback function, so we pass in a closure that takes the “value” $thing as its parameter.

Third, we operate on our value.

And fourth, we close out our tap function. The final return of the tap() function is the originally-passed value (the output of $this->thingFromInput($input)) so this is what is returned from our generateUseAndReturnThing() method.

Evaluating the refactor

How much did that help? What did it bring us?

Before we ask those questions, let’s read a few words from a recent post by Taylor Otwell about Tap (Tap, Tap, Tap). Remember also that Taylor and Adam Wathan are the ones who originally popularized tap()—think of their influences and values.

On first glance, this Ruby inspired function is pretty odd. … I find it often lets me write terse, one-line operations that would normally require temporary variables or additional lines.

This isn’t allowing us to do things we couldn’t do before.

Instead, it’s helping us write terser code, with less temporary variables and less lines of code.

A few real life examples

In Taylor’s article he gave an example of how he’s using Tap in the Laravel core.

Eloquent create

public function create(array $attributes = [])
{
return tap($this->newModelInstance($attributes), function ($instance) {
$instance->save();
});
}

This is the create() method on Eloquent models. To understand its value, let’s take a look at what this same method call would look like without tap():

public function create(array $attributes = [])
{
$instance = $this->newModelInstance($attribtues);

$instance->save();

return $instance;
}

We’re dropping the need for the $instance temporary variable and wrapping the instantiation, save() call, and the return of the instance itself up into the core workflow of the tap() function.

Decorate response middleware

Here’s another really practical use case. One of the most common workflows for writing middleware in Laravel looks a bit like this:

public function handle($request, Closure $next)
{
$response = $next($request);

$this->decorateResponseSomehow($response);

return $response;
}

We can now refactor this using tap():

public function handle($request, Closure $next)
{
return tap($next($request), function ($response) {
$this->decorateResponseSomehow($response);
});
}

Shortcut without affecting the value

There’s another interesting use case that I came across in Derek MacDonald’s article on Tap; Derek found that the AuthenticateSession middleware now uses tap(), but not quite the way I described it above.

public function handle($request, Closure $next)
{
return tap($next($request), function () use ($request) {
$this->storePasswordHashInSession($request);
});
}

Notice anything different? Here’s what that call would look like before tap():

public function handle($request, Closure $next)
{
$response = $next($request);

$this->storePasswordHashInSession($request);

return $response;
}

Unlike in my example, the Closure isn’t actually performing any operations working with the “value” (the result of $next($request)). Instead, this method uses tap because it still saves us from needing to save $response as a temporary variable before storing the hash.

“Higher order” tap

In Laravel 5.4, the tap() function got a new use case. Most of the examples I’ve shown up until this point have been calling an outside method on our value:

return tap($thing, function ($thing) {
$this->doSomethingToThing($thing);
});

But there are other times where you want to call a method on the object itself; in these cases, the benefit of using tap() is just to return the object when the method we’re calling on the object would normally return something else—for example, Eloquent models’ update() method returns a boolean.

That converts this call:

$user->update([
‘name’ => $name,
‘age’ => $age,
]);

return $user;

into this:

return tap($user, function ($user) {
$user->update([
‘name’ => $name,
‘age’ => $age,
]);
});

As you can see, this isn’t quite as much of an improvement as our previous refactorings-with-tap were. But in 5.4, you can now use tap() to call methods on the tapped object, and those methods—even if they natively return something other than the object—will return the object. Here’s how:

return tap($user)->update([
‘name’ => $name,
‘age’ => $age,
]);

Now that’s clean.

Collection tap in Laravel 5.4

In Laravel 5.4, we got the tap() method in our collections as well. Using tap() inline temporarily pauses your collection pipeline and passes you an instance of the collection itself, but once your tap Closure has executed, the pipeline continues as if nothing had happened.

Note that whatever you return from your tap method is just thrown away. This isn’t for returns; it’s for debugging with var_dump or for writing to a log or for performing some separate action.

return collect($peopleArray)
->sortBy(‘name’)
->tap(function ($people) {
// Useful for debugging
var_dump($people);
})
->filter(function ($person) {
return $person->syncable === true;
})
->tap(function ($people) {
// Useful for performing some operation without
// requiring a temporary variable
app(‘thirdPartyService’)->syncPeople($people);
});

My first response was to compare this method to pipe() and each(), but they’re different in that each() is passed each of the items in the collection one at a time where tap() is passed the entire collection; and pipe() modifies the collection to be whatever you return from the method, whereas tap() discards your return.

Tap to the end

I’m a huge fan of anything that makes our code simpler to read for developers down the road. I’m also a huge fan of coding practices that make our code more expressive and that avoid unnecessary extra code.

tap(), and collection pipelines before it, are strange in that, when they’re first introduced to your programming lexicon, there’s a cost; until you wrap your head around how tap() works, it’s actually more cognitive work than not using tap(). Same with collection pipelines.

Just like collection pipelines, I’ve also seen people get so excited about tap() that they use it everywhere—often in places where it doesn’t belong. Just because something is new, doesn’t mean you should use it everywhere.

All those caveats having been given, though, I do think tap() has a place in our programming vocabulary, and I’m glad it’s here to stay. Just search for tap() in the Laravel codebase and you can see how many places Taylor and others are putting tap() to good use.

I hope this longer writeup of tap() has helped it really click in your brain. Let me know on Twitter if anything in this article isn’t clear.