laravel

All my posts about laravel.

Some handy collection macros original

by Freek Van der Herten – 4 minute read

Laravel's collection class is truly wonderful. It contains a lot of handy methods and you can create some very elegant code with it. In client projects I found myself adding the same macro's over and over again. That's why my colleague Seb and I took some time to create a package aptly called…

Read more

Things I learned from reading Laravel: Up and running original

by Freek Van der Herten – 3 minute read

Matt Stauffer is currently putting the final touches on his new book called Laravel: Up And Running. It aims to be a good guide for newcomers to the framework. But even if you've got some experience with Laravel, it should be worth your time to read it. Even Matt himself picked up a lot of cool…

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.

The next version of Laravel News has been launched

Earlier today laravel-news.com, the official Laravel news source, received a new coat of paint. In a post announcing the launch Eric shares how the site works behind the curtains.

During this move, I have redone the way the site is powered. Previously it ran on WordPress with a custom theme I put together, it worked fine but added new features, and sections became harder and harder, and I wanted the ability to use what I am comfortable with, Laravel. However, I didn’t want to give up the media library and editing experience of WordPress.

So to have the best of both worlds I kept the old site on WordPress and used the WP Rest API paired with the Laravel Scheduler. This allows me to automatically sync data from WordPress into my database without having to rebuild an entire CMS admin area. I have the same setup for the podcast section, and it hooks into the Simplecast API to pull those over.

https://laravel-news.com/2016/08/welcome-to-the-next-version-of-laravel-news/

I sure would like to read a tutorial on how that sync works in detail.

Read more

Comparing laravel-mediable with laravel-medialibrary

Laravel-Mediable is a package to upload and handle all sorts of files (aka media) in a Laravel app. It was built by a Canadian based web agency called Plank.

With it you can do things like this:

$media = MediaUploader::fromSource($request->file('thumb'))
    ->toDestination('uploads', 'post/thumbnails')
    ->upload();

$post = Post::create($this->request->input());
$post->attachMedia($media, ['thumbnail']);

Pretty cool. You can read more on the way and how the package was built in an introductory post on the Plank blog.

At Spatie we've also built our own solution for handling media. In Plank's blogpost Sean lists these differences between their package and our Medialibrary.

spatie/laravel-medialibrary plank/laravel-mediable
Relationship many-to-one polymorphic, each media record is owned by one related model many-to-many polymorphic, each media record can connect to any number of related models, and vice versa.
Filesystem Files are stored in directories named after the media id relative to the disk root Files can be stored anywhere on the disk
Association Identifier Each media record belongs to one "collection" Media can be attached to a model with any number of "tags"
Aggregate Types Support for images and pdfs Configurable support for any number of custom types
Miscellaneous Features Glide manipulations Synchronization commands

Since our medialibary was introduced I've been asked from time to time why our medialibrary uses a many-to-one polymorphic relationship. The answer is: simplicity.

A previous iteration of our Blender CMS (a version that used Zend Framework 1 instead of Laravel ?) had a screen where the user could pick a file from all uploaded files (it looked much like this wordpress screen). We saw that, after having set up a lot of sites with Blender, that almost none of our clients used that screen...

In our projects we also see that our clients mostly need to attach an image, or a pdf or whatever, ... to only one model (for instance a news item). It rarely happens that a client wants to attach the same file to different models.

In our code we want to handle that use case as simple as possible and that's why we preferred using a many-to-one relation over a many-to-many relation. All the other differences listed in Plank's post are caused by the same reasoning, we preferred simplicity and ease of use over flexibility.

If you're looking for a good solution to handle media in a Laravel app I suggest you take a look at both our Medialibrary and Plank's Mediable package. Both packages are good at what they do. Pick the one that best fits your project (and just feels good to you).

Read more

Adding a vue component to Spark

On his blog Christoph Rumpel explains how you can add a vue component to a Spark app.

