Beginner’s Guide to Laravel: Mastering CRUD Operations

Introduction

Laravel, a popular PHP framework, has revolutionized web development with its elegant syntax and robust features. In this guide, we will focus on mastering CRUD operations using Laravel, using a "Post" model as an example. By following along, you'll gain practical experience in building a dynamic blog-like application with Create, Read, Update, and Delete functionalities.

What are CRUD Operations?

CRUD operations are the fundamental operations used to manage data in a database. The acronym CRUD stands for Create, Read, Update, and Delete. These operations encompass the basic functionalities needed to interact with a database and manipulate data in various ways:

  1. Create (C): This operation involves adding new records or data entries to the database. It typically corresponds to the "INSERT" operation in SQL. In CRUD terminology, creating refers to adding new data to the database.

  2. Read (R): Reading refers to retrieving or fetching data from the database. This operation corresponds to the "SELECT" operation in SQL. Reading can involve retrieving a single record, multiple records, or all records from a table.

  3. Update (U): Updating involves modifying existing records in the database. This operation corresponds to the "UPDATE" operation in SQL. Updates can be performed on specific records, and you can change the values of one or more fields.

  4. Delete (D): Deleting involves removing records from the database. This operation corresponds to the "DELETE" operation in SQL. Deletion can be performed on specific records, and it removes the entire record from the database.

These CRUD operations are the backbone of any data-centric application, as they enable you to perform essential tasks such as adding, retrieving, modifying, and removing data. Many software frameworks and libraries, including web frameworks like Laravel, provide tools and methods to facilitate these operations, making it easier to interact with databases and manage data effectively.

Creating a Database and Migration

Create a New Laravel Project

If you haven't already, you'll need to set up a new Laravel project. You can do this by running the following command in your terminal:

composer create-project laravel/laravel your-project-name

Configure Database Connection

Open the .env file in your project's root directory and configure your database connection settings, including database name, username, password, and host. For example:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_database_username
DB_PASSWORD=your_database_password

Create a Migration

Laravel's Artisan command-line tool simplifies the process of creating migrations. Run the following command to create a migration for the "posts" table:

php artisan make:migration create_posts_table

This will create a new migration file in the database/migrations directory with a name like 2023_08_01_000000_create_posts_table.php. The timestamp in the filename ensures that migrations are executed in the order they were created.

Define the Migration Schema

Open the newly created migration file. Inside the up method, you'll define the schema for the "posts" table using Laravel's fluent schema builder. Here's an example of how you might define the columns:

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

In this example, we're creating columns for the post's title, content, and timestamps for record creation and updates.

Run the Migration

To execute the migration and create the "posts" table in your database, run the following command:

php artisan migrate

Laravel will run the migration and create the table based on the schema definition.

Creating the Post Model

In Laravel, models are an integral part of the Model-View-Controller (MVC) architecture. They provide an elegant and efficient way to interact with your application's database tables. Continuing with our example of a "Post" model, let's dive into the process of creating a model for managing posts within your Laravel application.

Create the Model

Laravel's Artisan command-line tool makes it easy to generate models. Run the following command to create a "Post" model:

php artisan make:model Post

This will create a new file named Post.php in the app directory. The generated model will extend Laravel's base Model class and provide a foundation for your "Post" entity.

Defining Properties and Relationships

Inside the Post.php model file, you can define the properties that correspond to the columns in your "posts" table. For example:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = ['title', 'content'];

    // Additional methods and relationships will be defined here
}

In this example, we've defined the $fillable property to specify which attributes are mass-assignable, allowing you to use the create() method to insert new posts.

Adding Relationships

If your application requires relationships between models, you can define them within the model classes. For instance, if each post belongs to a user, you could define a relationship like this in Post.php:

public function user()
{
    return $this->belongsTo(User::class);
}

In User.php, add the following relationship:

public function posts()
{
    return $this->hasMany(Post::class);
}

This code establishes a relationship between the User model and the Post model, specifying that a user can have multiple posts. This sets up the inverse relationship, allowing you to easily retrieve the user who authored a specific post.

Defining the Routes

In Laravel, a resource route is a way to define multiple routes for a resourceful controller in a concise manner. A resourceful controller is a controller that provides the standard CRUD operations (Create, Read, Update, Delete) for a specific resource, such as "posts" in a blog application.

When you define a resource route, Laravel automatically generates a set of routes that correspond to the typical CRUD operations for the specified resource. This follows the RESTful design principles and helps in maintaining a consistent and predictable URL structure for your application.

Let's see how to define a resource route and what it generates:

  1. Open the routes/web.php file in your Laravel application.

  2. To define a resource route, use the Route::resource() method. Here's how it looks:

     use App\Http\Controllers\PostController;
    
     Route::resource('posts', PostController::class);
    

