フィールドセットのフィールドを多依存性にする方法は?


7

私はフィールドセットの親と管理パネルのを選択する(5つのオプションを持っている)と2つのフィールド親値を選択する場合に表示されるべき、3、4または5であろう私はMagentoのに同様のロジックの例を見つけていませんそして、通常の依存関係を類推して書き込もうとしましたが、機能しません。私の例では、依存フィールドは、selectから値5のオプションを選択しているときにのみ表示され、1、2、3、または4を選択すると表示されません。

完全なコード(ブロックの例):

<?php

namespace Siarhey\Test\Block\Adminhtml\Promo\Quote\Edit\Tab;

class Actions extends \Magento\Backend\Block\Widget\Form\Generic implements
    \Magento\Backend\Block\Widget\Tab\TabInterface
{
    /**
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\Data\FormFactory $formFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        array $data = []
    ) {
        parent::__construct($context, $registry, $formFactory, $data);
    }

    public function getTabLabel()
    {
        return __('Actions');
    }

    public function getTabTitle()
    {
        return __('Actions');
    }

    public function canShowTab()
    {
        return true;
    }

    public function isHidden()
    {
        return false;
    }

    protected function _prepareForm()
    {
        $model = $this->_coreRegistry->registry('current_promo_quote_rule');

        /** @var \Magento\Framework\Data\Form $form */
        $form = $this->_formFactory->create();
        $form->setHtmlIdPrefix('rule_');

        $fieldset = $form->addFieldset(
            'action_fieldset',
            ['legend' => __('Rules')]
        );

        $parentField = $fieldset->addField(
            'simple_action',
            'select',
            [
                'label' => __('Apply'),
                'name' => 'simple_action',
                'options' => [
                    1 => __('Amount 1'),
                    2 => __('Discount 1'),
                    3 => __('Amount 2'),
                    4 => __('Discount 2'),
                ]
            ]
        );

        $childFieldOne = $fieldset->addField(
            'amount',
            'text',
            [
                'name' => 'amount',
                'required' => true,
                'class' => 'validate-not-negative-number',
                'label' => __('Amount')
            ]
        );
        $model->setAmount($model->getAmount() * 1);

        $childFieldTwo = $fieldset->addField(
            'percent',
            'text',
            ['name' => 'percent', 'label' => __('Percent')]
        );
        $model->setPercent($model->getPercent() * 1);

        $this->setChild(
            'form_after',
            $this->getLayout()->createBlock(
                'Magento\Backend\Block\Widget\Form\Element\Dependence'
            )->addFieldMap(
                $parentField->getHtmlId(),
                $parentField->getName()
            )->addFieldMap(
                $childFieldOne->getHtmlId(),
                $childFieldOne->getName()
            )->addFieldMap(
                $childFieldTwo->getHtmlId(),
                $childFieldTwo->getName()
            )->addFieldDependence(
                $childFieldOne->getName(),
                $parentField->getName(),
                '1,3'
            )->addFieldDependence(
                $childFieldTwo->getName(),
                $parentField->getName(),
                '2,4'
            )
        );

        $form->setValues($model->getData());

        if ($model->isReadonly()) {
            foreach ($fieldset->getElements() as $element) {
                $element->setReadonly(true, true);
            }
        }

        $this->setForm($form);
        return parent::_prepareForm();
    }
}

結果(ビュー):

オプション1
オプション1を選択

オプション4 オプション4を選択

依存なし 依存なし

コードサンプル1(機能しません):

/*
 * $parentField is select with values (0,1,2,3,4,5)
 */
$this->setChild(
    'form_after',
    $this->getLayout()->createBlock(
        'Magento\Backend\Block\Widget\Form\Element\Dependence'
    )->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldOne->getHtmlId(),
        $childFieldOne->getName()
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        '3'
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        '4'
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        '5'
    )->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldTwo->getHtmlId(),
        $childFieldTwo->getName()
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        '3'
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        '4'
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        '5'
    )
);

コードサンプル2(機能しません):

/*
 * $parentField is select with values (0,1,2,3,4,5)
 */
$this->setChild(
    'form_after',
    $this->getLayout()->createBlock(
        'Magento\Backend\Block\Widget\Form\Element\Dependence'
    )->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldOne->getHtmlId(),
        $childFieldOne->getName()
    )->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldTwo->getHtmlId(),
        $childFieldTwo->getName()
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        array('3', '4', '5')
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        array('3', '4', '5')
    )
);

結果:

注意:/var/www/magento2/app/code/Magento/Backend/Block/Widget/Form/Element/Dependence.phpの95行目の配列から文字列への変換

更新:


コードサンプル3(選択した値がでない場合は機能しません'3,4,5'):

// Parent field
$typeField = $fieldset->addField(
    'action_type',
    'select',
    [
        'label' => __('Type'),
        'name' => 'action_type',
        'options' => ['1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '3,4,5' => '3,4,5']
    ]
);

$this->setChild(
    'form_after',
    $this->getLayout()->createBlock(
        'Magento\Backend\Block\Widget\Form\Element\Dependence'
    )->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldOne->getHtmlId(),
        $childFieldOne->getName()
    )->addFieldMap(
        $typeField->getHtmlId(),
        $typeField->getName()
    )->addFieldMap(
        $childFieldTwo->getHtmlId(),
        $childFieldTwo->getName()
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        '3,4,5'
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        '3,4,5'
    )
);

誰かが同じ問題に直面し、解決策を見つけましたか?

更新:

たぶん他の誰かがこの問題の存在を確認できますか?私は3つの異なるインストールでそれをチェックしましたが、この解決策(値がカンマで区切られている行)はまだ機能しません。


あなたの完全なコードを見せていただけますか、それは私にとってはうまくいきます。
Sohel Rana

@SohelRana私は今それを再現する必要があります(私は家にいます)。約1時間で公開できます。助けてくれてありがとう:)
Siarhey Uchukhlebau

@SohelRanaブロックのコードとスクリーンショット(結果)で質問を更新しました
Siarhey Uchukhlebau

更新された回答を確認してください。
Sohel Rana

M2.0.4で確認したところ、問題なく動作しています
Sohel Rana

回答:


6

ファイルの依存関係に従って対応するフィールドを追加するコードを確認lib/web/mage/adminhtml/form.jsすると、次のスキームが表示されます。

    var shouldShowUp = true;
    for (var idFrom in valuesFrom) {
        var from = $(idFrom);
        if (from) {
            var values = valuesFrom[idFrom]['values'];
            var isInArray = values.indexOf(from.value) != -1;
            var isNegative = valuesFrom[idFrom]['negative'];
            if (!from || isInArray && isNegative || !isInArray && !isNegative) {
                shouldShowUp = false;
            }
        }
    }

たとえば、カンマ区切りの値を設定する場合:

    /** @var \Magento\Backend\Block\Widget\Form\Element\Dependence $blockDependence */
    $blockDependence->addFieldMap(
        $actionType->getHtmlId(),
        $actionType->getName()
    )->addFieldMap(
        $amountField->getHtmlId(),
        $amountField->getName()
    )->addFieldDependence(
        $amountField->getName(),
        $actionType->getName(),
        implode(',', array(
            Rule::ACTION_TYPE_OVERWRITE_COST,
            Rule::ACTION_TYPE_ADD_SURCHARGE,
            Rule::ACTION_TYPE_ENABLE_SM_AND_OVERWRITE_COST
        ))
    );

次に、デバッグindexOf中に、1つの要素の配列(既存の場合はコンマ区切りの値)の既存の値を見つけようとしていることがわかります。この要素が見つかりません:

ここに画像の説明を入力してください

console.logメソッドからの段階的な出力:

