Ajout d'un élément de formulaire image à un formulaire d'ajout / modification

12

Je crée un module CRUD pour Magento 2 en utilisant des composants d'interface utilisateur pour la liste et le formulaire d'administration et l'une de mes entités a un champ d'image.
Mais je ne peux pas le faire fonctionner comme il se doit.
Voici comment cela devrait fonctionner.
En mode ajout ou en mode édition sans image téléchargée, cela devrait ressembler à une simple entrée de fichier.

Lorsqu'un fichier est téléchargé, il doit afficher l'aperçu de l'image et une zone de suppression en dessous.

Je ne cherche pas exactement ce design. Il pourrait avoir un aspect différent mais avoir les mêmes fonctionnalités.

Dans Magento 1, j'ai pu le faire, simplement en créant mon propre rendu de bloc

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;
    }
}

Et en ajoutant ceci dans mon bloc de formulaire

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

Mais je n'ai pas de bloc de formulaire dans Magento 2.
Je sais que je peux utiliser un nom de classe pour un champ de formulaire dans le fichier des composants de l'interface utilisateur

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

Évidemment, je dois créer cette classe, mais que dois-je étendre?
Tout ce que je sais, c'est que je dois implémenter l'interface Magento\Framework\View\Element\UiComponentInterfacemais je n'ai rien trouvé que je puisse étendre.
Ma vraie question est donc: puis-je étendre une classe pour obtenir le comportement souhaité? Sinon, comment puis-je commencer à créer ce rendu d'élément?

Marius
la source
Bonjour @Marius, j'ai essayé d'utiliser votre exemple pour pouvoir ajouter des images de produit dans ma page d'édition de grille personnalisée, mais j'ai obtenu cette erreur: Erreur fatale: la classe 'Varien_Data_Form_Element_' n'a pas été trouvée dans ... \ lib \ Varien \ Data \ Form \ Abstract.php sur la ligne 146
bestwebdevs

Réponses:

21

J'ai trouvé un moyen de le faire sans avoir besoin d'une classe attachée au terrain. Je veux dire qu'il y a une classe attachée à l'élément de formulaire mais pas en tant que moteur de rendu.
La colonne doit être définie comme suit:

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

J'ai également dû créer le fichier de modèle d'aperçu référencé par [Namespace]_[Module]/image-preview.
Voilà app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.htmlqui ressemble à ceci:

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

Ce code va générer un champ comme celui-ci:

Après avoir téléchargé une image (en temps réel), elle ressemble à ceci:

L' url élément à l'intérieur de l' uploaderConfigURL est l'URL où l'image est publiée lors du téléchargement. Je devais donc créer cela aussi:

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);
    }
}

Cette classe utilise une instance [Namespace]\[Module]\Model\ImageUploadersimilaire à \Magento\Catalog\Model\ImageUploader.

Cela semble fonctionner. J'ai toujours des problèmes pour enregistrer l'image dans la base de données, mais c'est un problème totalement différent.
J'ai utilisé comme inspiration le imagechamp de l'entité catégorie

Marius
la source
Je peux télécharger avec succès l'image et enregistrer le nom de l'image dans la base de données, puis lorsque j'ouvre l'enregistrement que je viens de créer, tous les champs autres que le champ d'image s'affichent tous comme prévu. Lorsque je change le champ d'image en un champ "texte" normal, il s'affiche. Avez-vous des idées à ce sujet?
Nero
1
@Nero. Vous avez besoin de la valeur de l'image dans un certain format json. Voici un exemple sur la façon de le transformer en un json approprié
Marius
Je ne veux pas télécharger l' image , mais je veux l' image d'affichage dans l' admin Ui form.Actually i Envoyer une image de la forme frontend et que vous souhaitez afficher dans l' admin ui form.So s'il vous plaît me aide comment faire
Sneha Panchal
Il y a une erreur dans [Espace de noms] [Module] \ Controller \ Adminhtml [Entité] \ Image \ upload.php sur la ligne numéro 61 Veuillez vérifier et mettre à jour la réponse.
Prince Patel
@PrincePatel Quel est le message d'erreur?
Marius
2

Oui, la classe à étendre est \Magento\Ui\Component\Form\Element\AbstractElement.

Cette classe implémente le ElementInterfacequi lui-même étend le dont UiComponentInterfacevous parlez.

En plus de cela, si vous vérifiez les composants déclarés sous, Magento\Ui\Component\Form\Elementvous pouvez voir qu'ils étendent tous cette classe.

La raison pour laquelle je choisirais cette classe est que la renderméthode \Magento\Backend\Block\Widget\Form\Renderer\Elementaccepte uniquement ce type de classe:(Ceci est en fait une instance Magento\Framework\Data\Form\Element\AbstractElementqui est acceptée, non \Magento\Ui\Component\Form\Element\AbstractElement)

Raphael chez Digital Pianism
la source
Des conseils sur la façon dont ma classe devrait ressembler?
Marius
@Marius hmmm Je ne suis pas trop sûr, je vais essayer de le découvrir
Raphael au Digital Pianism
1
Je ne pense pas que vous ayez encore besoin de le faire. Je pense avoir trouvé une solution sans utiliser de classe dans le composant ui, mais je dois d'abord tester.
Marius
@Marius hmmmm Je pense que je me trompais, je pense que vous devriez vérifier cela: github.com/magento/magento2-samples/tree/master/…
Raphael au Digital Pianism