Taylor Otwell, the creator of Laravel, is a big Vue fan and this is why you will find it in a lot of Laravel products. Spark is using Vue too. ... When I started to use Spark I wanted to use some of my already given .vue components too, but since Spark is a little bit different from standard Laravel projects I didn’t managed to use them. After some weeks of reaching out for help, I finally got the solution.

http://christoph-rumpel.com/2016/05/Larave-Spark-Using-Vue-Component/

Read more

Our packages are now postcardware original

by Freek Van der Herten – 1 minute read

My company has released a lot of PHP and Laravel packages. According to the packagist stats they have been downloaded for a little over 700 000 times. Up until now they've all been free. That is going to change. Our packages are now postcardware. This means that from now on you are required to send…

Read more

How to use PHP Solarium in a Laravel project

Apache Solr is a high performance search engine much like Elastic. On his blog Peter Steenbergen explains how you can use Solr in a Laravel app.

This is my second blog in a series about SOLR with the PHP Solarium library. My first blog was about the usage of OR filters to create Multi-Select facets with SOLR. With this blog item I will show you how easy it is to implement the PHP Solarium library in the Laravel framework.

http://petericebear.github.io/laravel-php-solarium-integration-20160725/

Read more

Comparing Laravel with Zend Expressive

In a post on masterzendframework.com Matthew Setter shares his experiences with building the same application in both Laravel and Zend Expression.

The reason being, is that you can't give a straight yes or no answer. It's like asking: is desktop Linux as easy as Windows? The presumption there is that you want to do exactly the same thing in Linux as you can with Windows.

Well, if you wanted the exact same experience on Linux, as you get with Windows, then use Windows! As you're working with two different systems, two different approaches to solving the same challenge, then the end result may be the same — but how they work will naturally be different.

So it is with Laravel and Zend Expressive. They're two exceptional PHP frameworks which can be used to create similar applications. Yet they were designed with different preconceptions about how an application's should be put together. They were designed for different developer mindsets. And the list goes on.

So, whilst I was able to create the same application, roughly about the same size, the way they were developed was different.

http://www.masterzendframework.com/zend-expressive-or-laravel/

I'm currently perfectly happy in the Laravel ecosystem, so I won't be making a switch soon. But I like to keep an eye out on how other frameworks and communities are doing things to learn from that.

Read more

Building a Laravel powered Slack bot

At Spatie we've recently introduced a bot to our Slack chat. We've named him Paolo (after the waiter in our favourite Italian restaurant in Antwerp: La Fontanella Da Enzo). Here's a demo of Paolo (the bot) in action.

Behind the scenes Paolo is powered by a Laravel application that responds to all requests Slack is sending to it. In this post I'd like to explain how you can set up your own Laravel powered Slack bot.

General flow

A message in slack that starts with a slash is called a slash command. Whenever you type in a slash command in Slack channel, an http request will be sent to your Laravel app. You have to respond to that command within 3 seconds. Failing to do some will result in an error being displayed in the channel.

After that initial response you're allowed to send multiple delayed responses. But there are some limitations for delayed responses. You may respond up to 5 times within 30 minutes after the user typed in the slash command on the slack channel. Want to know more about slash commands and how they work, then read this excellent article at Slack's API site.

To make responding to Slack a breeze we're going to used the package our team released a few days ago called spatie/laravel-slack-slash-command.

Setting things up

Before you can get started building our Laravel app, you'll need to set up slash command at Slack.com. Head over to the custom integrations page at Slack.com to get started. There click "Slash commands" and on the next page click "Add configuration". On that screen you can choose a name for your Slack command. In our examples we'll use paolo but you can choose anything that Slack allows.

You should now be on a screen that looks like this:

paolo integration settings

In the url field you should type the domain name of your Laravel app followed by one or more segments. In the screenshot we've added a slack segment. You can choose any segment you want. Normally the token field should already be filled. And that's all you need to do at Slack.com.

The next thing you'll need to do is to install the spatie/laravel-slack-slash-command package. Let's pull it in via Composer.

composer require spatie/laravel-slack-slash-command

Next, you must install the service provider:

// config/app.php
'providers' => [
    ...
    Spatie\SlashCommand\SlashCommandServiceProvider::class,
];