In this example, we are defining a resource route named "posts" that maps to the PostController class. Laravel will automatically generate the following standard routes for the "posts" resource:

  1. GET /posts: This route maps to the index method in the PostController and retrieves a list of all posts

  2. GET /posts/create: This route maps to the create method in the PostController and displays a form to create a new post.

  3. POST /posts: This route maps to the store method in the PostController and handles the submission of the create form.

  4. GET /posts/{post}: This route maps to the show method in the PostController and displays a specific post.

  5. GET /posts/{post}/edit: This route maps to the edit method in the PostController and displays a form to edit a specific post.

  6. PUT/PATCH /posts/{post}: This route maps to the update method in the PostController and handles the submission of the edit form.

  7. DELETE /posts/{post}: This route maps to the destroy method in the PostController and deletes a specific post.

By defining a resource route, you're setting up a set of routes that follow a RESTful convention and make it easier to organize your application's routing. You'll still need to implement the corresponding methods in your PostController to handle each of these routes' functionalities.

Resource routes are a powerful tool to quickly establish the standard CRUD routes for your application's resources, saving you time and effort in route definition.

Implementing the CRUD Operations

Create a controller for your CRUD operations:

php artisan make:controller PostController

Open the generated app/Http/Controllers/PostController.php file and define the CRUD methods:

namespace App\Http\Controllers;

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

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

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

    public function store(Request $request)
    {
        $data = $request->validate([
            'title' => 'required',
            'content' => 'required',
        ]);

        Post::create($data);

        return redirect('/posts');
    }

    public function show(Post $post)
    {
        return view('posts.show', ['post' => $post]);
    }

    public function edit(Post $post)
    {
        return view('posts.edit', ['post' => $post]);
    }

    public function update(Request $request, Post $post)
    {
        $data = $request->validate([
            'title' => 'required',
            'content' => 'required',
        ]);

        $post->update($data);

        return redirect('/posts/' . $post->id);
    }

    public function destroy(Post $post)
    {
        $post->delete();
        return redirect('/posts');
    }
}
  1. The index method fetches all posts from the database using the Post model and returns them to the posts.index view.

  2. The create method displays a view for creating new posts.

  3. The store method handles the form submission for creating posts. It validates the request data, creates a new post using the Post model, and redirects to the '/posts' route.

  4. The show method retrieves a specific post using route-model binding and displays it in the posts.show view.

  5. The edit method retrieves a specific post and displays a view for editing it.

  6. The update method handles the form submission for updating posts. It validates the request data, updates the post using the update method, and redirects to the updated post's route.

  7. The destroy method deletes a specific post and redirects to the /posts route.

Form Validation

Laravel's Form Request Validation is a powerful feature that allows you to validate incoming HTTP requests before they reach your controller methods. This helps secure your application by ensuring that the data is valid and meets your specified criteria before processing it further. It also assists in maintaining data quality and consistency. Let's integrate Form Request Validation into your CRUD operations for the Post model.

Create a Form Request Class

First, let's create a Form Request class that will handle validation for creating and updating posts.

Run the following command in your terminal:

php artisan make:request PostRequest

This command will generate a PostRequest.php file in the app/Http/Requests directory.

Define Validation Rules

Open the generated PostRequest.php file. Inside the rules method, define validation rules for the fields you want to validate. For example:

public function rules()
{
    return [
        'title' => 'required|string|max:255',
        'content' => 'required|string',
    ];
}

You can adjust the rules based on your specific requirements. In this example, we're requiring a non-empty title with a maximum length of 255 characters and a non-empty content field.

Use the Form Request in the Controller

Now, use the created Form Request class in your PostController for the store and update methods.

use App\Http\Requests\PostRequest;

// ...

public function store(PostRequest $request)
{
    Post::create($request->validated());

    return redirect('/posts');
}

public function update(PostRequest $request, Post $post)
{
    $post->update($request->validated());

    return redirect('/posts/' . $post->id);
}

By type-hinting PostRequest, Laravel will automatically validate the incoming request based on the rules you defined in the PostRequest class. If validation fails, Laravel will automatically return the user back to the form with the errors displayed.

Customize Error Messages (Optional)

You can customize the error messages for your validation rules by overriding the messages method in your PostRequest class. For example:

public function messages()
{
    return [
        'title.required' => 'A title is required.',
        'content.required' => 'Content is required.',
    ];
}

Rendering Data

To render the posts on the frontend, you'll need to create Blade view files that correspond to the different CRUD operations. In the provided PostController, the views are referenced as posts.index, posts.create, posts.show, and posts.edit. Let's create these views to render the posts on the frontend.

To make your Laravel application look more polished. We'll integrate Bootstrap classes into the Blade views we will create.

Include Bootstrap CSS and JS

In your main layout file (resources/views/layouts/app.blade.php), include the Bootstrap CSS and JS files. You can use a CDN or download Bootstrap files locally:

