The Laravel 9 New Features

Laravel is a web application framework that uses MVC (Model View Controller) design pattern.

It provides an easy way to craft web apps without worrying about a lot of stuff involved in web development.

Topics Covered:

 

Laravel Installation via composer:

composer create-project laravel/laravel laravel9app

You need to know Laravel 9.x requires a minimum PHP version of 8.0.

  1. Routing:

EX:

Basic Laravel Route

Route::get('/', function () {
return 'Hello World';
});

Route::get('/greeting', function () { //greeting is an endpoint
return 'Hello World';
});

Route::get('/', function () { //going back to normal
return view ('welcome');
});

Route with a Controller

php artisan make:controller UserController

UserControllerClass:

public function index() {
return view ("user");
 }
Make a view:resources/views/user.blade.php

web.php:

Import the controller App\Http\Controllers\UserController;

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

or you can this one below works the same..

Route::get('/user', 'App\Http\Controllers\UserController@index');

Route with Parameter

public function show($id) {
    return 'user Id:'. $id;
}

web.php

Route::get('/user/{id}', 'App\Http\Controllers\UserController@show');

Named Routes

You can have named routes like this,

Route::get('/user/profile', 'App\Http\Controllers\UserController@index')->name('profile');

Access the URL like this, http://127.0.0.1:8000/user/profile you get the same results.

Route Controller

If a group of routes all utilize the same controller, you may use the controller method to define the common controller for all of the routes within the group. This is introduced in laravel 9.

Import the controller class use App\Http\Controllers\UserController;

Route::controller(UserController::class)->group(function () {
Route::get('/user/profile', 'index');
Route::get('/user/{id}', 'show');
Route::post('/users', 'store');
});

If you run the php artisan route:list you can inspect the routes.

  1. Middleware:

Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application.

Middleware provides a way for a user to be authenticated in your application.

Authenticating particular routes:

Custom Middleware:

middleware can be used in three ways global, group and route level

php artisan make:middleware EnsureTokenIsValid

kernel.php:

register the middleware under the protected $routeMiddleware

'EnsureTokenIsValid' => \App\Http\Middleware\EnsureTokenIsValid::class,

EnsureTokenIsValid.php

Give the logic…

public function handle(Request $request, Closure $next)
{
if ($request->input('token') !== 'my-secret-token') {
          return redirect('noaccess');
      }
      return $next($request);

  }
}

Make a blade noaccess.blade.php

<title>Middleware</title>
</head>
<body>
    <h1>You are not authorized!</h1>
</body>
</html>

web.php

Route::controller(UserController::class)->group(function () {
Route::get('/user/profile','index')->middleware(EnsureTokenIsValid::class);
Route::get('/noaccess', 'noaccess');
Route::get('/user/{id}', 'show');
Route::post('/users', 'store');
});

UserController.php

public function noaccess() {
    return view ("noaccess");
}

access the Url: http://127.0.0.1:8000/user/profile?token=my-secret-token or..

Normal Url: http://127.0.0.1:8000/user/profile (redirected to noaccess page)

run php artisan route:list to inspect the routes created…

  1. CSRF Protection:

stands for cross-site request forgery whereby unauthorized commands are performed on behalf of an authenticated user.

The malicious user only needs to lure an unsuspecting user of your application to visit their website and their email

address will be changed in your application.

How it works:

A token will be generated this token is used to verify that the authenticated user is

the person actually making the requests to the application.

The App\Http\Middleware\VerifyCsrfToken middleware, which is included in the web middleware group by default,

will automatically verify that the token in the request input matches the token stored in the session.

Ex:

web.php

Route::controller(UserController::class)->group(function () {
Route::get('/user/profile','index');
Route::post('user/profile', 'post');
});

UserController.php

class UserController extends Controller
{
public function index() {
return view ("user");
}
public function post(Request $req) {
    return $req->input();
 }
}

User.blade.php

