Magento 2: Implementiere UI Fileuploader

21

Ich habe kürzlich die FileUploader Ui-Komponente in meinem Formular auf Magento 2.1.7 implementiert.

Der Code dafür ist hier ( 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>

Mein Controller dafür ist folgendes ( App / Code / Vendor / Blog / Controller / 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);
    }
}

Wenn ich jedoch ein Bild hochlade und den Aufruf in der Chrome-Konsole überprüfe, wird ein Fehler 500 mit der Ausnahme angezeigt : Das Array $ _FILES ist leer .

Ich kämpfe seit zwei Tagen, aber ich kann es nicht bekommen, um richtig zu arbeiten. Wenn ich die $pathZeile mit der alternativen Variablen auskommentiere, ist der Upload erfolgreich, aber ich erhalte keine Vorschau.

Ich habe gelesen, dass dies möglicherweise enctypedas Formular ist, das das Problem verursacht, aber ich habe keine Informationen dazu gefunden, wie dies für ein UI Component-Formular überprüft werden kann.

Wenn Sie den gesamten Ausnahmecode benötigen, lassen Sie es mich bitte wissen.

Ich schätze jede mögliche Hilfe. Vielen Dank!

Hallleron
quelle
warum versuchst du nicht eine andere Art des Uploads? für zB. webkul.com/blog/…
Pallavi
Leider darf ich für diese Erweiterung nur die reinen UI-Komponenten mit XML-Deklaration verwenden. Aber es wäre eine schöne Alternative.
Hallleron

Antworten:

35

Ich folge diesen Schritten, um die UI FileUploader-Komponente in Admin-Form hinzuzufügen

Ich verwende die UI FileUploader-Komponente, um ein Symbol für meine FAQ-Erweiterung hochzuladen. Sie können von hier aus auf Folgendes verweisen: https://github.com/mageprince/magento2-FAQ

1) Feld admin_form.xmlhinzufügen in (Admin-Formular)

<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) Nun müssen wir einen Controller erstellen, den wir uploaderConfigin Admin-Form definieren:<item name="url" xsi:type="url" path="vendor_module/faqgroup/upload"/>

app / code / Vendor / Module / Controller / 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) Erstellen ImageUploader.php

app / code / Vendor / Module / Model / 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) Erstellen image-preview.html

app / code / Anbieter / Modul / 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) ImageUploader.phpFügen Sie nun Argumente für in di.xml hinzu

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>

Überprüfen Sie diese Datei, um das hochgeladene Bild im Bearbeitungsformular zu laden: DataProvider.php

AUSGABE:

Bildbeschreibung hier eingeben

Bild in Datenbank speichern

app / code / Vendor / Module / Controller / 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;
    }
}

So zeigen Sie das hochgeladene Bild in der Formularbearbeitungsseite an:

app / code / Vendor / Module / Model / 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;
    }
}
Prinz Patel
quelle
Vielen Dank dafür, ich weiß es wirklich zu schätzen. Wenn ich jedoch Ihre Lösung implementiere und ein Image hochlade, lautet meine Antwort in der Chrome-Konsole: {"error": "$ _ FILES array is empty", "errorcode": 0}. Die Datei wurde nicht hochgeladen (ich habe chmod aktiviert) und natürlich kann die Vorschau nicht angezeigt werden.
Hallleron
1
Eigentlich habe ich es endlich mit Hilfe Ihres Codes zum Laufen gebracht. Also vielen Dank! Sie sind mein Held! :-)
Hallleron
Gern geschehen :)
Prince Patel
@PrincePatel das ist einfach großartig, aber wenn ich ein Bearbeitungsformular habe, wie kann ich die Bildvorschau-Vorlage aus den getData des Datenanbieters
auslesen lassen
1
@PrincePatel Ich arbeite in Magento 2.3 und rufe "ImageUploader" aus di.xml auf und sende baseTmpPath-, basePath- und allowedExtensions-Parameter aus demselben. Jetzt gibt mein Modell "ImageUploader" den Fehler "Ausnahme # 0 (BadMethodCallException): Erforderliches Argument $ baseTmpPath fehlt" aus. Können Sie mir bitte helfen, wie man von di.xml aus anstatt statisch in der Konstruktorfunktion des "ImageUploader" -Modells verwaltet?
Dhara Bhatti
6

Ergänzung für Magento 2.2 UI-Komponente

Vergleichen Sie mit Magento 2.1, in Magento 2.2 hatte die UI-Komponente einige optionale Unterschiede wie unten. Wir könnten den Beamten Magento_Catalog/image-previewals Vorschau-Vorlage verwenden, und der Rest der Codes wie Controller könnte sich auf die akzeptierte Antwort beziehen .

<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>
Key Shang
quelle
1
Ich bekomme den Fehler TypeError: value.map is not a function. Wie kann ich das beheben
Nero Phung
@NeroPhung Hallo, bitte versuchen Sie diese Lösung magento.stackexchange.com/q/138642/44237
Key Shang
Ich habe dieses Problem im Anschluss an diesen Beitrag selbst gelöst. Danke für die Unterstützung!
Nero Phung
@KeyShang, in Ihrem Code, wie und wo stelle ich die Validierung für Bild-Uploder-Feld
Jaisa
@Sri Ich sehe deine Frage, ich werde sie in deiner Frage beantworten. Magento.stackexchange.com/questions/211957/… , gib mir etwas Zeit.
Key Shang