Introduction

It's not a secret that Laravel has more than 10 features that I don't know about, I just don't want to make it as a very long article. Moreover, many of them are very insignificant. Some of them I will never probably use. I've chosen 10 features that I didn't know about, but now I'm using them in all projects.

10 Laravel features

  1. Prefix for route names.
  2. Customizing the route parameter key.
  3. Casting values from request.
  4. Check migration status.
  5. Migration names with spaces.
  6. Column modifier on timestamp method.
  7. Customizing Laravel stubs.
  8. Progress bar for artisan command.
  9. Method mapInto on Collections.
  10. Method “every” on Collections.

1. Prefix for route names

Documentation. Prefixes on route names allow you to add a prefix on all the routes in a group. Here is the example from my app:

Route::middleware('auth')->prefix('admin')->name('admin.')->group(function () {
    Route::resource('posts', AdminPostController::class)->except(['show']);
    Route::resource('tags', AdminTagController::class)->except(['show']);
});

Now, all the routes in a group will have the admin. prefix. For example, the route for all posts will be admin.posts.index, and for a single post admin.posts.show. Unfortunately, PHP Storm 2021.1.2 doesn't know about that, and you will not have the intellisense for prefixed routes.

2. Customizing the route parameter key

Documentation. Imagine you have a posts.show route, it's gonna look like that:

Route::get('posts/{post}', [PostController::class, 'show'])->name('posts.show');

When the user accesses the route /posts/1, in your show method you'll receive the instance of the post with the identifier 1.

public function show(Post $post): View {}

But if you want to get a post by its slug instead of identifier, you can customize the route parameter key.

Route::get('posts/{post:slug}', [PostController::class, 'show'])->name('posts.show');

After this, we can visit /posts/10-features-in-laravel-that-i-didnt-know-existed and get the post in our controller action.

3. Casting values from request

Documentation. Did you know you can get cast values from request? I used to get a boolean value from a checkbox like this:

 $is_published = $request->get('is-published') === 'on';

Illuminate\Http\Request class has a boolean method, that you can use:

$is_published = $request->boolean('is-published');

The boolean method returns true for 1, “1”, true, “true”, “on”, and “yes” values. For all the other values, it will return false.

You can do the same for integers, floats, strings, dates, and even enum types like this:

$post_id = $request->integer('post_id');
$is_published = $request->boolean('is-published');
$price = $request->float('price');
$created_date = $birthday = $request->date('created'); // Carbon instance
$status = $request->enum('status', Status::class); // Enum type

4. Check migrations status

Documentation. Artisan command that shows the list of all migrations with the additional information.

php artisan migrate:status

The result looks like this:

php artisan migrate:status command result

Very useful when you need to check if there are migrations that haven't been migrated yet.

5. Migration names with spaces

I couldn't find this features in the documentation, I've heard about it in a YouTube video Laravel Migrations: 12 Useful Tips in 12 Minutes. It's an artisan command that simplifies migration naming.

php artisan make:migration "create blog table"

You simply surround the name with quotes to use spaces in migration names. It's not really a feature, but I constantly use it in my apps.

6. Column modifier on timestamp method

Documentation. If you are like me, used DB::raw('CURRENT_TIMESTAMP') to set a default timestamp for the current date, then this feature is for you. Here's how I did it before:

public function up(): void
{
    Schema::create('social_shares', function (Blueprint $table) {
        $table->id();
        $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
    });
}

But you can actually use a useCurrent method on a timestamp.

$table->timestamp('created_at')->useCurrent();

7. Customizing Laravel stubs

Documentation. We have an artisan command that allows us to edit all the templates that Laravel uses for creating controllers, models and other classes.

php artisan stub:publish

In your project, you're going to see a stubs directory after executing this command. The directory contains many files that you can edit.

Files in stubs directory

I'm a big fan of using types, so I can take for example factory.stub and make it how I want it to look with return types and fewer comments.

Editing laravel stub

Every time when I create a new factory, it's going to use my newly created template instead of Laravel's one. Let's create a factory for the model Tag.

php artisan make:factory TagFactory --model Tag

Now, in my database/factories directory, I have a TagFactory.php file that looks like this:

<?php

namespace Database\Factories;

use App\Models\Tag;
use Illuminate\Database\Eloquent\Factories\Factory;

class TagFactory extends Factory
{
    protected $model = Tag::class;

    public function definition(): array
    {
        return [
            //
        ];
    }
}

8. Progress bar for artisan command

Documentation. I was once writing a console command in one project, that downloads files from multiple sources. I remember thinking “It would have been nice to make a progress bar here”, it is unclear to me why I haven't checked Laravel's documentation for that because it has a progress bar that I didn't know about.

There are 2 ways of handling a progress bar, one with loops and another with callbacks. I prefer loops because they are way faster. Here is the example of the command that checks the HTTP status of certain sites.

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;

class TestCommand extends Command
{
    protected $signature = 'sites:status';
    protected $description = 'Checks statuses of the sites';

    private array $urls = [
        'https://serhii.io',
        'https://github.com',
        'https://duckduckgo.com',
        'https://shobar.com',
        'https://twitter.com',
    ];

    public function handle(): void
    {
        $results = collect();

        $bar = $this->output->createProgressBar(count($this->urls));

        $bar->start();

        foreach ($this->urls as $url) {
            $results->push(Http::get($url)->status());
            $bar->advance();
        }

        $bar->finish();

        $this->newLine();
        $this->info('Statuses are: ' . $results->join(', '));
    }
}

After running a php artisan sites:status command in a console, we get a charming progress bar with our result.

Console result after running our command

9. Method "mapInto" on Collections

Documentation. This method iterates over the collection, and creates a new instance of the given class by passing the value into the constructor. So instead of having a collection of arrays, you can have a collection of classes.

For example, we have a collection like this:

$collection = collect([['Dress', 22.3], ['Hat', 2.12]]);

To wrap all the nested arrays into class instances, we can apply mapInto method. Let's say we want to have a collection of products. Here is our Product class:

class Product
{
    private string $name;
    private float $price;

    function __construct(array $data)
    {
        $this->name = $data[0];
        $this->price = $data[1];
    }
}

That's what we should do:

$collection = collect([['Dress', 22.3], ['Hat', 2.12]]);

$collection->mapInto(Product::class)->dd();

The result in a console:

The result in a console

10. Method “every” on Collections

Documentation. Many of you might already use this method, but not me. I've discovered it just a day before writing this article.

The method every loops through the collection and checks if every item passes the condition that you provide in a callback.

For example, we need to make sure that every animal has 3 letters in its name. That's how I would do it:

$animals = collect(['cat', 'dog']);
$result = $animals->filter(fn($animal) => strlen($animal) === 3)->count() === $animals->count();
// Variable $result is true

With the method every you can do it like that:

$animals = collect(['cat', 'dog']);
$result = $animals->every(fn($animal) => strlen($animal) === 3);
// Variable $result is true

More readable and simpler to write.

If you are eager to learn more about Laravel and PHP, I highly recommend using Laracasts. I've been watching Laracasts for a while, and it's been growing very rapidly thanks to a remarkable team of content creators there.

Conclusion

There you go! Thanks to Laravel for providing all the cool features that it has. It's such a pleasure to work with the framework. I hope this article was helpful, and you've learned something new about Laravel.

Which Laravel feature do you think is worth people knowing about? Please let us know in the comment section below.

❤️ Thanks to Mohammad Rahmani for the beautiful photo for this post.

Keywords: collection, backend