Magento 2: implémenter UI Fileuploader


22

J'ai récemment implémenté le composant FileUploader Ui sous ma forme sur Magento 2.1.7.

Le code correspondant est ici ( app / code / Vendor / Blog / view / adminhtml / ui_component / vendor_blog_form.xml ):

<field name="featured_images">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">Hervorgehobene Bilder:</item>
                    <item name="formElement" xsi:type="string">fileUploader</item>
                    <item name="componentType" xsi:type="string">fileUploader</item>
                    <item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
                    <item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
                    <item name="allowedExtensions" xsi:type="string">jpg jpeg gif png</item>
                    <item name="notice" xsi:type="string" translate="true">Erlaubte Dateitypen: png, gif, jpg, jpeg.</item>
                    <item name="maxFileSize" xsi:type="number">2097152</item>
                    <item name="source" xsi:type="string">blog</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                    <item name="dataScope" xsi:type="string">featured_images</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                    <item name="uploaderConfig" xsi:type="array">
                        <item name="url" xsi:type="url" path="vendor_blog/blog/upload"/>
                    </item>
                </item>
            </argument>
        </field>

Mon contrôleur est le suivant ( application / code / fournisseur / blog / contrôleur / Adminhtml / blog / upload.php ):

<?php

namespace Vendor\Blog\Controller\Adminhtml\Blog;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Backend\App\Action;  

class Upload extends \Vendor\Blog\Controller\Adminhtml\Blog
{

    protected $_fileUploaderFactory;
    protected $_directory_list;
    protected $_logger;

    public function __construct(
        Action\Context $context,
        \Magento\Framework\Registry $coreRegistry,
        \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory,
        \Magento\Framework\App\Filesystem\DirectoryList $directory_list,
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->_fileUploaderFactory = $fileUploaderFactory;
        $this->_directory_list = $directory_list;
        $this->_logger = $logger;
        parent::__construct($context, $coreRegistry);
    }

    public function execute(){
        $uploader = $this->_fileUploaderFactory->create(['fileId' => 'featured_images']);
        $uploader->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png']);
        $uploader->setAllowRenameFiles(false);
        $uploader->setFilesDispersion(false);
        $path = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath('blog');
        //$path = $this->_directory_list->getPath('media') . '/blog';
        $this->_logger->debug('Uploader.php: '.$path);
        $uploader->save($path);
    }
}

Cependant, lorsque je télécharge une image et inspecte l'appel dans la console de Chrome, j'obtiens une erreur 500 avec exception: le tableau $ _FILES est vide .

Je me bats depuis deux jours mais je n'arrive pas à faire fonctionner correctement. Lorsque je décommente la $pathligne de variable alternative , le téléchargement réussit mais je n'obtiens pas d'aperçu.

J'ai lu que c'était peut-être le enctypeformulaire à l'origine du problème, mais je n'ai trouvé aucune information sur la façon de vérifier cela pour un formulaire de composant d'interface utilisateur.

Si vous avez besoin de tout le code d'exception, faites-le moi savoir.

J'apprécie chaque aide possible. Je vous remercie!


pourquoi ne pas essayer une autre façon de télécharger? par exemple. webkul.com/blog/…
Pallavi

Malheureusement, je suis limité à utiliser uniquement les composants d'interface utilisateur purs avec déclaration XML pour cette extension. Mais ce serait une bonne alternative.
hallleron

Réponses:


35

Je suive ces étapes pour ajouter le composant UI fileuploader sous forme d'administration

J'utilise le composant UI fileuploader pour télécharger une icône pour mon extension FAQ. Vous pouvez prendre référence à partir d'ici: https://github.com/mageprince/magento2-FAQ

1) Ajouter un champ dans admin_form.xml(Formulaire Admin)

<field name="icon">
    <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">FaqGroup</item>
            <item name="label" xsi:type="string" translate="true">Group 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">Vendor_Module/image-preview</item>
            <item name="required" xsi:type="boolean">false</item>
            <item name="sortOrder" xsi:type="number">40</item>
            <item name="uploaderConfig" xsi:type="array">
                <item name="url" xsi:type="url" path="your_router/faqgroup/upload"/>
            </item>
        </item>
    </argument>
</field>

2) Maintenant, nous devons créer un contrôleur que nous définissons sous uploaderConfigforme d'administration:<item name="url" xsi:type="url" path="vendor_module/faqgroup/upload"/>

app / code / Vendeur / Module / Contrôleur / Adminhtml / FaqGroup / Upload.php

<?php

namespace Vendor\Module\Controller\Adminhtml\FaqGroup;

use Magento\Framework\Controller\ResultFactory;

class Upload extends \Magento\Backend\App\Action
{
    public $imageUploader;

    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Vendor\Module\Model\ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }

    public function _isAllowed()
    {
        return $this->_authorization->isAllowed('Vendor_Module::Faq');
    }

    public function execute()
    {
        try {
            $result = $this->imageUploader->saveFileToTmpDir('icon');
            $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);
    }
}

