Skip to content

Instantly share code, notes, and snippets.

@YugalXD
Last active October 22, 2024 10:34
Show Gist options
  • Save YugalXD/f66f714f1ca60fb4ec4826d4fda97030 to your computer and use it in GitHub Desktop.
Save YugalXD/f66f714f1ca60fb4ec4826d4fda97030 to your computer and use it in GitHub Desktop.

Filament Admin Panel Introduction

Objective:

  • Install and configure Filament in the Laravel project.
  • Create a basic CRUD interface using Filament.
  • Customize Filament resources (forms, tables) for a specific model.
  • Apply role-based access control for the admin panel.

Step 1: Install Filament in Laravel

Filament is a lightweight admin panel generator that allows you to create and manage resources easily. It is designed specifically for Laravel and integrates well with the Eloquent ORM.

Step 1.1: Install Filament In the terminal, run the following command to install Filament via Composer:

composer require filament/filament

Step 1.2: Publish Filament Assets Once installed, publish the Filament configuration and assets:

php artisan filament:install

This command will create necessary configuration files and assets for Filament.

Step 1.3: Run Migrations Filament also requires some database migrations for user roles and permissions. Run the migrations to set up these tables:

php artisan migrate

Step 1.4: Access the Admin Panel Now, start the Laravel development server:

php artisan serve

Visit http://127.0.0.1:8000/admin to access the Filament admin panel. You should see the Filament login page. Create a user by registering or logging in with an existing user.


Step 2: Creating a Filament Resource for a Model

We’ll now create a Filament resource to manage a model, like Post.

Step 2.1: Create the Post Model and Migration

If you don’t already have the Post model from Day 2, you can create it using Artisan:

php artisan make:model Post -m

Edit the migration file in database/migrations to add the necessary fields for the posts table:

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

Run the migration:

php artisan migrate

Step 2.2: Generate a Filament Resource

Use the following command to generate a Filament resource for the Post model:

php artisan make:filament-resource Post

This will generate a resource file located at app/Filament/Resources/PostResource.php along with default views for listing, creating, and editing posts.

Step 2.3: Customize the Post Resource

Open app/Filament/Resources/PostResource.php. You will see predefined configurations for fields and forms. Customize the table and form based on your needs.

  1. Defining Table Columns: Modify the table() method to define how the table should display the posts in the admin panel:

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('title')->sortable(),
                TextColumn::make('created_at')->dateTime()->label('Created'),
            ])
            ->filters([
                //
            ]);
    }
  2. Defining Form Fields: Modify the form() method to define the fields users will fill out when creating or editing posts:

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                TextInput::make('title')->required(),
                Textarea::make('content')->required(),
            ]);
    }

Step 3: Customize Filament Features (Forms, Tables)

Filament provides a range of tools to customize the admin panel’s look and feel. Here’s how you can extend the functionality of your admin panel.

Step 3.1: Adding Filters to the Table

You can add filters to the table to allow admins to quickly find posts based on certain criteria:

public static function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('title')->sortable(),
            TextColumn::make('created_at')->dateTime(),
        ])
        ->filters([
            SelectFilter::make('created_at')
                ->label('Filter by Date')
                ->options([
                    'today' => 'Today',
                    'this_week' => 'This Week',
                    'this_month' => 'This Month',
                ]),
        ]);
}

Step 3.2: Adding Validation to Forms

To ensure data integrity, add validation to the form fields. For example:

public static function form(Form $form): Form
{
    return $form
        ->schema([
            TextInput::make('title')
                ->required()
                ->maxLength(255)
                ->label('Post Title'),
            Textarea::make('content')
                ->required()
                ->label('Post Content'),
        ]);
}

Step 4: Implement Role-Based Access Control for the Admin Panel

You can restrict access to certain parts of the admin panel based on user roles.

Step 4.1: Add a Role Column to Users

If you haven’t already done so in Day 3, add a role column to the users table via migration:

php artisan make:migration add_role_to_users_table --table=users

Edit the migration to add the role column:

Schema::table('users', function (Blueprint $table) {
    $table->string('role')->default('user');
});

Run the migration:

php artisan migrate

Step 4.2: Assign Roles to Users

