Laravel for Beginners #1

Laravel is a powerful full-stack PHP framework that follows the MVC structure. It is designed for web developers who need a simple, elegant yet powerful toolkit to build a fully-featured website. This course explains the basic use of the Laravel framework by building a simple blogging system.

Without further ado, let’s start by setting up our first Laravel project.

Installing necessary software

For a typical web application, there are a few components that are necessary for the app to work properly. For instance, the app would need a programming language that functions in the backend, which in our case would be PHP, a database to store the information, and a server to handle requests and responses.

In this tutorial, we are going with PHP paired with SQLite, which is a lightweight, file-based database and Laravel’s built-in dev server. The advantage of this stack is that it is very easy to set up because you only need to install PHP and Composer, which is PHP’s official package manager. Remember, you need to install PHP first because composer needs to locate PHP to successfully install.

Download PHP | Download Composer

However, this stack is not designed to work in a production environment, so if you are building a serious project, I would recommend you to simulate the production environment on your local machine, using production-ready software like MySQL and Apache. Consider installing XAMPP instead if that’s what you want.

XAMPP is a free and open-source cross-platform web server solution stack package developed by Apache Friends. It contains MySQL, phpMyAdmin, PHP, and the Apache server. It combines everything you need for PHP web development in one place and spares you the time for installing and configuring each of them individually.

Download XAMPP

Finally, we need an IDE, or at least a proper code editor. If you are willing to spend the extra money, PhpStorm is an amazing IDE for PHP projects, and if you have a student email, you can use it for free. If you don’t want to spend the money, you can go with VS Code, with the right plugins, it can be as powerful as an IDE.

Download PhpStorm | Download VS Code

For this course, I’ll go with SQLite, Laravel’s built-in dev server, and Visual Studio Code.

Creating a fresh Laravel project

Next, assuming you’ve successfully set up the dev environment, let us create a new work folder, I’ll call it laravel-tutorial. Open the working folder with VS Code, and run the following command. This command will download the Laravel installer.

1
composer global require laravel/installer

Next, we can use the installer to create a new Laravel application in the project directory:

1
2
3
laravel new <app_name>
cd <app_name>
php artisan serve

The last command is one of Laravel’s artisan commands, which is a very powerful CLI tool that comes with Laravel. We are going to see a lot more artisan commands in the future. This command starts the development server at http://127.0.0.1:8000/. It could be http://localhost:8000/ on your machine, depending on what system you are using.

Laravel welcome page

Exploring Laravel application structure

Before we start writing code, let’s take a look at what has been installed into our project. Here I will briefly introduce the directories that we need to use in this tutorial since some might be a little confusing for beginners. If you are interested, you can read the Official Documentation, which explains the function of each directory in detail.

The root directory

Directory Detail
app This folder contains the entire source code of our project. It includes events, middleware, exceptions, and so on. But for now, we only care about models and controllers.
config As the name implies, it stores all configuration files for our project.
database The database directory is where we put all the seeds and migration files. They determine the structure of the database. In our course, we’ll use this directory to hold an SQLite database. But I don’t recommend using SQLite for huge projects.
public This directory holds the index.php file, which is the entry point for any Laravel applications. This folder should hold everything you wish to make public for the users, usually media files.
routes The route directory contains all URL declarations, usually referred to as routers, for our project. By default, there are four route files: web.php, api.php, console.php, and channels.php. For this tutorial, we only need to understand web.php. We’ll talk about routers in detail in the next section of this article.
resources This folder stores all the views and uncompiled assets such as CSS, or JavaScript files.

The app Directory

Directory Detail
Http/Controllers This is where we put all the controllers for our project. All of the logic to handle requests entering your application will be placed in this directory.
Models The Models directory contains all of your Eloquent model classes. The Eloquent ORM included with Laravel is a simple, easy-to-use interface for working with our database. Each database table has a corresponding model which is used to interact with that table. Models allow you to query for data in your tables, as well as insert new records into the table.

Project configurations

