كيفية جعل حقول من حقول multidependable?
-
29-09-2020 - |
سؤال
لدي حقول في لوحة الادارة مع أحد الوالدين حدد (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();
}
}
نتيجة (رأي):
نموذج التعليمات البرمجية 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
تحاول أن تجد القيمة الموجودة في عنصر الصفيف الذي هو في حالتك الخاصة بك قيم مفصولة بفواصل.هذا العنصر لا يمكن العثور عليه:
خطوة بخطوة إخراج 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
النتيجة ينبغي أن تبدو هذه:
محدث
إذا كنت متأكدا من أنك سوف تكون باستخدام قيمة مفصولة بفواصل في المستقبل ، فإن أفضل طريقة ستكون إضافة 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);