Manually update the role field in the database for users. You can use phpMyAdmin or any database management tool to assign the role of admin or user to each user.

Step 4.3: Restrict Access to the Admin Panel

To restrict access to the admin panel based on roles, open app/Providers/FilamentServiceProvider.php and modify the gate() method:

use Illuminate\Support\Facades\Gate;

public function boot()
{
    Filament::serving(function () {
        Gate::define('access-filament', function ($user) {
            return $user->role === 'admin';  // Only admins can access the admin panel
        });
    });
}

Now, only users with the admin role will have access to the Filament admin panel.


Step 5: Testing the Admin Panel

  1. Visit the Admin Panel: Visit http://127.0.0.1:8000/admin in your browser. If you are logged in as an admin, you should see the Post resource listed in the sidebar.

  2. Create, Edit, and Delete Posts:

    • Use the admin panel to create a new post.
    • Edit existing posts by clicking the “Edit” button.
    • Delete posts using the “Delete” button.
  3. Test Role-Based Access:

    • Log in as a user with the user role and try accessing the /admin route. You should be denied access.

Step 6: Additional Customizations (Optional)

Step 6.1: Customizing Admin Navigation

You can customize the navigation in the admin panel by modifying the PostResource.php file:

public static function getNavigationLabel(): string
{
    return 'Blog Posts';
}

Step 6.2: Creating Custom Pages or Widgets

Filament allows you to create custom pages and widgets within the admin panel. For example, you can create a dashboard with statistics about the posts or users.

  1. Generate a Dashboard Widget:

    php artisan make:filament-widget PostStatsWidget
    
  2. Customize the Widget: Edit the newly created widget in app/Filament/Widgets/PostStatsWidget.php to display statistics like total posts, recent posts, etc.


Outcome:

  • A fully functioning Filament admin panel.
  • CRUD operations implemented for the Post model using Filament.
  • Role-based access control applied to the admin panel.
  • Customized forms, tables, and navigation in the admin panel.



6: APIs in Laravel

Objective:

  • Understand the basics of RESTful APIs.
  • Build a REST API using Laravel for a resource (e.g., Post).
  • Implement API authentication using Laravel Sanctum.
  • Test the API endpoints with Postman or CURL.

Step 1: Introduction to RESTful APIs

What are RESTful APIs?

  • REST (Representational State Transfer) APIs follow a stateless, client-server architecture and use HTTP methods like GET, POST, PUT, and DELETE to interact with resources (such as models in Laravel).
  • Each resource is represented as a URL (endpoint) that the client interacts with.

Common HTTP Methods in REST APIs:

  • GET: Retrieve data from the server.
  • POST: Send data to the server to create a resource.
  • PUT/PATCH: Update an existing resource.
  • DELETE: Remove a resource from the server.

Step 2: Creating the API Routes and Controller

Step 2.1: Define API Routes

  1. Open routes/api.php: The api.php file is where you define all your API routes. By default, these routes are prefixed with /api.

  2. Define the Basic API Routes for the Post Model: Add the following routes to the api.php file for managing the Post resource:

    use App\Http\Controllers\API\PostController;
    
    Route::middleware('auth:sanctum')->group(function () {
        Route::get('/posts', [PostController::class, 'index']);
        Route::post('/posts', [PostController::class, 'store']);
        Route::get('/posts/{id}', [PostController::class, 'show']);
        Route::put('/posts/{id}', [PostController::class, 'update']);
        Route::delete('/posts/{id}', [PostController::class, 'destroy']);
    });

    These routes allow authenticated users to interact with the Post model via the API.


