DEV Community

Chabba Saad
Chabba Saad

Posted on • Edited on

Mastering Laravel : From Fundamentals to Advanced Web Development

Introduction

Environment & Tools

Editeur VS Code - Extensions

Editeur VS Code - Extensions

Mastering Laravel : From Fundamentals to Advanced Web Development


what is Laravel

Laravel is a web application framework with expressive, elegant syntax. It simplifies tasks in web development by easing common tasks, such as routing, sessions, caching, and authentication. Laravel aims to make the development process a pleasing one for the developer without sacrificing application functionality. It's accessible, yet powerful, providing tools needed for large, robust applications.

Why Laravel

Laravel is considered the best choice for many developers due to its elegant syntax, robust features, and extensive ecosystem. It offers a powerful ORM (Eloquent), efficient routing, an intuitive queue system, and simple authentication, which speeds up the web development process. Laravel's extensive libraries and MVC architecture make it ideal for building scalable applications. Moreover, its strong community support, comprehensive documentation, and built-in tools for testing and debugging enhance its appeal. This combination of ease of use, scalability, and functionality makes Laravel a top choice in modern web development.

💡 documentation. For further details on Laravel commands, in-depth explanations, and advanced usage, you can refer to the Laravel documentation at Laravel Official Documentation. This resource is highly recommended for staying updated with the latest Laravel features and best practices.

Environment & Tools

Laragon

Laragon is a portable, isolated, fast, and powerful universal development environment for PHP, Node.js, Python, Java, Go, Ruby. It is designed to provide developers with a quick and easy way to set up a local development environment. The interface displayed in your screenshot is user-friendly and typically includes options to manage services like Apache, MySQL, and others, with the ability to start, stop, and reload these services. It also integrates a terminal and other tools like root access and database management to streamline development workflows. Laragon is often favored for its simplicity and the convenience of having multiple development utilities in one place.

download link

XAMPP

Download XAMPP

XAMPP is a free and open-source cross-platform web server solution stack package. It simplifies the process of installing and configuring Apache server, MySQL, PHP, and Perl. XAMPP is widely used by developers to build and test web applications locally before deploying them. Its user-friendly interface and straightforward setup make it ideal for beginners and professionals alike, providing a reliable and consistent development environment.

Composer

Download Composer

Composer is a dependency manager for PHP, facilitating the management of libraries and packages in PHP projects. It allows developers to declare the libraries their project depends on and manages them for you. Composer streamlines the process of installing and updating libraries, ensuring compatibility and reducing conflicts. It's an essential tool for modern PHP development, promoting efficient and effective management of project dependencies.

Git

Download Git

Git is a distributed version control system used for tracking changes in source code during software development. It enables multiple developers to work collaboratively on the same project, allowing them to branch, merge, and track their work independently. Git is known for its speed, data integrity, and support for distributed, non-linear workflows, making it a staple in the toolkit of developers for managing and maintaining codebases efficiently.

HeidiSQL

Download HeidiSQL

HeidiSQL is a powerful, easy-to-use interface for managing MySQL, MariaDB, SQL Server, PostgreSQL, and SQLite databases. It allows users to browse and edit data, create and modify tables, views, procedures, triggers, and scheduled events. Additionally, HeidiSQL provides a user-friendly interface for importing and exporting data, making database management more accessible and manageable for developers and database administrators.

VS Code

Download Visual Studio Code

Visual Studio Code (VS Code) is a free, open-source code editor developed by Microsoft. It supports a variety of programming languages and includes features like syntax highlighting, intelligent code completion, snippets, and code refactoring. VS Code also has a vast extension library, which allows developers to customize their environment to suit their needs. Its lightweight design, powerful features, and ease of customization make it a popular choice among developers for writing and editing code.

Editeur VS Code - Extensions

In our course, we are installing several useful extensions for Visual Studio Code that greatly enhance our coding experience. These include:

  1. PHP IntelliSense: Provides smart code completion and navigation for PHP.
  2. PHP Intelephense: An efficient and feature-rich PHP language server.
  3. PHP DocBlocker: Assists in generating and maintaining PHP DocBlocks.
  4. PHP Namespace Resolver: Streamlines the management and resolution of namespaces.
  5. Laravel Blade Snippets: Offers handy snippets for Laravel Blade templates.
  6. Laravel Artisan: Integrates Laravel's Artisan commands into VS Code.
  7. Laravel Goto View: Simplifies navigation to Laravel views from controllers.

These extensions collectively improve our PHP and Laravel development workflow within Visual Studio Code

Mastering Laravel: From Fundamentals to Advanced Web Development

Installation & setup

now let start by installing our first laravel project with those command :

composer create-project laravel/laravel example-app
Enter fullscreen mode Exit fullscreen mode

The MVC (Model-View-Controller) architecture is a software design pattern that separates an application into three main logical components: the model, the view, and the controller. Each of these components is represented in the Laravel directory structure shown in your image:

  1. Model: The Models directory contains the application's business logic and is responsible for retrieving, inserting, and updating information in the database. In your screenshot, the User.php file inside the Models directory represents a model.
  2. View: The views directory inside the resources folder contains the presentation layer of the application. It's where the application's user interface is stored. Views are responsible for displaying data provided by the controller in a format that the user can interact with.
  3. Controller: The Controllers directory inside the Http folder contains the controllers. Controllers handle user requests, process them (often with the help of models), and return a response, usually by rendering a view.
