The magic behind Laravel Valet

Mohamed Said peeked behind the curtains and explains on his blog how Laravel Valet works behind the scenes.

The idea behind Valet is that it configures PHP's built-in web server to always run in the background when the operating system starts, then it proxies all requests to a given domain to point to your localhost 127.0.0.1
http://themsaid.github.io/magic-behind-laravel-valet-20160506/

If you want to keep Homestead around for some projects, know that your can also use dnsmasq to point an entire domain to your Homestead installation.

Read more

In Search of an Anonymous Class Factory

Mark Baker tried creating an Anonymous Class Factory.

I was intrigued by a request to find a way of dynamically applying Traits to a class at run-time. With time on my hands as I was sitting in the airport, I considered the problem; and my first thought was to build an Anonymous class, extending the requested class (so that it would still contain all the base properties and functionality, and could be type-hinted, but also applying the requested Trait or set of Traits.

https://markbakeruk.net/2016/05/03/in-search-of-an-anonymous-class-factory/

Read more

Join 9,500+ smart developers

Get my monthly newsletter with what I learn from running Spatie, building Oh Dear, and maintaining 300+ open source packages. Practical takes on Laravel, PHP, and AI that you can actually use.

No spam. Unsubscribe anytime. You can also follow me on X.

Route model binding using middleware

Our team is currently working on a Spark app. Spark makes is real easy to add an API that can be consumed by the users of the app. The generation of API tokens and authentication middleware comes out of the box. It all works really great.

In our API the a team owner can fetch information on every member on the team and himself. The url to fetch info of a user looks something like this: /users/<id-of-user>. Nothing too special. But we also want to make fetching a user's own information as easy as possible. Sure, the user could look op his own userid and then call the aforementioned url, but using something like /users/me is much nicer. In this way the user doesn't have to look op his own id. Let's make that possible.

In our app we use these functions to get the the current user and team:

/**
 * @return \App\Models\User|null
 */
function currentUser()
{
    return request()->user();
}

/**
 * @return \App\Models\Team|null
 */
function currentTeam()
{
    if (!request()->user()) {
        return;
    }

    return request()->user()->currentTeam();
}

The route look something to get the user data looks something like this:

Route::post('/users/{userId}', 'UserController@show');

My first stab to get /users/me working was to leverage route model binding. In the RouteServiceProvider I put this code:

$router->bind('userId', function ($userId) {
   if ($userId === "me") {
      return currentUser();
   }

   $user = currentTeam()->users->where('id', $userId)->first();

   abort_unless($user, 404, "There's no user on your team with id `{$id}`");

   return $user;
});

Unfortunately this does not work. When Laravel is binding route parameters the authentication has not started up yet. At this point currentUser and currentTeam will always return null.

Middleware comes to the rescue. Route-middleware is processed at a moment when authentication has started up. To make /users/me work this middleware can be used:

namespace App\Http\Middleware;

use Closure;

class BindRouteParameters
{
    public function handle($request, Closure $next)
    {
        if ($request->route()->hasParameter('userId')) {
            $id = $request->route()->parameter('userId');

            $user = $this->getUser($id);

            abort_unless($user, 404, "There's no user on your team with id `{$id}`");

            $request->route()->setParameter('userId', $user);
        }

        return $next($request);
    }

    public function getUser(string $id)
    {
        if ($id === 'me') {
            return currentUser();
        }

        return currentTeam()->users->where('id', $id)->first();
    }
}

There are two things you must do to use this middleware. First: it's route middleware so you such register it as such at the http-kernel.

// app/Http/Kernel.php

...
/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
...
'bindRouteParameters' => \App\Http\Middleware\BindRouteParameters::class,
]

Second: you must apply the middleware to certain routes. In a default Spark app you'll find all api-routes in a file at app/Http/api.php. That file starts with this line:

Route::group(['prefix' => 'api', 'middleware' => ['auth:api']], function () {
...

Just add the bindRouteParameters middleware to the group:

Route::group(['prefix' => 'api', 'middleware' => ['auth:api', 'bindRouteParameters']], function () {
...

I'm currently using the above solution in my app. You could make a solution that's more generic by checking if the parameters ends with orMe. Here's an example how that might work:

namespace App\Http\Middleware;

use Closure;

class BindCurrentUserRouteParameter
{
    public function handle($request, Closure $next)
    {
        collect($request->route()->parameters())
            ->each(function ($value, $parameterName) use ($request) {
                if (!ends_with($parameterName, 'orMe')) {
                    return;
                }

                if ($value === 'me') {
                    $request->route()->setParameter($parameterName, currentUser());
                }
            });

        return $next($request);
    }

If you have any questions about this approach or have any ideas how to make it better, let me know in the comments below.

Read more

Don't use illuminate/support in framework agnostic packages

In our framework agnostic packages we sometimes pull in illuminate/support. This package that's part of the core of Laravel provides some nice string and collection functions. But unfortunately a lot of other stuff gets pulled in as well. In a post on his blog Matthew Allen explains the downsides of requiring illuminate/support.

A lot of framework agnostic Composer packages (PHP) pull in illuminate/support, which contains helper functions and general purpose code used by the Laravel framework. Usually it’s because the support package has nice helper functions like array_get, or because of the nice collection class.

The helpers functions are nice, but I don’t think developers appreciate the ramifications of choosing to pull that package in. Everyone is afraid to get criticized for reinventing the wheel, so packages are pulling in 6000+ lines of code to avoid writing isset($arr[$k]) ? $arr[$k] : null themselves.

http://mattallan.org/2016/dont-use-illuminate-support/

One of the most useful functions of illuminate/support is the Collection class. In a thread on Reddit Taylor Otwell, the creator of Laravel, seems to agree that requiring illuminate/support isn't a good idea and that the Collection class could be extracted to it's own package. Let's hope that'll happen in the near future.

In the new major versions of our framework agnostic packages we'll swap out illuminate/support in favor of packages like the ones mentioned at the end of Matthew's post.

EDIT: Meanwhile Tighten has released a Collections-only split from Laravel's Illuminate Support.

Read more

Using Github authentication for login with Laravel Socialite

Laravel hero Matt Stauffer has a new article on his blog where he talks about using a social network site login as the primary login for your application.

Laravel's Socialite package makes it simple to authenticate your users to Facebook, Twitter, Google, LinkedIn, GitHub and Bitbucket. You can authenticate them for the purpose of connecting their pre-existing user account to a third-party service, but you can also use it as your primary login mechanism, which we'll be talking about here.

I'm working on a new little micro-SaaS that is purely dependent on GitHub in order to operate, so there's no reason to set up any user flow other than just GitHub. Let's do it.

https://mattstauffer.co/blog/using-github-authentication-for-login-with-laravel-socialite

Read more

Cleaning Up Form Input with Transpose

Adam Wathan has another excellent article on using collections. This time he tackles the less used transpose-function.

Transpose is an often overlooked list operation that I first noticed in Ruby.

The goal of transpose is to rotate a multidimensional array, turning the rows into columns and the columns into rows.

http://adamwathan.me/2016/04/06/cleaning-up-form-input-with-transpose/

Personally, I can't wait until the release of his book: Refactoring To Collections.

Read more

Easily integrate MailChimp in Laravel 5 original

by Freek Van der Herten – 2 minute read

Today we released a new major version of our laravel-newsletter package. This package makes it easy to integrate MailChimp in your Laravel app. Under the hood V3 of the MailChimp API is used. If you're used the older version of our package be sure to upgrade by the end of this year: MailChimp will…

Read more

Common files in PHP packages

Jordi Boggiano researched which files are common in PHP packages.

I queried GitHub's API for the file listing (only the root directory) of all PHP packages listed on packagist.org.

What this let me do is look at what files are commonly present (and not), which is quite interesting to get a picture of the whole ecosystem.

In total, this includes file listings from 78'992 packages (no GitHub API was harmed in the making of this blog post though). And here are a few interesting things that surfaced:

https://seld.be/notes/common-files-in-php-packages

Read more

Concurrent HTTP requests without opening too many connections

Hannes Van De Vreken shows what awesome async things you can do with Guzzle promises.

Now what happens if you need to perform a large number of concurrent requests? If you don’t control the number of requests you might end up with a dangerously large amount of open TCP sockets to a server. You’ll need to use some sort of dispatching to have a limited number of concurrent requests at any given time.

Let’s show you how to do that.

https://blog.madewithlove.be/post/concurrent-http-requests/

Read more

Dissecting a spammer’s spam script

Let’s take a look at a PHP script used to send spam. These types of scripts run on servers all over the world and might give you some insight into a spammer’s dedication to annoy the hell out of you. ... One of the WordPress sites on a shared hosting web server I manage was infected by a spam script. Fortunately, the script was unable to do any real damage and was detected within half an hour of infection. I thought it would be fun to show you the script and dissect it, to find out exactly how these things work and make thousands of email administrators’ lives a living hell.
https://jelleraaijmakers.nl/2016/04/dissecting-spammers-spam-script

Read more

Upgrading PHP 5.6 to 7.0 on a Forge provisioned server

If you've read some posts before on this blog, then you'll probably know that I'm a big fan of Forge. The service makes it very easy to set up and administer servers. At my company we've been using it since it launched.

We currently have 80 provisioned servers. Most of them are small droplets. We have a policy of running every site on it's own droplet. This approach has many benefits, but that's maybe something for a future post.

The bulk of our servers are on PHP 5.6. That's not too bad, but once you have some sites on PHP 7, the sites running on those servers feel a bit slow. It's amazing how fast you get used to the speed that PHP 7 offers. That's why I experimented a bit with upgrading the PHP version on a Forge provisioned server. My gut feeling was that upgrading the PHP version is less work that setting up a new server and moving a site to it.

To not mess up a live site I created a snapshot and used that to set up a server to toy around with. With a little bit of research I came up with these instructions to upgrade the PHP version.

sudo add-apt-repository ppa:ondrej/php

sudo apt-get update

sudo apt-get install php7.0

sudo apt-get install php7.0-fpm

Depending on your project you will need less or more php extensions, but these were the ones relevant for my site:

sudo apt-get install php7.0-gd

sudo apt-get install php7.0-mysql

sudo apt-get install php-memcached

sudo apt-get install php7.0-mcrypt

sudo apt-get install php-curl

sudo apt-get install php-imagick

Next, in the nginx configuration of the site I replaced unix:/var/run/php5-fpm.sock with unix:/var/run/php/php7.0-fpm.sock

The final adjustment I made was to make sure nginx would spawn the php processes under the forge. This will make sure that a php process can write to sites previously created by Forge:

// in the file /etc/php/7.0/fpm/pool.d/www.conf
...
user = forge
group = forge
...

After that I rebooted the server (maybe just restarting nginx is enough) and enjoyed browsing a site that was four times as fast. ?

If you decide to try this out for your server, be aware that what works for me doesn't necessarily work for you. Every site is a bit different. But I'm sure the instructions from this post will get you pretty far. Happy upgrading!

EDIT: Meanwhile DigitalOcean also published a guide on how to upgrade to PHP 7.

Read more

A great evening at PHPGent

Yesterday, after a winter sleep, PHPGent awoke and held a meetup at the offices of In The Pocket. It was nice to see some familiar and some new faces.

I had the honor of being the first speaker. My talk was titled "Backing up with Laravel". I started off with some best practices regarding backups and demonstrated the laravel-backup package which was released a few weeks ago.

Here are my slides:

https://speakerdeck.com/freekmurze/backing-up-with-laravel

phpgent_2016-Apr-14

Next up was Wouter Sioen of SumoCoders. He talked about building maintainable software. He showed how using the solid principles help to clean up the code of his home brew json to html converter. Then he continued with explaining object calisthenics: a few simple rules to greatly improve the readability of your code. Wouter's slides can found on github.io.

wouter

These two very beautiful graphic summaries of the talks were made by Peter Decuyper:

https://twitter.com/sgrame/status/720674134041235456

https://twitter.com/sgrame/status/720690758265778176

If you attended the meetup be sure to leave Wouter and me some feedback on joind.in so we can improve our speaking skills.

Visiting your local PHP user group is one of the best ways to learn new stuff and to getting to know the community. If you've never visited a user group, use this site to lookup the closest one to your home. If there isn't one close by, start one yourself.

Screen Shot 2016-04-14 at 23.43.52

Read more

Laravel medialibrary hits v4 original

by Freek Van der Herten – 2 minute read

Today we tagged a new major version of laravel-medialibrary. In case you're not familiar with this package here's a quick rundown of what it can do. The package can associate all sorts of files with Eloquent models. It provides a simple, fluent API to work with. Here's a quick example: $newsItem =…

Read more

Making Eloquent models translatable original

by Freek Van der Herten – 2 minute read

Spatie, the company where I work, is located in Belgium. Although our country is quite small, there are three official languages: Dutch, French and German. That's why nearly all of our projects are multilingual. In most projects we used to rely on Dimitris Savvopoulos popular translatable package to…

Read more

Easily store some loose values

For a site I was working on the admin should be able to switch on or off a form that's displayed on the homepage. Question: where's the best place to store the value of that switch? Creating a table and column for it in the database seems overkill. Putting it in a never expiring cache does not feel right. I think the best place to store such value is just write it to a simple file.

In the example above only one value needed to be stored, but for other projects there sometimes were two or three of them. Over the years I found myself writing the same code over and over again to store and work with such values.

Our intern Jolita and I whipped up a valuestore package. It only provides one class: Valuestore. The values will get written as JSON in a given file. The API mostly reflects Laravel's caching API. Here's how you can work with it:

$valuestore = Valuestore::make($pathToFile);

$valuestore->put('key', 'value');

$valuestore->get('key'); // Returns 'value'

$valuestore->has('key'); // Returns true

// Specify a default value for when the specified key does not exist
$valuestore->get('non existing key', 'default') // Returns 'default'

$valuestore->put('anotherKey', 'anotherValue');

// Put multiple items in one go
$valuestore->put(['ringo' => 'drums', 'paul' => 'bass']);

$valuestore->all(); // Returns an array with all items

$valuestore->forget('key'); // Removes the item

$valuestore->flush(); // Empty the entire valuestore

$valuestore->flushStartingWith('somekey'); // remove all items who's keys start with "somekey"

$valuestore->increment('number'); // $valuestore->get('key') will return 1 
$valuestore->increment('number'); // $valuestore->get('key') will return 2
$valuestore->increment('number', 3); // $valuestore->get('key') will return 5

// Valuestore implements ArrayAccess
$valuestore['key'] = 'value';
$valuestore['key']; // Returns 'value'
isset($valuestore['key']); // Return true
unset($valuestore['key']); // Equivalent to removing the value

// Valuestore impements Countable
count($valuestore); // Returns 0
$valuestore->put('key', 'value');
count($valuestore); // Returns 1

As you see it's quite a simple class, but I'm sure it'll come in handy in the future. The package can be found on GitHub.

Read more