Step 2.2: Generate an API Controller

  1. Create the API Controller: Use Artisan to generate an API controller for the Post model:

    php artisan make:controller API/PostController --api
    

    This creates a controller in app/Http/Controllers/API/PostController.php.

  2. Implement CRUD Logic in the Controller: Open PostController.php and add the following logic:

    • Index Method (Retrieve all posts):

      public function index()
      {
          $posts = Post::all();
          return response()->json($posts);
      }
    • Store Method (Create a new post):

      public function store(Request $request)
      {
          $validated = $request->validate([
              'title' => 'required|string|max:255',
              'content' => 'required|string',
          ]);
      
          $post = Post::create($validated);
          return response()->json($post, 201);  // 201: Resource created
      }
    • Show Method (Retrieve a single post by ID):

      public function show($id)
      {
          $post = Post::findOrFail($id);
          return response()->json($post);
      }
    • Update Method (Update an existing post):

      public function update(Request $request, $id)
      {
          $validated = $request->validate([
              'title' => 'required|string|max:255',
              'content' => 'required|string',
          ]);
      
          $post = Post::findOrFail($id);
          $post->update($validated);
      
          return response()->json($post);
      }
    • Destroy Method (Delete a post):

      public function destroy($id)
      {
          $post = Post::findOrFail($id);
          $post->delete();
      
          return response()->json(['message' => 'Post deleted successfully'], 200);
      }

Step 3: Setting Up Authentication with Laravel Sanctum

To secure your API, we will use Laravel Sanctum for token-based authentication. Sanctum is a lightweight package that provides API token management and allows authenticated access to API routes.

Step 3.1: Install Laravel Sanctum

  1. Install Sanctum: Run the following command to install Laravel Sanctum:

    composer require laravel/sanctum
    
  2. Publish Sanctum Configuration: After installation, publish the Sanctum configuration file:

    php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
    
  3. Run Sanctum Migrations: Run the migrations to create the necessary tables for API tokens:

    php artisan migrate
    
  4. Add Sanctum Middleware: To ensure Sanctum handles API authentication, add the Sanctum middleware to api middleware group in app/Http/Kernel.php:

    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

Step 3.2: Issue API Tokens

  1. Create a Route for User Login: Add a route in routes/api.php to handle user login and issue an API token:

    Route::post('/login', function (Request $request) {
        $credentials = $request->only('email', 'password');
    
        if (Auth::attempt($credentials)) {
            $user = Auth::user();
            $token = $user->createToken('API Token')->plainTextToken;
            return response()->json(['token' => $token], 200);
        }
    
        return response()->json(['error' => 'Unauthorized'], 401);
    });
  2. Login and Retrieve Token: Use Postman or CURL to send a POST request to /api/login with valid credentials. If successful, you’ll receive an API token that can be used to authenticate subsequent requests.


Step 4: Testing API Endpoints

Step 4.1: Test API Endpoints with Postman or CURL

You can now test your API endpoints using Postman or CURL.

  1. Login to Get an API Token: Send a POST request to http://127.0.0.1:8000/api/login with the following JSON payload:

    {
        "email": "[email protected]",
        "password": "password"
    }

    If successful, you will receive a token in the response. Copy this token for use in subsequent requests.

  2. Use the Token to Access Protected Routes: In Postman or CURL, send requests to the protected API routes (/api/posts, /api/posts/{id}, etc.) with the token in the Authorization header.

    • Example CURL Request:

      curl -X GET http://127.0.0.1:8000/api/posts \
      -H "Authorization: Bearer YOUR_API_TOKEN"
      
    • Example Postman Request:

      • Set the Authorization type to "Bearer Token".
      • Paste the token you received from the login request.
      • Send a request to http://127.0.0.1:8000/api/posts to get the list of posts.

Step 4.2: Test Other API Endpoints

Test the following endpoints by sending corresponding requests:

  • Get All Posts (GET):

    curl -X GET http://127.0.0.1:8000/api/posts -H "Authorization: Bearer YOUR_API_TOKEN"
    
  • Create a New Post (POST):

    curl -X POST http://127.0.0.1:8000/api/posts -H "Authorization: Bearer YOUR_API_TOKEN" \
    -d '{"title": "New Post", "content": "This is the content of the new post."}'
    
  • Update an Existing Post (PUT):

    curl -X PUT http://127.0.0.1:8000/api/posts/1 -H "Authorization: Bearer YOUR_API_TOKEN" \
    -d '{"title": "Updated Title", "content": "Updated content."}'
    
  • Delete a Post (DELETE):

    curl -X DELETE http://127.0.0.1:8000/api/posts/1 -H "Authorization: Bearer YOUR_API_TOKEN"
    