cd example-app

php artisan serve
Enter fullscreen mode Exit fullscreen mode

Routes, Vues & Layouts

creating first route and views in our project :

Home

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Home</title>
</head>
<body>
    <h1>Home Pge</h1>
    <p>Learn Laravel</p>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

About

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>About</title>
</head>
<body>
    <h1>About Page</h1>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

routes :

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

Route::get('/about', function () {
    return view('about');
});
Enter fullscreen mode Exit fullscreen mode

instead of duplicating the same HTML structure across different pages, you use a layout, often referred to as a "master page". This layout serves as a template for other views and contains common HTML structures such as the header, footer, and main navigation elements.

To implement a layout in Laravel, you create a master blade file, typically named layout.blade.php or master.blade.php, which includes placeholders for content (@yield directives) that can be filled by individual views. Here's a basic example of how you might structure a master layout:

let try to add only @extends('layout')

layout.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    {{-- @yield('content') --}}

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

home.blade.php

@extends('layout')

    <h1>Home Pge</h1>
    <p>Learn Laravel</p>

Enter fullscreen mode Exit fullscreen mode

When you use @extends('layout') in a Blade template with Laravel, it's typically used for inheriting a master layout. However, this current implementation is not optimal for search engine optimization (SEO) because it not respecting the Content Placement

home.blade.php

@extends('layout')

@section('content')
    <h1>Home Pge</h1>
    <p>Learn Laravel</p>
@endsection
Enter fullscreen mode Exit fullscreen mode

Comparing Route Definitions in Laravel: Closures vs. Route::view for Static Pages

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

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

Route::view('/','home');
Route::view('/about','about');
Enter fullscreen mode Exit fullscreen mode
  • The primary difference is in their simplicity and potential for expansion. The first method (using closures) is slightly more verbose but allows for added complexity, such as passing data to views, condition checks, or other operations before returning the view.
  • The second method (Route::view) is more succinct and is ideal for static pages where you're only returning a view without needing any additional logic or data passed to the view.

Handling Dynamic Route Parameters in Laravel

In this section, we explore how to define routes with dynamic parameters in Laravel. This is particularly useful when you want to fetch or manipulate data based on a variable part of the URL, like an ID from a database.

Example: Fetching a Post by ID

Consider a scenario where you need to display a specific post based on its ID. The ID is dynamically provided in the URL. Here's how you can define such a route:

Route::get('/posts/{id}', function ($id) {
    return $id;
});
Enter fullscreen mode Exit fullscreen mode

testing this dynamic Route :

http://127.0.0.1:8000/posts/4


Dynamic Routes with Multiple Parameters in Laravel

This example demonstrates how to use multiple dynamic parameters in Laravel routes and pass data to a view. We'll use a route with two dynamic parameters (id and author) and then pass the data to a Blade template.

Example 1 :

Route::get('/posts/{id}/{author}', function ($id,$author) {
    return $id. " author: $author ";
});
Enter fullscreen mode Exit fullscreen mode

Example 2:

show.blade.php

@extends('layout')

@section('content')
    <p>{{ $post['title'] }}</p>
@endsection
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • @extends('layout'): Indicates that this Blade file extends a master layout named layout.
  • @section('content'): Starts a section named content. This is where you define the content that will be injected into the layout.
  • {{ $post['title'] }}: Blade syntax for outputting the title of the post. This data is passed from the route.