The configuration file of the package can be published with:

php artisan vendor:publish --provider="Spatie\SlashCommand\SlashCommandServiceProvider" --tag="config"

This is the contents of the published config file:

return [

    /**
     * Over at Slack you can configure to which url the slack commands must be send.  
     * url here. You must specify that. Be sure to leave of the domain name.
     */
    'url' => 'slack',

    /**
     * The token generated by Slack with which to verify if a incoming slash command request is valid.
     */
    'token' => env('SLACK_SLASH_COMMAND_VERIFICATION_TOKEN'),

    /**
     * The handlers that will process the slash command. We'll call handlers from top to bottom
     * until the first one whose `canHandle` method returns true.
     */
    'handlers' => [
        //add your own handlers here


        //this handler will respond with a `Could not handle command` message.
        Spatie\SlashCommand\Handlers\CatchAll::class,
    ],
];

And with that you're ready to respond to http requests coming from Slack.

Setting up your first command handler

Whenever a user types in a slash command Slack will send an http request to the Laravel app. Next, our package will go over all classes in the handlers key of the config file from top to bottom until the first one whose canHandle method returns true. A handler is a class that is responsible for receiving a request from slack and sending a response back.

Let's create our first handler. Handlers must extend Spatie\SlashCommand\Handlers\BaseHandler and implement the two abstract methods from that BaseHandler: canHandle and Handle.

Here's an example.

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;
use Spatie\SlashCommand\Handlers\BaseHandler;

class Hodor extends BaseHandler
{
    /**
     * If this function returns true, the handle method will get called.
     *
     * @param \Spatie\SlashCommand\Request $request
     *
     * @return bool
     */
    public function canHandle(Request $request): bool
    {
        return true;
    }

    /**
     * Handle the given request.
     * 
     * @param \Spatie\SlashCommand\Request $request
     * 
     * @return \Spatie\SlashCommand\Response
     */
    public function handle(Request $request): Response
    {
        return $this->respondToSlack("Hodor, hodor...");
    }
}

This Hodor class will just respond with Hodor, hodor, ... to every request that is sent to it.

You'll need to register this class in the config file.

// app/config/laravel-slack-slash-command
    'handlers' => [
        App\SlashCommandHandlers\Hodor::class,
        ...
    ], 

Let's see that in action.

A slightly more advanced handler

Let's create a slightly more interesting handler. This one that just repeats the command you've sent to it but only if the text after the command starts with repeat.

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;
use Spatie\SlashCommand\Handlers\BaseHandler;

class Repeat extends BaseHandler
{
    public function canHandle(Request $request): bool
    {
        return starts_with($request->text, 'repeat');
    }

    public function handle(Request $request): Response
    {   
        $textWithoutRepeat = substr($request->text, 7)

        return $this->respondToSlack("You said {$textWithoutRepeat}");
    }
}

Let's register this handler as well.

// app/config/laravel-slack-slash-command

    'handlers' => [
        App\SlashCommandHandlers\Repeat::class,
        App\SlashCommandHandlers\Hodor::class,
        ...
    ],    

If you type in /paolo repeat Hi, everybody in a slack channel now, you'll get a response Hi, everybody back. When you type in /poalo bla bla bla you'll get a response Hodor, hodor... because the Hodor handler is the first one which canHandle-method returns true.

Notice that Spatie\SlashCommand\Request being past in canHandle and handle? It contains all data that's being passed by Slack to our Laravel app. These are it's most important properties:

  • `command`: the command name without the `/` that the user typed in. In our previous example this would be `paolo`.
  • `text`: all text text after the command. In our the example above this would be `repeat Hi, everybody`.
  • `userName`: the Slack username of the person that typed in the command
  • `userId`: the Slack user id of the person that typed in the command
  • `channelName`: the name of the channel where the user typed in the command
  • `teamDomain`: the name of the Slack subdomain. So if your team is on `example.slack.com` this would be `example`.

Customizing your response

