User Role and Permission with Laravel Policy

প্রথমে আপনাকে User Role এবং Permission কি তা জানার জন্য আমাদের User Role and Permission with Laravel Gate এই পোস্টটির প্রথম কয়েকটি প্যারাগ্রাফ পড়ে আসতে হবে।
এখন আমরা শুধু আলোচনা করব Laravel Policy কি শুধু এই বিষয়ে।

তো চলুন শুরু করা যাক :

Laravel Policy

Laravel Policy কি?

Laravel Policy হল এমন একটি ফীচার যা ডেভেলপারদের তাদের অ্যাপ্লিকেশনগুলির মধ্যে models, views এবং actions সহ resources গুলির জন্য authorization rules গুলি ডিফাইন করতে দেয়৷ উদাহরণ স্বরূপ, আপনি আপনার অ্যাপ্লিকেশনের অথেন্টিকেটেড ইউজারদের বা যাদের একটি নির্দিষ্ট role বা permission level রয়েছে তাদেরকে কিছু নির্দিষ্ট routes এ এক্সেস সীমাবদ্ধ করতে চাইতে পারেন ।

Policy গুলিকে লারাভেলের ক্লাস হিসাবে ডিফাইন করা হয়, যেখানে প্রতিটি আপনার অ্যাপ্লিকেশনের একটি নির্দিষ্ট মডেল বা রিসোর্সের সাথে মিলে যায়। policy ক্লাসে এমন মেথড রয়েছে যা সংশ্লিষ্ট মডেল বা রিসোর্সে অ্যাক্সেস করার জন্য authorization rules গুলিকে সংজ্ঞায়িত করে। এই মেথড গুলি true বা false রিটার্ন দেয়, ইউজার এটি অ্যাক্সেস করার জন্য অথোরাইজড কিনা তার উপর নির্ভর করে।

মনে রাখবেন যে Laravel policy গুলি নির্দিষ্ট মডেলের সাথে আবদ্ধ, এবং তারা Laravel-এর built-in gate authorization system এর সাথে একত্রে কাজ করে। যদিও policy গুলি resource-based authorization এর জন্য আদর্শ, আপনি আরও জটিল পরিস্থিতির জন্য gates গুলি ব্যবহার করতে পারেন বা যখন আপনাকে authorization checks গুলি সম্পাদন করতে হবে যা সরাসরি মডেলের সাথে আবদ্ধ নয়।

লারাভেল policy গুলি কার্যকরভাবে ব্যবহার করে, আপনি নিশ্চিত করতে পারেন যে আপনার অ্যাপ্লিকেশনের authorization logic গুলো সংগঠিত, রক্ষণাবেক্ষণযোগ্য এবং সুরক্ষিত এবং এটি আপনাকে আপনার অ্যাপ্লিকেশনের components গুলির মধ্যে concerns গুলির একটি clear separation বজায় রাখতে সহায়তা করে৷

Laravel Policy কেন গুরুত্বপূর্ণ?

Laravel Policy যেকোন Laravel অ্যাপ্লিকেশনের জন্য অপরিহার্য যার জন্য resources গুলিতে নিরাপদ অ্যাক্সেস প্রয়োজন। যথাযথ অনুমোদন ব্যতীত, ইউজাররা এমন কাজ সম্পাদন করতে সক্ষম হতে পারে যার জন্য তারা অনুমোদিত নয়, যার ফলে data breaches, unauthorized access এবং অন্যান্য security issues তৈরি হয়।

Laravel Policy গুলির সাহায্যে, ডেভেলপাররা প্রতিটি রিসোর্সের জন্য নির্দিষ্ট rules ডিফাইন করতে পারে, নিশ্চিত করে যে শুধুমাত্র অথোরাইজড ইউজাররা সেগুলি অ্যাক্সেস করতে পারে। এটি security vulnerabilities ঝুঁকি কমাতে সাহায্য করে এবং sensitive data সুরক্ষিত থাকে তা নিশ্চিত করে।

Mastering Laravel with ReactJS Course

কখন Laravel Policy Authorization ব্যবহার করবেন?

