本記事では、特定の機能をまとめておけるServiceの使い方と実装方法について紹介します。
Serviceを使うことで、特定の機能をControllerなどから分離することができます。これにより、コードの再利用性と保守性が高まり、管理が容易になります。EC-CUBEでは、支払いやカートに関する機能をまとめたServiceがデフォルトで多数実装されています。
特定のテキストを表示するServiceを作成し、Controllerで呼び出す
まずは、特定の文字列 ” Hello 〇〇! ” を出力するだけのシンプルなサービスを実装してみます。
以下のGreeingServiceクラスを定義したファイルを作成し、「app/Customize/Service」に保存します。(Serviceフォルダはデフォルトでは用意されていないので、フォルダも新しく作成します。)
<?php
namespace Customize\Service;
class GreetingService
{
public function getGreeting(string $name): string
{
return "Hello, " . $name . "!";
}
}
次に、作成したServiceをControllerで呼び出して実行します。
今回は、TestControllerという独自に準備したコントローラを使用します。
<?php
namespace Customize\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;
use Customize\Service\GreetingService;
class TestController extends AbstractController
{
/**
* @Route("/test", name="test")
* @Template("test.twig")
*/
public function index(Request $request, GreetingService $greetingService)
{
$greeting = $greetingService->getGreeting('Taro');
return [
'Greeting' => $greeting
];
}
}
先ほど作成したGreetingService
をindexメソッドの引数として受け取ることでサービスを使用できます。getGreetingメソッドの引数にはTaroを指定し、「Hello, Taro!」を$greetingに代入しています。
最後に、TwigテンプレートでConrollerから受け取った変数Greetingを表示させ、GreetingService
が機能しているか確認します。
{% extends 'default_frame.twig' %}
{% block main %}
<h1>Serviceのテストページです</h1>
<p>{{ Greeting }}</p>
{% endblock %}
想定通り「Hello, Taro!」が表示されました!
特定の商品情報を取得するServiceを作成し、Controllerで呼び出す
今度は、IDから特定の商品を検索し、商品名と商品説明を取得するServiceを実装してみます。
以下のGetProductServiceクラスを定義したファイルを作成し、「app/Customize/Service」に保存します。
<?php
namespace Customize\Service;
use Eccube\Repository\ProductRepository;
class GetProductService
{
private $productRepository;
public function __construct(ProductRepository $productRepository)
{
$this->productRepository = $productRepository;
}
public function getProduct($productId)
{
$product = $this->productRepository->find($productId);
return [
'name' => $product->getName(),
'description' => $product->getDescriptionDetail(),
];
}
}
Serviceクラス内でProductRepositoryを呼び出し、findメソッドを利用しています。(Repositoryについては こちらの記事 にて。)
作成したServiceはConrollerで実行し、先ほどと同様Twigテンプレートで表示させてみます。
getProductメソッドの引数には「1」を指定し、ID=1の商品を取得します。
<?php
namespace Customize\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;
use Customize\Service\GetProductService;
class TestController extends AbstractController
{
/**
* @Route("/test", name="test")
* @Template("test.twig")
*/
public function index(Request $request, GetProductService $productService)
{
$product = $productService->getProduct(1);
return [
'ProductName' => $product['name'],
'ProductDescription' => $product['description'],
];
}
}
{% extends 'default_frame.twig' %}
{% block main %}
<h1>Serviceのテストページです</h1>
<p>{{ ProductName }}</p>
<p>{{ ProductDescription }}</p>
{% endblock %}
想定通り、ID=1の商品名と商品説明を表示できました!
本記事のような簡単な実装であれば、わざわざServiceクラスを作らずにControllerですべて実装すれば良いのでは?と思われるかもしれませんが、機能が複雑になったり、関連する機能を纏めたり、複数のControllerで使用したりする場合に便利な機能ですね。