Before we can start working on our first Laravel app, there are some configurations we need to take care of. All the environment configurations in Laravel are stored in the .env file in the root directory. To make our project function properly, there are some changes we need to make.

App URL

First, let’s define the URL for our project. Since we are in the dev environment, the URL should be http://127.0.0.1:8000.

1
APP_URL=http://127.0.0.1:8000

Database

Next, we also need a database. For this course, we’ll go with SQLite. It is a single file database that can be stored in your file system. We can easily create a new SQLite database using the touch command. Make sure you are at the root directory of the app.

1
touch database/database.sqlite

And we can tell Laravel where to find this database in the .env file. Remember to use the absolute path. If you are using VS Code, there should be an option for you to copy the absolution path when you right-click on the database file.

1
2
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

We also need to enable the database foreign keys:

1
DB_FOREIGN_KEYS=true

We’ll talk about what foreign keys are when we get to database relations.

Application Key

Setting an application key is essential to the safety of our project. If the application key is not set, your user sessions and other encrypted data will not be secure. The following command will set the application key for you:

1
php artisan key:generate

File Storage

This configuration is not about the environment, but it is still very important. In order to make sure Laravel will find the media files (images, videos…) we uploaded, we need to create a symbolic link in the public directory with the following command. This command creates a symbolic link in the public directory that points to the storage directory. This makes sure that the storage can be “seen” from the outside.

1
php artisan storage:link

Basic routing in Laravel

In this section, we’ll take a look at Laravel’s route and middleware. In Laravel, the routes are defined in the routes folder. Notice that by default, there are four different files inside the routes folder, and for most projects, we are only concerned with api.php and web.php. If you intend to use Laravel strictly for the backend (without the view), you should define the routes in the api.php. For our course, we are going to use Laravel as a full-stack framework, so we are going to use web.php.

Their difference is that api.php is wrapped inside the api middleware group and web.php is inside the web middleware group, they provide different functions, and the routes defined in api.php will have the URL prefix /api/. Meaning that in order to access an api route, the URL has to be something like: http://example.com/api/somthing-else.

The most basic route in Laravel accepts a URL and then returns a value. The value could be a string, a view or a controller. Go to routes/web.php, and we can see there is already a pre-defined route:

1
2
3
4
5
use Illuminate\Support\Facades\Route;

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

This piece of code means when the Laravel route receives “/”, it returns a view called “welcome”, which is located at resources/views/welcome.blade.php.

Open the browser, go to http://127.0.0.1:8000, and you will get this:

Laravel welcome page

To verify that welcome.blade.php is the view we are looking at, try making some changes to the file, and refresh your browser and see if the page changes.

Router methods

Now, let’s take a closer look at this router and understand how it works.

1
2
3
4
5
use Illuminate\Support\Facades\Route;

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

We first import the Route class, and invoked the get() method. This get() matches the GET HTTP method we talked about before. There are other methods built into the Route class that allows us to match any other HTTP request methods.

1
2
3
4
5
6
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

If you want a route to match multiple HTTP methods, you can use the match or any method instead. match() requires you to specify an array of HTTP methods that you wish to match, and any() simply matches all HTTP requests.

1
2
3
4
5
6
7
Route::match(['get', 'post'], '/', function () {
    ...
});

Route::any('/', function () {
    ...
});

Passing data to view

Now, let’s look inside the get() method. There are two parameters, the first one is the URL that this router is supposed to match, and the second one is a callback function that executes when that match happens.

Inside the callback function, a built-in function view() is returned. This function will look for the corresponding view file based on the parameter that is passed to it.

Laravel offers a simple shortcut, Route::view(), if you only need to return a view. This method allows you to avoid writing a full route.

1
Route::view('/welcome', 'welcome');

The first argument is the URL, and the second parameter is the corresponding view. There is also a third argument, which allows us to pass some data to that view like this:

1
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

We’ll talk about how to access the data when we get to the blade templates.

From router to controller

We can also make the router point to a controller, which then points to a view. A controller is essentially an expanded version of the callback function. We’ll talk about controllers in detail in the next article.

1
Route::get('/user', [UserController::class, 'index']);