Route::get('/posts/{id}/{author}', function ($id,$author) {
    $posts = [
        1 => ['title' => 'Intro to Laravel'],
        2 => ['title' => 'Intro to PHP'],
    ];
    return view('posts.show', [
        'post' => $posts[$id] 
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Route::get('/posts/{id}/{author}', ...): Defines a GET route with two dynamic segments, {id} and {author}. Laravel will pass these as parameters to the provided closure.
  • $posts = [...];: An associative array simulating a data source (like database records).
  • return view('posts.show', ['post' => $posts[$id]]);: The function returns a view named posts.show, passing along the post data retrieved from the $posts array using the provided $id.

result expected :

Example: Optional Route Parameters in Laravel

Route::get('/posts/{id}/{author?}', function ($id,$author = "default name") {
    $posts = [
        1 => ['title' => 'Intro to Laravel'],
        2 => ['title' => 'Intro to PHP'],
    ];
    return view('posts.show', [
        'post' => $posts[$id] ,
        'author' => $author
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Route::get('/posts/{id}/{author?}', ...): Defines a GET route where {id} is a required parameter, and {author} is optional (indicated by the ? after the parameter name).
  • $author = "default name": Sets a default value for the $author parameter. If author is not provided in the URL, it will default to "default name".
  • The route closure returns the posts.show view, passing the post data (based on $id) and the author name.

Use Case:

This approach is valuable for creating more flexible web routes, where certain parts of the URL might be optional. It's particularly useful in scenarios where you want to provide additional context or filters for a page, but those filters are not mandatory.


Rendering HTML Content in Laravel Blade Templates

Background:

Laravel Blade templates escape output by default. This means that any HTML tags included in variables will not be rendered as HTML but will be displayed as plain text. This is a security feature to prevent Cross-Site Scripting (XSS) attacks, where malicious scripts are injected into web pages.

Example: Route with HTML Content in Data Array

Route::get('/posts/{id}/{author?}', function ($id,$author = "default name") {
    $posts = [
        1 => ['title' => '<a> Intro to Laravel </a>'],
        2 => ['title' => 'Intro to PHP'],
    ];
    return view('posts.show', [
        'post' => $posts[$id] ,
        'author' => $author
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • The $posts array includes HTML content (<a> Intro to Laravel </a>) for the title of the first post.
  • By default, Blade will escape this HTML content, meaning it will be displayed as plain text in the view, not as an actual link.

Blade Template with Unescaped Content

To render the HTML content as actual HTML rather than escaped text, you use the {!! !!} syntax in Blade:

@extends('layout')

@section('content')
    <h1>{!! $post['title'] !!}</h1>
    <p>Author: {{ $author }}</p>
@endsection
Enter fullscreen mode Exit fullscreen mode

Controller basics

Controllers in Laravel are used to organize the logic of handling HTTP requests. They serve as an intermediary between the models (which interact with the database) and views (which present data to the user). Controllers help in keeping the code clean and separating the logic from the routing layer.

Key Concepts:

  1. Creation and Structure: Controllers are typically stored in the app/Http/Controllers directory. They can be generated using the Artisan command php artisan make:controller <ControllerName>. A controller class usually extends the base controller class provided by Laravel.
  2. Methods and Routes: Each public method in a controller can be linked to a route. These methods handle requests and return responses. For example, a method can return a view, a redirect, or a JSON response.
  3. Passing Data: Data can be passed to controller methods via route parameters or request data. Controllers can then pass this data to views or use it to interact with models.
  4. Resource Controllers: For standard CRUD operations, Laravel provides resource controllers with methods like index, create, store, show, edit, update, and destroy. These can be automatically set up with a single route declaration.
  5. Dependency Injection: Controllers support dependency injection, allowing you to type-hint dependencies in the constructor or method signatures. Laravel's service container automatically injects these dependencies.

Let Create our first Controller

php artisan make:controller HomeController
Enter fullscreen mode Exit fullscreen mode
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    //

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

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

    public function blog($id,$author = "default name")
    {

        $posts = [
            1 => ['title' => '<a> Intro to Laravel </a>'],
            2 => ['title' => 'Intro to PHP'],
        ];
        return view('posts.show', [
            'post' => $posts[$id] ,
            'author' => $author
        ]);

    }

}
Enter fullscreen mode Exit fullscreen mode

replace welcome blade code with 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,600&display=swap" rel="stylesheet" />

        <!-- Styles -->

    </head>
    <body class="antialiased">
        <a href="{{ route('home') }}">Home</a>
        <a href="{{ route('about') }}">About</a>
        <a href="{{ route('blog-posts', ['id' => 1]) }}">Show Post</a>

    </body>

</html>
Enter fullscreen mode Exit fullscreen mode

let change our olds route with newest ones :


Route::get('/posts/{id}/{author?}', [HomeController::class, 'blog'])->name('blog-posts');
Route::get('/home', [HomeController::class, 'home'])->name('home');
Route::get('/about', [HomeController::class, 'about'])->name('about');
Enter fullscreen mode Exit fullscreen mode

Models and Migrations

after this phase we need to connect our application with a Database in mysql

For this, Laravel provides a robust and flexible database layer that integrates seamlessly with various database engines. The configuration settings for databases are primarily located in the config/database.php file, along with the .env file for environment-specific settings.

Configuring the Database Connection:

  1. Environment File (.env): Laravel uses the .env file to manage environment-specific configurations. To connect to a MySQL database, you need to set the appropriate values in your .env file for your database connection, like DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, and DB_PASSWORD. This is an example of how you might configure these:
  2. Database Configuration File (config/database.php): This file holds the configuration for all your database connections. Laravel supports several database drivers out of the box: MySQL, PostgreSQL, SQLite, and SQL Server. You can define settings for each of these and switch between them as needed. The configurations read the values from the .env file, ensuring security and ease of deployment across different environments.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
Enter fullscreen mode Exit fullscreen mode

Creating a MySQL Database

When you click on the database icon in Laragon, it opens an interface for HeidiSQL, which is included with the Laragon installation. Laragon is an all-in-one development environment that simplifies database management and other development tasks

i called my Database : first

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=first
DB_USERNAME=root
DB_PASSWORD=
Enter fullscreen mode Exit fullscreen mode

After creating your database named "first", you need to update your Laravel .env file to reflect the correct database settings, including the database name (DB_DATABASE=first). Then, you can use the Artisan migrate command to set up your database tables:

php artisan migrate
Enter fullscreen mode Exit fullscreen mode
**php artisan migrate:rollback**
Enter fullscreen mode Exit fullscreen mode

Key Aspects of php artisan migrate:rollback

  1. Undo Last Migrations: The command undoes the last batch of migrations that were run. In Laravel, migrations are batched each time you run the php artisan migrate command. migrate:rollback targets the migrations from the latest batch.
  2. Rollback to a Specific Point: You can specify how many steps of migrations you want to rollback using the -step option. For example, php artisan migrate:rollback --step=1 will rollback the last migration only.
  3. Invoking the down Method: Each migration file has two methods: up() and down(). The up() method is used to add new tables, columns, or indexes to your database, while the down() method should reverse the operations performed by the up() method. The migrate:rollback command calls the down() method for each migration in the last batch.

Creating a New Migration File in Laravel

Introduction:

In Laravel, migrations are essential for managing your application's database schema. They allow you to define and modify your database tables and columns in a programmatic and version-controlled manner. Let's walk through the process of creating a new migration file.

Step-by-Step Process:

 **Using Artisan Command:**
Enter fullscreen mode Exit fullscreen mode

Laravel provides an Artisan command-line tool to simplify the creation of migration files. To create a new migration, use the make:migration command followed by a name that describes the purpose of the migration. The naming convention typically involves a description of the action followed by the name of the table. For example:

php artisan make:migration create_posts_table
Enter fullscreen mode Exit fullscreen mode
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title',120);
            $table->text('content');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
Enter fullscreen mode Exit fullscreen mode

Migration File Structure:

The new migration file will be placed in the database/migrations directory. The file name includes a timestamp to ensure migrations are executed in the order they were created. Inside the migration file, you will find two methods: up() and down().

  • up() Method: Defines the database operations to be executed when the migration is run (e.g., creating a table, adding columns).
  • down() Method: Defines the operations to revert the actions of the up() method (e.g., dropping a table).

Steps to Create a Migration for Adding a New Column to table Post

  1. Generate the Migration File:

    First, you need to create a new migration file. The name of the migration should describe the action it performs. Use the Artisan command:

    php artisan make:migration add_slug_and_active_to_posts_table
    

<?php

    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    return new class extends Migration
    {
        /**
         * Run the migrations.
         */
        public function up(): void
        {
            Schema::table('posts', function (Blueprint $table) {
                //
                $table->string('slug')->unique();
                $table->boolean('active')->default(false);
            });
        }

        /**
         * Reverse the migrations.
         */
        public function down(): void
        {
            Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('slug');
            $table->dropColumn('active');
            // or this  $table->dropColumn(['slug','active']);
            });
        }
    };
Enter fullscreen mode Exit fullscreen mode
### Introduction to Laravel Models

**Overview:**

In Laravel, a model is a fundamental part of the Eloquent ORM (Object-Relational Mapping) and represents a single database table. Models provide a simple and elegant way to interact with your database. They allow you to query the database tables and perform various operations on the database records in an object-oriented manner.

**Naming Conventions:**

- **Singular and Capitalized**: By convention, model names in Laravel are singular and use "StudlyCaps" (also known as PascalCase). This means the first letter of each word is capitalized, and there are no underscores between words.
- **Correspondence with Database Tables**: The model name should be the singular form of the table name. For instance, if you have a table named **`posts`**, the corresponding model should be named **`Post`**.

### **Generating a Model**

To generate a model in Laravel, you use the Artisan command-line tool. Here's how you can create a model for a **`posts`** table:
Enter fullscreen mode Exit fullscreen mode
```makefile
php artisan make:model Post
```
Enter fullscreen mode Exit fullscreen mode
This command creates a **`Post`** model in the **`app/Models`** directory.

**Example of a Basic Post Model:**
Enter fullscreen mode Exit fullscreen mode
```php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Model content goes here
}
```
Enter fullscreen mode Exit fullscreen mode
**Key Features of Models:**

1. **Eloquent ORM**: Laravel's Eloquent ORM provides an active record implementation, making it easier to interact with your database. Each model you create corresponds to a database table, and each instance of the model represents a row in the table.
2. **Property Mapping**: The columns in the database table are automatically mapped to properties of the model. So, you can access and set these properties directly to interact with the corresponding database columns.
3. **Timestamps**: By default, Eloquent expects **`created_at`** and **`updated_at`** columns to be present in your table. It will automatically set these values when models are created or updated.
4. **Mass Assignment Protection**: You can specify either a **`fillable`** or **`guarded`** property on your model to protect against mass-assignment vulnerabilities.
5. **Relationships**: Models can define relationships (like one-to-many, many-to-many) with other models. These relationships are methods that return instances of the relationship.

However, if you want your model to use a different table name that doesn't follow this convention, you can explicitly define the table name in your model. To do this, you can set the **`$table`** property within your model class. Here's an example of how to do this:
Enter fullscreen mode Exit fullscreen mode
```php
protected $table = 'my_custom_posts';
```
Enter fullscreen mode Exit fullscreen mode
In Laravel, **`-mcr`** is a combination of options used with the **`artisan make:model`** command. This command is used to generate a new model, and the options specify additional files that should be created alongside the model. Here's what each letter in **`-mcr`** stands for:

- **`m`**: This option tells Artisan to also create a migration file for the model. Migrations are used to define the database schema. For example, if you're creating a **`Post`** model, using **`m`** will create a corresponding migration file for creating the **`posts`** table in the database.
- **`c`**: This option is for creating a controller. When used, Artisan will generate a new controller file in the **`app/Http/Controllers`** directory. The controller will be named after the model. For a **`Post`** model, this would create a **`PostController`**.
- **`r`**: This indicates that the generated controller should be a resource controller. A resource controller includes methods for the standard set of create, read, update, and delete operations (CRUD). This is useful for quickly scaffolding the basic CRUD functionality.
Enter fullscreen mode Exit fullscreen mode
```php
php artisan make:model Category -mcr
```
Enter fullscreen mode Exit fullscreen mode
---

### Tinker in Laravel

Tinker, included in Laravel, is an interactive shell that integrates with your Laravel application, providing a convenient way to interact with your app's data and functionalities directly from the command line. It leverages the PsySH package to offer an interactive PHP REPL (Read-Eval-Print Loop) for running PHP code in real-time.

Here's a brief overview of what Tinker allows you to do:

1. **Interact with Eloquent Models**: You can create, retrieve, update, and delete database records using Eloquent models directly from the command line.
2. **Run Application Code**: Tinker lets you execute any PHP code or Laravel-specific code in the context of your application. This is particularly useful for testing and debugging.
3. **Event and Job Testing**: You can dispatch events and jobs to test their behavior without needing to trigger them through the application's UI or API.
4. **Experimentation and Prototyping**: It provides a playground for experimenting with new ideas and code snippets, making it easier to prototype without the need to create routes or controllers.
5. **Database Queries**: Apart from Eloquent, you can also run raw database queries or use the query builder for more complex operations.

To use Tinker, you simply run **`php artisan tinker`** in your terminal. This command opens a shell where you can type in your PHP code, and it will be executed within the context of your Laravel application. This immediate feedback loop makes Tinker an invaluable tool for Laravel developers for quick testing and debugging.

let try to isnert first row in our table post :
Enter fullscreen mode Exit fullscreen mode
```php
php artisan tinker

> $post = new Post();

> $post->title = "learn laravel";
= "learn laravel"

> $post->slug = "learn-laravel";
= "learn-laravel"

> $post->content = "laravel is a php framwork";
= "laravel is a php framwork"

> $post->active = true;
= true

> $post->save();
= true

$post->title = "learn angular";
= "learn angular"

> $post->content = "angular is a js framwork";
= "angular is a js framwork"

> $post->slug = "learn-angular";
= "learn-angular"

> $post->active = false;
= false

> $post->save();
```
Enter fullscreen mode Exit fullscreen mode
```php

// get all the posts 
> Post::all();
= Illuminate\Database\Eloquent\Collection {#5019
    all: [
      App\Models\Post {#6025
        id: 1,
        title: "learn laravel",
        content: "laravel is a php framwork",
        created_at: "2024-01-13 21:06:26",
        updated_at: "2024-01-13 21:06:26",
        slug: "learn-laravel",
        active: 1,
      },
      App\Models\Post {#5016
        id: 2,
        title: "learn angular",
        content: "angular is a js framwork",
        created_at: "2024-01-13 21:10:34",
        updated_at: "2024-01-13 21:10:34",
        slug: "learn-angular",
        active: 0,
      },
    ],
  }
// get the First post 
> Post::first();
= App\Models\Post {#6026
    id: 1,
    title: "learn laravel",
    content: "laravel is a php framwork",
    created_at: "2024-01-13 21:06:26",
    updated_at: "2024-01-13 21:06:26",
    slug: "learn-laravel",
    active: 1,
  }

// get the last post 
> Post::get()->last();
= App\Models\Post {#6039
    id: 2,
    title: "learn angular",
    content: "angular is a js framwork",
    created_at: "2024-01-13 21:10:34",
    updated_at: "2024-01-13 21:10:34",
    slug: "learn-angular",
    active: 0,
  }
```
Enter fullscreen mode Exit fullscreen mode

Lazy Collection in laravel

Lazy Collections in Laravel are an efficient way to handle large datasets with minimal memory usage. When you use Post::cursor(), Laravel returns an instance of Illuminate\Support\LazyCollection. This collection leverages PHP's generators to keep memory usage low by only fetching one item at a time from the database as it's being iterated over.

Key points for Lazy Collections:

  1. Efficient Memory Usage: Ideal for processing large datasets without consuming a lot of memory. Only the current item in the iteration is loaded into memory.
  2. Seamless Iteration: Works like regular collections but under the hood, it fetches items one by one, which is great for large datasets.
  3. Useful for Data Export: Perfect for exporting or processing large amounts of data, like generating large CSV files or reports.
  4. Easy to Implement: Just replace get() with cursor() in your Eloquent query. The rest of the code remains the same.

Example Usage:

Post::cursor();
= Illuminate\Support\LazyCollection {#5813
    +source: Closure() {#6028 …4},
  }

> $posts = Post::cursor();
= Illuminate\Support\LazyCollection {#6038
    +source: Closure() {#5011 …4},
  }

> foreach ($posts as $post) { echo "{$post->title} \n"; }
learn laravel
learn angular
Enter fullscreen mode Exit fullscreen mode

This code fetches posts one by one from the database, echoing the title of each post. It's highly efficient for large tables where loading all records at once would be impractical due to memory constraints.


Creating, Updating and Reading data

php artisan make:controller PostController --resource
Enter fullscreen mode Exit fullscreen mode
  1. Creating the Controller:
    • The make:controller Artisan command is used to create a new controller file in your Laravel application.
    • PostController is the name of the controller. Laravel will place this controller in the app/Http/Controllers directory.
  2. Resource Controller:
    • The -resource flag generates a controller with methods for each of the available resource operations. These include index, create, store, show, edit, update, and destroy.
    • Each method corresponds to a specific CRUD operation and is pre-defined with a method signature.

and for creating route for each method exist in the post Controller , Laravel provides a very convenient and concise way to define routes for all the CRUD operations in a resource controller using the Route::resource method. When you use Route::resource('posts', PostController::class); in your routes/web.php file, it automatically creates routes for each method in the PostController.

Route::resource('posts', PostController::class);
Enter fullscreen mode Exit fullscreen mode

you can check all the Routes exist in your web.php with this command line :

php artisan route:list
Enter fullscreen mode Exit fullscreen mode

use in different case :

Route::resource('posts', PostController::class)->only(['create']);
Enter fullscreen mode Exit fullscreen mode

This line of code will register only the create route for the PostController. It means that Laravel will only set up the route that shows the form to create a new post (/posts/create with the GET method, mapped to the create method in PostController), and all other resource routes (like index, store, show, edit, update, destroy) will not be registered.

PostController (PostController.php)

Now, let's complete each method in the PostController:

<?php

namespace App\Http\Controllers;

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

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $posts = Post::all(); // or [] for forelse test in the blade
        return view('posts.index', [
            'posts' => $posts]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $post = Post::findOrFail($id);
        return view('posts.show', [
            'post' => $post
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. index: Lists all posts.
  2. create: Shows a form to create a new post.
  3. store: Saves a new post to the database.
  4. show: Displays a specific post.
  5. edit: Shows a form to edit an existing post.
  6. update: Updates an existing post in the database.
  7. destroy: Deletes a post from the database.

Each method interacts with the Post model to perform CRUD (Create, Read, Update, Delete) operations. The views

(posts.index, posts.create, posts.show, posts.edit) referenced in these methods need to be created within the resources/views/posts directory. These Blade templates will form the user interface for interacting with the posts.

Blade directives @if, @foreach, dates

index.blade.php

@extends('layout')

@section('content')
    <h1>list of Post</h1>
    <ul>
        @foreach($posts as $post)


        <li>
<h2><a href="{{route('posts.show',['post'=>$post->id])}}">{{$post->title}}</a></h2>
<p>{{$post->content}}</p>
<em>{{$post->created_at}}</em>
        </li>
        @endforeach
    </ul>
@endsection
Enter fullscreen mode Exit fullscreen mode

show.blade.php

@extends('layout')

@section('content')

    <h2>{{$post->title}}</h2>
    <p>{{$post->content}}</p>
    <em>{{$post->created_at}}</em>

    @if ($post->active)
        <p>status : Active</p>

    @else
    <p>status : Desactivated</p>
    @endif
@endsection
Enter fullscreen mode Exit fullscreen mode

Displaying a List of Posts with forelse

Example :

@extends('layout')

@section('content')
    <h1>list of Post</h1>
    <ul>
        @forelse($posts as $post)


        <li>
<h2><a href="{{route('posts.show',['post'=>$post->id])}}">{{$post->title}}</a></h2>
<p>{{$post->content}}</p>
<em>{{$post->created_at}}</em>
        </li>
        @empty
        <p>No blog post yet!</p>
        @endforelse
    </ul>
@endsection
Enter fullscreen mode Exit fullscreen mode
  • @forelse is a Blade directive that functions like a foreach loop, but it also handles the case where the array ($posts in this case) is empty.
  • It iterates over each Post object within the $posts collection.
  • Post Details
  • This section displays the title, content, and creation date of each post.
  • The title is wrapped in a hyperlink (<a> tag) generated by the route() function, which creates a URL to the route named posts.show, passing the post's ID as a parameter.
  • {{ }} is used to display the data, and it automatically escapes HTML entities to prevent XSS attacks.
  • Handling No Posts

  • The @empty directive is part of the @forelse loop. It specifies the content to show when the $posts collection is empty.

  • In this case, it displays a simple message: "No blog post yet!"

Understanding diffForHumans()

The diffForHumans() method in Carbon provides a human-readable difference between two dates. It's particularly useful when you want to display the time elapsed in a way that is easy for users to understand. For example, instead of showing a date like "2021-03-31 08:30:00", you could display "5 hours ago", "2 days ago", or "a month ago".

Basic Usage

When you retrieve a timestamp from the database in Laravel, Eloquent automatically casts it to a Carbon instance (if you're using standard timestamp fields like created_at, updated_at). This allows you to directly use Carbon methods on these fields. Here’s a basic example:

<em>{{$post->created_at->diffForHumans()}}</em>
Enter fullscreen mode Exit fullscreen mode

Other Features

  • Comparison with Other Dates: You can compare any two Carbon instances, not just the current time.
  • Localization: Carbon supports localization, so you can display time differences in different languages.
  • Precision: You can control the precision of the difference (like seconds, minutes, hours, etc.).

Forms and CSRF token

let create a blade to test our first senario for forms ;

@extends('layout')

@section('content')

<form action="{{route('posts.store')}}" method="POST">
    <div><label for="title">your title</label><input name="title" id="title" type="text" name="" id=""></div>
    <div><label for="content"></label><input name="content" id="content" type="text" name="" id=""></div>
<button type="submit">Create Post</button>
</form>

@endsection
Enter fullscreen mode Exit fullscreen mode

update the layout page :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <a href="{{ route('home') }}">Home</a>
    <a href="{{ route('about') }}">About</a>
    <a href="{{ route('posts.create') }}">new Post</a> // adding link for create new post
    @yield('content')

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

testing senario :

after clicking on create button we got this page :

The 419 error page (indicating a "Page Expired" issue) that you encounter when submitting a form in Laravel is due to the absence of a CSRF token in the form. CSRF stands for Cross-Site Request Forgery, which is a type of malicious exploit where unauthorized commands are transmitted from a user that the web application trusts.

Laravel includes CSRF protection as a default feature for all POST, PUT, PATCH, and DELETE requests to protect your application from such attacks. When you submit a form without a CSRF token, Laravel's security feature kicks in and rejects the request, resulting in a 419 error.

now let insert our first Post with from the Blade page

/**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        dd($request->all());

        $request->validate([
            'title' => 'required|min:3',
            'content' => 'required|min:10'
        ]);

    }
Enter fullscreen mode Exit fullscreen mode

use Illuminate\Support\Str;   // add this line 
/**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
       // dd($request->all());

    $title = $request->input('title');
    $content = $request->input('content');
    $slug = \Str::slug($title);
    $post = new Post();
    $post->title = $title;
    $post->content = $content;
    $post->slug = $slug;
    $post->save();
    return redirect()->route('posts.index');


    }
Enter fullscreen mode Exit fullscreen mode

Working Session flash messages

Here's a typical use case for setting a flash message in a controller and displaying it in a view:

$request->session()->flash('status', 'Post was created!');
Enter fullscreen mode Exit fullscreen mode

Displaying the Message in a View

To display this message, you would typically have something like the following in your Blade template (e.g., in resources/views/layout.blade.php or a similar layout file):

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

    @if(session()->has('status'))
    <h3 style="color: green">
        {{session()->get('status')}}
    </h3>
    @endif

    <a href="{{ route('home') }}">Home</a>
    <a href="{{ route('about') }}">About</a>
    <a href="{{ route('posts.create') }}">new Post</a>
    @yield('content')

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Validation basics

In Laravel, when you use the $request->validate() method in a controller action, it performs form validation based on the rules you have specified. If the validation fails (meaning the user input does not meet the validation criteria), Laravel automatically redirects the user back to the previous page, which is typically the form submission page. This redirection is a HTTP 302 (Found) response, which is a standard way of performing a redirection on the web.

Here's a breakdown of what happens:

  1. Form Submission: The user submits the form, sending a POST request to the server.
  2. Validation in Controller: In the store method of your controller, you validate the request using $request->validate().
  3. Validation Rules: The title and content fields have specific rules ('required|min:3' and 'required|min:10', respectively). If the user input doesn't meet these criteria, the validation fails.
  4. Automatic Redirection on Failure: If validation fails, Laravel automatically generates a session error bag containing the validation errors and then redirects the user back to the form page with a 302 HTTP status code.
  5. Displaying Errors: On the form page, you can display these validation errors to inform the user what they need to correct. Laravel's Blade templates make it easy to display these errors by accessing the session error bag.
$request->validate([
            'title' => 'required|min:3',
            'content' => 'required|min:10'
        ]);
Enter fullscreen mode Exit fullscreen mode

Displaying validation errors

Customize the Error message in the Front end

@extends('layout')

@section('content')

<form action="{{route('posts.store')}}" method="POST">
    @csrf  <!-- CSRF Token -->
    <div><label for="title">your title</label><input name="title" id="title" type="text" name="" id=""></div>
    <div><label for="content"></label><input name="content" id="content" type="text" name="" id=""></div>

    @if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
<button type="submit">Create Post</button>
</form>

@endsection
Enter fullscreen mode Exit fullscreen mode

For*m Requests*

Customize the Form Request

php artisan make:request StorePost
Enter fullscreen mode Exit fullscreen mode

First, open the generated StorePost.php file. You'll see two main methods: authorize() and rules().

  • authorize(): This method determines if the user is authorized to make this request. You return true to allow or false to deny the request. You can also include more complex logic using Laravel's authentication and authorization features.
  • rules(): Here, you define the validation rules for your form data.
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePost extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return false; // return this to true
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        return [
            'title' => 'required|min:3|max:255',
            'content' => 'required|min:10',
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Use the Form Request in a Controller

Next, modify the corresponding controller method to type-hint the StorePost request. This automatically triggers validation when the method is called.

Example:

/**
     * Store a newly created resource in storage.
     */
    public function store(StorePost $request)
    {
       // dd($request->all());
      // Get validated data
    $validated = $request->validated();

    $title = $request->input('title');
    $content = $request->input('content');
    $slug = Str::slug($title);
    $post = new Post();
    $post->title = $title;
    $post->content = $content;
    $post->slug = $slug;
    $post->save();

    $request->session()->flash('status', 'Post was created!');

    return redirect()->route('posts.index');
   // return redirect()->route('posts.show', ['post' => $post->id]');    

    }
Enter fullscreen mode Exit fullscreen mode

now let try to save our post with more concise way ;

To simplify your store method and use the Post::create method, you can take advantage of Laravel's Mass Assignment feature. This allows you to create a new Post model and save it to the database

for this to work, you need to ensure that the fields you are trying to mass assign are listed in the $fillable attribute of your Post model.

First, update your Post model to include the $fillable property:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

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

    // Other model properties and methods...
}
Enter fullscreen mode Exit fullscreen mode

Now, in your controller's store method, you can use the Post::create method. You will still need to manually create the slug before calling create:

$data = $request->only(['title', 'content']);
    $data['slug'] = Str::slug($data['title']);
    $data['active'] = false;

    $post = Post::create($data);
Enter fullscreen mode Exit fullscreen mode

old() helper in forms

The old() helper function in Laravel is a convenient tool used in forms to repopulate form fields with their previous values. This is particularly useful when a form submission fails (e.g., due to validation errors) and the page is reloaded. The old() function ensures that the user doesn't have to re-enter all the form data again.

Usage in Blade Templates

Here's how you might use the old() helper in a Blade template:

<input type="text" name="title" value="{{ old('title') }}">
Enter fullscreen mode Exit fullscreen mode

Handling Select, Checkbox, and Radio Inputs

For select, checkbox, and radio inputs, the old() helper can be used to determine which option should be selected or checked.

Select:

<select name="category">
    <option value="1" {{ old('category') == 1 ? 'selected' : '' }}>Category 1</option>
    <option value="2" {{ old('category') == 2 ? 'selected' : '' }}>Category 2</option>
</select>
Enter fullscreen mode Exit fullscreen mode

Checkbox

<input type="checkbox" name="agree" {{ old('agree') ? 'checked' : '' }}>
Enter fullscreen mode Exit fullscreen mode

Radio:

<input type="radio" name="gender" value="male" {{ old('gender') == 'male' ? 'checked' : '' }}>
<input type="radio" name="gender" value="female" {{ old('gender') == 'female' ? 'checked' : '' }}>.
Enter fullscreen mode Exit fullscreen mode

Edit & Update & Delete Method

edit method

/**
 * Show the form for editing the specified resource.
 */
public function edit(string $id)
{
    $post = Post::findOrFail($id);
    return view('posts.edit', [
        'post' => $post
    ]);
}
Enter fullscreen mode Exit fullscreen mode

Blade : edit.blade.php

@extends('layout')

@section('content')

<form action="{{route('posts.update',['post'=>$post->id])}}" method="POST">
    @csrf  <!-- CSRF Token -->
    @method('PUT')
    <div><label for="title">your title</label><input name="title" id="title" type="text" value="{{old('title',$post->title)}}"></div>
    <div><label for="content"></label><input name="content" id="content" type="text" value="{{old('content',$post->content)}}""></div>

    @if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
<button type="submit">Update Post</button>
</form>

@endsection
Enter fullscreen mode Exit fullscreen mode

adding this to the index.blade.php

<a href="{{route('posts.edit',['post'=>$post->id])}}">Edit</a>
Enter fullscreen mode Exit fullscreen mode

update method

/**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
{
    $request->validate([
        'title' => 'required|min:3|max:255',
        'content' => 'required|min:10',
    ]);

    $post = Post::findOrFail($id);
    $post->title = $request->input('title');
    $post->content = $request->input('content');
    $post->slug = Str::slug($request->input('title'));
    $post->save();

    $request->session()->flash('status', 'Post was updated!');

    return redirect()->route('posts.show', ['post' => $post->id]);
}
Enter fullscreen mode Exit fullscreen mode

Additional Points

  • The findOrFail method is used to retrieve the post by its ID. If the post is not found, it throws a ModelNotFoundException, which Laravel will automatically convert into a 404 response.

testing senario with find and findOrfail :

if we use findorFail :

if we use only find :

delete method

/**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
{
    $post = Post::findOrFail($id);
    $post->delete();

    session()->flash('status', 'Post was deleted!');
    return redirect()->route('posts.index');
}
Enter fullscreen mode Exit fullscreen mode

blade :

<form action="{{route('posts.destroy',['post'=>$post->id])}}" method="POST">
    @csrf  <!-- CSRF Token -->
    @method('DELETE')
    <button type="submit">Delete</button>
    </form>
Enter fullscreen mode Exit fullscreen mode

Our first CRUD View achevied :

Top comments (2)

Collapse
 
altesack profile image
Marat Latypov

Hi! Nice tutorial for beginners! Could you fix some format errors?

Collapse
 
chabbasaad profile image
Chabba Saad

thanks for your support ! i will fix it right now apperciate it