Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

Refactoring to actions

Original – by Freek Van der Herten – 6 minute read

In our recent projects at Spatie, we've started using a concept called "actions". It keeps our controllers and models skinny. It's a straightforward practice. In this blog post, I'd like to explain it to you.

From logic in controllers and models...

Consider you have a Laravel powered blog where you want to publish posts. When a post is published, the app should tweet out the title and link to it.

The controller that does that might look like this:

class PostsController
{
    public function create()
    {
        // ...
    }

    public function store()
    {
        // ...
    }

    public function edit()
    {
        // ...
    }

    public function update()
    {
        // ...
    }

    public function delete()
    {
        // ...
    }

    public function publish(Post $post, TwitterApi $twitterApi)
    {
        $post->markAsPublished();

        $twitterApi->tweet($post->title . PHP_EOL . $post->url);

        flash()->success('Your post has been published!');

        return back();
    }
}

If you're wondering why this controller doesn't extend the default controller, head over to this blog post on simplifying controllers.

To me, it's a bit dirty that a non-cruddy action lives in a crud controller. Let's follow Adam's advice and put the publish method in its own controller.

class PublishPostController
{
    public function __invoke(Post $post, TwitterApi $twitter)
    {
        $post->markAsPublished();

        $twitter->tweet($post->title . PHP_EOL . $post->url);

        flash()->success('Your post has been published!');

        return back();
    }
}

That's already a bit nicer, but we can take it even further. Imagine you want to create an artisan command to publish blog posts. Right now, this isn't possible because the logic to do this is inside the controller.

To make logic callable from a command (or anywhere else in an app) that logic shouldn't be in a controller. Ideally, the only code that is placed in a controller is code that handles the HTTP layer.

You might be tempted to move all this code to a publish method on the Post model. For smallish projects that is fine. But imagine there are more kinds of actions on a post, like archiving or duplicating. All these actions will make your model big.

... to logic in actions!

Instead of leaving this logic in the controller or putting it in a model, let's move it to a dedicated class. At Spatie, we call these classes "actions".

An action is a very simple class. It only has one public method: execute. You could name that method whatever you want.

namespace App\Actions;

use App\Services\TwitterApi;

class PublishPostAction
{
    /** @var \App\Services\TwitterApi */
    private $twitter;

    public function __construct(TwitterApi $twitter)
    {
        $this->twitter = $twitter;
    }

    public function execute(Post $post)
    {
        $post->markAsPublished();

        $this->tweet($post->title . PHP_EOL . $post->url);
    }
    
    private function tweet(string $text)
    {
        $this->twitter->tweet($text);
    }
}

Notice that markAsPublished method being called on $post? Because our app now has a dedicated place for published a post, that logic could move to this PublishPostAction, making the Post model a bit lighter.

// in PublishPostAction

public function execute(Post $post)
{
  $this->markAsPublished($post);

  $this->tweet($post->title . PHP_EOL . $post->url);
}

private function markAsPublished(Post $post)
{
  $post->published_at = now();

  $post->save();
}

private function tweet(string $text)
{
  $this->twitter->tweet($text);
}

In a controller, you can call the action like this:

namespace App\Http\Controllers;

use App\Actions\PublishPostAction;

class PublishPostController
{
    public function __invoke(Post $post, PublishPostAction $publishPostAction)
    {
        $publishPostAction->execute($post);

        flash()->success('Hurray, your post has been published!');

        return back();
    }
}

We use method injection to resolve PublishPostAction so Laravel's container will automatically inject a TwitterApi instance into the PublishPostAction itself.

An artisan command could now make use of the action too.

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Actions\PublishPostAction;
use App\Models\Post;

class PublishPostCommand extends Command
{
    protected $signature = 'blog:publish-post {postId}';

    protected $description = 'Publish a post';

    public function handle(PublishPostAction $publishPostAction)
    {
        $post = Post::findOrFail($this->argument('postId'));
        
        $publishPostAction->execute($post);
        
        $this->comment('The post has been published!');
    }
}

Another benefit we get from extracting to actions is that the code because it isn't tied to the HTTP layer anymore, is now more testable.

class PublishPostActionTest extends TestCase
{
    public function setUp(): void
    {
        parent::setUp();

        Carbon::setTestNow(Carbon::createFromFormat('Y-m-d H:i:s', '2019-01-01 01:23:45'));

        TwitterApi::fake();
    }

    /** @test */
    public function it_can_publish_a_post()
    {
        $post = factory(Post::class)->state('unpublished')->create();

        (new PublishPostAction())->execute($post);

        $this->assertEquals('2019-01-01 01:23:45', $post->published_at->format('Y-m-d H:i:s'));

        TweetterApi::assertTweetSent();
    }
}

Queueable actions

Imagine you have an action that performs some work that takes some time. A simple solution for this would be to create a queued job and dispatch that job from within the action.

Let's use a queue in the PublishPostAction to send out the tweet.

// in PublishPostAction

public function execute(Post $post)
{
    $this->markAsPublished($post);

    $this->tweet($post->title . PHP_EOL . $post->url);
}

private function markAsPublished(Post $post)
{
    $post->published_at = now();

    $post->save();
}

private function tweet(string $text)
{
    dispatch(new SendTweetJob($text));
}

Now, if you want to send tweets from somewhere else in your application. Sure you could do it like this using a job:

namespace App\Http\Controllers

class SendTweetController
{
    public function __invoke(SendTweetRequest $request)
    {
        dispatch(new TweetJob($request->text);
        
        flash()->success('The tweet has been sent');
        
        return back();
    }
}

That'll work perfectly. But wouldn't it be nice if we could use actions for everything, including asynchronous work?

Enter our laravel-queueable-action package. This package allows you to queue actions easily. You can make an action queueable by applying the provided QueueableAction to it. That trait adds an onQueue method.

use Spatie\QueueableAction\QueueableAction;

namespace App\Actions;

class SendTweetAction
{
    use QueueableAction;

    /** @var \App\Services\TwitterApi */
    private $twitter;

    public function __construct(TwitterApi $twitter)
    {
        $this->twitter = $twitter;
    }
    
    public function execute(string $text)
    {
        $this->twitter->tweet($text);
    }
}

Now we can call the action, and it will perform its work on a queue.

class SendTweetController
{
    public function __invoke(SendTweetRequest $request, SendTweetAction $sendTweetAction)
    {
        $sendTweetAction->onQueue()->execute($request->text);
        
        flash()->success('The tweet will be sent very shortly!');
        
        return back();
    }
}

You can also specify the queue where the work should be performed by passing its name to onQueue.

$sendTweetAction->onQueue('tweets')->execute($request->text);

If you want to know more about queueable actions, be sure to check our this informative blog post by my colleague and package creator Brent.

In closing

Extracting logic to actions makes that action callable from multiple places in your app. It also makes the code easier to test. If actions become big, you can divide them into smaller actions.

At Spatie, we've named this concept "action" and are using the execute method. You can call the concept and the method whatever you want. We didn't invent this practice. There are a lot of devs using it already. If you're coming from the DDD-world, you probably noticed that an action is just a command and its handler wrapped together.

Do you have any questions or remarks? Let me know in the comments below.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

avatar

I'm a bit late on the hype, but how does a Action differ from a service where a service is also bothered with business logic? To me, they seem to be doing in general the same thing, so would you say that there is a positive addition to choosing an action over a service?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.

Webmentions

Paulund liked on 3rd November 2019
Marco liked on 2nd November 2019
Shane liked on 31st October 2019
Manojkiran retweeted on 31st October 2019
Manojkiran liked on 31st October 2019
Thore Sünert liked on 31st October 2019
Mike liked on 31st October 2019
Stuart Wilsdon liked on 31st October 2019
Michael Dyrynda retweeted on 31st October 2019
Roman Pronskiy liked on 31st October 2019
Shane Smith liked on 31st October 2019
Jaxson Terra liked on 31st October 2019
Bas de Groot liked on 31st October 2019
Matthew Poulter liked on 31st October 2019
Semyon Chetvertnyh liked on 31st October 2019
Shane Oliver liked on 31st October 2019
oluwajubelo loves VueJS ? retweeted on 31st October 2019
oluwajubelo loves VueJS ? liked on 31st October 2019
Shane Smith retweeted on 31st October 2019
Mickaël Viaud liked on 31st October 2019
loreias liked on 31st October 2019
Mariusz Pianowski liked on 31st October 2019
Alex liked on 31st October 2019
Laracon AU retweeted on 31st October 2019
Zayn Buksh liked on 31st October 2019
Neil Carlo Faisan Sucuangco liked on 30th October 2019
Goran Gliga liked on 30th October 2019
Niels liked on 30th October 2019
Joan Morell liked on 30th October 2019
oussama.tn liked on 30th October 2019
Imran Ali liked on 30th October 2019
Imran Ali retweeted on 30th October 2019
Chris Bautista liked on 30th October 2019
Adi liked on 30th October 2019
Roman Pronskiy liked on 30th October 2019
Andrés Herrera García liked on 30th October 2019
Knight  liked on 30th October 2019
Pepe García liked on 30th October 2019
Mike liked on 30th October 2019
Ryzsk Zkhie liked on 30th October 2019
Matt Kingshott ? liked on 30th October 2019
Freek Van der Herten replied on 30th October 2019
Glad you like it. Keep in mind that there are many variations on this theme. Do whatever works best for you! ?
Asbjørn Pettersen replied on 30th October 2019
@freekmurze excellent blog post. I have been struggeling to find a good action pattern. Thank you!
Asbjørn Pettersen replied on 30th October 2019
Yes. But it is nice to find a good, and understandable pattern. With a good blog post explaining it, its easier to distribute the knowledge to the rest of the team.
Rich Klein liked on 29th October 2019
Pooyan Razian retweeted on 29th October 2019
Pooyan Razian liked on 29th October 2019
Ahmed Nagi liked on 29th October 2019
Wilman Barrios liked on 29th October 2019
Guus liked on 29th October 2019
? รtєթђคภ ןєรร ? liked on 29th October 2019
Wyatt liked on 29th October 2019
Johan van der Molen liked on 29th October 2019
Vincenzo La Rosa liked on 29th October 2019
Shahid H replied on 29th October 2019
So it is basically like a service class? Keep the controller and move the logic to a service class.
oluwajubelo loves VueJS ? liked on 29th October 2019
Tiago Silva Pereira liked on 29th October 2019
Oniya Daniel ?? liked on 29th October 2019
Ron Florax replied on 29th October 2019
When it’s something under about 12 lines I’d always have it straight in the model unless it needs to be shared by multiple models.
Tim Hall liked on 29th October 2019
Divan liked on 29th October 2019
Christian Leo-Pernold liked on 29th October 2019
Adrian Marin ⛵️ replied on 29th October 2019
Yeah, but how are Actions different from Jobs?
Taylor Otwell ? replied on 29th October 2019
For me I just don’t see a big deal in involving the queue system in something that A) won’t be queued and B) is essentially a function call
Iain Collins liked on 29th October 2019
Simon Payne liked on 29th October 2019
Ray Blair liked on 29th October 2019
Simon Payne retweeted on 29th October 2019
Pablo Román liked on 29th October 2019
Khai Rahman liked on 29th October 2019
Taylor Otwell ? replied on 29th October 2019
I actually still typically have methods on the models which just invoke the actions
Miguel Piedrafita ? liked on 29th October 2019
Ravi Bastola replied on 29th October 2019
Wow, thanks for the post! ❤️ while reading!
Simon Montoya P liked on 29th October 2019
Akram Chauhan liked on 29th October 2019
Cameron Scott liked on 29th October 2019
Ravi Bastola liked on 29th October 2019
Sam Snelling liked on 29th October 2019
Mina Abadir replied on 29th October 2019
Is there an advantage of using Actions over dispatching jobs synchronously?
Khai Rahman retweeted on 29th October 2019
Andrés Santibáñez liked on 29th October 2019
imabug liked on 29th October 2019
Ravi Bastola retweeted on 29th October 2019
Freek Van der Herten replied on 2nd October 2019
If not, mail me and I’ll take a look when I got a little time on my hands ?
Joren Van Hocht replied on 2nd October 2019
Going to rewatch them and see if one these strategies can solve the issue I'm facing right now ?
Joren Van Hocht replied on 2nd October 2019
Thanks man ?
Joren Van Hocht liked on 2nd October 2019
Uyo-obong liked on 13th August 2019
Guus liked on 13th August 2019
Kusha liked on 13th August 2019
Laurent B retweeted on 13th August 2019
Mitul Golakiya liked on 13th August 2019
Josh Bruce liked on 13th August 2019
Bobby Bouwmann liked on 13th August 2019
Ratting Gergely liked on 12th August 2019
Janos Papp liked on 12th August 2019
alaa m Ibrahim liked on 12th August 2019
Ashot Nalbandyan liked on 12th August 2019
Ashot Nalbandyan retweeted on 12th August 2019
Julius Ehrlich liked on 12th August 2019
이현석 Hyunseok Lee liked on 12th August 2019
Victor Guerrero liked on 12th August 2019
Franco Gilio liked on 12th August 2019
Drew Roberts liked on 12th August 2019
Charles Bowen liked on 12th August 2019
Marcin liked on 12th August 2019
Maulik Shah liked on 12th August 2019
Michaël De Boey liked on 12th August 2019
 Mario Mendoza  liked on 12th August 2019