Step 5: Testing and Error Handling

  1. Test Authentication Failures:

    • Try accessing protected routes without a token to ensure that they return a 401 Unauthorized response.
  2. Handle Validation Errors:

    • Ensure that invalid data (e.g., missing title

or content) triggers validation errors in the API response.


Outcome:

  • A fully functioning RESTful API for the Post model with CRUD operations.
  • API token-based authentication implemented using Laravel Sanctum.
  • Successful testing of API endpoints using Postman or CURL.

7: Advanced Features - Queues, Jobs, and Task Scheduling

Objective:

  • Understand and implement Laravel’s queue system to handle background tasks.
  • Create and dispatch jobs to perform tasks asynchronously.
  • Set up Laravel's task scheduler to automate recurring tasks.
  • Use workers to process queues efficiently.

Step 1: Introduction to Queues and Jobs in Laravel

What are Queues and Jobs?

  • Queues allow you to defer the processing of time-consuming tasks, such as sending emails, processing file uploads, or generating reports.
  • Jobs are the units of work that you want to run asynchronously. They are placed in a queue and processed by workers.
  • Laravel supports various queue drivers, including database, Redis, and Amazon SQS.

When to Use Queues:

  • For tasks that take a significant amount of time and would block the HTTP request-response cycle.
  • For tasks that need to be processed asynchronously, like sending notifications, file processing, or API calls.

Step 2: Setting Up the Queue System

Laravel has built-in support for queues and can use different backends (drivers) to manage them. For this guide, we'll use the database driver to store the jobs in the database.

Step 2.1: Configure Queue Driver

  1. Open the .env File: Set the queue driver to database in the .env file:

    QUEUE_CONNECTION=database
  2. Run the Queue Migration: Laravel provides a migration to create the jobs table. Run the migration to set up the table where queued jobs will be stored:

    php artisan queue:table
    php artisan migrate
    

Step 3: Creating and Dispatching Jobs

Step 3.1: Create a Job

  1. Generate a Job Class: Use the Artisan command to create a new job:

    php artisan make:job SendEmailJob
    

    This will create a job class located in app/Jobs/SendEmailJob.php.

  2. Define Job Logic: Open app/Jobs/SendEmailJob.php and define the task to be executed. For example, sending an email:

    <?php
    
    namespace App\Jobs;
    
    use App\Mail\NotifyUser;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Support\Facades\Mail;
    
    class SendEmailJob implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        protected $user;
    
        public function __construct($user)
        {
            $this->user = $user;
        }
    
        public function handle()
        {
            // Send email
            Mail::to($this->user->email)->send(new NotifyUser($this->user));
        }
    }

Step 3.2: Dispatch the Job

  1. Trigger the Job in a Controller: You can dispatch the job from a controller or anywhere else in your application. For example, in a controller method:

    use App\Jobs\SendEmailJob;
    use App\Models\User;
    
    public function sendEmailToUser($userId)
    {
        $user = User::find($userId);
    
        // Dispatch the job
        SendEmailJob::dispatch($user);
    
        return response()->json(['message' => 'Email queued successfully']);
    }

    This will place the SendEmailJob in the queue, and it will be processed asynchronously.


Step 4: Processing the Queue

Step 4.1: Start a Queue Worker

To process queued jobs, you need to run a queue worker that will monitor the queue and execute jobs.

  1. Run the Queue Worker: In a separate terminal window, run the following command to start the worker:

    php artisan queue:work
    

    This will start processing jobs in the queue. The worker listens for jobs placed in the queue and executes them as they arrive.

  2. Test the Queue:

    • Trigger the sendEmailToUser() method to dispatch a job.
    • Check that the queue worker processes the job and sends the email (or performs the intended task).

Step 4.2: Run the Queue Worker in Daemon Mode

For production, it’s common to run the queue worker as a daemon:

php artisan queue:work --daemon

This will keep the worker running indefinitely, processing jobs as they are added to the queue.


Step 5: Task Scheduling in Laravel

Laravel’s task scheduler allows you to schedule recurring tasks like sending out reports, cleaning up old data, or performing backups.

