Добавление элемента формы изображения в форму добавления / редактирования

12

Я создаю модуль CRUD для Magento 2, используя компоненты пользовательского интерфейса для списка и формы администратора, и одна из моих сущностей имеет поле изображения.
Но я не могу заставить его работать как следует.
Вот как это должно работать.
В режиме добавления или в режиме редактирования без загруженного изображения это должно выглядеть как простой ввод файла.

Когда файл загружен, он должен показать предварительный просмотр изображения и поле для удаления под ним.

Я не ищу именно этот дизайн. Это может выглядеть по-другому, но иметь одинаковую функциональность.

В Magento 1 я смог сделать это, просто создав собственный блок рендеринга.

class {{Namespace}}_{{Module}}_Block_Adminhtml_{{Entity}}_Helper_Image extends Varien_Data_Form_Element_Image
{
    protected function _getUrl()
    {
        $url = false;
        if ($this->getValue()) {
            $url = Mage::helper('{{namespace}}_{{module}}/{{entity}}_image')->getImageBaseUrl().$this->getValue();
        }
        return $url;
    }
}

И добавив это в моей форме блока

    $fieldset->addType(
        'image',
        Mage::getConfig()->getBlockClassName('{{namespace}}_{{module}}/adminhtml_{{entity}}_helper_image')
    );

Но у меня нет блока формы в Magento 2.
Я знаю, что могу использовать имя класса для поля формы в файле компонентов пользовательского интерфейса

    <field name="image" class="Class\Name\Here">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="dataType" xsi:type="string">text</item>
                <item name="label" xsi:type="string" translate="true">Resume</item>
                <item name="formElement" xsi:type="string">image</item>
                <item name="source" xsi:type="string">[entity]</item>
                <item name="dataScope" xsi:type="string">image</item>
            </item>
        </argument>
    </field>

Очевидно, я должен создать этот класс, но что я должен расширить?
Все, что я знаю, это то, что мне нужно реализовать интерфейс, Magento\Framework\View\Element\UiComponentInterfaceно я не нашел ничего, что мог бы расширить.
Итак, мой реальный вопрос: могу ли я расширить какой-то класс для достижения желаемого поведения? Если нет, как я могу начать создавать этот элемент рендерера?

Мариус
источник
Здравствуйте, @Marus! Я пытался использовать ваш пример, чтобы иметь возможность добавлять изображения продуктов на моей странице редактирования пользовательской сетки, но получил эту ошибку: Неустранимая ошибка: класс 'Varien_Data_Form_Element_' не найден в ... \ lib \ Varien \ Data \ Form \ Abstract.php на линии 146
bestwebdevs

Ответы:

21

Я нашел способ сделать это, не требуя присоединения класса к полю. Я имею в виду, что есть класс, прикрепленный к элементу формы, но не как средство визуализации.
Столбец должен быть определен так:

<field name="image">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="dataType" xsi:type="string">string</item>
            <item name="source" xsi:type="string">[entity]</item>
            <item name="label" xsi:type="string" translate="true">Image</item>
            <item name="visible" xsi:type="boolean">true</item>
            <item name="formElement" xsi:type="string">fileUploader</item>
            <item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
            <item name="previewTmpl" xsi:type="string">[Namespace]_[Module]/image-preview</item>
            <item name="required" xsi:type="boolean">false</item>
            <item name="uploaderConfig" xsi:type="array">
                <item name="url" xsi:type="url" path="[namespace_module]/[entity]_image/upload"/>
            </item>
        </item>
    </argument>
</field>

Мне также нужно было создать файл шаблона предварительного просмотра, на который ссылается [Namespace]_[Module]/image-preview.
Вот app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.htmlчто выглядит так:

<div class="file-uploader-summary">
    <div class="file-uploader-preview">
        <a attr="href: $parent.getFilePreview($file)" target="_blank">
            <img
                class="preview-image"
                tabindex="0"
                event="load: $parent.onPreviewLoad.bind($parent)"
                attr="
                    src: $parent.getFilePreview($file),
                    alt: $file.name">
        </a>

        <div class="actions">
            <button
                type="button"
                class="action-remove"
                data-role="delete-button"
                attr="title: $t('Delete image')"
                click="$parent.removeFile.bind($parent, $file)">
                <span translate="'Delete image'"/>
            </button>
        </div>
    </div>

    <div class="file-uploader-filename" text="$file.name"/>
    <div class="file-uploader-meta">
        <text args="$file.previewWidth"/>x<text args="$file.previewHeight"/>
    </div>
