Magento 2は特性の依存性注入をサポートしていませんか?


8

トレイトは実際にMagentoの依存性注入で機能しますか?次のコードを検討してください。

特性クラス

namespace Frame\Slick\Block;
use Frame\Slider\Slick\Block\Data as Helper

trait Slick
{
   protected $_slickHelper;
   public function __construct(Helper $slickHelper) 
   {
     $this->_slickHelper = $slickHelper;
   }
}

トレイトを使用するクラス

namespace Frame\Slick\Block;

class Product ListProduct implements BlockInterface 
{
   use Slick;
   public function testTrait()
   {
      return $this->_slickHelper->getHelloWorld();
   }
}

これは常にnullを返すようです。すべてが適切に含まれていることを確信しています。トレイトは依存関係注入を本当にサポートできますか?

編集:たとえば、トレイトコンストラクターでdiを実行してトレイト変数に割り当て、そのトレイトを使用するクラスで呼び出した場合、常にnullが返されます。その他はすべて正常に動作します。


ただ1つの質問...「testTrait()」がnullを返すか、「$ this-> _ slickHelper」がnullですか?
Phoenix128_RiccardoT

$ this-> _ slickHelperはnullを返します。トレイトの他のメソッドは、トレイト変数に割り当てられたdiのみが機能しません。
アンドレ・Ferrazの

1
良い質問。MagentoはReflectionを使用してコンストラクターの引数を検査し、これはトレイト3v4l.org/jbVTUでうまく機能すると思いますが、コード生成を詳しく確認して確認する必要があります。
Fabian Schmengler、2016

しかし、なぜあなたは特性を使いたいのですか?実例を挙げていただけますか?多分それを回避するより簡単な方法があるでしょう
マリウス

@Marius私はこのモジュールを作成しました。このモジュールは、CMSブロック、クロスセル、(特定のカテゴリの)製品、およびアップセルのスライダーとして機能します。これらのブロッククラスのそれぞれが別のクラスを拡張します。たとえば、製品はMagento \ Catalog \ Block \ Product \ ListProductを拡張します。本当に私が特性を使用している理由は、それがPHPの単一継承アーキテクチャの「問題」を解決するためです。これにより、コードの繰り返しが少なくなります。
アンドレ・Ferrazの

回答:


2

私は特性を使用してテストしましたが、それは正常に動作します。

これが私の特性のようなものです:

<?php

namespace ProjectName\ModuleName\Controller\Adminhtml;

use Magento\Backend\App\Action\Context;
use ProjectName\ModuleName\Model\ResourceModel\Distributor\CollectionFactory as DistributorCollectionFactory;

trait DistributorTrait
{
    protected $distributorCollectionFactory;

    public function __construct(
        Context $context,
        DistributorCollectionFactory $distributorCollectionFactory
    )
    {
        parent::__construct($context);

        $this->distributorCollectionFactory = $distributorCollectionFactory;
    }
}

私はそれをこのようにコントローラーで使用します:

<?php

namespace ProjectName\ModuleName\Controller\Adminhtml\Distributor;

use Magento\Backend\App\Action;
use ProjectName\ModuleName\Controller\Adminhtml\DistributorTrait;

class Index extends Action
{
    use DistributorTrait;

    public function execute()
    {
        dump($this->distributorCollectionFactory->create()->getItems());exit;
    }
}

そしてここに結果があります:

特性テスト結果


0

私はちょうどこれに直面していました。元の投稿はかなり古いので、投稿されたときとは異なる場合がありますが、コンストラクターDIは機能しますが、かなり大きな注意事項があることがわかりました。

コードで次のトレイトを使用する場合:

<?php

namespace My\Module\Util;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
    protected $logger;

    public function __construct(
        LoggerInterface $logger
    ) {
        $this->logger = $logger;
    }

    /**
     * @return Logger
     */
    public function getLogger()
    {
        return $this->logger;
    }

    /**
     * @param Logger $logger
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
    }
}

その後、クラスでその特性を使用します。

<?php

namespace My\Module;

use \My\Module\Util\LoggerTrait;

class Service
{
    use LoggerTrait;

    public function doSomething() {
        $this->getLogger()->log('Something was done!');
    }
}

ロガーインターフェイスは完全に注入され、すべてが正常に動作します。ただし、コンストラクターメソッドを使用して自分のクラスをServiceクラスに挿入する場合。例えば:

<?php

namespace My\Module;

use \My\Module\Util\LoggerTrait;


class Service
{
    use LoggerTrait;

    public function __construct(
         \Some\Other\Class $class
    ) {
        $this->other = $class;
    }


    public function doSomething() {
        $this->getLogger()->log('Something was done!');
    }
}

この場合、私の特性のコンストラクタメソッドが呼び出されることはありません。つまり、クラスの$ loggerプロパティが設定されることはありません。確かに私はトレイトをあまり使用していないので、私の知識はある程度制限されていますが、これは私のクラスがトレイトのコンストラクターメソッドをオーバーライドしたためであると想定しています。ほとんどのMagentoコードベースは、依存関係を注入するためにコンストラクターを使用し、トレイトでの使用を効果的に排除しているため、これはかなりショーストッパーです。

これに対して私が理解できる唯一の実際の解決策は、ObjectManagerを直接使用して、特性の依存関係を注入することです。

<?php

namespace My\Module\Util;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
    protected $logger;


    /**
     * @return Logger
     */
    public function getLogger()
    {
        if (is_null($this->logger)) {
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $this->logger = $objectManager->create('Psr\Log\LoggerInterface');
        }
        return $this->logger;
    }

    /**
     * @param Logger $logger
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
    }
}

免責事項:MagentoでのObjectManagerの使用は一般的には推奨されませんが、私がこの例で見ることができることから、それが唯一の現実的なオプションです。私の例では、クラスに別のロガーインターフェイスを設定したい場合は、コンストラクターに注入し、クラスの$ loggerプロパティをオーバーライドすることで、それを行うことができます。


クラスで2を宣言しました__construct。1つはトレイトからインポートされ、もう1つはクラス自体にインポートされています。ただし、1つのクラスに同じ名前の2つのメソッドを含めることはできません。したがって、基本的にあなたのケースで__constructは、トレイトは__constructクラス自体によってオーバーライドされます。
Rendy Eko Prastiyo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.