Laravel Logo

A basic introduction to Laravel 11

A basic introduction to Laravel 11 | Blog

A basic introduction to Laravel 11

I haven’t really planned this blog post out, so I hope it doesn’t end up being a rambling mess, but in this post, we’re going to build some simple things with Laravel 11. Partly because I want to run through some docs to see if there is anything new that I don’t know (and care about) and I thought I’d just jot down some basics as I work through this, just incase any readers want to come along for the ride.

Laravel Herd

Of course, as a MacOS user (at the moment), I will be using Laravel Herd, this is pretty much a one stop tool that gives me all the typical things I’ll need for a Laravel app, at least throughout the development stage on my laptop anyway. I understand this is available for Windows as well, probably Linux, but I can’t be sure on that tbh.

There is a Pro version of Herd, but it’s not required for most people, certainly not for the learning stage of your Laravel journey, in fact, if you’re learning anything, don’t pay for tools and hosting etc, there’s always a free option, you just might need to look a bit harder to find it.

Paying for courses is a different thing completely. Again, I think there are loads of top quality free resources out there, you probably don’t need to pay for it, but there are benefits that come with paying for something, the biggest of which is structure. That said, even structure doesn’t help if all you do is follow along and copy your way through the material. You need to use the material as a guide only, you need to get your brain to hold on to stuff and the only way it can, for most people, is to actually do things, think about things and do them, and keep doing them until that thing is locked in your brain forever.

Getting started

Now, this may not be as simple on some machines as adding new commands to your terminal can take a minute, but for many MacOS users at least, getting started should be as simple as opening a terminal (or a terminal in your code editor), getting to the directory where you want to build your Laravel apps and typing


laravel new mySuperNewApp

You will be asked if you want any starter kits, these are extra built in functionality, you don’t need them but if you know you will use them in this project, it is worth adding them at build stage, but you can always come back and add them later if you wish.

You’ll see a couple more questions, testing and GitHub related, I won’t go into those on this post, but you can just leave the answers at default and not worry about that for now anyway.

You should see a new directory is created, it will match the name you typed into the command laravel new xyz

You will be asked for your database choice, for the early learning, it is worth just using SQLite as it’s basically just a file and doesn’t need any heavy lifting in the background.

The ~/Herd directory

It is worth remembering, that on MacOS at least, anything in the this directory will be available to the Herd application and will therefore be ‘served’ by your local PHP Web Server. However, it is worth knowing that you can keep, change, or add other directories for Herd to monitor.

Feedback Loop

I prefer to work with PHP which is predominantly a backend thing, but the nice thing about working with the frontend is that you get an almost instant feedback loop, you make a change, you see the change.

When working with Laravel Herd, assuming you asked Herd to monitor your build directory, you get this instant feedback loop by opening a browser and typing the name of your project with a .test extension.

Now in my case, I used a camelCase naming convention, Herd respected my naming preference, but in the address bar, I can either type the name all in lower case, or I can type it in camelCase and Herd will simply convert it to lowercase for me, so this bit doesn’t matter too much, with the exception that you obviously can’t have one project called laravelProject and another called laravelproject, because, whilst MacOS will respect them as two unique entities, Herd will have no idea what you’re up to.

Directory Structure

If you’re new to this, the directory structure may seem a bit overwhelming. However, that’s true of all modern frameworks for PHP, Dart, JavaScript, etc. You don’t need all this stuff to write in PHP, but we want all the extras that come with Laravel, so we get a busy directory structure right off the bat:

Laravel 11 Directory Structure

Don’t worry about this, it sort of makes sense the more you use it.

Routes

Let’s start with Routes. The Routes directory is how you tell Laravel to handle different types of requests.

A brand new Laravel project has 2 files, a console file and a web file. The web file tells Laravel what to do with web page requests. The console file tells Laravel what to do with console requests. For example:


 php artisan inspire

 I have not failed. I've just found 10,000 ways that won't work.
 Thomas Edison

This is the result of this file:


<?php

use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;