console.log(values);
console.log('Value: '+from.value);
console.log('Is in array: '+isInArray);

フィールドの複数依存関係を作成するには、同じカンマ区切り値を使用できますが、いくつかの変更が加えられています。あなただけのブロックが必要になります、それは拡張され\Magento\Backend\Block\Widget\Form\Element\Dependenceます:

<?php

namespace Vendor\Module\Block\Widget\Form\Element;

/**
 * Form element dependencies mapper
 * Assumes that one element may depend on other element values.
 * Will toggle as "enabled" only if all elements it depends from toggle as true.
 */
class Dependence extends \Magento\Backend\Block\Widget\Form\Element\Dependence
{
    /**
     * @param \Magento\Backend\Block\Context $context
     * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
     * @param \Magento\Config\Model\Config\Structure\Element\Dependency\FieldFactory $fieldFactory
     * @param array $data
     */
    public function _construct(
        \Magento\Backend\Block\Context $context,
        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
        \Magento\Config\Model\Config\Structure\Element\Dependency\FieldFactory $fieldFactory,
        array $data = []
    )
    {
        parent::_construct($context, $jsonEncoder, $fieldFactory, $data);
    }

    /**
     * {@inheritdoc}
     */
    protected function _toHtml()
    {
        if (!$this->_depends) {
            return '';
        }

        return '<script>
                require(["uiRegistry", "mage/adminhtml/form"], function(registry) {
                    var controller = new FormElementDependenceController(' . $this->_getDependsJson() .
        ($this->_configOptions ? ', ' .
            $this->_jsonEncoder->encode(
                $this->_configOptions
            ) : '') . ');
                    registry.set("formDependenceController", controller);
                });</script>';
    }

    /**
     * Field dependences JSON map generator * @return string
     */
    protected function _getDependsJson()
    {
        $result = [];
        foreach ($this->_depends as $to => $row) {
            foreach ($row as $from => $field) {
                $values = $this->_prepareValues($field->getValues());
                /** @var $field \Magento\Config\Model\Config\Structure\Element\Dependency\Field */
                $result[$this->_fields[$to]][$this->_fields[$from]] = [
                    'values' => $values,
                    'negative' => $field->isNegative(),
                ];
            }
        }
        return $this->_jsonEncoder->encode($result);
    }

    /**
     * @param $values
     * @return array
     */
    protected function _prepareValues($values)
    {
        if (!is_array($values)) {
            return $values;
        }

        $result = array();
        foreach ($values as $value) {
            if (stripos($value, ',')) {
                $result += explode(',', $value);
            } else {
                $result += $value;
            }
        }

        return $result;
    }
}

ご覧のとおり、値は強制的に1値配列に変更されています。

主な問題はaddFieldDependenceクラスのにあり\Magento\Backend\Block\Widget\Form\Element\Dependenceます:

ポイントは、値(依存関係からの線)が配列の唯一の要素として転送されることです。indexOf対応する選択されたオプションの値を見つけようとしますが、完全に一致するものを見つけることができません。その結果、「false」が返されます。

PHPはNotice: Array to string conversionの変換のためにを返すため、値を配列として転送する方法もありません'value' => (string)$refField

この例では、1要素の配列を複数要素の配列に再作成しました。各要素はいくつかの依存関係で構成されています。

依存関係のコードを変更する必要があります(ブロックを変更する必要があります)。これは次の方法です。

// Dependency START
/** @var \Magento\Backend\Block\Widget\Form\Element\Dependence $blockDependence */
$blockDependence = $this->getLayout()->createBlock(
// 'Magento\Backend\Block\Widget\Form\Element\Dependence'
'{Vendor}\{Module}\Block\Widget\Form\Element\Dependence'
);

$blockDependence->addFieldMap(
    $parentField->getHtmlId(),
    $parentField->getName()
)->addFieldMap(
    $childFieldOne->getHtmlId(),
    $childFieldOne->getName()
)->addFieldMap(
    $childFieldTwo->getHtmlId(),
    $childFieldTwo->getName()
)->addFieldDependence(
    $childFieldOne->getName(),
    $parentField->getName(),
    '1,3'
)->addFieldDependence(
    $childFieldTwo->getName(),
    $parentField->getName(),
    '2,4'
);

$this->setChild('form_after', $blockDependence);
// Dependency END

結果は次のようになります。

ここに画像の説明を入力してください

UPD

将来カンマ区切りの値を使用することが確実UNIQUE_DELIMITERな場合は、デリミタの必要な値を持つconst をクラスに追加するのが最善の方法ですVendor\Module\Block\Widget\Form\Element\Dependence。例:

const UNIQUE_DELIMITER = '~#!~';

次に、パーティションメソッドを変更します。

/**
 * @param $values
 * @return array
 */
protected function _prepareValues($values)
{
    if (!is_array($values)) {
        return $values;
    }

    $result = array();
    foreach ($values as $value) {
        if (stripos($value, self::UNIQUE_DELIMITER)) {
            $result += explode(self::UNIQUE_DELIMITER, $value);
        } else {
            $result += $value;
        }
    }

    return $result;
}

次に、Vendor\Module\Block\Widget\Form\Element\Dependence::UNIQUE_DELIMITERクラスで使用 しますActions

便宜上、クラスをDependence(名前空間の後に)追加します。

use Vendor\Module\Block\Widget\Form\Element\Dependence;

そして、このようにコードを書きます:

 // Dependency START
    /** @var \Magento\Backend\Block\Widget\Form\Element\Dependence $blockDependence */
    $blockDependence = $this->getLayout()->createBlock(
    // 'Magento\Backend\Block\Widget\Form\Element\Dependence'
        '{Vendor}\{Module}\Block\Widget\Form\Element\Dependence'
    );

    $childFieldOneToParentValues = implode(Dependence::UNIQUE_DELIMITER, array('1','3'));
    $childFieldTwoToParentValues = implode(Dependence::UNIQUE_DELIMITER, array('2','4'));

    $blockDependence->addFieldMap(
        $parentField->getHtmlId(),
        $parentField->getName()
    )->addFieldMap(
        $childFieldOne->getHtmlId(),
        $childFieldOne->getName()
    )->addFieldMap(
        $childFieldTwo->getHtmlId(),
        $childFieldTwo->getName()
    )->addFieldDependence(
        $childFieldOne->getName(),
        $parentField->getName(),
        $childFieldOneToParentValues
    )->addFieldDependence(
        $childFieldTwo->getName(),
        $parentField->getName(),
        $childFieldTwoToParentValues
    );

    $this->setChild('form_after', $blockDependence);
    // Dependency END

2
いい説明ですが、値の1つがコンマを含む文字列である場合はどうなるのだろうと思っています。たとえば、「15,50」としましょう。コードはそれを2つの値として処理しますか、それとも1つの値として適切に処理しますか?
デジタルピアニズムのラファエル、

@RaphaelatDigitalPianism合理的な質問:)
Siarhey Uchukhlebau

回答ありがとうございます!今日、このソリューションを実装して確認します。あなたがラファエル事件の解決策であなたの答えを更新することができればそれは素晴らしいでしょう。
Siarhey Uchukhlebau

@RaphaelatDigitalPianism応答を更新しました(申し訳ありませんが、最初に間違ったスレッドに誤って投稿しました)。:)
MageWorx

@MageWorx私はそれをチェックしました、そしてそれは機能します。あなたの助けをありがとう:)
Siarhey Uchukhlebau

2

私は間違っているかもしれませんが、残念ながらデフォルトのMagento\Backend\Block\Widget\Form\Element\Dependenceクラスではそれができないと思います。

説明させてください:

addFieldDependenceこの方法は、次のようになります。