3) Créer ImageUploader.php

app / code / Vendeur / Module / Modèle / ImageUploader.php

<?php

namespace Prince\Faq\Model;

class ImageUploader
{
    private $coreFileStorageDatabase;
    private $mediaDirectory;
    private $uploaderFactory;
    private $storeManager;
    private $logger;
    public $baseTmpPath;
    public $basePath;
    public $allowedExtensions;

    public function __construct(
        \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->coreFileStorageDatabase = $coreFileStorageDatabase;
        $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
        $this->uploaderFactory = $uploaderFactory;
        $this->storeManager = $storeManager;
        $this->logger = $logger;
        $this->baseTmpPath = "faq/tmp/icon";
        $this->basePath = "faq/icon";
        $this->allowedExtensions= ['jpg', 'jpeg', 'gif', 'png'];
    }

    public function setBaseTmpPath($baseTmpPath)
    {
        $this->baseTmpPath = $baseTmpPath;
    }

    public function setBasePath($basePath)
    {
        $this->basePath = $basePath;
    }

    public function setAllowedExtensions($allowedExtensions)
    {
        $this->allowedExtensions = $allowedExtensions;
    }

    public function getBaseTmpPath()
    {
        return $this->baseTmpPath;
    }

    public function getBasePath()
    {
        return $this->basePath;
    }

    public function getAllowedExtensions()
    {
        return $this->allowedExtensions;
    }

    public function getFilePath($path, $imageName)
    {
        return rtrim($path, '/') . '/' . ltrim($imageName, '/');
    }

    public function moveFileFromTmp($imageName)
    {
        $baseTmpPath = $this->getBaseTmpPath();
        $basePath = $this->getBasePath();
        $baseImagePath = $this->getFilePath($basePath, $imageName);
        $baseTmpImagePath = $this->getFilePath($baseTmpPath, $imageName);
        try {
            $this->coreFileStorageDatabase->copyFile(
                $baseTmpImagePath,
                $baseImagePath
            );
            $this->mediaDirectory->renameFile(
                $baseTmpImagePath,
                $baseImagePath
            );
        } catch (\Exception $e) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Something went wrong while saving the file(s).')
            );
        }
        return $imageName;
    }

    public function saveFileToTmpDir($fileId)
    {
        $baseTmpPath = $this->getBaseTmpPath();
        $uploader = $this->uploaderFactory->create(['fileId' => $fileId]);
        $uploader->setAllowedExtensions($this->getAllowedExtensions());
        $uploader->setAllowRenameFiles(true);
        $result = $uploader->save($this->mediaDirectory->getAbsolutePath($baseTmpPath));
        if (!$result) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('File can not be saved to the destination folder.')
            );
        }

        $result['tmp_name'] = str_replace('\\', '/', $result['tmp_name']);
        $result['path'] = str_replace('\\', '/', $result['path']);
        $result['url'] = $this->storeManager
                ->getStore()
                ->getBaseUrl(
                    \Magento\Framework\UrlInterface::URL_TYPE_MEDIA
                ) . $this->getFilePath($baseTmpPath, $result['file']);
        $result['name'] = $result['file'];
        if (isset($result['file'])) {
            try {
                $relativePath = rtrim($baseTmpPath, '/') . '/' . ltrim($result['file'], '/');
                $this->coreFileStorageDatabase->saveFile($relativePath);
            } catch (\Exception $e) {
                $this->logger->critical($e);
                throw new \Magento\Framework\Exception\LocalizedException(
                    __('Something went wrong while saving the file(s).')
                );
            }
        }
        return $result;
    }
}

4) Créer image-preview.html

app / code / Vendor / 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>

5) Ajoutez maintenant des arguments pour ImageUploader.phpdans di.xml

app / code / Vendor / Module / etc / di.xml

<type name="Vendor\Module\Model\ImageUploader">
    <arguments>
        <!-- Temporary file stored in pub/media/faq/tmp/icon -->
        <argument name="baseTmpPath" xsi:type="string">faq/tmp/icon</argument>
        <argument name="basePath" xsi:type="string">faq/icon</argument>
        <argument name="allowedExtensions" xsi:type="array">
            <item name="jpg" xsi:type="string">jpg</item>
            <item name="jpeg" xsi:type="string">jpeg</item>
            <item name="gif" xsi:type="string">gif</item>
            <item name="png" xsi:type="string">png</item>
        </argument>
    </arguments>
</type>

Vérifiez ce fichier pour charger l'image téléchargée sur le formulaire d'édition: DataProvider.php

PRODUCTION:

entrez la description de l'image ici

Pour enregistrer l'image dans la base de données

app / code / Vendeur / Module / Contrôleur / Adminhtml / Save.php

<?php

namespace Vendor\Module\Controller\Adminhtml;