<section> 
  <form action ="" method="POST"> 
    @csrf 
    <input type="text" name="username" placeholder="Username"> 
    <input type="password" name="password" placeholder="Password"> 
    <input type="submit" name="submit" value="Submit"> 
  </form> 
</section> 

run (php artisan route:clear) in case of the error POST method is not supported…

output:

{"_token":"LmdXT6OqYhQfciwyGZK1Xsc8gSVFun6uRFpK3gAi","username":"brian","password":"admin","submit":"Submit"}

Remember this token is unique and should match the token stored in the session.

  1. Controllers:

By default, controllers are stored in the app/Http/Controllers directory.

You can have a controller dedicated to a specific page ex UserController.php for users

So far we have defined a basic controller at the start of the tutorial now let’s look at

resource and middleware controllers

a) Resource Controllers:

To create a resource controller start by running this command

php artisan make:controller PostsController --resource

The controller will contain a method for each of the available resource operations. Then register a resource route that points to the controller:

Ex:

use App\Http\Controllers\PostsController;

Route::resource('posts', PostsController::class);

Remember you can run this command php artisan route:list to have a quick overview of the application routes.

You can have many resource controllers at once in an array in resources like this

Ex:

Route::resources([
'pages' => PagesController::class,
'posts' => PostsController::class,
]);

b) Controller Middleware

In Controller middleware, you can have something like this,

Ex:

Route::controller(UserController::class)->group(function () {
Route::get('/user/profile','index')->middleware('auth');
});

This means that the route /user/profile will be authenticated with a login page before you are allowed to see the contents of the page. Remember this will affect the particular route you have placed the middleware auth.

To apply the middleware auth in all your routes within your controller you will need to create a constructor and place it in your controller like this.

Ex:

class UserController extends Controller
{
/**
 * Instantiate a new controller instance.
 *
 * @return void
 */
public function __construct()
{
    $this->middleware('auth');
}
}

If you access any route defined in your controller you will be presented with a login page.

  1. Requests:

We have used requests already in our application.

public function post(Request $req) {
    return $req->input(); // $req->all(),
 }

We can query any particular value from our form, for example,

return $req->input('username'); // Brian
return $req->input('password'); // password

or you can have the method $req->all() which does the same function as $req->input() returns all the values.

  1. Responses

All routes and controllers should return a response to be sent back to the user’s browser.

The most basic is returning a string from a route Ex:

Route::get('/greeting', function () {
return "Hello World";
});

i) Responses Array

Here you may return an array Ex:

public function index() {
  return [1, 2, 3];
}

ii) Return redirect

This is simply redirecting a user to another Url

Route::get('/greeting', function () {
return "Hello World";
//return redirect('user/profile');
});

iv) Return redirect back with input returns with input values in a form.

public function post(Request $req) {
    // return $req->input();  

    return back()->withInput();
 }

What method does it redirect us back with the same input instead of submitting the data? What it does is validates the request if the data submitted is invalid from the form will redirect us back.

v) Redirecting To Named Routes

to generate a RedirectResponse to a named route, you may use the route method:

Ex:

Route::get('/greeting', function () {
return redirect()->route('myprofile');
});

Route::get('/user/profile','index')->name('myprofile'); //named route

vi) Redirecting With Flashed Session Data

Ex:

Route::get('/greeting', function () {
return redirect('user/profile')->with('status', 'Welcome to laravel!');
});

user.blade.php

@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif
  1. Blade Templates

Blade templates can use plain PHP code and are compiled into plain PHP code and cached until they are modified.

Blade template files use the .blade.php file extension and are typically stored in the resources/views directory.

Ex:

go to resources/views/layouts/app.blade.php or you can use touch command

touch resources/views/layouts/app.blade.php copy and paste the code below into the app.blade.php

app.blade.php


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>

<body>

@include('inc.navbar')

    <div class="container">

    @yield('content')

   </div>

</body>

</html>