By default the response will be sent to the user who typed in the original message. If you want the response to be visible to all users in the channel you can do this:

    public function handle(Request $request): Response
    {
        return $this
           ->respondToSlack("Hodor, hodor...")
           ->displayResponseToEveryoneOnChannel();
    }

There are also many formatting options. Take a look at this response on Slack: attachments

$this->respondToSlack()
    ->withAttachment(Attachment::create()
        ->setColor('good')
        ->setText('This is good!')
    )
    ->withAttachment(Attachment::create()
        ->setColor('warning')
        ->setText('Warning!')
    )
    ->withAttachment(Attachment::create()
        ->setColor('danger')
        ->setText('DANGER DANGER!')
    )
    ->withAttachment(Attachment::create()
        ->setColor('#439FE0')
        ->setText('This was a hex value')
    );

There are many more options to format a message. Take a look at Slacks documentation on attachments to learn what's possible.

Using signature handlers

A console command in Laravel can make use of a signature to set expectations on the input. A signature allows you to easily define arguments and options.

If you let your handler extend Spatie\SlashCommand\Handlers\SignatureHandler you can make use of a $signature and the getArgument and getOption methods to get the values of arguments and options.

Let's take a look at an example.

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;
use Spatie\SlashCommand\Handlers\SignatureHandler;

class SendEmail extends SignatureHandler
{
    public $signature = "paolo email:send {to} {message} {--queue}"

    public function handle(Request $request): Response
    {   
        $to = $this->getArgument('to');

        $message = $this->getArgument('message');

        $queue = $this->getOption('queue') ?? 'default';

        //send email message...
    }
}

Notice that there is no canHandle method present in that class. The package will automatically determine that a command /paolo email:send test@email.com hello can be handled by this class.

Sending delayed responses

Remember that restriction mentioned above about the initial response to a slash command. Your Laravel app only has three seconds to respond otherwise an error message will be shown at Slack. After that initial fast response you're allowed to send 5 more responses in the next 30 minutes for the command. These responses are called "delayed responses". We're going to leverage Laravel's queued jobs to send those delayed responses. Please make sure that you've set up a real queue driver in your app, it needs to be something other than sync.

Imagine you need to call a slow API to get a response for a slash command. Let's first create a handler that will send the initial fast response.

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;

class SlowApi extends BaseHandler
{
    public function canHandle(Request $request): bool
    {
        return starts_with($request->text, 'give me the info');
    }

    public function handle(Request $request): Response
    {
        $this->dispatch(new SlowApiJob());

        return $this->respondToSlack("Looking that up for you...");
    }
}

Notice that we're dispatching a job right before sending a response. Behind the scenes Laravel will queue that job.

This is how that SlowApiJob would look like.

namespace App\SlashCommand\Jobs;

use Spatie\SlashCommand\Jobs\SlashCommandResponseJob;

class SlowApiJobJob extends SlashCommandResponseJob
{
    // notice here that Laravel will automatically inject dependencies here
    public function handle(MyApi $myApi)
    {
        $response = $myApi->fetchResponse();

        $this
           ->respondToSlack("Here is your response: {$response}")
           ->send();
    }
}

Notice that, unlike in the Handlers the response is not returned and that send() is called after the respondToSlack-method.

With this in place a quick response Looking that info for you... will be displayed right after the user typed /your-command get me the info. After a little while, when MyApi has done it's job Here is your response: ... will be sent to the channel.

Some useful handlers

The previous examples of this post were quite silly. You'll probably never going to use to handlers in your bot. Let's review a real life example. Our Poalo bot can lookup dns records for a given domain. This is how that looks like in a Slack channel.

This is the actual class that we use in our bot:

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Attachment;
use Spatie\SlashCommand\AttachmentField;
use Spatie\SlashCommand\Handlers\SignatureHandler;
use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;

class Dns extends SignatureHandler
{
    protected $signature = 'paolo dns {domain}';

