Drupalで既存のサービスを上書きする
Drupalのサービスとは
Drupalではカスタマイズ性を確保するためにD8から「サービス」という仕組み導入しています。
サービスはざっくりいうと、任意のクラスにサービス名という「名札」を付け、クラス名で直接呼び出すのを防ぐ仕組みです。
例えばDrupalのコアにはDrupal\Core\Language\LanguageManager
というクラスがあります。
このクラスを呼び出すには通常のPHPのやり方だと
use Drupal\Core\Language\LanguageManager;
$language_manager = new LanguageManager();
と書く必要がありますが、このクラスは/core/core.services.yml
で
language_manager:
class: Drupal\Core\Language\LanguageManager
arguments: ['@language.default']
のようにサービスとして登録されているので、
\Drupal::service('language_manager')
という風に呼び出すこともできます。コアやコントリビュートモジュールではほとんどの場合後者が使用されています。
サービスのメリット
これにはどのようなメリットがあるのでしょうか。
例えば、Drupalサイト開発中にLanguageManager
内の処理を一部だけ変更する必要が出てきたとします。
もし、コアやコントリビュートモジュールでLanguageManager
を直接呼び出していた場合、処理を変更するのは困難になります。
単純な方法としては
-
LanguageManager
クラスそのものを上書きする -
LanguageManager
に修正を加えたMyLanguageManager
を作り、呼び出し側でそちらを呼び出すように変更する
等があると思いますが、どちらにしてもコアやコントリビュートの一部に手を加えないといけません。画像は後者の方法で書き換える場合のイメージです。(白がカスタムモジュール、青はコアかコントリビュート。)コアやコントリビュートをがっつり書き換えてしまってますね。
逆にコアやコントリビュートモジュールのすべてがlanguage_manager
サービスを介してLanguageManager
を呼び出していた場合、ServiceProvider
というクラスを書くことでlanguage_manager
の紐付け対象をMyLanguageManager
に差し替えることができます。こちらはすべてカスタムコードで完結していますね。
つまりサービス = クラスそのものやクラスの呼び出し元を修正することなくオーバーライドできるようにする仕組みということですね。
開発中に修正したいコアやコントリビュートのコードが出てきた場合は、まずはその箇所がサービスとして登録されているかどうかを確認するのがおすすめです。(登録されてたらラッキー!)
サービスを上書きする方法
先程説明したように、サービスを上書きするには
MyLanguageManager
MyModuleServiceProvider
という2つのクラスを書く必要があります。
MyLanguageManager
こちらは既存クラスを上書きするためのクラスです。
- クラス名は適当でOK
- ディレクトリも多分適当でいい(既存クラスのディレクトリを真似られる場合はその方がベター)
namespace Drupal\my_module;
use Drupal\Core\Language\LanguageManager;
class MyLanguageManager extends LanguageManager {
// 上書きしたいメソッドだけ上書き.
function getCurrentLanguage($type = LanguageInterface::TYPE_INTERFACE) {
// 処理
}
}
MyModuleServiceProvider
こちらはサービスクラスの切り替えを指示するためのクラスです。
- クラス名は
[モジュール名]ServiceProvider
の形式にする - ディレクトリは
my_module/src/MyModuleServiceProvider.php
-
ServiceProviderBase
を継承する
namespace Drupal\my_module;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* Language Managerクラスのサービスを上書きする.
*/
class MyModuleServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
if ($container->hasDefinition('language_manager')) {
$definition = $container->getDefinition('language_manager');
$definition->setClass('Drupal\my_module\MyLanguageManager')
}
}
}
元のサービスは
arguments: ['@language.default']
の部分でlanguage.default
という他のサービスを引数にしてますが、そちらは何も明示しなくても勝手に引き継がれるようです。
というわけで、Drupalの既存のサービスを上書きする方法でした。
Author And Source
この問題について(Drupalで既存のサービスを上書きする), 我々は、より多くの情報をここで見つけました https://qiita.com/863/items/97d935a733369553144d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .