LoginSignup
3
2

More than 3 years have passed since last update.

SymfonyでServiceにFactory Methodで生成したオブジェクトを注入する

Posted at

「ServiceにFactory Methodで生成したオブジェクト刺せたらいいなー」と調べたらできたのでメモ。
例として、Guzzleを利用し、Qiitaのプロフィール取得APIにアクセスして取得したユーザプロフィールを表示するものを作成しました。

まずはFactoryを作る。

GuzzleのClientを生成するFactoryを作ります。

src/Factory/HttpClientFactory
<?php

namespace App\Factory;

use GuzzleHttp\Client;

class HttpClientFactory
{
    public static function create($baseUri)
    {
        $httpClient = new Client(['base_uri' => $baseUri, 'timeout' => 2]);
        return $httpClient;
    }
}

HttpClientFactory::create('http://localhost:8080'); のような形でbase_uriを指定したClientオブジェクトを返します。

Serviceを作る

Qiitaから指定したユーザIDのプロフィールを取得するServiceを作ります。

src/Service/QiitaService.php
<?php

namespace App\Service;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;

class QiitaService
{
    private $client;
    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    public function getUser($userId)
    {
        try {
            $response = $this->client->get('api/v2/users/' . $userId);
            return json_decode((string) $response->getBody(), true);
        } catch (ClientException $e) {
            return null;
        }
    }
}

コンストラクタでClientのオブジェクトを引数としています。このオブジェクトを利用してQiitaのAPIにアクセスしますが、get()で呼び出しているURIはClientオブジェクトにbase_uriが指定されていないと正しく動作しません。では、このServiceにFactoryで生成したClientオブジェクトを注入してみましょう。

Service Containerの設定をする

Service Containerを設定してServiceにClientオブジェクトを注入します。

config/services.yaml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones
+
+    qiitaClient:
+        class: GuzzleHttp\Client
+        factory: ['App\Factory\HttpClientFactory', 'create']
+        arguments:
+            $baseUri: 'https://qiita.com'
+
+    App\Service\QiitaService:
+        arguments:
+            $client: '@qiitaClient'

まず、qiitaClientでQiita用のClientを生成する設定を行います。 factory: ['App\Factory\HttpClientFactory', 'create']を指定することで、HttpClientFactoryのcreate()メソッドを呼び出してくれます。argumentsにはcreate()メソッドの引数を指定します。ここでhttps://qiita.comを指定することで、Qiita用のClientオブジェクトを生成できます。

続いてQiitaServiceのargumentsに@qiitaClientを指定し、Qiita用のClientオブジェクトを注入します。これで完成です。さいごにControllerでこのServiceを使って、プロフィールを表示させます。

ControllerでServiceを使う

ControllerへはautowiringでServiceが注入されるので、こんな感じでOK。

src/Controller/UserController.php
<?php

namespace App\Controller;

use App\Service\QiitaService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class UserController extends AbstractController
{
    /** @var QiitaService  */
    private $qiitaService;

    public function __construct(QiitaService $qiitaService)
    {
        $this->qiitaService = $qiitaService;
    }

    /**
     * @param $userId
     * @return Response
     * @Route("/user/{userId}", name="user")
     */
    public function index($userId)
    {
        $user = $this->qiitaService->getUser($userId);
        return $this->render('user/index.html.twig', ['user' => $user]);
    }
}

で、実行した結果がこちら。

http://localhost:8000/user/ippey_s
result.png

バッチリQiitaからプロフィール情報を取得できました!

今回のサンプルはこちらに公開しています。
https://github.com/Ippey/factory-injection-test

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2