目次

サービスコンテナとサービスプロバイダ

一般的な構成の場合

以下に、サービスコンテナ、サービスプロバイダ、サービスクラス、コントローラクラス、モデルクラスを使用したコード例を示します。

1.サービスクラスの作成

// app/Services/PostService.php
 
namespace App\Services;
 
use App\Models\Post;
 
class PostService
{
    public function getAllPosts()
    {
        return Post::all();
    }
}

2.サービスプロバイダの作成と登録

// app/Providers/PostServiceProvider.php
 
namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
use App\Services\PostService;
 
class PostServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(PostService::class, function ($app) {
            return new PostService();
        });
    }
 
    public function boot()
    {
        //
    }
}

3.config/app.php の providers 配列に PostServiceProvider を追加して登録します。

// config/app.php
 
'providers' => [
    // ...
    App\Providers\PostServiceProvider::class,
],

4.モデルクラスの作成

// app/Models/Post.php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
    protected $fillable = ['title', 'body'];
}

5.コントローラクラスの作成

// app/Http/Controllers/PostController.php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use App\Services\PostService;
 
class PostController extends Controller
{
    protected $postService;
 
    public function __construct(PostService $postService)
    {
        $this->postService = $postService;
    }
 
    public function index()
    {
        $posts = $this->postService->getAllPosts();
        return view('posts.index', compact('posts'));
    }
}

6.ルーティングの設定

// routes/web.php

use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index']);

このコード例では、PostService サービスクラスを作成し、PostServiceProvider でサービスコンテナに登録しています。PostController コントローラクラスでは、コンストラクタインジェクションを使用して PostService のインスタンスを取得し、ビジネスロジックを実行しています。最後に、ルーティングでコントローラの index メソッドにリクエストをディスパッチしています。

記の例では、サービスプロバイダを使用してサービスコンテナへの登録を行っていますが、Laravelではサービスコンテナが自動的にクラスの依存関係を解決し、インスタンスを生成できます。従って、サービスプロバイダの作成とサービスコンテナへの登録がなくても、このケースでは動作します。

サービスプロバイダとサービスコンテナが生かせる場合

異なる実装やインターフェースを使用する場合の具体例として、メール送信機能を考えます。メール送信機能には、さまざまなメールサービス(SMTP、SendGrid、Mailgun など)を使用することができます。インターフェースと異なる実装を用いて、アプリケーションの構成を簡単に変更できるようにします。

1.インターフェースの作成

// app/Contracts/Mailer.php
 
namespace App\Contracts;
 
interface Mailer
{
    public function send(string $to, string $subject, string $body);
}

2.異なる実装の作成 SMTPを使った実装:

// app/Services/SmtpMailer.php
 
namespace App\Services;
 
use App\Contracts\Mailer;
 
class SmtpMailer implements Mailer
{
    public function send(string $to, string $subject, string $body)
    {
        // SMTPを使ってメールを送信するロジック
    }
}

3.SendGridを使った実装:

// app/Services/SendGridMailer.php
 
namespace App\Services;
 
use App\Contracts\Mailer;
 
class SendGridMailer implements Mailer
{
    public function send(string $to, string $subject, string $body)
    {
        // SendGridを使ってメールを送信するロジック
    }
}

4.サービスプロバイダの作成と登録

// app/Providers/MailServiceProvider.php
 
namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
use App\Contracts\Mailer;
use App\Services\SmtpMailer;
use App\Services\SendGridMailer;
 
class MailServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(Mailer::class, function ($app) {
            // 実装を切り替えるための条件分岐
            $mailer = config('mail.mailer');
            if ($mailer === 'smtp') {
                return new SmtpMailer();
            } elseif ($mailer === 'sendgrid') {
                return new SendGridMailer();
            }
 
            throw new \Exception('Invalid mailer configuration.');
        });
    }
 
    public function boot()
    {
        //
    }
}

5.config/app.php の providers 配列に MailServiceProvider を追加して登録します。

// app/Http/Controllers/MailController.php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use App\Contracts\Mailer;
 
class MailController extends Controller
{
    protected $mailer;
 
    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }
 
    public function sendMail()
    {
        $to = 'example@example.com';
        $subject = 'Test Mail';
        $body = 'This is a test mail.';
 
        $this->mailer->send($to, $subject, $body);
 
        return 'Mail sent.';
    }
}

この例では、メール送信機能のインターフェースMailerを定義し、異なる実装(SmtpMailerSmtpMailer と SendGridMailer)を作成しました。MailServiceProvider を使って、アプリケーションの設定に基づいて実装を切り替えることができます。

この方法の利点は、メール送信機能を使用するすべての箇所でインターフェース Mailer を使ってコーディングすることで、実装が柔軟に切り替えられる点です。例えば、メール送信サービスを変更したい場合、config/mail.php の設定を変更するだけで、アプリケーション全体で新しいメール送信サービスが適用されます。

サービスプロバイダとサービスコンテナを使用することで、アプリケーションの依存関係が一元管理され、コードの整理やメンテナンスが容易になります。また、アプリケーションの構成を変更することで、実装を簡単に切り替えることが可能です。