Добавление пользовательского элемента формы в форму Adminhtml

Есть ли способ добавить пользовательский элемент формы в форму Magento Adminhtml без размещения пользовательского элемента в папке lib/Varian?

Я проследил код, по существу, Varian_Data_Form_Element_ factory

public function addField($elementId, $type, $config, $after=false)
{
    if (isset($this->_types[$type])) {
        $className = $this->_types[$type];
    }
    else {
        $className = 'Varien_Data_Form_Element_'.ucfirst(strtolower($type));
    }
    $element = new $className($config);
    $element->setId($elementId);
    if ($element->getRequired()) {
        $element->addClass('required-entry');
    }
    $this->addElement($element, $after);
    return $element;
}

Итак, если я правильно это читаю, я гарантирую, что внешний интерфейс атрибута EAV возвращает конкретный тип fieldType (например, supertextfield), и система будет создавать/отображать Varien_Data_Form_Element_Supertextfield при отображении этой формы редактирования атрибута.

Это хорошо и хорошо, но это означает, что мне нужно включить мой пользовательский элемент формы в иерархию папок lib/Varian. Учитывая, насколько модульным является Magento, кажется, что это делает это неправильно.

Я понимаю, что я мог бы разыгрывать автозагрузчик custo или символические ссылки в lib, но мне в первую очередь интересно узнать, есть ли там

  • Канонический способ добавления пользовательских элементов формы для атрибутов

  • Канонический способ настройки автозагрузчика Magento.

Ответы

Ответ 1

Служба самопомощи снова наносит удар. Похоже, что Magento устанавливает пути включения таким образом, что вы можете отбрасывать файлы классов из lib (а не только из пространства имен Mage_) в локальную ветвь кода

app/code/local/Varien/etc

Когда автозагрузчик пытается загрузить класс lib/Varien, он сначала проверит ваш каталог. Это все еще ставит вас под угрозу, если Varien когда-либо создает элемент данных с тем же именем, что и ваш, но поскольку риски идут относительно низко.

Ответ 2

Это старый пост, но он может быть полезен для кого-то:

да, вы можете.

Код ниже расположен в: app/code/local/MyCompany/MyModule/Block/MyForm.php

class MyCompany_MyModule_Block_MyForm extends Mage_Adminhtml_Block_Widget_Form 
{       
    protected function _prepareForm()
    {
        $form = new Varien_Data_Form(array(
            'id'        => 'edit_form',
            'action'    => $this->getUrl('*/*/save'),
            'method'    => 'post'
        ));

        $fieldset = $form->addFieldset('my_fieldset', array('legend' => 'Your fieldset title')));

        //Here is what is interesting us          
        //We add a new type, our type, to the fieldset
        //We call it extended_label
        $fieldset->addType('extended_label','MyCompany_MyModule_Lib_Varien_Data_Form_Element_ExtendedLabel');

        $fieldset->addField('mycustom_element', 'extended_label', array(
            'label'         => 'My Custom Element Label',
            'name'          => 'mycustom_element',
            'required'      => false,
            'value'     => $this->getLastEventLabel($lastEvent),
            'bold'      =>  true,
            'label_style'   =>  'font-weight: bold;color:red;',
        ));
    }
}

Вот код вашего пользовательского элемента, который находится в приложении /code/local/MyCompany/MyModule/Lib/Varien/Data/Form/Element/ExtendedLabel.php:

class MyCompany_MyModule_Lib_Varien_Data_Form_Element_ExtendedLabel extends Varien_Data_Form_Element_Abstract
{
    public function __construct($attributes=array())
    {
        parent::__construct($attributes);
        $this->setType('label');
    }

    public function getElementHtml()
    {
        $html = $this->getBold() ? '<strong>' : '';
        $html.= $this->getEscapedValue();
        $html.= $this->getBold() ? '</strong>' : '';
        $html.= $this->getAfterElementHtml();
        return $html;
    }

    public function getLabelHtml($idSuffix = ''){
        if (!is_null($this->getLabel())) {
            $html = '<label for="'.$this->getHtmlId() . $idSuffix . '" style="'.$this->getLabelStyle().'">'.$this->getLabel()
                . ( $this->getRequired() ? ' <span class="required">*</span>' : '' ).'</label>'."\n";
        }
        else {
            $html = '';
        }
        return $html;
    }
}

Ответ 3

Класс Varien_Data_Form_Abstract имеет метод addType(), где вы можете добавлять новые типы элементов и их соответствующие имена классов. Чтобы использовать эту функциональность, вы можете скопировать блок Mage_Adminhtml_Block_Widget_Form в локальный пул кодов и расширить метод _getAdditionalElementTypes():

protected function _getAdditionalElementTypes()
{
    $types = array(
        'my_type' => 'Namespace_MyModule_Block_Widget_Form_Element_MyType',
    );

    return $types;
}

Поскольку класс Mage_Adminhtml_Block_Widget_Form является базовым классом для всех других классов форм, к сожалению, просто переписывание блока в config не будет работать.

EDIT: если вам нужны типы пользовательских элементов только в одной форме, вы можете переопределить конкретный класс и добавить туда тип, переопределив метод _getAdditionelElementTypes(). Это было бы более чистым решением, чем копирование импортируемого класса magento в локальный пул кодов.

EDIT2: Если смотреть Mage_Adminhtml_Block_Widget_Form::_setFieldset(), существует еще одна возможность: если атрибут имеет значение в frontend_input_renderer (например, mymodule/element_mytype), то загружается блок с этим именем. См. Также Mage/Eav/Model/Entity/Attribute/Frontend/Abstract.php line 160. Это должно работать без переопределения любых классов Magento.