    /**
     * Handle the given request. Remember that Slack expects a response
     * within three seconds after the slash command was issued. If
     * there is more time needed, dispatch a job.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function handle(Request $request): Response
    {
        $domain = $this->getArgument('domain');

        if (empty($domain)) {
            return $this->respondToSlack("You must provide a domain name.");
        }

        $sanitizedDomain = str_replace(['http://', 'https://'], '', strtolower($this->getArgument('domain')));

        $dnsRecords = dns_get_record($sanitizedDomain, DNS_ALL);

        if (!count($dnsRecords)) {
            return $this->respondToSlack("Could not get any dns records for domain {$domain}");
        }

        $attachmentFields = collect($dnsRecords)->reduce(function (array $attachmentFields, array $dnsRecord) {
            $value = $dnsRecord['ip'] ?? $dnsRecord['target'] ?? $dnsRecord['mname'] ?? $dnsRecord['txt'] ?? $dnsRecord['ipv6'] ?? '';

            $attachmentFields[] = AttachmentField::create('Type', $dnsRecord['type'])->displaySideBySide();
            $attachmentFields[] = AttachmentField::create('Value', $value)->displaySideBySide();

            return $attachmentFields;
        }, []);

        return $this->respondToSlack("Here are the dns records for domain {$domain}")
            ->withAttachment(Attachment::create()
                ->setColor('good')
                ->setFields($attachmentFields)
            );
    }
}

In order to get home every member of our team needs to bike a bit. That's why we've also created a command to display a rain forecast. This is what happens when /paolo rain is typed in our slack channels.

This is the class responsible for creating that response.

namespace App\SlashCommandHandlers;

use Spatie\SlashCommand\Attachment;
use Spatie\SlashCommand\Handlers\SignatureHandler;
use Spatie\SlashCommand\Request;
use Spatie\SlashCommand\Response;

class Rain extends SignatureHandler
{
    protected $signature = 'paolo rain';

    /**
     * Handle the given request. Remember that Slack expects a response
     * within three seconds after the slash command was issued. If
     * there is more time needed, dispatch a job.
     *
     * @param Request $request
     *
     * @return Response
     */
    public function handle(Request $request): Response
    {
        return $this
            ->respondToSlack("Here you go!")
            ->withAttachment(
                Attachment::create()->setImageUrl('http://api.buienradar.nl/image/1.0/radarmapbe?width=550')
            );
    }
}

In closing

The spatie/laravel-slack-slash-command package makes is it easy to let a Laravel app respond to a slash command from Slack. If you start using the package, let me know in the comments below what your bot can do. And if you like our package, take a look at this list of Laravel packages we've previously released to see if we've made something that can be of use to you.

Read more

Writing modular applications in Laravel

Nicolas Widart, author of Asgard CMS, created a new package called laravel-modules that can help splitting up a large Laravel app in modules.

On his blog he published an introductory post.

