Symfonyの機能を使ったカスタマイズ
概要
EC-CUBEは、SymfonyやDoctrineをベースに開発されています。 そのため、SymfonyやDoctrineが提供している拡張機構を利用することができます。
ここでは、代表的な拡張機構とその実装方法を紹介します。
Symfony Event
Symfonyのイベントシステムを利用することができます。
hello worldを表示するイベントリスナーを作成する
app/Customize/EventListener配下ににHelloListener.phpを作成します。
<?php
namespace Customize\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class HelloListener implements EventSubscriberInterface
{
public function onResponse(ResponseEvent $event): void
{
$response = $event->getResponse();
$response->setContent($response->getContent().'hello world');
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => 'onResponse',
];
}
}
作成後、画面を表示(どのページでも表示されます)し、hello worldが表示されていれば成功です。
表示されない場合は、bin/console cache:clear --no-warmupでキャッシュを削除してください。
また、bin/console debug:event-dispatcherで登録されているイベントリスナーを確認できます。
イベントに関する詳細は以下を参照してください。
Command
bin/consoleから実行できるコンソールコマンドを作成することが出来ます。
hello worldを表示するコマンドを作成する
app/Customize/Command配下にHelloCommand.phpを作成します。
<?php
namespace Customize\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class HelloCommand extends Command
{
// コマンド名
protected static $defaultName = 'acme:hello';
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
// hello worldを表示
$io->success('hello world');
}
}
$defaultNameはコマンド名を表します。$io->success('hello world')で、hello worldを表示します。
作成後、bin/consoleで実行することができます。
$ bin/console acme:hello
[OK] hello world
※ コマンドが認識されない場合は、bin/console cache:clear --no-warmupでキャッシュを削除してください。
Commandに関する詳細は以下を参照してください。
Doctrine Event
Doctrineのイベントシステムを利用することができます。
ショップ名にようこそを付与するイベントリスナーを作成する
app/Customize/Doctrine/EventSubscriber配下にHelloEventSubscriber.phpを作成します。
<?php
namespace Customize\Doctrine\EventSubscriber;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Events;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Eccube\Entity\BaseInfo;
#[AsDoctrineListener(event: Events::postLoad)]
class HelloEventSubscriber
{
public function postLoad(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if ($entity instanceof BaseInfo) {
$shopName = $entity->getShopName();
if (!str_contains($shopName, 'ようこそ')) {
$entity->setShopName('ようこそ '.$shopName.' へ');
}
}
}
}
作成後、トップページを開き、ようこそ [ショップ名] へが表示されていれば成功です。
表示されない場合は、bin/console cache:clear --no-warmupでキャッシュを削除してください。
ログを出力するイベントリスナーを作成する
app/Customize/Doctrine/EventSubscriber配下にLogEventSubscriber.phpを作成します。
<?php
namespace Customize\Doctrine\EventSubscriber;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Events;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Eccube\Entity\BaseInfo;
use Psr\Log\LoggerInterface;
#[AsDoctrineListener(event: Events::postLoad)]
class LogEventSubscriber
{
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function postLoad(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
// BaseInfoがロードされたらログを出力
if ($entity instanceof BaseInfo) {
$this->logger->info('Shop info loaded: '.$entity->getShopName(), [
'id' => $entity->getId(),
'time' => date('Y-m-d H:i:s')
]);
}
}
}
作成後、トップページを開きます。
その後、/var/www/html/var/log/のログファイルを確認すると、Shop info loaded・・・のログが出力されます。
表示されない場合は、bin/console cache:clear --no-warmupでキャッシュを削除してください。
イベントに関する詳細は以下を参照してください。
※ Doctrine Event Listeners and Subscribersでは、services.yamlでの設定方法が記載されていますが、EC-CUBEはDoctrineのイベントリスナーをコンテナへ自動登録します。そのため、services.yamlでの設定は不要です。
SymfonyのBundleを利用する
EC-CUBEへSymfony Bundle を直接導入するかどうかは、要件に応じて判断が必要です。 EC-CUBEのプラグインだけでは実現が難しい場合は、Symfony Bundle での利用を検討してください。
プラグインで Symfony Bundle を導入する場合
Web API プラグインの実装を参考にしてください。
- composer.json
composer.json に利用するBundleを記載します。
{
"name": "ec-cube/api42",
"version": "4.3.2",
"description": "Web API",
"type": "eccube-plugin",
"require": {
"ec-cube/plugin-installer": "^2.0",
"league/oauth2-server-bundle": "^0.5",
"nyholm/psr7": "^1.2",
"php-http/message-factory": "*",
"webonyx/graphql-php": "^14.0"
},
"extra": {
"code": "Api42",
"entity-namespaces": ["League\\Bundle\\OAuth2ServerBundle\\Model"]
}
}
- Bundle/ApiBundle.php
bundles.phpを追加してください。
namespace Plugin\Api42\Bundle;
use Plugin\Api42\DependencyInjection\ApiExtension;
use Plugin\Api42\DependencyInjection\Compiler\ApiCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ApiBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
$container->addCompilerPass(new ApiCompilerPass());
}
public function getContainerExtension(): ?ExtensionInterface
{
return new ApiExtension();
}
}
Bundleのファイルが必要です。
- Controller/Admin/OAuthController.php
必要なBundleのクラスを利用し、実装してください。
・・・
use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface;
use League\Bundle\OAuth2ServerBundle\Manager\ClientFilter;
use League\Bundle\OAuth2ServerBundle\Manager\ClientManagerInterface;
・・・
CustomizeディレクトリからSymfony Bundleをインストール #6141
EC-CUBE 4.3 から、Customizeディレクトリ配下に Symfony Bundle を配置して利用できるようになりました。
<?php
namespace Customize\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CustomizeBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
var_dump('hello world.');
}
}
app/Customize/Resource/config/bundles.php
<?php
return [
\Customize\Bundle\CustomizeBundle::class => ['all' => true],
];