Laravel Exercise - Inserting a Record

In this exercise, we will use a controller method to insert a new record into a table.

Inserting a record in Laravel.

Exercise text

In a Laravel application:

  1. Create a posts table with the following columns:
    • id - auto-incrementing ID field.
    • slug - VARCHAR(255) string field for storing the post's slug.
    • title - VARCHAR(255) string field for storing a title.
    • post_text - TEXT column for storing the post's text.
  2. Create a Post model and associate it with the posts table.
  3. Create the following Blade templates:
    • index.blade.php - shows all posts.
    • create.blade.php - a template that displays a HTML form for inserting a new post.
  4. Create a PostController controller class with the following member functions:
    • index - fetches and displays all posts.
    • create - shows a form for inserting a new post.
    • store - validate the data and insert a new record.
  5. Define the following GET and POST routes:
    • /posts - show all posts (GET).
    • /posts/create - displays a form for inserting a new post (the GET request).
    • /posts/create - validates the data and stores/inserts the new record into a posts table.

Note: The PostController's store() method does the actual inserting into a table.

Creating a table

Create a migration that creates the posts table. In the terminal, we write:

php artisan make:migration create_posts_table
Creating a migration for the posts table in Laravel.

Open the newly created migration file whose name ends with the _create_posts_table.php. Replace the existing Schema::create function code with the following code:

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

This code modifies the database schema and creates a posts table with the specified columns.

Running a migration

To run the above code and create a table in a database, we run the migration in the terminal:

php artisan migrate
Running a migration that modifies a schema and creates a posts table in our database.

The database schema has been modified, and now, our database has a posts table:

Using the PHPMyAdmin software to inspect the structure of the posts table.

Note: Here, we used the PHPMyAdmin software to inspect the posts table structure.

Creating a Post model

To create a Post model that maps to the posts table, in the terminal, we execute:

php artisan make:model Post
Creating a Post.php file that contains the Post model.

This command creates the Post.php file and prefills it with the Post model source code.

Defining routes

Open the web.php file and paste the following source code:

<?php

use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::post('/posts/create', [PostController::class, 'store'])->name('posts.store');

This code defines the following routes:

  • /posts - The GET route that displays all the posts from a posts table.
  • /posts/create - The GET route that displays a form for inserting a new post.
  • /posts/create - The POST route that handles the submitted data and inserts a new record.

Note: Using named routes constitutes good practice. We named all the routes using multiple name() function calls.

Creating views

The index view

Create the index Blade template that shows all the posts:

php artisan make:view index
Creating the index Blade template that shows all records.

Note: The above step is required if there is no index.blade.php template in our Laravel app. If you already created the index.blade.php file (ex. in one of the previous exercises), you can simply open the existing index.blade.php file and skip the creation step.

Open the index.blade.php file and paste the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Showing All Posts</title>
    <style>
        body { font-family: sans-serif; }
        table { border-collapse: collapse; }
        th, td { border: 1px solid #ccc; padding: 8px 12px; }
        th { background: #f5f5f5; }
        body a { font-size: 1.25rem; display: inline-block; margin-bottom: 20px; }
    </style>
</head>
<body>
    <h1>All Posts</h1>
    <a href="{{ route('posts.create') }}">Create a new post</a>
    <table>
        <thead>
            <tr>
                <th>Id</th>
                <th>Slug</th>
                <th>Title</th>
                <th>Text</th>
            </tr>
        </thead>
        <tbody>
            @foreach($allPosts as $post)
                <tr>
                    <td>{{ $post->id }}</td>
                    <td>{{ $post->slug }}</td>
                    <td>{{ $post->title }}</td>
                    <td>{{ $post->post_text }}</td>
                </tr>
            @endforeach
        </tbody>
    </table>
</body>
</html>

This HTML code will be used to display all the records from a posts table and display a "Create a new post" link.

The create view

To create the Blade template, named create, that displays a HTML form for inserting a new post, execute the following Artisan command in the terminal:

php artisan make:view create

Note: The above creation step can be skipped if you already created the create.blade.php file in one of the previous exercises.

Open the create.blade.php file and paste the following code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Insert New Post</title>
  <style>
    body { font-family: Arial, sans-serif; padding: 10px; }
    form { max-width: 400px; display: flex; flex-direction: column; gap: 10px; }
    input, textarea, button { padding: 5px; }
    textarea { height: 150px; }
    button { margin-top: 5px; border: none; cursor: pointer; width: 100px; }
    .errors-list { max-width: 380px; background-color: #f6cfd2; color: #7f1f27; padding: 10px; }
    .errors-item { margin-left: 20px; }
  </style>
</head>
<body>
  <h2>New Post</h2>
  <!-- Display validation errors, if any -->
    @if ($errors->any())
        <ul class="errors-list">
            @foreach ($errors->all() as $error)
                <li class="errors-item">{{ $error }}</li>
            @endforeach
        </ul>
  @endif
  <form action="{{ route('posts.store') }}" method="POST">
    @csrf
    <label for="slug">Slug:</label>
    <input type="text" name="slug" value="{{ old('slug') }}">
    <label for="title">Title:</label>
    <input type="text" name="title" value="{{ old('title') }}">
    <label for="post_text">Post Text:</label>
    <textarea name="post_text">{{ old('post_text') }}</textarea>
    <button type="submit">Submit</button>
  </form>
</body>
</html>

This template displays a HTML form for inserting a new post.

Creating a controller

Create a PostController controller in the terminal:

php artisan make:controller PostController

Note: The above step can be skipped if you already created the PostController.php file in one of the previous exercises.

Open the PostController.php file and paste the following source code:

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class postController extends Controller
{
    public function index()
    {
        $allPosts = Post::all();
        return view('index', [
            'allPosts' => $allPosts;
        ]);
    }

    public function create()
    {
        return view('create');
    }

    public function store(Request $request)
    {
        // use the validate() method to validate the data
        $validated = $request->validate([
            // validate the slug field against the 'required', 'string', 'min:3',
            // and the 'unique in the posts table' rules
            'slug' => 'required|string|min:3|unique:posts,slug',
            // validate the title field against the 'required' 'string' and 
            // 'minimum 3 characters in length' rules
            'title' => 'required|string|min:3',
            // validate the post_text field against the 'required', 'string',
            // 'min:3' and 'max 1000 characters' rules
            'post_text' => 'required|string|min:3|max:1000',
        ]);
        // if the validation is successful, insert the record
        $newPost = new Post();
        $newPost->slug = $validated['slug']; 
        $newPost->title = $validated['title'];
        $newPost->post_text = $validated['post_text'];
        $newPost->save();

        // and redirect the user to the `/posts` route
        // using the posts.index named route
       return redirect()->route('posts.index');
    }
}

This code defines the controller class with several member functions.

  • index() - fetches and displays all the records from the posts table using the Post model.
  • create() - returns a view/template that displays a HTML form for inserting a new post.
  • store() - validates the data, and, if the validation is successful, inserts a new record into a table. Then, it redirects the user to the /posts route.

Usage

To show all posts, we access the 127.0.0.1:8000/posts route in a browser:

Showing a route that displays all the records and a link. Currently, the table is empty.

Note: Currently, the posts table is empty, so we do not see any records on the page.

To insert a new post, we click on the "Create a new post" link, which takes us to the 127.0.0.1:8000/posts/create route in a browser:

A form used for inserting a new post.

We enter the data and click the Submit button:

Inserting the sample data for the first post.

When we submit the form, the POST request is sent to the /users/create route and the controller's store() method handles that route. The data gets validated and inserted into a table. Then, we are redirected back to the 127.0.0.1:8000/posts route. Now, we see the newly inserted record:

Showing the newly inserted record.

If we repeat the process of inserting new records, we will see multiple records on our page:

Showing all the records from a table.