A recap of Laracon EU 2017

Devron Baldwin wrote down a few words on the excellent Laracon EU conference, edition 2017.

The awesome talks and the amazing people made Laracon EU 2017 an experience to remember. I’ll split this up into a few sections to talk about the non-technical and the technical talks. I found myself enjoying the non-technical talks slightly more than the technical this year.


I can’t believe it’ already over and am already looking forward to Laracon EU 2018.

Getting started with laravel-medialibrary: a video tutorial

laravel-medialibrary is probably one of our most powerful packages. It can associate files with Eloquent models. It can also generate derived images such as thumbnails. It has a very developer-friendly API to work with. Here’s a quick example:


Want to store some large files on another filesystem? No problem:

$yourModel->addMedia($bigFile)->toMediaCollection('downloads', 's3');

Because the package can do so much, the docs have grown quite large. If you’re a visual learner, you’ll be happy to know that I’ve made a video that shows what the medialibrary is capable of.

What Laravel 5.5 means for our packages

At Spatie we’ve released a plethora of Laravel packages. Now that Laravel 5.5 has been released most of our packages will get a new (major) version. In this blogpost I’d like to explain how we handle new releases of the framework and what it means for our packages.

Preparing for release

Laravel has a bi-yearly release cycle. It doesn’t follow semver. Breaking changes are often introduced in point releases. That’s why our Laravel packages mostly have very conservative composer constraints on them so that they are not installable in future versions of the framework. Every half year we go through them all, make sure that they are compatible with the latest and greatest version of the framework and tag new releases. We try to do this as quickly as possible after a new stable Laravel release has been tagged.

In previous releases of Laravel we’ve waited working a new versions of our stuff until the newest version of the framework was publicly available. The rationale behind this was that even in the last days before Laravel’s release breaking code may be introduced, so it’s best to create compatible packages after the release. Looking at the past learns us that a few weeks before a new version of Laravel gets released the development version is already pretty stable. That’s why this time around we created laravel-55 branches to make our code compatible ahead of Laravel’s release.

Auto discovery

Laravel 5.5 has an awesome new feature called package auto-discovery. There’s no need anymore to manually register service provides and facades. Laravel will now automatically do that for you. It does this by looking at a special extra key in the composer.json of a package. All our L5.5 compatible packages will support this feature.

Let’s take a look at a small package of ours that utilises this: laravel-tail. That one provides an artisan command to tail the logs. The only thing you need to do in a Laravel 5.5 application is composer require spatie/laravel-tail. The service provider gets registered automatically which in it’s turn registers an artisan command in the kernel. You can just use the php artisan tail command. It’s that simple.

Leaving older framework versions behind

Laravel 5.5 is a new LTS release. Personally I’m not a big fan of the concept of LTS, but in this case, for some packages, I’m grabbing the opportunity to break compatibility with previous versions of Laravel so I can make use of new features introduced in Laravel 5.5. Examples are laravel-feed, laravel-medialibrary, laravel-collection-macros, … which all are getting new major releases. Even though we’re not going to support the older versions actively anymore, the old major versions should all be pretty stable. We won’t release any new features for older versions of our packages, but we will still accept PRs for bugfixes for quite some time.

In the past we’ve named our config files laravel-<package-name>. We’re going to simplify that by dropping the laravel- prefix. So config/laravel-backup.php just becomes config/backup.php.

Leaving packages behind

Laravel 5.5 contains many new features. Some of the features will replace things that we already had in place via our packages.

Take dd and dump macros for instance. We’ve been using those already for a long time in our projects. We’ve included them in v2 of laravel-collection-macros. Laravel now has dd and dump functions on the collection by default, no need to macro them anymore.

Laravel has this really sweet functionality to build up json reponses for your API. It does more or less the same than Fractal but in a more integrated way. For most projects I’m probably going to use Laravel’s baked in solution, but I still plan on maintaining our popular laravel-fractal package for people who want to use it in their Laravel app.

We have a package called laravel-failed-job-monitor that can send you a notification whenever a queued job fails. Laravel Horizon is a new awesome looking dashboard for managing queued job. It can also send notifications when something goes wrong. We are probably going to use Horizon for all our future projects. That’s why we are leaving our own laravel-failed-job-monitor behind.