Just imagine having a medium sized application where everything is in the `app/ù folder, worse, every model is in the root of the app folder! At some point you will spend a lot of time looking for things because everything is bunched together.

This is what being modular is trying to resolve. You split of the business logic into different parts, which belongs together. If you're into Domain Driven Design, you can consider a module an aggregate.

Every module has its own routes/controllers/models/views/business logic/etc. Meaning every module contains a group of classes that all are related to each other in some way.

https://nicolaswidart.com/blog/writing-modular-applications-with-laravel-modules

Read more

Improvements to Authentication in Laravel 5.3

In my book Joseph Silber is one of the unsung heroes of the Laravel ecosystem. Whenever I open up internals on Larachat or Github he's giving friendly and thoughtful advice. I was happy to learn that Joseph started a blog.

In the first post he goes over all the improvements made to authentication in Laravel 5.3.

Authentication has gotten some nice improvements in 5.3, so let's examine it piece by piece.
  • Introducing the authenticate method
  • The exception handler's unauthenticated method
  • The Authenticate middleware
  • Authenticating against multiple guards
  • Route model binding and global scopes
  • Bonus: the request's expectsJson method

https://josephsilber.com/posts/2016/07/10/authentication-improvements-in-laravel-5-3

If you're looking for a package that can handle roles and abilities in Laravel, be sure to check out his Bouncer package.

Read more

Using MySQL's JSON columns in Laravel 5.3

Laravel 5.3, which will be released at this years Laracon US, has some new very handy functionality to work with MySQL 5.7 JSON columns. In a post on his site Matt Stauffer demonstrates the new API.

While Laravel has had the ability to cast your data to and from JSON since version 5.0, it was previously just a convenience—your data was still just stored in a TEXT field. But MySQL 5.7 introduced an actual JSON column type.

Laravel 5.3 introduces a simple syntax for lookups and updates based on the value of specific keys in your JSON columns.

https://mattstauffer.co/blog/new-json-column-where-and-update-syntax-in-laravel-5-3

If you're going to use this functionality, you should also read Mohamed Said's post on how to improve performance by using MySQL generated columns.

JSON columns cannot be indexed. You can work around this restriction by creating an index on a generated column that extracts a scalar value from the JSON column.

http://themsaid.com/laravel-mysql-json-colum-fast-lookup-20160709/

Read more

Processing a csv file in Laravel original

by Freek Van der Herten – 2 minute read

From time to time I need to process a csv file. PHP provides a fgetcsvfunction to help with that task. Unfortunately this is a very basic function. It will not, for instance, recognize a header column as such. In this quick post I'll show how using the excellent laravel-excel package (which can…

Read more

A package to log activity in a Laravel app original

by Freek Van der Herten – 4 minute read

In your apps there's probably a lot going on. Users log in and out, they create, update and delete content, mails get sent and so on. For an administrator of an app these events provide useful insights. In almost every project we make at Spatie we log these events and show them in the admin-section…

Read more

Make your Laravel app comply with the crazy EU cookie law

All sites owned by EU citizens or targeted towards EU citizens must comply to a crazy EU law. This law requires a dialog to be displayed to inform the users of your websites how cookies are being used. You can read more info on the legislation on the site of the European Commission. The newest Laravel package made by my colleagues at Spatie and myself makes your app compliant with that law.

Once installed the package will render the following dialog that, when styled, will look very much like this one: 68747470733a2f2f7370617469652e6769746875622e696f2f6c61726176656c2d636f6f6b69652d636f6e73656e742f696d616765732f6469616c6f672e706e67

When the user clicks "Allow cookies" a laravel_cookie_consent cookie will be set and the dialog will be removed from the DOM. On the next request Laravel will notice that the laravel_cookie_consent has been set and will not display the dialog again.

We've made it easy to customize the texts shown by the dialog. You can also make changes to the dialog or JavaScript itself.

The legislation is pretty very vague on how to display the warning, which texts are necessary, and what options you need to provide. This package will go a long way towards compliance, but if you want to be 100% sure that your website is ok, you should consult a legal expert.

Take a look at the package on GitHub to learn how to install the package and which options it provides. If you like it, be sure to check out our full list of Laravel packages.

Read more

Laravel Analytics v2 has been released original

by Freek Van der Herten – 2 minute read

One of our more popular packages is laravel-analytics. The package makes it easy to fetch information such as pageviews, top referrers, etc... from the Google Analytics API. In our Blender-based projects we use the fetched data to display a nice chart in the admin section: Laravel-analytics is one…

Read more

Test Driven API Development using Laravel, Dingo and JWT with Documentation

In a new tutorial posted at dotdev.co Diaa Fares shows a good way to develop API's using Laravel. Along the way he touches on the Dingo packages, JSON Web tokens and documentation generation.

Let’s look at everything we will cover: Landmark 1: Prepare our TDD environment and creating our first test. Landmark 2: Installing and configuring Dingo API package. Landmark 3: What are Transformers, why the need for them and how to use thephpleague/fractal as our transformation layer. Landmark 4: Introduction about JWT and how to use tymondesigns/jwt-auth for our token based authentication. Landmark 5: How to use laravel-apidoc-generator to generate nice documentation for our API. So, pack your bags and let’s dive into our journey!

https://dotdev.co/test-driven-api-development-using-laravel-dingo-and-jwt-with-documentation-ae4014260148#.iynir3ftm

Read more