public function addFieldDependence($fieldName, $fieldNameFrom, $refField)
{
    if (!is_object($refField)) {
        /** @var $refField \Magento\Config\Model\Config\Structure\Element\Dependency\Field */
        $refField = $this->_fieldFactory->create(
            ['fieldData' => ['value' => (string)$refField], 'fieldPrefix' => '']
        );
    }
    $this->_depends[$fieldName][$fieldNameFrom] = $refField;
    return $this;
}

したがって、次のコードを試してみましょう。

addFieldDependence($child,$parent,'2,4')

value$refField次の文字列2,4になります。選択にそのような値がないため、機能しません。

このコードを試してみると:

addFieldDependence($child,$parent,array('2,4'))

あなたはなりますArray to string conversionので誤差が(string)$refFieldコード

このコードを試してみると:

addFieldDependence($child,$parent,'2')->addFieldDependence($child,$parent,'4')

最初の呼び出しでは$refField、値2 を設定し、次のコードを使用して依存関係に割り当てます。

$this->_depends[$fieldName][$fieldNameFrom] = $refField;

ただし、$fieldNameおよび$fieldNameFrom変数は最初の呼び出し時と同じであるため、2番目のコードはその依存関係を上書きします。

どのようなソリューションがありますか?

  • 設定またはプラグインを使用してMagento\Backend\Block\Widget\Form\Element\Dependenceクラスの動作を変更する

ここを見て重要な方法があるaddFieldDependence_getDependsJson。ここでの問題はFormElementDependenceController、依存関係を処理するJavaScript クラスを変更しなければならない可能性が高いということです。

  • 名前が異なる複数の重複フィールドを使用します。これはダーティですが、うまくいくと思います。

例:

    $parentField = $fieldset->addField(
        'simple_action',
        'select',
        [
            'label' => __('Apply'),
            'name' => 'simple_action',
            'options' => [
                1 => __('Amount 1'),
                2 => __('Discount 1'),
                3 => __('Amount 2'),
                4 => __('Discount 2'),
            ]
        ]
    );

    $childFieldOne = $fieldset->addField(
        'amount',
        'text',
        [
            'name' => 'amount',
            'required' => true,
            'class' => 'validate-not-negative-number',
            'label' => __('Amount')
        ]
    );

    $childFieldOneCopy = $fieldset->addField(
        'amount',
        'text',
        [
            'name' => 'amount',
            'required' => true,
            'class' => 'validate-not-negative-number',
            'label' => __('Amount')
        ]
    );

次に使用します:

->addFieldDependence(
            $childFieldOne->getName(),
            $parentField->getName(),
            '1'
        )    
->addFieldDependence(
            $childFieldOneCopy->getName(),
            $parentField->getName(),
            '3'
        )

ここでの問題は、データを処理するコントローラーにいくつかのチェックを追加して、非表示のコピーフィールドではなく正しいデータを処理していることを確認する必要があることです。


お返事ありがとうございます。今ではより明確です。複数のフィールドを使用するか、独自のForm\Element\Dependenceブロックを作成しますか?
Siarhey Uchukhlebau

1
@SiarheyUchukhlebau私の答えで言ったように、あなた自身の作成Form\Element\Dependenceはそれが行われるべき方法です。問題は、扱うファイルがたくさんあるため、このような機能の開発に長い時間がかかることです。いくつかのフィールドソリューションはより汚いですが、私はその方法を使用すると、必要なものをすぐに取得でき、何も壊すことなく機能することを確信しています
Raphael at Digital Pianism

2

あなたはクラスに見えるべきだと思いますMagento\Backend\Block\Widget\Form\Element\Dependence。このクラスから継承された独自のブロックを作成し、必要に応じて書き換えることができます。あなたのコードでブロック呼び出しを置き換えます:

$this->getLayout()->createBlock(
    'Magento\Backend\Block\Widget\Form\Element\Dependence'
)

に:

this->getLayout()->createBlock(
    'Siarhey\Test\Block\Widget\Form\Element\Dependence'
)