I’m really happy that the entire functionality of two of our packages is now included in the framework. For these two we are not going to create a Laravel 5.5 version, but we’ll still do maintainance on the current version:

  • laravel-migrate-fresh: This package provides an artisan command that can rebuild your entire database. It does this by dropping all tables first and then running all up migrations. You don’t need to write any down migrations. Our package triggered the work that resulted the migrate:fresh command being included in Laravel itself.

  • laravel-tinker-tools: When working with tinker it’s kinda bothersome that you need to type the fully qualified class name. Wouldn’t it be nice of you could just use the short class name? That’s exactly what this package does. So instead of typing App\Models\BlogPost::first() you can do BlogPost::first(). The code of this package was ported to the laravel/tinker package. Laravel 5.5 ships with this feature out of the box.

In conclusion

Laravel 5.5 is probably the best release yet. But, in all honesty, I think that of every Laravel release. My recommendation is to get your apps upgraded to this version as soon as possible. The reward is that you can make use of all L5.5’s new features and the latest major versions of our packages. Keep an eye out on my Twitter account to learn which of our packages are tagged as L5.5 compatible. You’ll find a full list of our Laravel packages on our company website.

Generating IDE Stubs for IonCube-Encoded Classes

Here’s a great story by Collin O’Dell, maintainer of league/commonmark amongst other things, on how he was able to extract the class definitions out of obfuscated PHP source files.

Per the framework’s license, decrypting the IonCube-protected code was not allowed. This meant it was impossible to recover the original source code. However, I could require those files and execute them in PHP, which would cause those classes to become usable in code. So how does one figure out what code just got loaded & executed?


Theme-based views in Laravel using vendor namespaces

At Spatie, we’re building a multi-tenant app. Seb figured out a great way to handle theme based views.

Laravel allows you register a view vendor namespace which points to a specific directory containing Blade files. This feature is intended for package development, but it’s a perfect solution to our problem.

By registering a namespace with the current theme’s location, we can drop all the dynamic parts of our view names when we’re calling them.


An interview with Jef, Spatie’s account manager

My colleague Jef, who handles accounts at Spatie, recently was interviewed by Viraj Khatavkar. Read it to learn some interesting tidbits on how our company is being run.

Originally, Spatie was founded 12 years ago by Willem Van Bockstal as a one-person company. In 2009 both Freek and I jumped on board, and we founded the official company Spatie as it is known today.

You can always mention your hourly rate, but that’s just a number. What can you achieve in an hour? We try to be very transparent and pragmatic towards our customers. This approach creates trust and avoids lengthy discussions about change requests.


Open-sourcing our guidelines

At Spatie we recently launched a new site: guidelines.spatie.be. It contains articles on how we go about setting things up at Spatie and a collection of styleguides. The source code of the site is available on GitHub. In this blogpost I’d like to share why and how we created our guidelines site.

Why did we create this?

Let’s start with a quote from Sandi Metz from her excellent post on why we argue about style:

I firmly believe that all of the code that I personally have to examine should come to me in a consistent format. Code is read many more times than it is written, which means that the ultimate cost of code is in its reading. It therefore follows that code should be optimized for readability, which in turn dictates that an application’s code should all follow the same style. Adhering to a common style saves you money.

Spatie is web agency. So most of the time we are working on multiple projects at the same time. When the initial project is done, more of than not, we will also maintain it for several years. To keep things manageable we try to code things in a consistent way. That way we can dive into a project and easily reason about it. I’d argue that in addition to adhering to a common code style, setting up your projects in a consistent way will save time and money too.

For years I’ve been the sole developer at Spatie. It was seemingly easy to keep things consistent because there was nobody else working on the code. But the truth is that at the time I certainly did not notice the little differences in my code style across the projects (PSR-2 wasn’t a thing back then). Now that the company is growing (Alex recently joined our team with more new members on the way) it’s getting more and more important to keep things consistent.

Like Sandi mentioned in the above quote code should be optimized for readability. Having all code in a common style will save you money because it takes less time to understand the code. But I’d argue having a style guide will save you time writing code as well. Trying to decide if the view names or route names should be camelCases or kebab-cased? Don’t waste your time and just check the relevant guidelines.