আপনি যখন আপনার Laravel অ্যাপ্লিকেশনের মধ্যে নির্দিষ্ট model instances গুলিতে অ্যাক্সেস নিয়ন্ত্রণ করতে চান তখন Laravel Policies Authorization ব্যবহার করা হয়। এটি মডেলের প্রকারের উপর ভিত্তি করে authorization logic ডিফাইন করার এবং নির্দিষ্ট মডেলের সাথে যুক্ত সাধারণ অথোরাইজেশন পরিস্থিতি পরিচালনা করার একটি সুবিধাজনক উপায় প্রদান করে। আমরা নিম্নোক্ত পরিস্থিতিতে Laravel Policies Authorization ব্যবহার করতে পারি:

  1. Resource-Based Authorization:
  2. আপনার যখন user roles বা ownership এর উপর ভিত্তি করে নির্দিষ্ট resources গুলিতে (যেমন, models) অ্যাক্সেস নিয়ন্ত্রণ প্রয়োজন হবে। উদাহরণস্বরূপ, আপনি শুধুমাত্র একটি পোস্টের owner কে এটি edit বা delete করার অনুমতি দিতে চান ৷ লারাভেল policies এই ধরণের পরিস্থিতির জন্য বিশেষভাবে উপযুক্ত।

  3. Model-Centric Authorization Logic:
  4. যখন আপনার authorization logic গুলো model instances এবং তাদের relationships এর চারপাশে ঘোরে। তখন Policies গুলি আপনাকে সংশ্লিষ্ট মডেল ক্লাসের মধ্যে authorization logic কে এনক্যাপসুলেট করার অনুমতি দেয়, এটি ম্যানেজ এবং এর understanding সহজ করে তোলে।

  5. Simple CRUD Operations:
  6. যখন আপনার মডেলগুলিতে সাধারণ Simple CRUD (Create, Read, Update, Delete) অপারেশন্স গুলোতে authorize করার প্রয়োজন হবে। তখন আপনি Laravel Policies গুলি ব্যবহার করে এই ধরণের বেসিক অথোরাইজেশন চেকগুলিকে সুন্দরভাবে পরিচালনা করতে পারেন, কারণ সেগুলি নির্দিষ্ট মডেলের জন্য তৈরি।

  7. Consistent (সামঞ্জস্যপূর্ণ ) Authorization Rules:
  8. আপনি যখন একই মডেল জড়িত একাধিক routes বা অ্যাকশনগুলিতে consistent authorization rules প্রয়োগ করতে চান। Policy গুলি authorization logic কে একটি সেন্ট্রাল লোকেশনে রাখতে সাহায্য করে৷

  9. Explicit (স্পষ্ট) Authorization:
  10. আপনি যদি আপনার application এ authorization rules সম্পর্কে স্পষ্ট হতে পছন্দ করেন। তাহলে আপনি Policy গুলি ব্যবহার করে authorization logic কে আরো স্পষ্টভাবে সংজ্ঞায়িত করতে পারেন , যা আপনার কোডবেসকে আরও maintainable অর্থাৎ রক্ষণাবেক্ষণযোগ্য এবং পর্যালোচনা করা সহজ করে তুলতে পারে।

  11. Clear Separation of Concerns (দুশ্চিন্তা মুক্ত ):
  12. আপনি যদি আপনার controllers বা routes থেকে authorization দুশ্চিন্তা গুলিকে আলাদা করতে চান। এক্ষেত্রে আপনি policies ব্যবহার করে, আপনার controller actions গুলিকে ক্লিন রাখতে পারেন এবং business logic কে ফোকাস করতে পারেন, যেখানে authorization logic গুলো policy ক্লাসে আলাদাভাবে হ্যান্ডেল করা হবে।

  13. Granular (প্রতিটি ক্ষুদ্র থেকে ক্ষুদ্রতর) Access Control :
  14. যখন আপনার প্রতি-মডেলের ভিত্তিতে প্রতিটি ক্ষুদ্র থেকে ক্ষুদ্রতর অর্থাৎ granular access control প্রয়োগ করার প্রয়োজন হবে। Policies আপনাকে বিভিন্ন মডেলের জন্য বিভিন্ন অনুমোদনের নিয়ম ডিফাইন করার অনুমতি দেয়, আপনার আবেদনের উপর সূক্ষ্ম নিয়ন্ত্রণ প্রদানের সুযোগ দিবে ।

  15. Complex Authorization Logic:
  16. যখন আপনার simple user roles বা ownership বাইরে আরও জটিল authorization rules এর প্রয়োজন হয়। Laravel policies গুলি আপনার নির্দিষ্ট use cases এর ক্ষেত্রে উপযোগী method গুলো ব্যবহার করে custom logic ডিফাইন করার flexibility প্রদান করে।

