Dodawanie elementu formularza graficznego do formularza dodawania / edycji

12

Buduję moduł CRUD dla Magento 2 przy użyciu komponentów interfejsu użytkownika do listy administracyjnej i formularza, a jedna z moich jednostek ma pole obrazu.
Ale nie mogę sprawić, żeby działało tak, jak powinno.
Oto jak powinno to działać.
W trybie dodawania lub w trybie edycji bez przesłanego obrazu powinno to wyglądać jak zwykły plik wejściowy.

Po przesłaniu plik powinien wyświetlać podgląd obrazu i pole usuwania poniżej.

Nie szukam dokładnie tego projektu. Może wyglądać inaczej, ale ma tę samą funkcjonalność.

W Magento 1 mogłem to zrobić, po prostu tworząc własny renderer bloków

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

I dodając to w moim bloku formularza

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

Ale nie mam bloku formularza w Magento 2.
Wiem, że mogę użyć nazwy klasy dla pola formularza w pliku składników interfejsu użytkownika

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

Oczywiście muszę stworzyć tę klasę, ale co mam przedłużyć?
Wiem tylko, że muszę wdrożyć interfejs, Magento\Framework\View\Element\UiComponentInterfaceale nie znalazłem nic, co mógłbym rozszerzyć.
Tak więc moje prawdziwe pytanie brzmi: czy mogę rozszerzyć klasę, aby osiągnąć pożądane zachowanie? Jeśli nie, jak mogę rozpocząć tworzenie tego mechanizmu renderującego elementy?

Marius
źródło
Cześć @Marius, próbowałem użyć twojego przykładu, aby móc dodać zdjęcia produktów na mojej stronie edycji niestandardowej siatki, ale otrzymałem ten błąd: Błąd krytyczny: nie znaleziono klasy „Varien_Data_Form_Element_” w ... \ lib \ Varien \ Data \ Form \ Abstract.php na linii 146
bestwebdevs

Odpowiedzi:

21

Znalazłem sposób na zrobienie tego bez wymagania zajęć w terenie. Mam na myśli klasę dołączoną do elementu formularza, ale nie jako renderer.
Kolumnę należy zdefiniować następująco:

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

Musiałem także utworzyć plik szablonu podglądu, do którego odwołuje się [Namespace]_[Module]/image-preview.
To app/code/[Namespace]/[Module]/view/adminhtml/web/template/image-preview.htmlwygląda tak:

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

Ten kod wygeneruje takie pole:

Po przesłaniu obrazu (w czasie rzeczywistym) wygląda to tak:

Elementem url wewnątrz uploaderConfigjest adres URL, w którym obraz jest publikowany po przesłaniu. Więc musiałem to również utworzyć:

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

Ta klasa używa instancji [Namespace]\[Module]\Model\ImageUploadertego typu \Magento\Catalog\Model\ImageUploader.

To szwy do pracy. Nadal mam problemy z zapisaniem obrazu w bazie danych, ale to zupełnie inny problem.
Użyłem jako inspiracji imagepola dla encji kategorii

Marius
źródło
Mogę z powodzeniem przesłać obraz i zapisać nazwę obrazu w bazie danych, a następnie po otwarciu rekordu, który właśnie utworzyłem, wszystkie pola inne niż pole obrazu są wyświetlane zgodnie z oczekiwaniami. Kiedy zmienię pole obrazu na zwykłe pole „tekstowe”, to się pojawi. Czy masz jakiś pomysł na ten temat?
Nero,
1
@Nero. Potrzebujesz wartości obrazu w określonym formacie json. Oto przykład, w jaki sposób możesz przekształcić go w właściwego jsona
Marius
Nie chcę wgrywać obrazu, ale chcę wyświetlać obraz w formularzu interfejsu administratora. Właściwie przesyłam obraz z formularza interfejsu i chcę go wyświetlić w formularzu interfejsu użytkownika administratora, więc pomóżcie mi jak to zrobić
Sneha Panchal
Wystąpił błąd w [Namespace] [Module] \ Controller \ Adminhtml [Entity] \ Image \ upload.php w linii nr 61 Sprawdź i zaktualizuj odpowiedź.
Prince Patel
@PrincePatel Jaki jest komunikat o błędzie?
Marius
2

Tak, klasa, którą powinieneś przedłużyć, to \Magento\Ui\Component\Form\Element\AbstractElement.

Ta klasa implementuje to, ElementInterfaceco samo rozszerza odniesienie, o UiComponentInterfacektórym mówisz.

Ponadto, jeśli sprawdzisz składniki zadeklarowane pod Magento\Ui\Component\Form\Element, możesz zobaczyć, że wszystkie one rozszerzają tę klasę.

Powodem, dla którego wybrałbym tę klasę jest to, że rendermetoda \Magento\Backend\Block\Widget\Form\Renderer\Elementakceptuje tylko taki typ klasy:(W rzeczywistości jest to przypadek Magento\Framework\Data\Form\Element\AbstractElementzaakceptowany, nie \Magento\Ui\Component\Form\Element\AbstractElement)

Raphael at Digital Pianism
źródło
Wszelkie wskazówki na temat tego, jak powinna wyglądać moja klasa?
Marius
@Marius hmmm Nie jestem zbyt pewny, postaram się dowiedzieć
Raphael w Digital Pianism
1
Nie sądzę, że musisz to jeszcze zrobić. Myślę, że znalazłem rozwiązanie bez użycia klasy w komponencie interfejsu użytkownika, ale najpierw muszę przetestować.
Marius
@Marius hmmmm Myślę, że się myliłem, uważam, że powinieneś to sprawdzić: github.com/magento/magento2-samples/tree/master/…
Raphael w Digital Pianism