سؤال

لدي حقول في لوحة الادارة مع أحد الوالدين حدد (5 خيارات) و 2 الحقول, التي يجب عرضها في حالة الوالد القيمة حدد سيكون 3 أو 4 أو 5.أنا لا يمكن العثور على أمثلة مشابهة من المنطق في الماجنتو و حاولت أن أكتب قياسا المعتادة التبعية ، لكنه لا يعمل.في بلدي على سبيل المثال ، تعتمد المجالات يتم عرضها فقط في حين أن اختيار الخيارات مع القيمة 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();
    }
}

نتيجة (رأي):

Option 1
الخيار 1 مختارة

Option 4 الخيار 4 مختارة

Without dependency دون الاعتماد

نموذج التعليمات البرمجية 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 منشآت مختلفة و هذا الحل ( الخط مع القيم غيبوبة فصل ) لا يزال لا يعمل.

هل كانت مفيدة؟

المحلول

إذا كنت تحقق من التعليمات البرمجية التي هي مسؤولة عن إضافة الحقول المقابلة وفقا تبعيات الملف 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
        ))
    );

ثم حين debuging سترى أن indexOf تحاول أن تجد القيمة الموجودة في عنصر الصفيف الذي هو في حالتك الخاصة بك قيم مفصولة بفواصل.هذا العنصر لا يمكن العثور عليه:

enter image description here

خطوة بخطوة إخراج 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 يحاول أن يجد قيمة المقابلة الخيار الذي تم اختياره ، ولكنه يفشل في تحديد المطابقة التامة.ونتيجة لذلك ، فإنه يعود 'كاذبة'.

كما لا توجد وسيلة لنقل القيم كما صفيف ، كما PHP ترجع Notice: Array to string conversion بسبب تحويل 'value' => (string)$refField.

في المثال ، لدينا صوغه أحد عناصر المصفوفة إلى متعدد عنصر واحد ، حيث كل عنصر يتكون من عدة تبعيات.

قانون الاعتماد الخاصة بك ينبغي تعديل (سوف تحتاج إلى تغيير كتلة).هذا هو كيفية:

// 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

النتيجة ينبغي أن تبدو هذه:

enter image description here

محدث

إذا كنت متأكدا من أنك سوف تكون باستخدام قيمة مفصولة بفواصل في المستقبل ، فإن أفضل طريقة ستكون إضافة const UNIQUE_DELIMITER مع القيمة المطلوبة محدد إلى فئة Vendor\Module\Block\Widget\Form\Element\Dependence:E. g.

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

نصائح أخرى

قد أكون مخطئا ولكن للأسف أنا لا أعتقد أنك يمكن مع الافتراضي 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 المتغيرات هي نفسها من خلال المكالمة الأولى.

ما هي الحلول التي لديك ؟

  • استخدام تفضيلات أو الإضافات إلى تعديل سلوك Magento\Backend\Block\Widget\Form\Element\Dependence الدرجة

الطرق الهامة أن ننظر إلى هنا addFieldDependence و _getDependsJson.المشكلة هنا هي أن هناك الكثير من الفرص التي قد لتعديل جافا سكريبت FormElementDependenceController الطبقة التي تتعامل مع التبعيات.

  • استخدام العديد من الحقول المكررة مع أسماء مختلفة:حسنا هذا هو قذر ولكن أعتقد أن ذلك العمل.

على سبيل المثال:

    $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'
        )

المشكلة هنا هو أنه سيكون لديك لإضافة عدة شيكات في وحدة تحكم عمليات البيانات لضمان معالجة البيانات الصحيحة وليس خفية نسخ المجال.

أعتقد أنه يجب أن ننظر الدرجة 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 و يمكنك تنفيذ في ذلك المنطق الخاص بك التحقق.

فمن المشورة فقط.آمل أن يساعدك.

إنشاء di.xml تحت adminhtml و إضافة التعليمات البرمجية التالية:

تحتاج أساسا إلى الكتابة الماجنتو\الخلفية\كتلة\القطعة\تشكيل\العنصر\الاعتماد الدرجة


<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 ذاكرة التخزين المؤقت.

أنا لست متأكد من هذا, لم أجربها ولكن النظر في 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
)

تعريف $this->_fieldFactory ومحاولة أقل من واحد ، يعمل بالنسبة لي:

    $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);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى magento.stackexchange
scroll top