এতক্ষণে নিশ্চয়ই আপনার Laravel Policy সম্পর্কে মোটামুটি একটা ধারণা হলো। এখন আপনার এই ধারণাকে আমরা একটা বাস্তব রূপ দেব। চলুন একটা প্রেক্ষাপট নিয়ে আলোচনা করি।

ধরুন আমাদের posts এবং users নামে দুটি টেবিল আছে। ইউজারদের তিন ধরণের role থাকবে:

১. user (সাধারণ ইউজার)
2. editor এবং
৩. admin

যেখানে ইউজারদের মধ্যে যাদের role শুধু user তার নিজের পোস্ট শুধু update এবং Delete করতে পারবে, এবং অন্য ইউজারদের পোস্ট গুলো শুধু দেখতে পারবে। আর যাদের role হচ্ছে editor তারা অন্যের পোস্ট গুলো দেখার পাশাপাশি edit করতে পারবে তবে delete করতে পারবেনা। আবার যাদের role যদি admin হয়, তারা চাইলে অন্যের পোস্ট গুলো edit এর পাশাপাশি delete ও করতে পারবে।

যেহেতু আমরা এই কাজটি সম্পূর্ণ নতুন ভাবে করব। তো চলুন প্রথমে আমরা সম্পূর্ণ নতুনভাবে আমাদের লারাভেল ফ্রেমওয়ার্ক টি ইনস্টল করে ফেলি।

Install Fresh Laravel

তো চলুন তার আগে আমরা একটা ফ্রেশ লারাভেল ইনস্টল করে ফেলি। আপনার পি সি তে যদি ইতিমধ্যে কোনো লারাভেল ইনস্টল না থাকে তাহলে প্রথমে কম্পোজার এর মাধ্যমে নিম্নোক্ত কমান্ড ব্যবহার করে লারাভেল টি ইনস্টল করে ফেলুন :

composer global require laravel/installer

একবার কম্পোজার গ্লোবালি ইনস্টল হয়ে গেলে, নিম্নোক্ত আর্টিসান কমান্ড ব্যবহার করে একটি নতুন লারাভেল প্রজেক্ট তৈরি করুন:

laravel new your-project-name

এবার আপনার লারাভেল প্রজেক্টের , .env ফাইলটি খুলুন এবং আপনার ডাটাবেস বিষয়ক প্রয়োজনীয় সেটিংস সেট করুন। উদাহরণ স্বরূপ:

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

এরপরে, authentication এর জন্য প্রয়োজনীয় টেবিল তৈরি করতে database migrations রান করুন :

php artisan migrate

এবার Laravel authentication scaffolding install করার পালা। Laravel Framework এর জন্য একটি ui আর্টিসান কমান্ড প্রদান করে। আপনি একাধিক front-end presets যেমন “bootstrap,” “vue,” “react,” বা “none” (কোনও preset না করতে চাইলে) থেকে যেকোনো একটি বেছে নিতে পারেন ।

উদাহরণস্বরূপ, আপনি যদি আপনার front-end এর জন্য Bootstrap ব্যবহার করতে চান, তাহলে আর্টিসান কমান্ড টি হবে নিম্নরুপঃ

composer require laravel/ui
php artisan ui bootstrap --auth

এটি authentication এর জন্য প্রয়োজনীয় views, controllers এবং routes ইনস্টল করবে।

এবার আপনার fron-end assets যেমন CSS বা JavaScript গুলি কম্পাইল করতে হবে। আর এর জন্য আপনাকে নিম্নলিখিত কমান্ড চালাতে হবে :

npm install && npm run dev

এবার মূল কাজে আসা যাক:

Update users Table

এবার, (database/migrations ডিরেক্টরিতে অবস্থিত) সদ্য তৈরি হওয়া মাইগ্রেশন ফাইলটি খুলুন এবং নিম্নোক্ত কোড গুলো দিয়ে প্রতিস্থাপন করুন:

<?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('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->boolean('is_authenticated')->default(false); // Assuming you have an "is_authenticated" column.
            $table->enum('role', ['User', 'Editor', 'Admin'])->default('User');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};


Mastering Laravel with ReactJS Course

Create posts Table

এবার posts table তৈরির পালা। নিম্নোক্ত আর্টিসান কমান্ডের মাধ্যমে posts table এর জন্য একটি Migration File তৈরি করুন :

php artisan make:migration create_posts_table

এবার, (database/migrations ডিরেক্টরিতে অবস্থিত) সদ্য তৈরি হওয়া মাইগ্রেশন ফাইলটি খুলুন এবং নিম্নোক্ত কোড গুলো দিয়ে প্রতিস্থাপন করুন:

<?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->unsignedBigInteger('user_id');
            $table->string('title');
            $table->text('content');
            $table->boolean('is_published')->default(false);
            $table->timestamps();
            // Define foreign key constraint
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        });
    }

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


এবার নিম্নোক্ত command এর মাধ্যমে Migration File গুলো রান করে টেবিল দুটি তৈরি করে ফেলুন:

php artisan migrate

Create User Model and Post Model

আমাদের ইতিমধ্যে User নামে একটি বাইডিফল্ট Model রয়েছে এখন আমরা php artisan make:model Post কম্যান্ড ব্যবহার করে Post নামে একটি Model তৈরি করব। এবং সেই সাথে User এবং Post Model কে নিচের মতো করে আপডেট করে নিব:

User.php Model

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Models\Post;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];

    /**
     * Determine if the user is an admin.
     *
     * @return bool
     */
    public function isAdmin()
    {
        // Logic to determine if the user is an admin (e.g., check a 'role' column).
        return $this->role === 'admin';
    }

    // Define the relationship between User and Post
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

Post.php Model

<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'content',
        'is_published', // Assuming you have a field to track if a post is published.
        'user_id', // Assuming you have a foreign key to associate posts with users.
    ];

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

    // Define an accessor to check if the post is published.
    public function getIsPublishedAttribute()
    {
        return $this->attributes['is_published'] === 1;
    }
}

আমাদের users এবং posts table তৈরির কাজ শেষ। এখন আমরা কিছু dummy data তৈরি করব। প্রথমে নিম্নোক্ত কমান্ডের মাধ্যমে users table এর জন্য একটি seed file তৈরি করুন :

php artisan make:seeder UsersTableSeeder

এবার, (database/seeders ডিরেক্টরিতে অবস্থিত) সদ্য তৈরি হওয়া seeder ফাইলটি খুলুন এবং নিম্নোক্ত কোড গুলো দিয়ে প্রতিস্থাপন করুন:

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        User::create([
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'password' => Hash::make('password'),
            'role' => 'User',
        ]);

        User::create([
            'name' => 'Jane Smith',
            'email' => 'jane@example.com',
            'password' => Hash::make('password'),
            'role' => 'User',
        ]);

        User::create([
            'name' => 'Masud Alam',
            'email' => 'masud.eden@gmail.com',
            'password' => Hash::make('password'),
            'role' => 'Admin',
        ]);

        User::create([
            'name' => 'Sohel Alam',
            'email' => 'sohel@gmail.com',
            'password' => Hash::make('password'),
            'role' => 'Editor',
        ]);

    }
}

আমাদের users table এর জন্য প্রয়োজনীয় dummy data তৈরির কাজ শেষ। এখন আমরা posts table এর জন্য কিছু dummy data তৈরি করব। প্রথমে নিম্নোক্ত কমান্ডের মাধ্যমে posts table এর জন্য একটি seed file তৈরি করুন :

php artisan make:seeder PostsTableSeeder

এবার, (database/seeders ডিরেক্টরিতে অবস্থিত) সদ্য তৈরি হওয়া seeder ফাইলটি খুলুন এবং নিম্নোক্ত কোড গুলো দিয়ে প্রতিস্থাপন করুন:

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Post;

class PostsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $user1 = User::where('email', 'john@example.com')->first();
        $user2 = User::where('email', 'jane@example.com')->first();

        Post::create([
            'user_id' => $user1->id,
            'title' => 'First Post',
            'content' => 'This is the content of the first post.',
        ]);

        Post::create([
            'user_id' => $user2->id,
            'title' => 'Second Post',
            'content' => 'This is the content of the second post.',
        ]);
    }
}

এবার নিম্নোক্ত কমান্ডের মাধ্যমে seed file দুটি রান করুন:

php artisan db:seed --class=UsersTableSeeder
php artisan db:seed --class=PostsTableSeeder

মোটামুটি আমাদের প্রয়োজনীয় Model, database table এবং dummy data তৈরির কাজ শেষ। এবার আমরা একজন ইউজার লগিনের পর সব গুলো post কে যেন একটি টেবিল এ লিস্ট আকারে দেখতে পায় , সে কাজটি করব :

প্রথমে চলুন আমরা আমাদের প্রয়োজনীয় Route গুলো লিখে ফেলি :

use App\Http\Controllers\PostController;

//Show all posts
Route::get('/', [PostController::class, 'index'])->name('posts.list');

// Route to display the create post form

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

// View a post
Route::get('/posts/{post}', [PostController::class, 'view'])->name('posts.view');

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

// Edit an existing post
Route::get('/posts/{post}/edit', [PostController::class, 'edit'])->name('posts.edit');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('posts.update');

// Delete a post
Route::get('/posts/{post}/delete',  [PostController::class, 'delete'])->name('posts.delete');
Route::delete('/posts/{post}',  [PostController::class, 'destroy'])->name('posts.destroy');

Make a Policy

এবার আমরা একটি policy তৈরি করব। যেখানে আমরা নির্ধারণ করে দিব , আমাদের apps এর ইউজাররা কে কতটুকু এক্সেস পাবেন। Laravel Framework এ policy তৈরি করার জন্য আপনার terminal এ নিম্নোক্ত কমান্ডটি রান করুন :

php artisan make:policy PostPolicy

কমান্ডটি রান করে থাকলে , এতক্ষনে আপনার app ফোল্ডারের মধ্যে policies/PostPolicy.php নামে একটি ক্লাস ফাইল তৈরি হয়েগেছে। এখন এই policies/PostPolicy.php ফাইল কে নিচের মতো করে আপডেট করেন। মানে আপনি আপনার ইউজারদের পোস্ট গুলোতে একসেস এর ক্ষেত্রে কে কতটুকু এক্সেস পাবে সেটি নিচের মতো করে লিখে /আপডেট করে দিন।

Note:আর যেহেতু আমরা User এবং Post দুটি Model কেই এখানে ব্যবহার করতে হবে। তাই Model দুটি কে সবার উপরে use করতে ভুলবেন না।

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    public function viewList(User $user)
{
    // Check if the user is authenticated (any authenticated user can view the list)
    return $user->is_authenticated; // You should replace 'is_authenticated' with the actual authentication check
}


    public function view(User $user, Post $post)
    {
        // Logic to determine if the user can view the post.
        // For example, allow if the post is published or if the user is the author.
        return $post->is_published || $user->id === $post->user_id;
    }

    public function create(User $user)
    {
        // Logic to determine if the user can create a post.
        // For example, allow if the user is authenticated (any authenticated user can create).
        return $user->is_authenticated;
    }
    

    public function update(User $user, Post $post)
    {
        // Logic to determine if the user can update the post.
        // For example, allow if the user is the author of the post.
        return $user->id === $post->user_id || $user->isAdmin() || $user->role=='Editor';
    }

    public function delete(User $user, Post $post)
    {
        // Logic to determine if the user can delete the post.
        // For example, allow if the user is the author of the post or has admin privileges.
        return $user->id === $post->user_id || $user->isAdmin();
    }
}

আমি প্রতিটি মেথডের ভিতরে সংশ্লিষ্ট মেথড এর কাজকে comment এর মধ্যে ব্যাখ্যা করে দিয়েছি। তাই আর এখানে নতুন করে ব্যাখ্যা করলামনা।