<!DOCTYPE html>
<html>
<head>
    <title>Your App</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    @yield('content')
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

Index View (resources/views/posts/index.blade.php)

@extends('layouts.app')

@section('content')
    <div class="container mt-5">
        <h1>Posts</h1>
        <ul class="list-group">
            @foreach ($posts as $post)
                <li class="list-group-item">
                    <a href="{{ route('posts.show', $post) }}">{{ $post->title }}</a>
                </li>
            @endforeach
        </ul>
        <a class="btn btn-primary mt-3" href="{{ route('posts.create') }}">Create New Post</a>
    </div>
@endsection

The view above:

  • Extends the main layout template layouts.app.

  • The @section('content') directive defines the content specific to this view.

  • Displays a list of posts using Bootstrap's list group and anchor tags.

  • Iterates through the $posts collection and generates list items for each post's title.

  • Provides a link to the posts.show route for each post.

  • Offers a "Create New Post" button that links to the posts.create route.

Create View (resources/views/posts/create.blade.php)

@extends('layouts.app')

@section('content')
    <div class="container mt-5">
        <h1>Create New Post</h1>
        <form method="post" action="{{ route('posts.store') }}">
            @csrf
            <div class="form-group">
                <label for="title">Title:</label>
                <input type="text" class="form-control" name="title" id="title">
            </div>
            <div class="form-group">
                <label for="content">Content:</label>
                <textarea class="form-control" name="content" id="content"></textarea>
            </div>
            <button type="submit" class="btn btn-success">Create Post</button>
        </form>
    </div>
@endsection

The view above:

  • Provides a form to create a new post.

  • The form submits data to the posts.store route using the HTTP POST method.

  • Utilizes Bootstrap's form classes for styling.

  • Includes fields for entering the post's title and content.

  • Has a "Create Post" button for submitting the form.

Show View (resources/views/posts/show.blade.php)

@extends('layouts.app')

@section('content')
    <div class="container mt-5">
        <h1>{{ $post->title }}</h1>
        <p>{{ $post->content }}</p>
        <a href="{{ route('posts.edit', $post) }}" class="btn btn-primary">Edit</a>
        <form method="post" action="{{ route('posts.destroy', $post) }}" class="d-inline">
            @csrf
            @method('DELETE')
            <button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this post?')">Delete</button>
        </form>
        <a href="{{ route('posts.index') }}" class="btn btn-secondary">Back to Posts</a>
    </div>
@endsection

The view above:

  • Displays the title and content of the selected post.

  • Offers buttons for editing and deleting the post.

  • The edit button links to the posts.edit route for the current post.

  • Provides a delete button that triggers a form submission to the posts.destroy route.

  • Includes a "Back to Posts" button that links back to the list of posts.

Edit View (resources/views/posts/edit.blade.php)

@extends('layouts.app')

@section('content')
    <div class="container mt-5">
        <h1>Edit Post</h1>
        <form method="post" action="{{ route('posts.update', $post) }}">
            @csrf
            @method('PUT')
            <div class="form-group">
                <label for="title">Title:</label>
                <input type="text" class="form-control" name="title" id="title" value="{{ $post->title }}">
            </div>
            <div class="form-group">
                <label for="content">Content:</label>
                <textarea class="form-control" name="content" id="content">{{ $post->content }}</textarea>
            </div>
            <button type="submit" class="btn btn-success">Update Post</button>
            <a href="{{ route('posts.show', $post) }}" class="btn btn-secondary ml-2">Cancel</a>
        </form>
    </div>
@endsection

The view above:

  • Provides a form to edit the selected post.

  • The form submits data to the posts.update route using the HTTP PUT method.

  • Utilizes Bootstrap's form classes for styling.

  • Pre-fills the form fields with the current post's title and content.

  • Includes an "Update Post" button for submitting the form.

  • Offers a "Cancel" button that links back to the posts.show route for the current post.

These additions to the Blade views introduce Bootstrap classes to style the content, forms, buttons, and layout of your Laravel application. Make sure to tailor the styling to your preferences and your application's design requirements.

Test Your App

Start Laravel Development Server

Open your terminal or command prompt and navigate to your Laravel project's root directory. Run the following command to start the Laravel development server:

php artisan serve

This will start the server on the default address http://127.0.0.1:8000. You can also specify a different port using the --port option.

Access Routes in Browser

Open your web browser and enter the URL for the routes you've defined. Routes are constructed based on the HTTP methods (GET, POST, PUT, DELETE) and URI segments.

Conclusion

In this comprehensive guide, we've utilized the "Post" model as a practical example to lead you through mastering CRUD operations in Laravel. By following the steps outlined here, you'll not only gain proficiency in building CRUD functionalities but also become familiar with Laravel's elegance and power. Remember, CRUD operations are just the beginning; Laravel offers a vast ecosystem to explore and create more sophisticated web applications. Happy coding, and enjoy your Laravel journey