Using non-breakable spaces in test method names

Mattieu Napoli shows how you can use non breaking spaces to make long test function names more readable.

Yes. This article is about using non-breakable spaces to name tests. And the fact that it’s awesome. And why you should use them too.

public function test a user can add a product to a wishlist()
// …

The code above is valid PHP code and works. Non-breaking spaces (aka   in HTML) look like spaces in editors but are actually interpreted like any other character by PHP.

It’s cool that it works, but I’m not really a fan of this. I very much prefer how test runners like jest go about this by passing the name of the test to a function so you can use spaces.

What is snapshot testing, and is it viable in PHP?

In a new blogpost at Sitepoint Christopher Pitt talks about snapshot testing. He first explains how snapshot testing can help test React components. Then he demonstrates how you can use our home grown package to use snapshot testing in PHP. Finally he shows pretty cool use cases for snapshot tests.

Ah-ha moments are beautiful and rare in programming. Every so often, we’re fortunate enough to discover some trick or facet of a system that forever changes how we think of it.

For me, that’s what snapshot testing is.

You probably write a lot of PHP code, but today I want to talk about something I learned in JavaScript. We’ll learn about what snapshot testing is and then see how it can help us write better PHP applications.

If you want know more about snapshot testing, check out this blogpost by my colleague Sebastian, or watch this video where I refactor some tests to use snapshots.

Building a realtime dashboard powered by Laravel and Vue (2017 edition)

At Spatie we have a tv screen against the wall that displays a dashboard. This dashboard displays the tasks our team should be working on, important events in the near future, which music is playing at our office, and so on. Here’s what it looks like:

We’ve opensourced our dashboard, so you can view the entire source code on GitHub. It is built with Laravel 5.4 and Vue.

This dashboard is not new, we orginally published it last year. But at our company we like to tinker with new stuff. That’s why we did a big refactor of the source code and updated all the dependencies used. The css used got a big update as well, it now uses CSS grid and CSS vars. In this blogpost, which is an update to the previous one, I like to explain how this dashboard is built.

You’ll need to be familiar with both Laravel and Vue to get the most out of this post. If you need to brush up your Vue knowledge, I can highly recommend Laracast’s lessons on Vue.


We’ve had a dashboard at Spatie for quite some time now. Before our current Laravel-based one we used Dashing, a framework to quickly build dashboards. The framework was created by the folks at Shopify and uses Ruby under the hood.

The time I first built our dashboard, a few years ago, we were at a crossroads at Spatie. There wasn’t much momentum in the PHP world and we were toying with the idea of switching over to Ruby. The idea was that by playing with Dashing we would get some experience with the language. Then Composer and Laravel happened and we decided to stick with PHP (and given the current state of PHP ecosystem we don’t regret that choice at all).

Now that support for Dashing has officially stopped, I thought it was a good time to completely rebuild the dashboard using Laravel and Vue.

High level overview

Let’s take a closer look at what the dashboard is displaying. The configured dashboard from the above screenshot has the following tiles:

  • A twitter tile that show all mentions of quotes of @spatie_be
  • A team calendar that pulls in it’s events of a Google Calendar.
  • The music that is currently playing in our office, fetched from‘s API.
  • A clock with the current date, and some weather conditions, retrieve from the Yahoo Weather API.
  • The todo’s of each member of our team. It’s managed through a few markdown files in a private repo on GitHub.
  • Number of package downloads are pulled in via the Packagist API.
  • Same statistics of our numerous public repositories on GitHub

After the browser displays the dashboard for the first time we’ll never refresh the page again. WebSockets and Vue are being leveraged to update the tiles. Doing it this way will avoid having to refresh the page and in turn avoid flashing screens.

Each tile is it’s own Vue component. Laravel’s default scheduler is used to periodically fetch some data from the API’s of Google Calendar,, etc… When Laravel receives a response from any of those services a broadcast event is fired to Pusher. This powerful service leverages websockets to carry over server events to clients in realtime. On the client side we’ll use Laravel Echo. That JavaScript library makes handling those Pusher events very easy. Still on the client side each Vue component will listen for incoming events to update the displayed tiles.

The grid

Before diving into the Laravel and Vue code I’d like to explain how the grid system works. The grid system allows you to easily specify where a tile should be positioned on the dashboard and how big it should be.

This is the html of the actual blade view that renders the dashboard page.

<dashboard id="dashboard" columns="5" rows="3">
    <twitter :initial-tweets="{{ json_encode($initialTweets) }}" position="a1:a3"></twitter>
    <calendar position="b1:b2"></calendar>
    <music position="c1:d1"></music>
    <uptime position="b3"></uptime>

    <tasks team-member="alex" position="c2"></tasks>
    <tasks team-member="freek" position="d2"></tasks>
    <tasks team-member="seb" position="c3"></tasks>
    <tasks team-member="willem" position="d3"></tasks>

    <time-weather position="e1" date-format="ddd DD/MM"></time-weather>
    <packagist position="e2"></packagist>
    <github position="e3"></github>


Grid columns are named with a letter and rows are named with a number, like a spreadsheet. The size and positioning of a tile is determined in a position property per component that accepts a column name and a row number. a1 will render the component on the first row in the first column. If you look at the first tasks component you see c2, so as you see in the screenshot of the dashboard, this component will get displayed in the third column on the second row.

You can also pass a range to the position attribute. The music component is a good example. Setting grid to c1:d1 causes it to be displayed in the second an third column of the first row.

Our dashboard uses five columns and three rows. Want to change the size of your dashboard? No problem: those numbers can be adjusted by passing your prefered number of columns and rows to the columns and rows properties of the dashboard component.

Most modern tv’s use a 16:9 ratio, but we’ve gone the extra mile to make the layout fully responsive so it still works on tv’s and monitors with a different ratio.

My colleague Willem did an awesome job in making the dashboard look very pretty. To position the tiles Willem leveraged CSS grid which was recently introduced in most modern browsers.

The internet connection component

Let’s take a deeper look at a component to grasp the general flow. A simple one is the internet-connection tile which notifies us when the internet connection is down.

By default is it is not shown. When there’s no internet connection a small overlay will be displayed. Here’s how that looks:

It works by listening to an event, called Heartbeat, that is sent out every minute by the server. When it doesn’t get an event within a couple of minutes it’ll determine that our internet connection is down (although it could also mean that the server where the dashboard is running on is having problems).

Server side

In the Laravel app you’ll see a directory app/Events that containts all events. It also contains subdirectories for each component of the dashboard. All events are sent from the server to the client reside there. In the app/Events directory you’ll also see a file named DashboardEvent which is used to transfer data from the server to the client through events.

namespace App\Events;

use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

abstract class DashboardEvent implements ShouldBroadcast
    public function broadcastOn()
        return new PrivateChannel('dashboard');

That ShouldBroadcast interface is provided by Laravel. All events will get broadcasted on the private channel named dashboard. The client will listen to all events on that channel. Using the PrivateChannel class will ensure that all data will be sent in a secure way so nobody can listen in. More on that later.

Let’s take a look at the app/Console/Components directory. Almost all logic that the server needs to do to fetch data for the dashboard has a home here. If you open up that directory you’ll see that each component has it’s own subdirectory. In each subdirectory you’ll find an Artisan command that can be scheduled. In our example the App\Components\InternetConnectionStatus class contains this code:

namespace App\Console\Components\InternetConnection; use Illuminate\Console\Command; use App\Events\InternetConnection\Heartbeat; class SendHeartbeat extends Command { protected $signature = 'dashboard:send-heartbeat'; protected $description = 'Send a heartbeat to the internet connection tile'; public function handle() { event(new Heartbeat()); } }

The only thing that this code does is send out a HeartBeat-event. This command is scheduled to run every minute in the Console kernel.

Client side

All JavaScript code used by the dashboard lives in the resources/assets/js directory. In resources/assets/js/app.js you see that the main Vue instance is being initialized on the body element:

new Vue({

    el: '#dashboard',

    components: {

    created() {
        broadcaster: 'pusher',
        key: window.dashboard.pusherKey,
        cluster: window.dashboard.pusherCluster,

        this.echo = new Echo(options);

The components themselves live in the resources/assets/js/components directory. This is the code of the InternetConnection.vue inside that directory:

    <section v-if="offline" class="internet-connection">
        <div class="internet-connection__alert">
            <span class="internet-connection__icon h-icon"></span>
            <span class="internet-connection__text">Internet connection</span>

    import echo from '../mixins/echo';
    import { addClassModifiers } from '../helpers';
    import moment from 'moment';

    export default {

        mixins: [echo],

        data() {
            return {
                offline: false,
                lastHeartBeatReceivedAt: moment(),

        created() {
            setInterval(this.determineConnectionStatus, 1000);

        methods: {

            determineConnectionStatus() {
                const lastHeartBeatReceivedSecondsAgo = moment().diff(this.lastHeartBeatReceivedAt, 'seconds');

                this.offline = lastHeartBeatReceivedSecondsAgo > 125;

            getEventHandlers() {
                return {
                    'InternetConnection.Heartbeat': () => {
                        this.lastHeartBeatReceivedAt = moment();

There’s a whole lot going on in that code. Let’s break it down. Everything between the <template>-tags is the html code that actually gets rendered. That v-if directive makes sure that the section is onlyrendered when the state variable offline is true. Again, if you’re having trouble following this, check the series on Vue on Laracasts). In the created method, which is fired as soon as the Vue component is created, we’ll make sure that a method on the Vue instance called determineConnectionStatus is fired every second. That function is responsible for determining the value of online. If the last received heartbeat is less than 125 seconds ago, online will be true, otherwise it will be false.

Let’s review how we can listen for events. In the code above you’ll see a method called getEventHandlers. It expects an object of which the property names are the the events names. The event name is the fully qualified class name of the event that get sent out by the server (App\Events\InternetConnection\Heartbeat) but without App\Events and with the \ replaced by a .. So in our example that would become InternetConnection.Heartbeat. The value of the of a property on that object should be a function that will get executed whenever that event comes in from the server. So in our case whenever the InternetConnectionStatus.Heartbeat.HeartBeat event comes in we’re going to set the state of lastHeartBeatReceivedAt to the current time. So if this event comes in the determineConnectionStatus function will determine that we’re online for the next 125 seconds.

Did you notice that the component uses a Echo mixin? A mixin can be compared to a trait in the PHP-world. A mixin contains some functions. Every component that uses the mixin will get those functions. So, like a trait, a mixin is a way to bundle reusable code.

The Echo mixin is responsible for adding the power of Laravel Echo to the component. Laravel Echo is a JavaScript library that makes it easy to handle websockets. It will handle all authentication and communication with Pusher. Echo is being set up in app.js

Laravel Echo can handle multiple broadcasters, we’re going to use Pusher here. That key is a public value that’s needed to communicate with Pusher.

Let’s go back take a look at the code of the Echo mixin.

import { forIn } from 'lodash';

export default {
    created() {
        forIn(this.getEventHandlers(), (handler, eventName) => {
                .listen(`.App.Events.${eventName}`, response => handler(response));

Whenever a component that uses the mixin is created the created function will be executed. It will process the output of getEventHandlers function from the component itself. First, we’ll build up the fully qualified event name. Then we’ll let Echo listen for events with that name on the private dashboard channel. Whenever an event with the right name comes in we’re going to pass the response to the handler and execute it.

The Package statistics component

Let’s take a look at another component. In the screenshot of the dashboard you can see that there are some statistics displayed regarding how many times our packages get downloaded.

The FetchTotals class, located in app/Console/Components/Packagist/FetchTotals.php is responsible for fetching the package statistics via the Packagist API files on GitHub, and transforming it to an array. After that it’ll fire off an event to inform the Vue side of things that new data is available.

namespace App\Console\Components\Packagist;

use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Spatie\Packagist\Packagist;
use App\Events\Packagist\TotalsFetched;

class FetchTotals extends Command
    protected $signature = 'dashboard:fetch-packagist-totals';

    protected $description = 'Fetch totals for all our PHP packages';

    public function handle()
        $packagist = new Packagist(new Client());

        $totals = collect($packagist->getPackagesByVendor(config('services.packagist.vendor'))['packageNames'])
                ->map(function ($packageName) use ($packagist) {
                    return $packagist->findPackageByName($packageName)['package'];
                ->pipe(function ($packageProperties) {
                    return [
                        'daily' => $packageProperties->sum('downloads.daily'),
                        'monthly' => $packageProperties->sum('downloads.monthly'),
                        'total' => $packageProperties->sum(''),

        event(new TotalsFetched($totals));

Most of this code should be self-explanatory. It’s also scheduled to run periodically. Let’s take a look at the TotalsFetched event that’s being sent out:

namespace App\Events\Packagist;

use App\Events\DashboardEvent;

class TotalsFetched extends DashboardEvent
    public $daily;

    public $monthly;

    public $total;

    public $stars;

    public function __construct($totals)
        foreach ($totals as $sumName => $total) {
            $this->$sumName = $total;

When broadcasting events in Laravel, all public properties of an event are being broadcasted as well. So using this code the Vue component can easily get to the values of $daily, $monthly, $total and $stars.

Here’s the Vue Component that renders the tile on the dashboard:

    <tile :position="position" modifiers="overflow">
        <section class="statistics">
            <h1>Package Downloads</h1>
                <li class="statistic">
                    <span class="statistic__label">24 hours</span>
                    <span class="statistic__count">{{ formatNumber(daily) }}</span>
                <li class="statistic">
                    <span class="statistic__label">30 days</span>
                    <span class="statistic__count">{{ formatNumber(monthly) }}</span>
                <li class="statistic">
                    <span class="statistic__label">Total</span>
                    <span class="statistic__count">{{ formatNumber(total) }}</span>

    import { formatNumber } from '../helpers';
    import echo from '../mixins/echo';
    import Tile from './atoms/Tile';
    import saveState from 'vue-save-state';

    export default {

        components: {

        mixins: [echo, saveState],

        props: ['position'],

        data() {
            return {
                daily: 0,
                monthly: 0,
                total: 0,

        methods: {

            getEventHandlers() {
                return {
                    'Packagist.TotalsFetched': response => {
                        this.daily = response.daily;
                        this.monthly = response.monthly;

            getSaveStateConfig() {
                return {
                    cacheKey: 'packagist',


Notice that in the getEventHandlers function we’ll update the state variables stars, daily, monthly, total to the values that we get from the TotalsFetched-event.


Because there is some semi-sensitive info being displayed (the tasks of our team members and the events on the calendar) we’ve added some security to the dashboard. That’s why you can’t just visit

The url itself is protected by a basic auth filter on the routes. The filter is native to laravel package. Relying on basic auth can be a bit insecure. So if you are going to fork our dashboard be sure to pick a long password and do some rate limiting server side to prevent brute force attacks.

The data sent through the websockets is secured as well. In the Echo mixin you might have noticed that a private method is called. This will ensure that, under the hood, a private Pusher channel is used, so nobody can listen in to what is sent via the websockets.

Displaying the dashboard on a TV

Behind our tv there is a Raspberry Pi 2 that displays the dashboard. It is powered by a USB port in the tv and it has a small Wifi dongle to connect to the internet, so cables aren’t necessary at all.

IMG_0938 (1)

The Pi used the default Raspian OS. When it is powered on it’ll automatically launch Chromium 56 and display the contents of

IMG_0939 (1)

Reloading the dashboard

For most components, the communication between the server and client is one-way. The client will receive data solely through the events sent out by the server. The client will never make a request for data itself.

When our last team member leaves the office he will switch off the wall mounted TV. This will cause the Pi to be powered down as well. The next time when the tv is powered back on the dashboard will be empty, waiting for events sent out by the server. We don’t want to stare at an empty dashboard the first hour after the tv is powered on, let’s fix that.

Every Vue component preserves it’s own state in data. Wouldn’t it be great to save that data whenever it is changed? Then it could be reloaded whenever the dashboard gets powered on. The SaveState-mixin, which is used on almost every component, does exactly that.

The mixin watches the data of the component it’s applied to. Whenever data changes, it will serialize the data and write it to local storage. Afterwards, when the component is created, the mixin will restore it’s state with the values in local storage. This means that when we power on our tv the saved data will immediately be displayed.

We’ve extracted that mixin to it’s own package, so you can use it in your projects:

Packages used

The dashboard is fetching data from various sources: Google Calendar, Packagist, Lastfm,… Here’s the list of packages used to pull in the data:


We mainly built our own custom Dashboard to toy around with Vue and also just because it’s fun.

There are many alternatives available to display dashboards:

Choose a solution that feels good to you.

Closing notes

I hope that you’ve enjoyed this little tour of the code behind our dashboard. I don’t have the intention of creating full documentation for the dashboard and make it monkey-proof as that would require just too much time. On the other hand I do think that if you have some experience with Laravel and Vue it’s not that hard to make your own dashboard with our code.

The entire source code is available on GitHub. If you have any questions on the dashboard, feel free to open up an issue on the issue tracker.

The broken windows theory or “Why some projects are just destined to suck”

In a new post on his blog, my favorite stalwart of the industry Frederick Vanbrabant, gives a explanation on why some projects turn into a big mess and how you can avoid it.

I truly believe that the broken window theory can be applied to software projects. In my personal experiences I’ve rarely seen a project start out as a total mess. If it ended up as a mess, it was gradually. I also believe that this is not necessary the fault of developers working on the project, think of it more as frogs in a pot with gradually increased temperature of water. One morning you just wake up and take a look at the project and realise that it has gotten really messy.

Performant Laravel

Chris Fideo, of Servers For Hackers and Shipping Docker, published a new free video serious on optimizing performance for Laravel apps. He shows how to use the built in artisan commands such as config:cache and route:cache,how to optimize queries, build up good indexes and how to add an object cache in a clean way.

There are some super common reasons your Laravel app might be slow.
This course shows you how to avoid speed issues with simple changes you can implement immediately.

Chris is also a working on a paid course on how to scale Laravel apps. If you want to stay in the loop for that one, subscribe to his newsletter.

The status antipattern

In a new blogpost on the author (I couldn’t find his real name) argues against using a simple status field.

Dear programmer, do you ever use the name state for your variables? Like state = 42?
“Hell no, that’s a terribly generic word. Better to use the domain-specific wording the variable refers to: is_invoiced, visit_count, shopping_cart, things like that.”

Sounds reasonable. But sometimes, you have a database column called status, and use it through your codebase, right?

Were you aware that status and state mean basically the same thing in English?

How to build screens for users, permissions and roles in a Laravel app

One of our more popular packages is laravel-permission. It enables you to easily save roles and permissions in the database. It hooks into Laravel’s native authorization capabilities. Allthough it’s quite powerful, the package doesn’t come with any UI out of the box.

If you do need a UI for this in your projects you’re in luck. On Caleb Oki wrote down an extensive tutorial on how you can build screens to manage users, permissions and roles that use our package.

When building an application, we often need to set up an access control list (ACL). An ACL specifies the level of permission granted to a user of an application. For example a user John may have the permission to read and write to a resource while another user Smith may have the permission only to read the resource.

In this tutorial, I will teach you how to add access control to a Laravel app using laravel-permission package. For this tutorial we will build a simple blog application where users can be assigned different levels of permission.

What to expect from JavaScript ES2017

In a new blogpost André Neves, a React Native engineer at Big Human, introduces the new features that are coming with ES2017.

I think it is a fair assessment to say that a large portion of JavaScript developers seem to appreciate the new, the shiny, the bleeding-edge tools. Whether it is to completely embrace a new technology, or simply to test out a tool’s functionality, we like to know what is out there to at least ‘dip our toes in the water’.

If you’re like me, keen on knowing about all of the new technology this incredible community has to offer, here is a breakdown of what ES2017 has in store.

Make your app fly with PHP OPcache

Recently this button to optimize PHP’s OPcache was added to Laravel Forge.

If you were wondering what PHP OPcache is all about and what pressing this button does with your application, read this article Olav van Schie wrote on the subject a while ago.

Every time you execute a PHP script, the script needs to be compiled to byte code. OPcache leverages a cache for this bytecode, so the next time the same script is requested, it doesn’t have to recompile it. This can save some precious execution time, and thus make your app faster (and maybe save some server costs).

A straightforward Vue component to filter and sort tables

Today we released our newest Vue component called vue-table-component. It aims to be a very easy to use component to make tables filterable and sortable. In this post I’d like to tell you all about it.

Why creating yet another table component?

Let’s first touch upon why we created it. To make lists of models sortable and filterable we used to rely on the venerable component. It works great, but comes with a few caveats. First, it’s built on jQuery. In our projects we avoid using jQuery nowadays and use Vue specific components. Secondly, there’s a lot of stuff in there that we don’t need, we probably are only using 10% of it’s features. So for our use cases, it’s a bit bloated. And lastly, because it contains so much features, using it can be a little unwieldy.

When creating our own table component we had only our specific use case in mind: a small set of data that is passed via json.

Using vue-table-component

Here’s an example of how you can use the component:

     { firstName: 'John', lastName: 'Lennon', instrument: 'Guitar', editUrl: '<a href='#john'>Edit</a>', birthday: '04/10/1940', songs: 72 },
     { firstName: 'Paul', lastName: 'McCartney', instrument: 'Bass', editUrl: '<a href='#paul'>Edit</a>', birthday: '18/06/1942', songs: 70 },
     { firstName: 'George', lastName: 'Harrison', instrument: 'Guitar', editUrl: '<a href='#george'>Edit</a>', birthday: '25/02/1943', songs: 22 },
     { firstName: 'Ringo', lastName: 'Starr', instrument: 'Drums', editUrl: '<a href='#ringo'>Edit</a>', birthday: '07/07/1940', songs: 2 },
     <table-column show="firstName" label="First name"></table-column>
     <table-column show="lastName" label="Last name"></table-column>
     <table-column show="instrument" label="Instrument"></table-column>
     <table-column show="songs" label="Songs" data-type="numeric"></table-column>
     <table-column show="birthday" label="Birthday" data-type="date:DD/MM/YYYY"></table-column>
     <table-column show="editUrl" label="" :sortable="false" :filterable="false"></table-column>

Let’s take a look on how our component will render that piece of html. The component doesn’t come with any styling, so you’ll need to provide your own css.

Head over to the demo page to play with the rendered output.

You’ve probably noticed that a filter field is added to the top. By default all data will be used in to filter. If any columns contain html it will be filtered out before filtering. So even though that last column contains links, filtering on href won’t yield any results. If you don’t want a column of data to be filterable just add :filterable="false to table-column.

Like expected, clicking a column header will sort the data. If the data contains a column with numerical values or dates you must set a data-type prop on table-column. Don’t want a column to be sortable? No problem! Just pass a sortable property set to false to table-column.

The component will also remember it’s state for 15 minutes. So when you reload the page that filter and sorting you used previously will still be used.

Head over to the readme on GitHub to learn all the props that can be passed.

In closing

Like mentioned before our table component is very much targeted to our use case. Our intent is to keep this component very clean and simple. If you need more features, take a look at the numerous other Vue components out there that can render table data.

Because in our client projects we are using Vue more and more you can expect some more opensource Vue components from us soon. If you haven’t already done so, be sure to take a look at this list of things we opensourced previously.

Classes, complexity, and functional programming

In this article Kent C. Dodds clearly explains what the downsides are of using Class in JavaScript.

Classes (and prototypes) have their place in JavaScript. But they’re an optimization. They don’t make your code simpler, they make it more complex. It’s better to narrow your focus on things that are not only simple to learn but simple to understand: functions and objects.

https:[email protected]/classes-complexity-and-functional-programming-a8dd86903747

What the hell are generics and why would I want them in PHP?

Frederick Vanbrabant, developer at madewithlove and co-organiser of PHP Antwerp, explains on his blog what generics are.

So everyone is talking about this hip “new” kid on the block for PHP: Generics. The rfc is on the table and a lot of people are getting all excited about it, but you don’t fully see the excitement? Let’s explore what it’s all about!

Diving Laravel

Mohammed Said, Laravel employee number #1, recently announced that he published a new site where he shares stuff he learned while researching the Laravel code base. The site is called “Diving Laravel”, which is kinda nice knowing that Mohammed is an incredible diver himself.

In this website I’m going to share notes on the internals of Laravel core, packages, as well as the technologies behind the different components. My goal is to help people understand how things work under the hood and also to be a reminder for me for when I need to look into something that I’ve already studied before.

JavaScript’s comma operator

Vitaly Gordon explains how the little known comma operator makes it easy to add some debugging statements in short hand array functions.

What if you want to add a console.log call before x + 1 ? With comma operator, adding side-effects to functional expressions is simple:

const fun = x => (console.log (x), x + 1)

https:[email protected]/javascript-did-you-know-about-the-comma-operator-ff9b511cc33

How to Scan Fingerprints with Async PHP and React Native

In an amazing article on SitePoint, Christopher Pitt demonstrates how to create an async PHP server that can requests a fingerprint scan on the client side. He uses React Native, WebSocket, an async PHP server, PHP preprocessing, … Really amazing stuff.

I’m going to describe the process of building custom multi-factor authentication for all transactions. I don’t want to do the usual (and boring on its own) SMS or push notification one-time-password stuff. I want to build a fingerprint scanner right into my phone.

In this tutorial, we’re going to look at how to set up a simple iOS app using React Native. We will also set up an asynchronous HTTP server, with a web socket connection to the app.

We will follow this up by adding fingerprint scanning capabilities to the app, and asking for these fingerprint scans from the HTTP server. Then we will build an endpoint through which GET requests can request a fingerprint scan and wait for one to occur.

Taylor Otwell on Laravel and Symfony

In a recent interview published on the Cloudways blog Taylor Otwell shares his thoughts on the similarities differences between Laravel and Symfony.

Both Laravel and Symfony are more rapid than building an entire PHP application from scratch. So, in that sense, they both allow rapid application development. However, Laravel does make strong efforts to have a very clean and productive working environment for building applications of all sizes. I think Symfony has also made efforts in this direction over the last few years with their “DX” initiatives and some of the more opinionated things they are doing with Symfony Flex.