Since you can see an inc.navbar you may be wondering, make a folder inc in resources/views/inc/navbar.blade.php or

touch resources/views/inc/navbar.blade.php and copy and paste the code below

<nav class="navbar navbar-expand-lg navbar-dark ftco_navbar bg-dark ftco-navbar-light" id="ftco-navbar">
	    <div class="container">
	      <a class="navbar-brand" href="#"></i> <span>Big</span> <span>Store</span></a>
	      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#ftco-nav" aria-controls="ftco-nav" aria-expanded="false" aria-label="Toggle navigation">
	        <span class="oi oi-menu"></span> Menu
	      </button>

	      <div class="collapse navbar-collapse" id="ftco-nav">
	        <ul class="navbar-nav ml-auto">
	          <li class="nav-item active"><a href="/" class="nav-link">Home</a></li>
	          <li class="nav-item"><a href="/about" class="nav-link">About</a></li>
	          <li class="nav-item"><a href="/events" class="nav-link">Services</a></li>
	          <li class="nav-item"><a href="/sermons" class="nav-link">Shop</a></li>
	          <li class="nav-item"><a href="/blog" class="nav-link">Blog</a></li>
	          <li class="nav-item"><a href="/contact" class="nav-link">Contact</a></li>
	        </ul>
	      </div>
	    </div>
	  </nav>

this code gives us a bootstrap navbar to work with, remember in the app.blade.php we have imported the bootstrap cdn url to

give us bootstrap classes and so forth…

Now in the user.blade.php we need to make changes such as below

user.blade.php

@extends('layouts.app')

 @if (session('status'))
        <div class="alert alert-success">
            {{ session('status') }}
        </div>
        @endif
    
    @section('content')

    <h1>Hi user</h1>

    <section> 
      <form action ="" method="post"> 
        @csrf 
        <input type="text" name="username" placeholder="Username"> 
        <input type="password" name="password" placeholder="Password"> 
        <input type="submit" name="submit" value="Submit"> 
      </form> 
    </section> 
    @endsection

The layout.app extends the app.blade.php which has the navbar and yields the content that is presented in our app. Then we

have the starting and ending section which typically defines the blade sections that has the content.

We can do other many interesting stuff on the blade templates such as below…

@extends('layouts.app')

@section('content')
    @if (session('status'))
        <div class="alert alert-success">
            {{ session('status') }}
        </div>
    @endif

    <h1>Hi user</h1>

    <!--Display Data-->

    Hello, {{ $name }}.

Your controller should be as follows

UserController.php

public function index() {
 
        return view('user', ['name' => 'Brian'], compact('users'));
     }
  <!--get data from database-->

    @forelse ($users as $user)

        <li>{{ $user->name }}</li>

        <li>{{ $user->email }}</li>

    @empty

        <p>No users</p>

    @endforelse

UserController.php