</div>

Этот код сгенерирует поле вроде этого:

После загрузки изображения (в реальном времени) оно выглядит так:

url Элемент внутри uploaderConfigесть URL , где изображение размещено при загрузке. Так что мне нужно было создать это также:

namespace [Namespace]\[Module]\Controller\Adminhtml\[Entity]\Image;

use Magento\Framework\Controller\ResultFactory;

/**
 * Class Upload
 */
class Upload extends \Magento\Backend\App\Action
{
    /**
     * Image uploader
     *
     * @var \[Namespace]\[Module]\Model\ImageUploader
     */
    protected $imageUploader;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \[Namespace]\[Module]\Model\ImageUploader $imageUploader
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \[Namespace]\[Module]\Model\ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }

    /**
     * Check admin permissions for this controller
     *
     * @return boolean
     */
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('[Namespace]_[Module]::[entity]');
    }

    /**
     * Upload file controller action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        try {
            $result = $this->imageUploader->saveFileToTmpDir('image');

            $result['cookie'] = [
                'name' => $this->_getSession()->getName(),
                'value' => $this->_getSession()->getSessionId(),
                'lifetime' => $this->_getSession()->getCookieLifetime(),
                'path' => $this->_getSession()->getCookiePath(),
                'domain' => $this->_getSession()->getCookieDomain(),
            ];
        } catch (\Exception $e) {
            $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
        }
        return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
    }
}

Этот класс использует экземпляр, [Namespace]\[Module]\Model\ImageUploaderкоторый похож на \Magento\Catalog\Model\ImageUploader.

Это швы на работу. У меня все еще есть проблемы с сохранением изображения в БД, но это совсем другая проблема.
Я использовал в качестве вдохновения imageполе для объекта категории

Мариус
источник
Я могу успешно загрузить изображение и сохранить имя изображения в базе данных, затем, когда я открываю только что созданную запись, все поля, кроме поля изображения, отображаются так, как ожидалось. Когда я изменю поле изображения на обычное текстовое поле, оно будет отображаться. У вас есть идеи по этому поводу?
Nero
1
@Nero. Вам нужно значение изображения в определенном формате JSON. Вот пример того, как вы можете преобразовать его в правильный JSON
Marius
Я не хочу загружать изображение, но хочу отобразить изображение в форме интерфейса администратора. На самом деле я загружаю изображение из формы интерфейса и хочу отобразить его в форме интерфейса администратора. Поэтому, пожалуйста, помогите мне, как это сделать
Sneha
Ошибка в [Пространстве имен] [Module] \ Controller \ Adminhtml [Entity] \ Image \ upload.php в строке № 61 Пожалуйста, проверьте и обновите ответ.
Принц Патель
@PrincePatel Что за сообщение об ошибке?
Мариус
2

Да, класс, который вы должны расширить, это \Magento\Ui\Component\Form\Element\AbstractElement.

Этот класс реализует тот, ElementInterfaceкоторый сам расширяет то, на UiComponentInterfaceчто вы ссылаетесь.

Кроме того, если вы проверите компоненты, объявленные под, Magento\Ui\Component\Form\Elementвы увидите, что они все расширяют этот класс.

Причина, по которой я бы выбрал этот класс, заключается в том, что renderметод \Magento\Backend\Block\Widget\Form\Renderer\Elementпринимает только такой тип класса:(Это на самом деле пример того, Magento\Framework\Data\Form\Element\AbstractElementчто принято, а не \Magento\Ui\Component\Form\Element\AbstractElement)

Рафаэль в цифровом пианизме
источник
Любые указатели на то, как должен выглядеть мой класс?
Мариус
@Marius хммм Я не слишком уверен, я постараюсь выяснить
Рафаэль в Digital Pianism
1
Я не думаю, что вам нужно делать это еще. Я думаю, что нашел решение без использования класса в компоненте пользовательского интерфейса, но мне нужно сначала проверить.
Мариус
@Marius хммммм Я думаю, что я был неправ, я считаю, что вы должны это проверить: github.com/magento/magento2-samples/tree/master/…
Рафаэль в Digital Pianism