Step 5.1: Setting Up the Task Scheduler

  1. Open the app/Console/Kernel.php File: The schedule() method inside the Kernel.php file defines scheduled tasks.

  2. Define a Scheduled Task: For example, if you want to clean up old posts daily:

    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            \App\Models\Post::where('created_at', '<', now()->subDays(30))->delete();
        })->daily();
    }

    This will delete posts older than 30 days, every day.

Step 5.2: Running the Scheduler

  1. Set Up a Cron Job: To run the Laravel scheduler, you need to set up a cron job on your server. Open your server’s crontab file:

    crontab -e
    

    Add the following cron job to run the Laravel scheduler every minute:

    * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
    

    This command runs the Laravel scheduler every minute, allowing it to execute any tasks that are scheduled to run at that time.


Step 6: Handling Failed Jobs

It’s important to handle job failures gracefully. Laravel provides a built-in system to handle failed jobs and retry them.

Step 6.1: Configure Failed Job Handling

  1. Run the Failed Job Migration: Laravel provides a migration to create a table for storing failed jobs. Run the migration:

    php artisan queue:failed-table
    php artisan migrate
    
  2. Retry Failed Jobs: If a job fails, you can retry it using the following command:

    php artisan queue:retry all
    
  3. Manually View Failed Jobs: You can also view and manage failed jobs using the following commands:

    php artisan queue:failed  // View failed jobs
    php artisan queue:forget {job_id}  // Forget a failed job
    

Step 7: Testing and Debugging Jobs and Scheduled Tasks

Step 7.1: Test Queued Jobs

  1. Dispatch Jobs and Verify: Dispatch multiple jobs to the queue and verify that the queue worker processes them successfully.

    SendEmailJob::dispatch($user);
  2. Simulate Job Failures: Introduce a deliberate error in the SendEmailJob to simulate a job failure and check that the failed job is recorded.

Step 7.2: Test Scheduled Tasks

  1. Test Task Scheduling Locally: Use the schedule:run command to manually run the scheduler and verify that your scheduled tasks execute correctly.

    php artisan schedule:run
    
  2. Check the Cron Job: On production, ensure the cron job runs the scheduler every minute and your tasks are being executed at the defined intervals.


Outcome:

  • Queued jobs implemented using Laravel's queue system.
  • A working queue worker processing jobs in the background.
  • Task scheduling set up for automating recurring tasks.
  • Proper handling of failed jobs and job retries.



8: Performance Optimization

Objective:

  • Implement caching strategies to reduce load times and database queries.
  • Optimize database queries and relationships for better performance.
  • Apply general Laravel performance tips to enhance application speed.

Step 1: Caching in Laravel

What is Caching? Caching stores frequently accessed data in memory or disk to reduce repeated queries to the database or calculations, improving the speed of your application.

Laravel supports several caching drivers, such as file, database, Memcached, and Redis. For this guide, we will focus on file and Redis caching.

Step 1.1: Configure Cache Driver

  1. Set Cache Driver: Open your .env file and set the cache driver. You can use file for a basic setup or redis for a more advanced setup.

    CACHE_DRIVER=file  // For local development, use file caching
     or
    CACHE_DRIVER=redis  // For advanced caching, use Redis
  2. Install Redis (If Using Redis): If you are using Redis for caching, ensure that Redis is installed locally or on your server. You can install it with:

    sudo apt install redis-server
    
  3. Install PHP Redis Extension: If Redis is not already installed, use Composer to install the Redis package:

    composer require predis/predis
    

Step 1.2: Cache Data in Your Application

  1. Caching Database Queries: Instead of hitting the database every time for common queries, you can cache the results. Use the cache() helper in Laravel to store and retrieve cached data.

    For example, cache a list of posts:

    use Illuminate\Support\Facades\Cache;
    
    public function getAllPosts()
    {
        $posts = Cache::remember('posts', 60, function () {
            return Post::all();  // Query is only executed if cache is empty
        });
    
        return $posts;
    }

    This will store the result of the Post::all() query in the cache for 60 seconds. Subsequent calls within this time will return the cached result, avoiding additional database queries.

  2. Remove Cache when Data Changes: When the data changes (like when a post is added, updated, or deleted), you should clear the relevant cache:

    Cache::forget('posts');

Step 1.3: Cache API Responses