ブロックSiarhey\Test\Block\Widget\Form\Element\Dependenceを作成すると、検証のロジックをブロックに実装できます。

ただのアドバイスです。お役に立てば幸いです。


2

adminhtmlの下にdi.xmlを作成し、次のコードを追加します。

基本的にMagento \ Backend \ Block \ Widget \ Form \ Element \ Dependenceクラスを上書きする必要があります


<preference for="Magento\Backend\Block\Widget\Form\Element\Dependence"
                type="Vendor\Module\Block\Widget\Form\Element\Dependence" />


namespace Vendor\Module\Block\Widget\Form\Element;

class Dependence extends \Magento\Backend\Block\Widget\Form\Element\Dependence
{
    /**
     * Register field name dependence one from each other by specified values
     *
     * @param string $fieldName
     * @param string $fieldNameFrom
     * @param \Magento\Config\Model\Config\Structure\Element\Dependency\Field|string $refField
     * @return \Magento\Backend\Block\Widget\Form\Element\Dependence
     */
    public function addFieldDependence($fieldName, $fieldNameFrom, $refField)
    {
        if (!is_object($refField)) {
            /** @var $refField \Magento\Config\Model\Config\Structure\Element\Dependency\Field */
            $refField = $this->_fieldFactory->create(
                ['fieldData' => ['value' => (string)$refField, 'separator' => ','], 'fieldPrefix' => '']
            );
        }
        $this->_depends[$fieldName][$fieldNameFrom] = $refField;
        return $this;
    }
}

これで、次のように使用できます。


->addFieldDependence(
    $childFieldTwo->getName(),
    $parentField->getName(),
    '2,4'
)

Magento2キャッシュをクリアします。


回答ありがとうございます。ただし、選択した値が「3,4,5」(コンマを含む文字列)でない場合は機能しません
Siarhey Uchukhlebau

選択した値がこの文字列「3,4,5」のいずれかである場合、機能するはずです。
Sohel Rana 2016

配列の代わりにカンマ区切りの文字列を使用する必要があります。
Sohel Rana

テストしましたが、選択した値3または4または5の場合は機能しません:(しかし、選択した値が '3,4,5'(文字列)の場合は機能します
Siarhey Uchukhlebau

このファイルの完全なコードのみを表示
Sohel Rana '11

1

これについてはよくわかりませんが、テストしていませんが、addFieldDependenceメソッドと\Magento\Config\Model\Config\Structure\Element\Dependency\Fieldクラスを見るとうまくいくと思います。

これをクラスに追加します。

protected $fieldFactory;
public function __construct(
   ....
   \Magento\Config\Model\Config\Structure\Element\Dependency\FieldFactory $fieldFactory,
   ....
) {
    $this->fieldFactory = $fieldFactory;
}

次に、代わりに

->addFieldDependence(
    $childFieldOne->getName(),
    $parentField->getName(),
    '1,3'
)

これを試して:

$someField = $this->fieldFactory()->create([
    'fieldData' => [
         'separator' => ',',
          'value' => '1,3',
    ],
    'fieldPrefix' => ''
]);

->addFieldDependence(
    $childFieldOne->getName(),
    $parentField->getName(),
    $someField
)

0

$this->_fieldFactory以下の1つを定義して試してみてください。

    $blockDependence = $this->getLayout()->createBlock(
        'Magento\Backend\Block\Widget\Form\Element\Dependence'
    );

    $filter = $this->_fieldFactory->create([
        'fieldData' => [
            'separator' => ',',
            'value' => '0,1',
        ],
        'fieldPrefix' => '',
    ]);

    $blockDependence->addFieldMap(
        "discount_type",
        'discount_type'
    )->addFieldMap(
        "discount",
        'discount'
    )->addFieldDependence(
        'discount',
        'discount_type',
        $filter
    );

    $this->setChild('form_after', $blockDependence);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.