PurchaseFlowをカスタマイズしたい。
でも競合はできるだけ避けたい。
結論
app/Customize/Common/Collections/DecorativeArrayCollection.php
<?php
namespace Customize\Common\Collections;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class DecorativeArrayCollection extends ArrayCollection
{
public function __construct($elements = [])
{
$elements = ($elements instanceof Collection)
? $elements->toArray()
: $elements;
parent::__construct($elements);
}
}
app/config/eccube/packages/purchaseflow_customize.yaml
services:
eccube.purchase.flow.shopping.item_validators_decorate:
class: Customize\Common\Collections\DecorativeArrayCollection
decorates: eccube.purchase.flow.shopping.item_validators
arguments: ['@eccube.purchase.flow.shopping.item_validators_decorate.inner']
calls:
- [add, ['@Customize\Service\PurchaseFlow\Processor\CustomizeItemValidator']]
解説
本体ファイルの変更を避ける
- 本体ファイル(
app/config/eccube/packages/purchaseflow.yaml
)を変更するのは簡単だが、本体アップデートの追従の手間が増える。別ファイル(今回はapp/config/eccube/packages/purchaseflow_customize.yaml
)に記述する。 - 読み込み順は恐らくファイル名の昇順であるため、ファイル名に気をつける。(なんなら
z_purchaseflow.yaml
とかでもいい)
ServiceをDecorateする
- Decorateの説明はこちら https://symfony.com/doc/3.4/service_container/service_decoration.html
- 要は、元となるサービスをコンストラクタに渡して別のサービスに置き換える機能。
- しかしDoctrineのCollectionのコンストラクタにはarrayしか渡せない。そのためCollectionを受け取れる独自のCollection(今回はDecorativeArrayCollection)が必要。
-
calls
にて追加したい機能をadd
する。
おしまい。
追記
ある程度任意の順番にProcessorを挿入したい
こんな感じでいいんじゃないですか。しらんけど。
app/Customize/Common/Collections/DecorativeArrayCollection.php
<?php
namespace Customize\Common\Collections;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Eccube\Service\PurchaseFlow\Processor\PriceChangeValidator;
class DecorativeArrayCollection extends ArrayCollection
{
public function __construct($processor, $elements = [])
{
$elements = ($elements instanceof Collection)
? $elements->toArray()
: $elements;
/* 最初に挿入する
array_unshift($elements, $processor);
*/
/* 任意のクラスの後に挿入する
$newElements = [];
$inserted = false;
foreach ($elements as $element) {
$newElements[] = $element;
if ($element instanceof PriceChangeValidator) {
$newElements[] = $processor;
}
}
if (!$inserted) {
// 任意のクラスが存在しなかった場合の処理
}
*/
parent::__construct($elements);
}
}
app/config/eccube/packages/purchaseflow_customize.yaml
services:
eccube.purchase.flow.shopping.item_validators_decorate:
class: Customize\Common\Collections\DecorativeArrayCollection
decorates: eccube.purchase.flow.shopping.item_validators
arguments:
- '@Customize\Service\PurchaseFlow\Processor\CustomizeItemValidator'
- '@eccube.purchase.flow.shopping.item_validators_decorate.inner'