David Cottila retweeted on 12th August 2019
 Mario Mendoza  retweeted on 12th August 2019
Renato VG liked on 12th August 2019
Anton Kristensen liked on 12th August 2019
Marcel Pociot ? retweeted on 12th August 2019
Adam Wathan liked on 12th August 2019
Spatie retweeted on 12th August 2019
Rajesh Dewle liked on 12th August 2019
Max Pshenichnikov liked on 12th August 2019
Juan Pablo ??‍? liked on 11th August 2019
iBoedel replied on 11th August 2019
Thank you for sharing. Looking fwd for Amsterdam
Khurram Shahzad liked on 11th August 2019
Melbourne Laravel retweeted on 11th August 2019
Roberto B liked on 11th August 2019
David liked on 11th August 2019
patrosmania liked on 11th August 2019
Thibault Lavoisey liked on 11th August 2019
Andikan Affiah liked on 10th August 2019
Strotgen liked on 10th August 2019
arondeparon liked on 10th August 2019
Stefan liked on 10th August 2019
Carlos Cruz retweeted on 10th August 2019
Ihor Vorotnov • 25% liked on 10th August 2019
od3n liked on 10th August 2019
Cody liked on 10th August 2019
ApoNie liked on 10th August 2019
Prasad Chinwal liked on 10th August 2019
Alejandro Vásquez N. liked on 10th August 2019
Miguel Piedrafita ?‍? liked on 10th August 2019
Burak Erdem liked on 10th August 2019
Pooyan R replied on 10th August 2019
I wish we could have you in our meetup in Copenhagen. :)
Pablo Román liked on 10th August 2019
Gültekin Yaman liked on 10th August 2019
Mak Man liked on 10th August 2019
Simon Payne liked on 10th August 2019
Simon Payne retweeted on 10th August 2019
Javier Quintana retweeted on 10th August 2019
Felipe Dalcin liked on 10th August 2019
Javier Quintana liked on 10th August 2019
Johnson Page liked on 10th August 2019
Gabriel liked on 10th August 2019
marco asperti liked on 10th August 2019
marco asperti retweeted on 10th August 2019
Laravel School replied on 10th August 2019
Ibm Plex mono looks amazing
Ulrich Anani liked on 10th August 2019
Laravel School retweeted on 10th August 2019
Ulrich Anani retweeted on 10th August 2019
Laravel School liked on 10th August 2019
Beta liked on 10th August 2019
Adrian Nürnberger ? replied on 10th August 2019
Nice talk thanks for sharing!
Adrian Nürnberger ? liked on 10th August 2019
Bilal retweeted on 10th August 2019
Wrends liked on 10th August 2019
Makabi Yelmis liked on 10th August 2019
envomer liked on 10th August 2019
Roman Pronskiy liked on 10th August 2019
Boris DEHOUMON liked on 10th August 2019
Clevon Noel ?? liked on 10th August 2019
Jeri liked on 10th August 2019
Jeri retweeted on 10th August 2019
JuanDMeGon liked on 10th August 2019
JuanDMeGon retweeted on 10th August 2019
swapnilsarwe liked on 10th August 2019
Ahmad Ripaldi liked on 10th August 2019
Elie Andraos retweeted on 10th August 2019
Craig Potter liked on 10th August 2019
Martin Medina liked on 10th August 2019
Jordan Hall retweeted on 10th August 2019
Jordan Hall liked on 10th August 2019
Adinnu Benedict retweeted on 9th August 2019
João Patrício liked on 9th August 2019
Adinnu Benedict liked on 9th August 2019
Andrew Clinton liked on 9th August 2019
Andrew Clinton retweeted on 9th August 2019
Wyatt liked on 9th August 2019
Mubassir Hayat retweeted on 9th August 2019
Mickaël Isaert liked on 9th August 2019
zorigitano liked on 9th August 2019
DN liked on 9th August 2019
Lib liked on 9th August 2019
Herman Schutte liked on 9th August 2019
Andrei Scripcaru liked on 9th August 2019
Axel Alvarado liked on 9th August 2019
PHP Synopsis retweeted on 9th August 2019
Solum DeSignum liked on 9th August 2019
Michael Dyrynda retweeted on 9th August 2019
Gareth Redfern retweeted on 9th August 2019
Mozammil liked on 9th August 2019
Gareth Redfern liked on 9th August 2019
Vitaly Yushkevich liked on 9th August 2019
Joe Rushton liked on 9th August 2019
Maarten Buis liked on 9th August 2019
[object Object] liked on 9th August 2019
Brian replied on 9th August 2019
Nice talk! Id watch SpatieCasts: the making and maintaining of Spatie packages. Hell maybe even subscribe haha
Richard Ottinger liked on 9th August 2019
Chea Bonnak liked on 9th August 2019
Lee Overy liked on 9th August 2019
Günther Debrauwer liked on 9th August 2019
Manuel Teuber liked on 9th August 2019
ArielSalvadorDev liked on 9th August 2019
Ramiro Varandas Jr liked on 9th August 2019
ArielSalvadorDev retweeted on 9th August 2019
alan wilson retweeted on 9th August 2019
Ray Blair liked on 9th August 2019
Alan Scott‽ liked on 9th August 2019
Anne Koep retweeted on 9th August 2019
Vítor Arjol liked on 9th August 2019
Dennis Rodis liked on 9th August 2019
Luis Cortés liked on 9th August 2019
Muhammad Shafeeq liked on 9th August 2019
laravelgr retweeted on 9th August 2019
OZA ?? liked on 9th August 2019
zaichaopan liked on 9th August 2019
Flamur Mavraj liked on 9th August 2019
Jarryd liked on 9th August 2019
Paul Rose liked on 9th August 2019
Vladyslav liked on 9th August 2019
Jino Antony liked on 9th August 2019
Jess Archer ?‍? liked on 9th August 2019
ariesw liked on 9th August 2019
Patrick Brouwers liked on 9th August 2019
Ed Grosvenor liked on 9th August 2019
Tom Witkowski retweeted on 9th August 2019
Tom Witkowski liked on 9th August 2019
Gurinder Chauhan retweeted on 9th August 2019
Matt Libera liked on 9th August 2019
Stephan Köllen liked on 9th August 2019
tokobuku_jiban liked on 9th August 2019
Matt Murtaugh liked on 9th August 2019
Patrick Brouwers retweeted on 9th August 2019
Vaibhav Pardeshi liked on 9th August 2019
Osasu Aebong liked on 9th August 2019
Julio Serpone liked on 9th August 2019
eCreeth liked on 9th August 2019
austin kregel liked on 9th August 2019
Rudi van Zandwijk liked on 9th August 2019
Eddie Palmans liked on 9th August 2019
Mihai liked on 9th August 2019
Rod Elias liked on 9th August 2019
mwm [ ⚡️ , ? ] liked on 9th August 2019
Ashish K. Poudel liked on 9th August 2019
Carlos Rodríguez retweeted on 9th August 2019
Mithicher Baro liked on 9th August 2019
Mithicher Baro retweeted on 9th August 2019
Osasu Aebong retweeted on 9th August 2019
docker system prune liked on 9th August 2019
oluwajubelo loves VueJS ? liked on 9th August 2019
Célien Boillat ?? liked on 9th August 2019
kapil retweeted on 9th August 2019
Ruslan liked on 9th August 2019
Levis Orgil liked on 9th August 2019
NUNO MADURO ? liked on 9th August 2019
jaouad liked on 9th August 2019
jaouad retweeted on 9th August 2019
Bas de Groot liked on 9th August 2019
Brendan Urquhart liked on 9th August 2019
Cameron Scott liked on 9th August 2019
Vaughany liked on 9th August 2019
Victor Hugo retweeted on 9th August 2019
Edwin I Arellano liked on 9th August 2019
Arash liked on 9th August 2019
Victor Hugo liked on 9th August 2019
Daniel Schmitz liked on 9th August 2019
Roman Pronskiy liked on 25th July 2019
Ariel Costa liked on 25th July 2019
Skugga liked on 25th July 2019
Hazz Azimi liked on 25th July 2019
SergioS liked on 25th July 2019
Marian liked on 25th July 2019
Rémi Latrille liked on 25th July 2019
Stefan Tanevski liked on 25th July 2019
Kennedy Tedesco liked on 25th July 2019
Jarryd liked on 25th July 2019
Duy Ha Nguyen liked on 25th July 2019
Mark Myers liked on 25th July 2019
Ned Fenstermacher retweeted on 25th July 2019
Daryl Geyer II retweeted on 25th July 2019
Daryl Geyer II liked on 25th July 2019
Lee Cox liked on 25th July 2019
Knight  liked on 25th July 2019
Lars Schou ?? liked on 25th July 2019
Dario Diaz liked on 24th July 2019
Luke Curtis liked on 24th July 2019
jamieconnor liked on 24th July 2019
Guus liked on 24th July 2019
Kevin Morris liked on 24th July 2019
Guus retweeted on 24th July 2019
Axel Pardemann liked on 24th July 2019
Axel Pardemann retweeted on 24th July 2019
eminiarts liked on 24th July 2019
Powolny Marcel ?‍? liked on 24th July 2019
Drew Roberts liked on 24th July 2019
Powolny Marcel ?‍? retweeted on 24th July 2019
Laravel Academy Cape Town liked on 24th July 2019
Duncan McClean liked on 24th July 2019
Tiagosimoes liked on 24th July 2019
Wyatt liked on 24th July 2019
Windu liked on 24th July 2019
Robin Dirksen liked on 24th July 2019
Emmanuel Oduro liked on 24th July 2019
MD Iyasin Arafat liked on 24th July 2019
Батыр liked on 24th July 2019
zorigitano liked on 24th July 2019
Alexander Diachenko liked on 24th July 2019
Robert S. Getty III liked on 24th July 2019
oluwajubelo loves VueJS ? liked on 24th July 2019
Sanket Gandhi ? ? liked on 24th July 2019
Zaff Ja retweeted on 24th July 2019
Roy Francis Ponce de Leon liked on 24th July 2019
Prasad Chinwal liked on 24th July 2019
Sanket Gandhi?? retweeted on 24th July 2019
이현석 Hyunseok Lee liked on 24th July 2019
Yassir Awad liked on 24th July 2019
Hardik Shah liked on 24th July 2019
Ilya Sakovich liked on 24th July 2019
Michiel Abé liked on 24th July 2019
Adrian Brown ?? liked on 24th July 2019
Alan Scott‽ liked on 24th July 2019
? Yogesh Chatrola ? liked on 24th July 2019
Mike liked on 24th July 2019
Bee business liked on 24th July 2019
Thibault Lavoisey liked on 24th July 2019
Thore Sünert liked on 24th July 2019
Martin Carlin liked on 24th July 2019
Logan H. Craft liked on 24th July 2019
Hadjidoro ?? liked on 24th July 2019
kapil retweeted on 24th July 2019
Omar Andrés Barbosa Ortiz liked on 24th July 2019
jason liked on 24th July 2019
Mansa Musa liked on 24th July 2019
ósásù aèbóng retweeted on 24th July 2019
Alex Hackney liked on 24th July 2019
Filipe liked on 24th July 2019
David liked on 24th July 2019
Peter Brinck ? liked on 24th July 2019
Marco Bellido retweeted on 24th July 2019
Tony Messias liked on 24th July 2019
ósásù aèbóng liked on 24th July 2019
Terry Tan liked on 24th July 2019
Hamed liked on 24th July 2019
Harry ? liked on 24th July 2019
Rizwan Aslam retweeted on 24th July 2019
Gareth Redfern liked on 24th July 2019
Pepe García liked on 24th July 2019
owls liked on 24th July 2019
Soumil Roy liked on 24th July 2019
Christoph Rumpel ? liked on 24th July 2019
Adib Hanna liked on 24th July 2019
Johnathan Barrett liked on 24th July 2019
Matthew Poulter liked on 24th July 2019
Oliver Musovski liked on 24th July 2019
Whisk retweeted on 24th July 2019
kevinhenney liked on 24th July 2019
Whisk liked on 24th July 2019
Derek Martin liked on 24th July 2019
Adam ?? Mench liked on 24th July 2019
Adib Hanna retweeted on 24th July 2019
James Mills liked on 24th July 2019
Simon Montoya P liked on 24th July 2019
Mubashar Iqbal liked on 24th July 2019
Christopher Dosin liked on 24th July 2019
Teun de Kleijne liked on 24th July 2019
Gareth Redfern retweeted on 24th July 2019
Rizwan Aslam liked on 24th July 2019
technomike retweeted on 24th July 2019
Dries Vints retweeted on 24th July 2019
Iven liked on 24th July 2019
Miguel Orellana liked on 24th July 2019
Ismail Xahy retweeted on 24th July 2019
dowilcox liked on 24th July 2019
Славка liked on 24th July 2019
technomike liked on 24th July 2019
Richard Ottinger liked on 24th July 2019
Spatie retweeted on 24th July 2019
Maurizio Lepora liked on 24th July 2019
Osmar Alves liked on 24th July 2019
Fakhar Khan liked on 24th July 2019
Dries Vints liked on 24th July 2019
Harish Patel liked on 24th July 2019
Patrick Muriungi liked on 24th July 2019
James Healey liked on 24th July 2019
LaravelMade retweeted on 24th July 2019
Marcel Pociot ? retweeted on 24th July 2019
Stefan Bauer liked on 24th July 2019
Florian Voutzinos ⚡ liked on 24th July 2019
Ismail Xahy liked on 24th July 2019
Maurizio Lepora retweeted on 24th July 2019