iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
自我挑戰組

我推的Laravel系列 第 15

【Day-14】我推的Laravel-進階篇-Service Container & Service Provider

  • 分享至 

  • xImage
  •  

簡介

Service Container

Service Container的觀念滿抽象的,以下是其觀念:

Laravel 的 Service Container(服務容器)是框架中一個關鍵的功能,它是一種依賴注入(Dependency Injection)和服務解析(Service Resolution)的容器。它有助於簡化依賴注入、服務解析和管理相依性的過程,使您能夠更輕鬆地構建可維護和可測試的應用程序 - ChatGPT

上一篇使用的

public function index(PostService $postService) {
    ...
}

PostService $postService 就是使用Service Container

當然也可以不只注入一個,如:

public function index(PostService $postService, Request $request) {
    ...
}

Service Provider

提供綁定功能,綁定甚麼?
在注入的時候,決定該綁定到哪個Class
接著看吧

實作

今天筆者想用這部影片
結合我們之前所使用的Post功能,增加限時貼文(expired_at)

  1. 修改Post表
  2. 新增PostRepositoryInterface
  3. 新增StoryRepository(限時貼文)和修改PostRepository
  4. 新增PostServiceProvider
  5. 註冊PostServiceProvider
  6. 測試

修改Post表

今天沿用前面使用的Post表,新增type、expired_at

database\migrations\2023_09_19_164215_create_posts_table.php

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->bigInteger('user_id')->default(0)->comment('關聯使用者')->index();
        $table->text('title');
        $table->text('content');
        $table->integer('views')->default(0)->comment('觀看數');
        $table->string('type', '20')->nullable();
        $table->timestamp('expired_at')->nullable();
        $table->timestamps();
        $table->softDeletes();
    });
}

在終端跑php artisan migrate:rollback && php artisan migrate
https://ithelp.ithome.com.tw/upload/images/20230928/20163286S3Z0n8MUzx.png

新增PostRepositoryInterface

https://ithelp.ithome.com.tw/upload/images/20230928/201632863KPWgIcfC4.png
手動建立PostRepositoryInterface
app\Interfaces\PostRepositoryInterface.php

<?php

namespace App\Interfaces;

interface PostRepositoryInterface
{
    public function get();

    public function create(array $data): void;
}

新增StoryRepository(限時貼文)和修改PostRepository

app\Repositories\PostRepository.php

<?php 
namespace App\Repositories;

use App\Interfaces\PostRepositoryInterface;
use App\Models\Post;
use Illuminate\Database\Eloquent\Collection;

class PostRepository implements PostRepositoryInterface
{
    public function get(): Collection
    {
        return Post::where('type', 'post')
        ->orderBy('id', 'desc')
        ->get();
    }

    public function create($data): void
    {
        $data['type'] = 'post';
        Post::create($data);
    }
}

app\Repositories\StoryRepository.php

<?php 
namespace App\Repositories;

use App\Interfaces\PostRepositoryInterface;
use App\Models\Post;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;

class StoryRepository implements PostRepositoryInterface
{
    public function get(): Collection
    {
        return Post::where('expired_at', '>', Carbon::now())
        ->where('type', 'story')
        ->orderBy('id', 'desc')
        ->get();
    }

    public function create($data): void
    {
        $data['expired_at'] = Carbon::now()->addDay();
        $data['type'] = 'story';
        Post::create($data);
    }
}

新增PostServiceProvider

php artisan make:provider PostServiceProvider
https://ithelp.ithome.com.tw/upload/images/20230928/20163286ji6QwULBJ8.png

app\Providers\PostServiceProvider.php

<?php

namespace App\Providers;

use App\Interfaces\PostRepositoryInterface;
use App\Repositories\PostRepository;
use App\Repositories\StoryRepository;
use Illuminate\Support\ServiceProvider;

class PostServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        $this->app->bind(PostRepositoryInterface::class, function ($app){
            if (request()->input('type') === 'story'){
                return new StoryRepository();
            } else {
                return new PostRepository();
                // default is normal post
            }
        });
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        //
    }
}

註冊PostServiceProvider

config\app.php 加入 App\Providers\PostServiceProvider::class,
https://ithelp.ithome.com.tw/upload/images/20230928/20163286QjcmY7MTTH.png

測試

新增post
https://ithelp.ithome.com.tw/upload/images/20230928/20163286vKRt2ixxHg.png
取得post
https://ithelp.ithome.com.tw/upload/images/20230928/201632863A6g00FM83.png
新增story
https://ithelp.ithome.com.tw/upload/images/20230928/20163286wCiSCWZGYj.png
取得story
https://ithelp.ithome.com.tw/upload/images/20230928/20163286HVJPIvGrVP.png

總結

本篇簡單有實際例子演示如何使用Service Provider,註冊PostRepository到Service Container中
並在Service Provider作了一些判斷來演示其中的發展性

如以下幾個例子,比較生活化能應用的到:
銀行、各第三方訊息API(Line、Telegram、Discord...)、File Cloud(AWS、GCP...)

  • 銀行: 付款、轉帳
  • 訊息API: 發送訊息、自動回復
  • File Cloud: 圖片、影音等

如果想多了解的話建議可以看開頭的影片,那我們下篇見~

參考

如何理解 Laravel 的 IoC 容器
Laravel 6 Advanced - e1 - Service Container


上一篇
【Day-13】我推的Laravel-進階篇-Service & Repository Pattern
下一篇
【Day-15】我推的Laravel-進階篇-Queue
系列文
我推的Laravel31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言