Artisan::command('inspire', function () {
    $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote')->hourly();

Essentially what the file is saying is that if you type php artisan inspire then it will return an Inspiring Quote.

We can add to this, like so:


<?php

use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;

Artisan::command('hello', function () {
    $this->info('Hello, from OneMoreDavid!');
})->purpose('Display a greeting');

Would give us an ability to pass simple messages:


php artisan hello  
Hello, from OneMoreDavid!

I like the progress bar:


Artisan::command('progress:demo', function () {
    $bar = $this->output->createProgressBar(100);
    $bar->start();
    for ($i = 0; $i < 100; $i++) {
        usleep(50000);
        $bar->advance();
    }
    $bar->finish();
    $this->newLine();
    $this->info('Task completed!');
})->purpose('Demonstrate progress bar');

Typing php artisan progress:demo will give you a progress bar that slowly fills up.

That web routes file

Oh yeah, getting back to that, this is where we tell Laravel what our web routes look like, so for now it looks like this:


<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

This says that when the user goes to the root of our website (/) they will be sent to a view called welcome. We find that view in the directory ./resources/views/ and for this basic example, that file will be called welcome.blade.php.

As you get a little deeper into developing with Laravel, you might have Routes that send users to different pages depending on their authentication or membership status. As an example, consider this:


<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Auth;

Route::get('/', function () {
    if (Auth::check()) {
        $user = Auth::user();
        
        if ($user->isPremium()) {
            return redirect()->route('premium.dashboard');
        } else {
            return redirect()->route('dashboard');
        }
    } else {
        return view('welcome');
    }
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware('auth')->name('dashboard');

Route::get('/premium-dashboard', function () {
    return view('dashboard-with-perks');
})->middleware(['auth', 'premium'])->name('premium.dashboard');

// Assuming you have these views: welcome.blade.php, dashboard.blade.php, and dashboard-with-perks.blade.php

We are saying that if the user isn’t authenticated at all, just take them to the regular welcome page, this might be your call to action page, the page you use to tell people about the platform and why they might want to sign-up.

If the user is authenticated, then they will go to either a premium dashboard or a regular dashboard. So in this scenario, you may have a free tier and a paid tier, the paid tier gets access to extra functionality for example. You could also use this to route an admin user to a different page as another example.

You don’t have to return blade files, in fact you don’t have to retuen a file at all. One thing I sometimes do is I set placeholders for the pages I want to build later, and you can do this be returning text instead of a view, for example:


<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/login-page', function () {
    return 'We will build the Sign-Up / Sign-In stuff here';
});

Route::get('/404', function () {
    return 'We might build a custom 404, or something else, etc';
});

In that example, we’re just returning plain old text without any formatting or anything interesting. If you went to that url, remember, we can use the .test environment, you wwould see just that simple text:

Laravel simple place-holder

What are Blade files?

Blade files are not essential, but if we want to use them, then they are basically templates, they allow you to mix HTML and Blade commands in a single file to speed up and generally simplify development. If you know React or JavaScript, it’s kind of like using a .jsx file which are files that mix HTML with JavaScript basically. You end up with files that look similar to this:


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
        <!-- Styles / Scripts -->
        @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot')))
            @vite(['resources/css/app.css', 'resources/js/app.js'])
        @else
            <style>
                /*  I removed this style code because I want to shorten the code sample */
            </style>
        @endif
    </head>

We have common HTML elements like <head> but we also have things that aren’t HTML, such as @if, @else and you may notice that comments look different inside the PHP part of the code verses the HTML part of the code.

A basic site

Let’s think about the basics here, if we wanted to build an old-school website, we’d want the home page, a page that describes the project and a way for people to contact us to learn more. So let’s go back to the routes:


<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/contact', function () {
    return view('contact');
});

Route::get('/about', function () {
    return view('about');
});

We need to create 3x .blade.php files for each of those routes. We can just copy the existing example welcome.blade.php or create our own, it doesn’t matter at this stage. I won’t put the code for those pages here, either make your own or just copy the example file for now.

We’re going to waant to build some common elements as well, things like the navigation menu and the footer. For these common elements, we can create a new folder resources/views/layouts and add the files navbar.blade.php and footer.blade.php, app.blade.php.

navbar.blade.php

<nav class="navbar navbar-expand-lg navbar-custom">
    <div class="container">
        <a class="navbar-brand" href="/">L322 Tribute Page</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav ml-auto">
                <li class="nav-item">
                    <a class="nav-link" href="/">Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/about">About</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/contact">Contact</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

<style>
    .navbar-custom {
        background-color: #333;
        border-bottom: 3px solid #ff6600;
    }
    .navbar-custom .navbar-brand {
        color: #fff;
        font-size: 1.5rem;
        font-weight: bold;
    }
    .navbar-custom .nav-link {
        color: #fff;
        margin-left: 15px;
        transition: color 0.3s;
    }
    .navbar-custom .nav-link:hover {
        color: #ff6600;
    }
</style>

footer.blade.php

<footer class="footer-custom">
    <div class="container text-center py-3">
        <p class="mb-0">L322 Tribute Page</p>
    </div>
</footer>

<style>
    .footer-custom {
        background-color: #333;
        color: #fff;
        padding: 20px 0;
        border-top: 3px solid #ff6600;
    }
    .footer-custom p {
        font-size: 1.2rem;
        margin: 0;
    }
</style>

app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'My L322 Tribute Page')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            display: flex;
            flex-direction: column;
            min-height: 100vh;
        }
        main {
            flex: 1;
        }
        .navbar-custom {
            background-color: #333;
            border-bottom: 3px solid #ff6600;
        }
        .navbar-custom .navbar-brand {
            color: #fff;
            font-size: 1.5rem;
            font-weight: bold;
        }
        .navbar-custom .nav-link {
            color: #fff;
            margin-left: 15px;
            transition: color 0.3s;
        }
        .navbar-custom .nav-link:hover,
        .navbar-custom .nav-link.active {
            color: #ff6600;
        }
        .footer-custom {
            background-color: #333;
            color: #fff;
            padding: 20px 0;
            border-top: 3px solid #ff6600;
        }
        .footer-custom p {
            font-size: 1.2rem;
            margin: 0;
        }
        @media (min-width: 992px) {
            .navbar-nav {
                width: 100%;
                justify-content: space-around;
            }
        }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-custom">
        <div class="container">
            <a class="navbar-brand" href="/">L322 Tribute Page</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav ms-auto">
                    <li class="nav-item">
                        <a class="nav-link {{ request()->is('/') ? 'active' : '' }}" href="/">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link {{ request()->is('about') ? 'active' : '' }}" href="/about">About</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link {{ request()->is('contact') ? 'active' : '' }}" href="/contact">Contact</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <main>
        @yield('content')
    </main>

    <footer class="footer-custom">
        <div class="container text-center py-3">
            <p class="mb-0">L322 Tribute Page</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

My L322 Tribute Page

As the code has been eluding to so far, I kind of like the L322 Range Rover, this might not mean much to most people, but in terms of Range Rovers, I used to have one of these (no longer) and this one is my favourite. My welcome page now looks like this:

L322 Tribute Page (zoomed out)

GitHub Repo:

I’m also going to build out a basic about and contact page. The final code for this Laravel 11 Basics post can be found HERE.