Register Your PostPolicy

এবার আপনার app/Providers/AuthServiceProvider.php ফাইলে protected $policies property এর মধ্যে নিচের মতো করে PostPolicy কে রেজিস্টার করুন :

<?php

namespace App\Providers;

// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    /**
     * Register any authentication / authorization services.
     */
    public function boot(): void
    {
        //
    }
}

Create PostController and Assign Laravel PostPolicy

প্রথমে আমরা নিম্নোক্ত কম্যান্ড এর মাধ্যমে আমাদের PostController টি তৈরি করব:

php artisan make:controller PostController

কমান্ডটি রান করে থাকলে , এতক্ষনে আপনার app ফোল্ডারের মধ্যে controllers/PostController.php নামে একটি ক্লাস ফাইল তৈরি হয়েগেছে। এখন এই PostController.php ফাইলে নিচের মতো করে আপডেট করে নিন। এবং PostPolicy তে অবস্থিত authorization Method গুলোকে $this->authorize() দিয়ে ব্যবহার করুন :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;
use Illuminate\Support\Facades\Auth;
use Illuminate\Auth\Access\AuthorizationException;
class PostController extends Controller
{
     /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
    
    public function index()
    {
        // Retrieve all posts from the database
        $posts = Post::orderBy('created_at', 'desc')->paginate(10);
    
        // Return the view with the posts data
        return view('posts.index', compact('posts'));
    }

    public function view(Post $post)
    {
        // Authorize the view action using the PostPolicy
        $this->authorize('view', $post);

        // View logic:
        // Display the post content.
        return view('posts.view', compact('post'));
    }

    public function create()
    {
        // Authorize the create action using the PostPolicy
        $this->authorize('create', Post::class);
    
        // Create logic:
        // Show a form to create a new post.
        return view('posts.create');
    }
    

    public function store(Request $request)
    {
        // Validate the request data
        $validatedData = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
            'is_published' => 'boolean',
        ]);

        // Create the post with the user as the author.
        $post = new Post();
        $post->user_id = Auth::id(); // Assign the current user as the author.
        $post->title = $validatedData['title'];
        $post->content = $validatedData['content'];
        $post->is_published = isset($validatedData['is_published']) ? true : false;
        $post->save();

        // Redirect to the post view page or some other appropriate action.
        return redirect()->route('posts.view', ['post' => $post->id]);
    }

    public function edit(Post $post)
    {
        // Authorize the update action using the PostPolicy
        $this->authorize('update', $post);

        // Edit logic:
        // Show an edit form for the post.
        return view('posts.edit', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
        // Authorize the update action using the PostPolicy
        $this->authorize('update', $post);

        // Validate the request data
        $validatedData = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
            'is_published' => 'boolean',
        ]);

        // Update the post based on the submitted form data.
        $post->title = $validatedData['title'];
        $post->content = $validatedData['content'];
        $post->is_published = isset($validatedData['is_published']) ? true : false;
        $post->save();

        // Redirect to the post view page or some other appropriate action.
        return redirect()->route('posts.view', ['post' => $post->id]);
    }

    public function delete(Post $post)
    {
        // Authorize the delete action using the PostPolicy
        $this->authorize('delete', $post);

        // Delete logic:
        // Show a confirmation page for deleting the post.
        return view('posts.delete', compact('post'));
    }

    public function destroy(Post $post)
    {
        // Authorize the delete action using the PostPolicy
        $this->authorize('delete', $post);

        // Delete the post.
        $post->delete();

        // Redirect to a post list or some other appropriate action.
        return redirect()->route('posts.index');
    }
}

Mastering Laravel with ReactJS Course

Create Blade Files

আমরা laravel/ui এবং ui bootstrap –auth ইনস্টল করার ফলে আমাদের প্রজেক্টের resources/views/layouts ফোল্ডারের মধ্যে মাস্টার টেম্পলেট হিসেবে app.blade.php টি তৈরি হয়ে আছে । আমরা আমাদের পরবর্তী প্রতিটি view ফাইল এ এটিকে আমরা master template হিসেবে ব্যবহার করব।