use Magento\Framework\Exception\LocalizedException;

class Save extends \Magento\Backend\App\Action
{
    protected $dataPersistor;

    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\App\Request\DataPersistorInterface $dataPersistor
    ) {
        $this->dataPersistor = $dataPersistor;
        parent::__construct($context);
    }

    public function execute()
    {
        ...
        ...
        $data = $this->_filterFoodData($data);
        $model->setData($data);
        $model->save();
        ...
        ...     
    }

    public function _filterFoodData(array $rawData)
    {
        //Replace icon with fileuploader field name
        $data = $rawData;
        if (isset($data['icon'][0]['name'])) {
            $data['icon'] = $data['icon'][0]['name'];
        } else {
            $data['icon'] = null;
        }
        return $data;
    }
}

Pour afficher l'image téléchargée dans la page d'édition du formulaire:

app / code / Vendeur / Module / Modèle / DataProvider.php

<?php

namespace Vendor\Module\Model;

use Magento\Store\Model\StoreManagerInterface;

class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
    ...
    ...

    public function getData()
    {
        ...
        ...
        $items = $this->collection->getItems();

        //Replace icon with fileuploader field name
        foreach ($items as $model) {
            $this->loadedData[$model->getId()] = $model->getData();
            if ($model->getIcon()) {
                $m['icon'][0]['name'] = $model->getIcon();
                $m['icon'][0]['url'] = $this->getMediaUrl().$model->getIcon();
                $fullData = $this->loadedData;
                $this->loadedData[$model->getId()] = array_merge($fullData[$model->getId()], $m);
            }
        }
        ...
        ...

        return $this->loadedData;
    }

    public function getMediaUrl()
    {
        $mediaUrl = $this->storeManager->getStore()
            ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA).'faq/tmp/icon/';
        return $mediaUrl;
    }
}

Merci beaucoup pour cela, je l'apprécie vraiment. Cependant, lorsque j'implémente votre solution et télécharge une image, ma réponse retournée dans la console de Chrome est: {"error": "$ _ FILES array is empty", "errorcode": 0}. Le fichier n'a pas été téléchargé (j'ai vérifié chmod) et bien sûr l'aperçu ne peut pas apparaître.
hallleron le

1
En fait, je l'ai finalement fait fonctionner avec l'aide de votre code. Alors merci beaucoup! Tu es mon héros! :-)
hallleron

Vous êtes les bienvenus :)
Prince Patel

@PrincePatel c'est tout simplement génial, mais en supposant que j'ai un formulaire d'édition, comment puis-je faire lire le modèle d'aperçu d'image à partir du getData du fournisseur de données
Yehia A.Salam

1
@PrincePatel Je travaille dans Magento 2.3 et j'appelle "ImageUploader" depuis di.xml et j'envoie les paramètres baseTmpPath, basePath et allowedExtensions depuis le même. Maintenant, mon modèle "ImageUploader" renvoie une erreur "Exception # 0 (BadMethodCallException): Argument requis manquant $ baseTmpPath". Pouvez-vous m'aider à gérer à partir de di.xml au lieu de le définir statiquement dans la fonction constructeur du modèle "ImageUploader"?
Dhara Bhatti

6

Supplément pour le composant Magento 2.2 UI

Comparer avec Magento 2.1, dans Magento 2.2 , le composant UI avait quelques différences optionnelles comme ci-dessous. Nous pourrions utiliser l'officiel Magento_Catalog/image-previewcomme modèle de prévisualisation, et le reste des codes comme contrôleur pourrait faire référence à la réponse acceptée .

<field name="image" formElement="fileUploader">
    <settings>
        <notice translate="true">Allowed file types: jpg, jpeg, gif, png.</notice>
        <label translate="true">Image</label>
        <componentType>fileUploader</componentType>
    </settings>
    <formElements>
        <fileUploader>
            <settings>
                <allowedExtensions>jpg jpeg gif png</allowedExtensions>
                <maxFileSize>10240000</maxFileSize>
                <placeholderType>image</placeholderType>
                <previewTmpl>Magento_Catalog/image-preview</previewTmpl>
                <uploaderConfig>
                    <param xsi:type="string" name="url">path/to/controller</param>
                </uploaderConfig>
            </settings>
        </fileUploader>
    </formElements>
</field>

1
Je reçois l'erreur TypeError: value.map is not a function. Comment puis-je résoudre ce problème
Nero Phung

@NeroPhung Bonjour, essayez cette solution magento.stackexchange.com/q/138642/44237
Clé Shang

J'ai fait ce problème moi-même dans la suite de ce post. Merci pour le soutien!
Nero Phung

@KeyShang, dans votre code, comment et où dois-je mettre la validation pour le champ uploder d'image
Jaisa

@Sri Je vois votre question, je vais y répondre dans votre question magento.stackexchange.com/questions/211957/… , donnez-moi un peu de temps.
Key Shang
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.