This line of code means if the router receives “/user”, Laravel will go to the UserController, and invoke the index method. Remember, this is the new syntax from Laravel 8, the old syntax will not work here!

Route parameters

Sometimes you need to use segments from a URL as parameters. For example, imagine we have a fully developed blog and there is a user who is looking for a blog post with the slug this-is-a-post, and he is trying to find that post by typing http://www.example.com/posts/this-is-a-post in his browser.

To make sure that the user finds the correct post, we need to take the segment after posts/ as a parameter, and send it to the backend. After that, our controller can use that parameter to find the correct post and return it back to the user.

To do that, we write the following code:

1
Route::get('post/{slug}', [PostController::class, 'show']);

This will make sure the Laravel router matches the word after post/ as a parameter, and give assign it to the variable slug when Laravel sends it to the backend. Route parameters are always encased within {} braces and should consist of alphabetic characters, and may not contain a - character.

Since we haven’t talked about the controllers, we can replace the second parameter with a simple callback function, and test this code:

1
2
3
Route::get('/post/{slug}', function ($slug) {
    return $slug;
});

Now, open your browser and go to http://127.0.0.1:8000/posts/this-is-a-slug.

Router Parameters

It is also possible to match multiple parameters in a URL:

1
Route::get('category/{category}/post/{slug}', [PostController::class, 'show']);

In this case, the segment after category/ will be assigned to the variable category, and the segment after post/ will be assigned to slug.

Sometimes you don’t know if a parameter will be present in the URL, in this case, you can make that parameter optional by appending a question mark (?).

1
Route::get('post/{slug?}', [PostController::class, 'show']);

And finally, you can validate the parameters using regular expressions. For example, we can make sure the user ID is always a number.

1
Route::get('user/{id}', [UserController::class, 'show'])->where('id', '[0-9]+');

Named routers

Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the name method onto the route definition.

1
Route::get('user/profile', [UserController::class, 'show'])->name('profile');

And now, when we need to access this URL, all we need to do is invoke the function route('profile').

Group routers

When you are building a large website, it is very common for you to have a few dozen or even hundreds of routers. In this case, it would make more sense if we group them together. For example, we can group them based on the middleware.

1
2
3
4
Route::middleware(['auth'])->group(function () {
    Route::get('/user/profile', [UserController::class, 'show']);
    Route::get('/user/setting', [UserController::class, 'setting']);
});

Now both these routers will be assigned the middleware auth.

We can also assign prefixes to a group of routers like this:

1
2
3
4
Route::prefix('admin')->group(function () {
    Route::get('/users', [UserController::class, 'show']);
    ...
});

All the routers defined in this group will have the prefix /admin/.

Middleware

A middleware is something that can inspect and filter the incoming HTTP requests, before it hits your application. It is something that happens after the route has matched the URL, but the callback function hasn’t been executed, it is something in the middle, hence the name middleware. An example of middleware would be user authentication. If the user is authenticated, the route will take the user to the supposed destination, if not, it will take the user to the login page first.

For this course, we are not writing any middleware. The only one we need to use is the built-in auth middleware for authentication purposes, but I’d like to explain the basics of it. To create a middleware, run the following command:

1
php artisan make:middleware EnsureTokenIsValid

This will create a new EnsureTokenIsValid class under the app/Http/Middleware directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

namespace App\Http\Middleware;

use Closure;

class EnsureTokenIsValid
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('home');
        }

        return $next($request);
    }
}

This middleware will get the token value from the request, and compare it with the secret token stored on our site, and if it matches, proceed to the next step, if not, redirect to the home page.

In order to use this middleware, we still need to register it with Laravel. Go to app/Http/Kernel.php, and find the $routeMiddleware property, list the middleware we just created.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
  * The application's route middleware.
  *
  * These middleware may be assigned to groups or used individually.
  *
  * @var array<string, class-string|string>
**/
  protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
  ];

And finally, you probably already know how to use middleware on a router.

1
Route::get('/profile', function () {...})->middleware('auth');

comments powered by Disqus