public function index() {
       
        $users = User::all(); 
         
        return view('user);
     }

other features

 <!--check if user is authenticated-->

    @auth
    The user is authenticated...
    @endauth

    @guest
     The user is not authenticated...
    @endguest

    </br>

    <!--Using if statement-->

    @if (count($users) === 1)

    I have one user!

    @elseif (count($users) > 1)

    I have multiple users!

    @else

    I don't have any users!

    @endif

Ensure you create a database in the phpmyadmin or the server you are using same as the one created in the laravel framework then run php artisan migrate to migrate the user tables.

We also have other features in the blade template we may look at them in the future.

  1. Validation:

With Laravel validation, we can validate any content in laravel like title, body, images on a blog website. Here are the steps

Make a post.blade.php as follows and paste the code below

post.blade.php

@extends('layouts.app')
@section('content')

<div class ="text">
<h1 class="heading">This is the page for all the posts</h1>
</div>

@if(Session::has('message'))
            <div class="alert alert-success alert-dismissible">
                <button type="button" class="close" data-dismiss="alert" aria-hidden="true">x</button>
                {{ Session('message') }}
            </div>
        @endif

<div class="card-body">
<table class="table table-bordered mb-0">
    <thead>
    <tr>
        <th scope="col">Id</th>
        <th scope="col">Title</th>
        <th scope="col">Body</th>
    </tr>
    </thead>
<tbody>
@foreach($posts as $post)
    <tr>
        <td>{{ $post->id }}</td>
        <td>{{ $post->title }}</td>
        <td>{{ $post->body }}</td>
        </tr>
        @endforeach
</tbody>
      </table>
  </div>
@endsection

This is just a simple table made with bootstrap where we can display the title and body of the post.

Let’s create a blade template for creating a post where we will validate the post title and body.

create.blade.php

@extends('layouts.app')

@section('content')

  <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-12">
                <div class="card">
                    <div class="card-header">Post - create</div>

                    <div class="card-body">
                        {!! Form::open(['route' => 'posts.store']) !!}
                        <div class="form-group @if($errors->has('title')) has-error @endif">
                            {!! Form::label('Title') !!}
                            {!! Form::text('title', null, ['class' => 'form-control', 'placeholder' => 'title']) !!}
                            @if ($errors->has('title'))
                                <span class="help-block">{!! $errors->first('title') !!}</span>@endif
                        </div>

                        <div class="form-group @if($errors->has('body')) has-error @endif">
                            {!! Form::label('body') !!}
                            {!! Form::text('body', null, ['class' => 'form-control', 'placeholder' => 'body']) !!}
                            @if ($errors->has('body'))
                                <span class="help-block">{!! $errors->first('body') !!}</span>@endif
                        </div>
                        {!! Form::submit('Create',['class' => 'btn btn-sm btn-primary']) !!}
                        {!! Form::close() !!}
                    </div>
              </div>
          </div>
      </div>
</div>
@endsection

Now the code in create.blade.php has a form from laravel collective so for us to use it run the command below to add it to laravel framework.

composer require laravelcollective/html 

Now we are ready to use the form.

From the create.blade.php we route to posts.store where the title and body of our post gets validated and created so we will create a PostsController

PostsController.php


<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;

class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::orderBy('id', 'DESC')->get();
        return view('post', compact('posts')); 
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ],

        [
            'title.required' => 'Enter the title',
             'body.required' => 'Enter the body',
        ]

        );

        $post = new  Post();
        $post->title = $request->title;
        $post->body = $request->body;
        $post->save();

        Session::flash('message', 'Post created successfully');
        return redirect()->route('posts.index');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        return 'post Id:'. $id;
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

Remember we created the PostsController at the start of our tutorial by running the command php artisan make:controller PostsController –resource

We are validating the post title and body before it gets created in the database. Take note of the post function create a view method, this enables us to create the post having the route posts.create.

In the web.php you should have this route Route::resource(‘posts’, PostsController::class); then run php artisan route:list to inspect the routes created.

Lastly create a model Post.php to connect to our database by running the command php artisan make:model Post.php and paste the code below

Post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'body'];

}

Create the posts table

php artisan make:migration create_posts_table

Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title')->unique();
            $table->text('body');
            $table->timestamps();
        });

Finally, run

php artisan migrate

Sign up for free tutorials in your inbox.

We don’t spam! Read our privacy policy for more info.

10 thoughts on “The Laravel 9 New Features”

  1. Pingback: Laravel Multi Authentication - Webdev Trainee

  2. Pingback: Laravel Livewire Crud - Webdev Trainee

  3. Pingback: Laravel Livewire Tutorial - Webdev Trainee

  4. Pingback: Laravel 9 Open AI PHP Client - Webdev Trainee

  5. Pingback: The Laravel Pennant - Webdev Trainee

  6. Pingback: Laravel 10 Crash Course For Beginners. - Webdev Trainee

Leave a Comment

Your email address will not be published. Required fields are marked *