Most of these rules originate from a discussion of the entire team (or they’ve been decided by an individual who cared enough to put it in a rule). Having these rules written down avoids discussing them over and over again. Because “best practices” really are nothing more than “current practices” you should still, from time to time, re-evaluate the rules to see if they still make sense.

Behind the screens

The guidelines site itself is build with Laravel. It’s completely open source. Here’s the repo containing the code that’s actually deployed on our server.

We’ve set up the guidelines site in such a way that everybody can contribute it. At the bottom of every page there’s an Edit this page on GitHub link. Clicking it will create a PR against the repo. When we merge in the PR the code will automatically get deployed (we use Forge‘s auto deploy feature for this).

Because the guidelines are our very opinionated thoughts on how to do things, we’re not going to just accept every single PR we get. You can ‘t change our minds just by PRing a new rule. But we do welcome new rules that we agree with, or a discussion why our existing rules could be bad. And of course we’re also grateful for PRs that fix typos.

Storing the content

The content itself is stored as a set of markdown files. To display every page (expect for the home page), the PageController is used:

namespace App\Http\Controllers;

use App\Markdown\MarkdownConverter;

class PageController extends Controller
    public function __invoke($url)
        abort_unless($page = app('navigation')->getPage($url), 404);

        return view('page', [
            'title' => $page->title,
            'editUrl' => $page->edit_url,
            'contents' => MarkdownConverter::convert($page->contents),

Making content private

The aforementioned PageController controller will ask the Navigation class which page should be displayed. When looking at the code of the Navigation class you’ll notice that it also tries to get content from a private directory. This private directory contains content that we don’t want to share publicly, such as semi sensitive information and custom procedures that are not interesting for the outside world.

The content of that private directory is not in our public repo, but in a separate private repo that’s being symlink so Navigation can read it. And of course that private content is only viewable by users who are logged in.

Logging in

At Spatie we use Google Apps and every team member has his or her own email-address on the spatie.be domain. Wouldn’t it be nice if anyone with a spatie.be address on Google would be able to login? Then we wouldn’t have to create credentials manually whenever we onboard a new team member.

That’s why we opted leveraging Laravel Socialite to handle logins. Socialite makes it very easy to authenticate with OAuth providers such as Google, Facebook, Github, … Installing Socialite is very easy. After it is installed and configured the necessary APIs at Google you don’t need too much to code to handle social logins.

This is the entire LoginController:

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Socialite;

class LoginController extends Controller
    public function __construct()

    public function redirectToProvider()
        return Socialite::driver('google')

    public function handleProviderCallback()
        $user = Socialite::driver('google')->stateless()->user();

        abort_unless(ends_with($user->getEmail(), '@spatie.be'), 403);

        $authenticatableUser = User::findOrCreate($user);

        auth()->login($authenticatableUser, true);

        return redirect('/');

    public function logout()

        return redirect('/');

When visiting /login the app will execute the redirectToProvider method. The user will get redirected to a login page at Google. When users provide the right credentials Google will redirect them back to our site. That response from Google is handled in handleProviderCallback. There we abort unless the email-address of logged in user ends with @spatie.be. And then there’s a piece of boring code. Because a socialite user isn’t directly authenticatable we find (or create) a regular user in the database and log that one in.

In closing

If you’re working in a company that doesn’t follow any guidelines to keep code and configuration consistent, I highly recommend talking to your team and convincing them of the value of writing such guidelines down. Take the time to discuss and agree on some common rules. I bet nearly everybody on your team will find such guidelines helpful and it’ll make it easy for newcomers to your team.

You could opt to just follow our guidelines or create your own set of rules. If you choose the latter, maybe you could use the code of our guidelines site to set up your own.

The site and the writing down of the guidelines was largely spearheaded my colleague Sebastian, who, as always, did an excellent job.

That site isn’t the first thing we’ve open sourced. Take a look at the opensource pages on our company site to find out the Laravel, PHP and JavaScript packages we previously created.

Use your Laravel named routes in JavaScript

Daniel Coulbourne, an engineer at Tighten Co and co-host of the amazing Twenty Percent Time podcast, recently released Ziggy, a tool to share your Laravel named routes with JavaScript.

Ziggy creates a Blade directive which you can include in your views. This will export a JavaScript object of your application’s named routes, keyed by their names (aliases), as well as a global route() helper function which you can use to access your routes in your JavaScript.


Laravel/MySQL JSON documents faster lookup using generated columns

In an older post on his blog Mohamed Said demonstrates how you can leverage virtual columns to speed up queries on data stored as JSON.

Laravel 5.3 is shipped with built-in support for updating and querying JSON type database fields, the support currently fully covers MySQL 5.7 JSON type fields updates and lookups,

Let’s see how we may create a generated column to store users favorite color for later indexing.


Using global mixins in Vue.js

Recently I needed to add some global functionality to nearly all Vue components in an app. My colleague Seb told me a good way to achieve this: global mixins. In this post I’d like share that knowledge.

In Vue a mixin is some functionality bundled in a file that can be added to one or more Vue components. It’s very similar to a trait in PHP.

Let’s take a look at how such a regular mixin looks like. It’s really nothing more than a .js with some stuff in it. Here’s one with a computed property to grab some global info of the current user that has been set on the window object.

export default {
    computed: {
        currentUser() {
            return window.currentUser;

If you import and register the mixin you can use it.

import Auth from './mixins/Auth';

export default {
   mixins: [ Auth ],

   created() {
      // Let's use the function provided by the mixin.
      console.log(`${this.currentUser.name} is currently logged in.`);

Nice. But image now you want to use the same mixin on almost every component in your app. Registering that mixin will grow old pretty fast. Enter global mixins. It’s extremely simple. Just register the mixin where you set up Vue. Commenly this would in app.js:

import Vue from 'vue';
import Auth from './mixins/Auth';


And with that you can use the functions defined in the mixin in any component:

export default {
   created() {
      // No need to import the mixin anymore.
      console.log(`${this.currentUser.name} is currently logged in.`);

We can make a small improvement to this. In the Vue world things that are globally accessible (such as this.$set, this.$root, …) are commonly prefixed with $. We could follow that convention too:

The mixin:

export default {
    computed: {
        $currentUser() {
            return window.currentUser;

A component:

export default {
   created() {
      // so nice
      console.log(`${this.$currentUser.name} is currently logged in.`);

And that’s really all there is to it.

What’s in our .babelrc?

Sebastian De Deyne, my colleague and all round wizard at Spatie, wrote a new blogpost on how we use Babel.

A lot has been going in in JavaScript the past few years. One of my favorite things has been the usage of babel, which allows us to write future JavaScript syntax today. The babel ecosystem has tons of plugins and configuration options, I’d like to elaborate on our usage at Spatie.


CSS Utility Classes and “Separation of Concerns”

In my day to day work I don’t write any css at all, but I still very much enjoyed this blogpost by Adam Wathan where he shares some interesting things about how css should be structured and he makes the case for using utility classes to make visual tweaks.

When you think about the relationship between HTML and CSS in terms of “separation of concerns”, it’s very black and white.

You either have separation of concerns (good!), or you don’t (bad!). This is not the right way to think about HTML and CSS. Instead, think about dependency direction.

One of the biggest benefits of using small, composable utilities is that every developer on your team is always choosing values from a fixed set of options.


The disadvantages of single page applications

Adam Silver lists a bunch of problems you need to solve if you opt to build a single page application.

Ironically, SPAs are harder to design and harder to build. And yet, they typically produce slow, disagreeable experiences for users.

Javascript is never going to beat the browser at what it does best—browsing. We can still give users rich and enhanced experiences without cramming an entire site into one document.

We should let the browser manage the browsing experience, and spend our time solving real user problems.


Precision Through Imprecision: Improving Time Objects

Ross Tuck is probably one of my favourite bloggers. He doesn’t publish something often (his previous post is from 2015), but when he does it’s very much worth your time.

The important takeaway here isn’t “value objects, yay, inline juggling, boo!” It’s that we were able to remove several classes of errors by reducing the precision of the DateTime we were handling. If we hadn’t done that, the value object would still be handling all of these edges cases and probably failing at some of them too.

Reducing the quality of data to get a correct answer might seem counter-intuitive but it’s actually a more realistic view of the system we’re trying to model. Our computers might run in picoseconds but our business (probably) doesn’t. Plus, the computer is probably lying anyways.