For heavy API responses, you can cache the response to reduce processing time:

  1. Cache API Response:

    use Illuminate\Support\Facades\Cache;
    
    public function index()
    {
        $response = Cache::remember('api.posts', 3600, function () {
            return response()->json(Post::all());
        });
    
        return $response;
    }

    This will cache the API response for an hour (3600 seconds).


Step 2: Database Query Optimization

Step 2.1: Use Eager Loading to Prevent N+1 Query Problem

The N+1 query problem happens when you fetch a model with related models, and each related model triggers a separate query. Eager loading helps to avoid this by loading related models in a single query.

  1. Eager Load Relationships: In your controller or query, use with() to eager load relationships:

    $posts = Post::with('comments')->get();  // This will load posts and their comments in one query

    Without eager loading, if you loop over the posts and access comments, it will trigger a query for each post.

Step 2.2: Use Select Statements to Limit Columns

If you don't need all columns from a table, retrieve only the necessary ones to reduce the size of the query result.

  1. Limit Columns in a Query: Instead of retrieving all fields with *, specify the columns you need:

    $posts = Post::select('id', 'title', 'created_at')->get();

    This reduces the load on the database and speeds up the query.

Step 2.3: Paginate Results

For large datasets, paginate the results to avoid loading too much data at once.

  1. Paginate Queries: Instead of fetching all records, use pagination to limit the number of records retrieved at once:

    $posts = Post::paginate(10);  // Fetches 10 posts at a time

    Pagination not only improves performance but also enhances user experience by loading data in chunks.


Step 3: Optimize Laravel Code

Step 3.1: Minimize Middleware Use

Middleware can add unnecessary overhead if used too often. Ensure middleware is only applied where absolutely necessary.

  1. Use Middleware Groups: Laravel allows you to group middleware, reducing the overhead:
    Route::middleware(['web', 'auth'])->group(function () {
        Route::get('/dashboard', [DashboardController::class, 'index']);
    });

Step 3.2: Use Chunk() for Processing Large Data Sets

When working with large datasets, processing them in chunks can significantly reduce memory usage.

  1. Process Data in Chunks: Instead of retrieving all records at once, process them in smaller chunks:

    Post::chunk(100, function ($posts) {
        foreach ($posts as $post) {
            // Process each post
        }
    });

    This reduces memory consumption and improves performance.


Step 4: Use Laravel Optimization Commands

Laravel provides a number of Artisan commands to optimize the application.

Step 4.1: Config and Route Caching

Caching configurations and routes can improve the performance of your application by reducing the need to parse the config and route files repeatedly.

  1. Cache Configuration Files: Run the following command to cache your configuration files:

    php artisan config:cache
    
  2. Cache Routes: To speed up routing, cache your routes:

    php artisan route:cache
    

Step 4.2: Optimize Class Autoloading

You can optimize the class autoloader for faster application loading using:

composer dump-autoload --optimize

Step 5: Use OPcache for PHP Optimization

OPcache improves PHP performance by storing precompiled script bytecode in memory, thus eliminating the need for PHP to load and parse scripts on each request.

Step 5.1: Enable OPcache

  1. Install and Enable OPcache: On most systems, you can install OPcache via PHP extensions. On Ubuntu, for example:

    sudo apt-get install php-opcache
    
  2. Configure OPcache in php.ini: Ensure OPcache is enabled in your PHP configuration:

    opcache.enable=1
    opcache.memory_consumption=128
    opcache.max_accelerated_files=10000
    opcache.revalidate_freq=2

Step 6: Testing and Profiling Performance

Step 6.1: Use Laravel Telescope (Optional)

Laravel Telescope is a debugging assistant that provides insights into your application’s performance, including queries, requests, and jobs.

  1. Install Laravel Telescope:

    composer require laravel/telescope
    php artisan telescope:install
    php artisan migrate
    
  2. Use Telescope to Monitor Performance: Visit /telescope to view performance metrics for requests, queries, and jobs.

Step 6.2: Use Blackfire or Xdebug for Profiling

Tools like Blackfire or Xdebug can help profile your application and identify bottlenecks.

  1. Install Blackfire: You can install Blackfire (a paid service) for profiling PHP applications: https://blackfire.io/docs

  2. Use Xdebug for Local Profiling: Set up Xdebug to profile your Laravel application and identify performance bottlenecks.