Create index.blade.php File

এখন আমরা আমাদের সবগুলো Post কে লিস্ট আকারে দেখানোর জন্য resources/views/posts ফোল্ডারে index.blade.php ফাইলে নিম্নোক্ত কোড গুলো লিখব :

@extends('layouts.app') {{-- Assuming you have a layout template --}}

@section('content')
    <div class="container">
        <h2>All Posts</h2>
        <a href="{{ route('posts.create') }}" class="btn btn-primary mb-3">Add New Post</a>

        @foreach ($posts as $post)
            @can('view', $post)
                <div class="card mb-3">
                    <div class="card-header">
                        <h2><a href="{{ route('posts.view', ['post' => $post->id]) }}">{{ $post->title }}</a></h2>
                    </div>
                    <div class="card-body">
                        <p>Published on {{ $post->created_at->format('F j, Y') }}</p>
                        <p>{!! nl2br(e(Str::limit($post->content, 200))) !!} <a href="{{ route('posts.view', ['post' => $post->id]) }}">Read more</a></p>
                    </div>
                </div>
            @endcan
        @endforeach

        {{ $posts->links() }} {{-- Pagination links --}}
    </div>
@endsection

Note:যেহেতু এখানে প্রত্যেক ইউজার অন্য ইউজারের পোস্ট গুলো দেখতে পাবে , তাই এখানে কোনো রকমের policy চেক করার দরকার হয় নাই।

এখন যদি আপনি http://localhost:8000/ এই URL এ হিট করেন , এবং আপনি যদি ইতিমধ্যে লগইন থাকেন তাহলে নিচের মতো করে সব ইউজারের লিস্ট দেখতে পাবেন :

Display Post List with Laravel Policy Authorization

Create view.blade.php File

এবার আমরা প্রত্যেকটি Post এর ডিটেলস দেখানোর জন্য resources/views/posts ফোল্ডারে view.blade.php ফাইল তৈরি করব। তবে এখানে আমরা কিছু অতিরিক্ত কাজ করতে হবে। আর সেটি হচ্ছে authorize ইউজার ছাড়া যেন অন্য ইউজাররা কোন post কে edit বা delete করতে না পারে, সে জন্য আমরা @can এবং @endcan এই দুটি Blade Directive ব্যবহার করব।

@extends('layouts.app') {{-- Assuming you have a layout template --}}

@section('content')
    <div class="container">
        <h2>{{ $post->title }}</h2>
        <p>Published on {{ $post->created_at->format('F j, Y') }}</p>

        <div class="post-content">
            {!! nl2br(e($post->content)) !!}
        </div>

        @can('update', $post)
            <p><a href="{{ route('posts.edit', ['post' => $post->id]) }}">Edit Post</a></p>
        @endcan

        @can('delete', $post)
            <form action="{{ route('posts.destroy', ['post' => $post->id]) }}" method="POST">
                @csrf
                @method('DELETE')
                <button type="submit" class="btn btn-danger">Delete Post</button>
            </form>
        @endcan
    </div>
@endsection

এখন যদি আপনি Post Title অথবা Read More লিংকে ক্লিক করেন। তাহলে নিচের মতো দেখতে পাবেন:

See Post Details with Authorization

এখানে ইউজার নিজেই নিজের পোস্টে এক্সেস করাতে Edit এবং Delete এর সুযোগ পেয়েছে। এছাড়াও যদি কোনো Admin Role ধারী এক্সেস করে, সেও Edit এবং Delete এর সুযোগ পাবে। অন্যদিকে যদি কোনো Editor Role ধারী এক্সেস করে সেক্ষেত্রে সে শুধু Edit এর সুযোগ পাবেন কিন্তু পোস্টটি Delete করতে পারবেন না।

Creeate create.blade.php File

এবার আমরা নতুন Post তৈরির জন্য resources/views/posts ফোল্ডারে create.blade.php ফাইল তৈরি করব। যেহেতু আমরা প্রত্যকে ইউজারকে নতুন পোস্ট তৈরি করতে দিব , তাই এখানে Post Policy এর কোনো কিছু এপলাই করার দরকার নাই।

@extends('layouts.app') {{-- Assuming you have a layout template --}}

@section('content')
    <div class="container">
        <h2>Create a New Post</h2>

        <form method="POST" action="{{ route('posts.store') }}">
            @csrf

            <div class="form-group">
                <label for="title">Title</label>
                <input type="text" id="title" name="title" class="form-control" value="{{ old('title') }}" required>
            </div>

            <div class="form-group">
                <label for="content">Content</label>
                <textarea id="content" name="content" class="form-control" rows="5" required>{{ old('content') }}</textarea>
            </div>

            <div class="form-check">
                <input type="checkbox" id="is_published" name="is_published" class="form-check-input" value="1" {{ old('is_published') ? 'checked' : '' }}>
                <label class="form-check-label" for="is_published">Publish this post</label>
            </div>

            <button type="submit" class="btn btn-primary">Create Post</button>
        </form>
    </div>
@endsection

এখন যদি আপনি Add New Post বাটনে ক্লিক করেন। তাহলে নিচের মতো দেখতে পাবেন:

Add New Post without Post Policy Authorization

Creeate edit.blade.php File

এবার আমরা Post কে আপডেট এর সুযোগ দেওয়ার জন্য resources/views/posts ফোল্ডারে edit.blade.php ফাইল তৈরি করব।

@extends('layouts.app') {{-- Assuming you have a layout template --}}

@section('content')
    <div class="container">
        <h2>Edit Post</h2>

        <form method="POST" action="{{ route('posts.update', ['post' => $post->id]) }}">
            @csrf
            @method('PUT')

            <div class="form-group">
                <label for="title">Title</label>
                <input type="text" id="title" name="title" class="form-control" value="{{ old('title', $post->title) }}" required>
            </div>

            <div class="form-group">
                <label for="content">Content</label>
                <textarea id="content" name="content" class="form-control" rows="5" required>{{ old('content', $post->content) }}</textarea>
            </div>

            <div class="form-check">
                <input type="checkbox" id="is_published" name="is_published" class="form-check-input" value="1" {{ $post->is_published ? 'checked' : '' }}>
                <label class="form-check-label" for="is_published">Publish this post</label>
            </div>

            <button type="submit" class="btn btn-primary">Update Post</button>
        </form>
    </div>
@endsection

এখন যদি আপনি Edit Post লিংকে ক্লিক করেন। তাহলে নিচের মতো দেখতে পাবেন:

Edit Post with Policy Authorization

আমি মাসুদ আলম, বাংলাদেশের ৩৬ তম Zend Certified Engineer । ২০০৯ সালে কম্পিউটার সাইন্স থেকে বেচেলর ডিগ্রী অর্জন করি। দীর্ঘ ১৫ বছর আমি Winux Soft, SSL Wireless, IBCS-PRIMAX, Max Group, Canadian International Development Agency (CIDA), Care Bangladesh, World Vision, Hellen Keller, Amarbebsha Ltd সহ বিভিন্ন দেশি বিদেশী কোম্পানিতে ডেটা সাইন্স, মেশিন লার্নিং, বিগ ডেটা, ওয়েব ডেভেলপমেন্ট এবং সফটওয়্যার ডেভেলপমেন্ট এর উপর বিভিন্ন লিডিং পজিশন এ চাকরি এবং প্রজেক্ট লিড করি। এছাড়াও বাংলাদেশের ১৮৫ জন জেন্ড সার্টিফাইড ইঞ্জিনিয়ার এর মধ্যে ১২০ এরও অধিক ছাত্র আমার হাতে জেন্ড সার্টিফাইড ইঞ্জিনিয়ার হয়েছেন। বর্তমানে w3programmers ট্রেনিং ইনস্টিটিউট এ PHP এর উপর Professional এবং Advance Zend Certified PHP -8.2 Engineering, Laravel Mastering Course with ReactJS, Python Beginning To Advance with Blockchain, Machine Learning and Data Science, Professional WordPress Plugin Development Beginning to Advance কোর্স করাই। আর অবসর সময়ে w3programmers.com এ ওয়েব টেকনোলজি নিয়ে লেখালেখি করি।

Leave a Reply