Step 7: Testing Performance Optimizations

After implementing each performance optimization, test the results to ensure they have a positive impact.

  1. Test Before and After:

    • Measure the load times and response times before applying optimizations.
    • Apply the optimizations incrementally and measure the impact after each change.
  2. Test with Large Datasets: Use large datasets in your application to ensure that your queries, caching, and chunking strategies work effectively under high load.


Outcome:

  • Caching strategies implemented for common queries and API responses.
  • Database queries optimized using eager loading, pagination, and chunking.
  • Laravel's Artisan optimization commands applied to speed up the application.
  • OPcache enabled to optimize PHP performance.



Day 9: Filament Deep Dive and Custom Widgets

Objective:

  • Understand how to create custom widgets in Filament.
  • Build a custom dashboard with widgets displaying important metrics.
  • Customize the Filament admin panel's appearance and behavior.
  • Implement role-based access to specific widgets.

Step 1: Introduction to Filament Customization

Filament is a highly customizable admin panel for Laravel, allowing you to create your own widgets and dashboards. Today, we’ll focus on creating custom widgets and using them on the admin dashboard to display useful data such as recent posts, user statistics, or other business-specific metrics.

What are Widgets in Filament? Widgets in Filament allow you to present information or metrics in a visually organized manner. You can place widgets on dashboards or custom pages.


Step 2: Create a Custom Widget in Filament

Let’s create a custom widget that displays statistics about the posts in the system.

Step 2.1: Generate a Widget Class

  1. Use Artisan to Create a New Widget: Run the following command to generate a widget:

    php artisan make:filament-widget PostStatsWidget
    

    This will create a widget class located at app/Filament/Widgets/PostStatsWidget.php.

  2. Define Widget Content: Open PostStatsWidget.php and customize the widget’s render() method. This widget will display the total number of posts:

    <?php
    
    namespace App\Filament\Widgets;
    
    use App\Models\Post;
    use Filament\Widgets\Widget;
    
    class PostStatsWidget extends Widget
    {
        protected static string $view = 'filament.widgets.post-stats-widget';
    
        public function getData(): array
        {
            return [
                'postCount' => Post::count(),
            ];
        }
    }
  3. Create the Widget Blade View: Create a view for the widget in the resources/views/filament/widgets directory and name it post-stats-widget.blade.php:

    <x-filament::widget>
        <x-filament::card>
            <h2 class="text-xl font-bold">Total Posts: {{ $postCount }}</h2>
        </x-filament::card>
    </x-filament::widget>

Step 2.2: Display Widget on the Dashboard

To display this widget on the dashboard, open app/Filament/Resources/DashboardResource.php (or wherever your main dashboard is defined) and register the widget:

  1. Modify the Dashboard to Include the Widget: In the app/Filament/Pages/Dashboard.php file (or similar file if the dashboard is elsewhere), add the widget:

    use App\Filament\Widgets\PostStatsWidget;
    
    public static function getWidgets(): array
    {
        return [
            PostStatsWidget::class,
        ];
    }
  2. Test the Widget: Visit the admin dashboard at http://127.0.0.1:8000/admin. You should see the custom widget showing the total number of posts.


Step 3: Adding Multiple Widgets to the Dashboard

Widgets can display various types of information, such as user statistics, recent activities, or other metrics.

Step 3.1: Create More Widgets

  1. User Stats Widget: Create another widget for displaying the total number of users:

    php artisan make:filament-widget UserStatsWidget
    
  2. Define Widget Logic: Open UserStatsWidget.php and define the logic to get the number of users:

    <?php
    
    namespace App\Filament\Widgets;
    
    use App\Models\User;
    use Filament\Widgets\Widget;
    
    class UserStatsWidget extends Widget
    {
        protected static string $view = 'filament.widgets.user-stats-widget';
    
        public function getData(): array
        {
            return [
                'userCount' => User::count(),
            ];
        }
    }
  3. Create the View for User Stats: Create a new view for the UserStatsWidget at resources/views/filament/widgets/user-stats-widget.blade.php:

    <x-filament::widget>
        <x-filament::card>
            <h2 class="text-xl font-bold">Total Users: {{ $userCount }}</h2>
        </x-filament::card>
    </x-filament::widget>
  4. Add the Widget to the Dashboard: Add this widget to the dashboard as well:

    use App\Filament\Widgets\UserStatsWidget;
    
    public static function getWidgets(): array
    {
        return [
            PostStatsWidget::class,
            UserStatsWidget::class,
        ];
    }
  5. Test Multiple Widgets: Visit the dashboard to see both the post and user stats widgets displayed.


Step 4: Customizing the Widget Layout

You can further customize how the widgets are displayed, including changing the layout and adding CSS or JavaScript for more interactive elements.

Step 4.1: Organize Widgets in a Grid Layout

  1. Define Grid Layout in Dashboard View: You can customize the layout of the dashboard by organizing the widgets in a grid. Open the Dashboard.php file and define a grid layout:

    public static function getWidgets(): array
    {
        return [
            PostStatsWidget::class => [
                'columnSpan' => 'full',
            ],
            UserStatsWidget::class => [
                'columnSpan' => 2,  // Span two columns
            ],
        ];
    }
  2. Customize Widget Blade Files: Adjust the Blade files to fit the grid layout, applying CSS for better alignment. You can use Tailwind CSS classes since Filament uses Tailwind for styling.


Step 5: Role-Based Access to Widgets

Filament allows you to control access to specific widgets based on user roles.

Step 5.1: Restrict Widget Access Based on Role

  1. Modify the Widget Class: In the PostStatsWidget.php and UserStatsWidget.php files, you can restrict access to the widgets based on the user’s role:

    public static function canView(): bool
    {
        return auth()->user()->role === 'admin';  // Only admins can see this widget
    }
  2. Test Role-Based Access:

    • Log in as an admin user and check that both widgets are visible.
    • Log in as a regular user and verify that the widgets are not displayed.

Step 6: Adding Custom Actions to Widgets

Widgets can also have custom actions, such as buttons that perform specific tasks (e.g., sending reports or clearing cache).

Step 6.1: Add a Button to the Post Stats Widget

  1. Modify the Widget to Include a Button: Open the PostStatsWidget and modify it to include a button that clears the post cache:

    public function clearPostCache()
    {
        Cache::forget('posts');
        $this->notify('success', 'Post cache cleared!');
    }
  2. Update the Widget View: In post-stats-widget.blade.php, add a button that triggers the cache clearing action:

    <x-filament::widget>
        <x-filament::card>
            <h2 class="text-xl font-bold">Total Posts: {{ $postCount }}</h2>
            <x-filament::button wire:click="clearPostCache">Clear Cache</x-filament::button>
        </x-filament::card>
    </x-filament::widget>
  3. Test Custom Actions: Visit the admin panel and click the "Clear Cache" button. Check that the post cache is cleared and the user is notified of the success.


Step 7: Testing and Debugging Custom Widgets

  1. Test Widget Functionality:

    • Test all widgets to ensure they display correct data.
    • Verify that any custom actions work as expected.
  2. Test Role-Based Access: Ensure that the widgets are only visible to users with the appropriate roles.

  3. Debugging: Use Laravel’s telescope or log functionality to debug any issues with data retrieval, widget rendering, or custom actions.


Step 8: Further Customization (Optional)

  1. Custom Widget Styles: Customize the look and feel of widgets by adding CSS to the Blade views or using Tailwind classes.

  2. Dynamic Widgets: Implement more dynamic widgets, such as charts or graphs, using JavaScript libraries like Chart.js or D3.js.

  3. Create Custom Pages: Beyond widgets, Filament allows you to create fully custom pages for more complex use cases. Use the make:filament-page Artisan command to generate a new page.


Oucome:

  • Custom widgets for the admin dashboard displaying key statistics (e.g., post and user stats).
  • Custom actions integrated into widgets (e.g., clearing the cache).
  • Role-based access control applied to specific widgets.
  • A customized and more user-friendly Filament dashboard.



Final task that we have to create https://gist.github.com/YugalXD/b60238777651d298e3f17b795b70e6c1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment