Blog

Upload, Save and Download PDF in Magento2 Custom Module Frontend and Admin UI Grid

Today I will discuse how to File or image upload via frontend custom module form and Controller. Open your module form.phtml file and make sure that the form attribute method to post method=”post” and also make sure that the form attribute enctype like enctype=”multipart/form-data”.

I have explained the process of uploading PDF on form, saving PDF file in the database and provide the download option in the admin grid in Magento2.

Steps to achieve :-

    1. Allow Form to accept PDF on frontend form Magento2
    2. Add upload PDF option on the frontend form in Magento2
    3. Save PDF file in the Database in Magento2
    4. Display Download link in the Admin Grid Magento2
    5. Give Url to the Download Link in Magento2
    6. Controller for Downloading PDF in Magento2

Let’s get started….

1. Allow Form to accept PDF on frontend form Magento2

<form id="contact-form" class="form contact" action=# method="post" enctype="multipart/form-data" data-mage-init={"validation":{}}>
.............
...........
</form>

2. Add upload PDF option on the frontend form in Magento2

Also make sure that INPUT field type attribute type=”file”, I have use file field name “resume”.

<form id=contact-form class="form contact" action=# method=post enctype=multipart/form-data data-mage-init={"validation":{}}>
    <fieldset class=fieldset>
        <div class="field resume">
          <label class=label for=resume><span><?= $block->escapeHtml(__('Resume')) ?></span> </label>
          <div class=control>
             <input name="resume" id="resume" title="<?= $block->escapeHtmlAttr(__('Resume')) ?>" class="input-file" type="file" />
          </div>
       </div>
    </fieldset>
    <div class=actions-toolbar>
       <div class=primary>
        <input type=hidden name=hideit id=hideit value />
        <button type=submit title="<?= $block->escapeHtmlAttr(__('Submit')) ?>" class="action submit primary"><span><?= $block->escapeHtml(__('Submit')) ?></span></button>
        </div>
    </div>
</form>

3. Save PDF file in the Database in Magento2

Now open you costom module Controller php file VENDOR\MODULE\Controller\Index\Post.php and use some library class for DirectoryList, UploaderFactory and Filesystem in top of file below namespace.

Add some protected on top of Controller class before __construct() method. Then update your Controller method public function __construct() like below.

Then add code for fileupload in your Controller method public function execute(). You can see I do not use $_FILES Global Variable in Magento because it does not meet with Magento standards. Instead of $_FILES Variable please use $this->getRequest()->getFiles();

<?php
namespace Thecoachsmb\Pdfmodule\Controller\Index; use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Framework\Image\AdapterFactory;
use Magento\Framework\Filesystem;
use Thecoachsmb\Pdfmodule\Model\ViewFactory; class Post extends \Magento\Framework\App\Action\Action
{
/**
* @var _customform
*/
protected $_customform; /**
* @var UploaderFactory
*/
protected $uploaderFactory; /**
* @var AdapterFactory
*/
protected $adapterFactory; /**
* @var Filesystem
*/
protected $filesystem; /**
* @param Context $context
* @param ConfigInterface $contactsConfig
* @param MailInterface $mail
* @param DataPersistorInterface $dataPersistor
* @param LoggerInterface $logger
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
ViewFactory $customform,
UploaderFactory $uploaderFactory,
AdapterFactory $adapterFactory,
Filesystem $filesystem
) {
$this->uploaderFactory = $uploaderFactory;
$this->adapterFactory = $adapterFactory;
$this->filesystem = $filesystem;
$this->_customform = $customform;
parent::__construct($context);
} /**
* Execute view action
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$data = $this->getRequest()->getParams();
if ($data) {
$files = $this->getRequest()->getFiles();
if (isset($files['resume']) && !empty($files['resume']["name"])){
try{
$uploaderFactory = $this->uploaderFactory->create(['fileId' => 'resume']);
$uploaderFactory->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png', 'pdf', 'docx', 'doc']);
$uploaderFactory->setAllowRenameFiles(true);
//$uploaderFactory->setFilesDispersion(true);
$mediaDirectory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA);
$destinationPath = $mediaDirectory->getAbsolutePath('thecoachsmb');
$result = $uploaderFactory->save($destinationPath);
if (!$result) {
throw new LocalizedException(
__('File cannot be saved to path: $1', $destinationPath)
);
}
$imagePath = $result['file']; //Set file path with name for save into database
$data['resume'] = $imagePath;
} catch (\Exception $e) {
//$this->messageManager->addErrorMessage($e->getMessage());
}
$_customform = $this->_customform->create();
$_customform->setData($data);
if($_customform->save()){
$this->messageManager->addSuccessMessage(__('You saved the data.'));
}else{
$this->messageManager->addErrorMessage(__('Data was not saved.'));
}
$resultRedirect = $this->resultRedirectFactory->create();
$resultRedirect->setPath('*/*/index');
return $resultRedirect;
}
}
}
}

Here resume is the input name and also the field name of database table. Upload image file will be saved at pub/media/thecoachsmb directory. And $data[‘resume’] = $imagePath; the value of $imagePath; that will be saved in the database field.

4. Display Download link in the Admin Grid Magento2

Since we are adding a column in the grid, at first we need to edit the ui-component file of the grid app/code/Thecoachsmb/Pdfmodule/view/adminhtml/ui_component/blog_listing.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    ............
       <columns name="unique_column_columns">
        <selectionsColumn name="ids">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">primary_id</item>
                </item>
            </argument>
        </selectionsColumn>
        <column name="primary_id">
            <settings>
                <filter>textRange</filter>
                <label translate="true">ID</label>
                <resizeDefaultWidth>25</resizeDefaultWidth>
            </settings>
        </column>
.................
        <actionsColumn name="download_action" class="Thecoachsmb\Pdfmodule\Ui\Component\Listing\Columns\Download">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">primary_id</item>
                    <item name="viewUrlPath" xsi:type="string">routeid/controllername/download</item>
                    <item name="urlEntityParamName" xsi:type="string">id</item>
                    <item name="sortOrder" xsi:type="number">50</item>
                </item>
            </argument>
            <settings>
                <label translate="true">Download</label>
            </settings>
        </actionsColumn>
    </columns>
</listing>

The bold content from the above code, you need to update as per your module.

Here, at the end I have added a new tag actionsColumn to add the action column which will let us downlaod a single row at a time. We have used a class Thecoachsmb\Pdfmodule\Ui\Component\Listing\Columns\Downloadfor this column. With that class we will be displaying the urls for each row.

With the argument tag we can pass some data to the class. It will get clear when we see the code for the Download class.

primary_id replace this text with your Primary Id of the table.

NOTE that here for the url we are using the route id instead of the front name. It’s because of some strange issue with magento. So please keep both the route id and the front name the same when you are developing any module.

5. Give Url to the Download Link in Magento2

Now let’s create the class of the action column, app/code/Vendor/Module/Ui/Component/Listing/Columns/Download.php

<?php
namespace Thecoachsmb\Pdfmodule\Ui\Component\Listing\Columns;

use Magento\Framework\UrlInterface;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;

class Download extends \Magento\Ui\Component\Listing\Columns\Column
{
    public $urlBuilder;

    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as &$item) {
                if (isset($item['primary_id'])) {
                    $viewUrlPath = $this->getData('config/viewUrlPath');
                    $urlEntityParamName = $this->getData('config/urlEntityParamName');
                    $item[$this->getData('name')] = [
                        'view' => [
                            'href' => $this->urlBuilder->getUrl(
                                $viewUrlPath,
                                [
                                    $urlEntityParamName => $item['primary_id'],
                                ]
                            ),
                            'label' => __('Download'),
                        ],
                    ];
                }
            }
        }

        return $dataSource;
    }
}

The bold content from the above code, you need to update as per your module.

We used prepareDataSource to loop through each row and set the data for each row. We have looped over $dataSource['data']['items'] and we are setting url data for each row as [ ‘view’ => [ ‘href’ => ‘#’ , ‘label’ => ‘Link’ ] ]; format.

Here you can notice that we have used getData function. So what it does is that it allows us to get the values that we passed from the ui component in the argument tag.

6. Controller for Downloading PDF in Magento2

Now let’s create the controller which will handle the download action Ui/Component/Listing/Columns/Download.php

<?php
namespace Vendor\Module\Controller\Adminhtml\Index;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;

class Downlaod extends Action
{
    public $blogFactory;
    
    public function __construct(
        Context $context,
        \Magento\Framework\App\Response\Http\FileFactory $fileFactory,
        \Magento\Framework\Filesystem\DirectoryList $directory,
        \Thecoachsmb\Pdfmodule\Model\ViewFactory $blogFactory
    ) {
         $this->blogFactory = $blogFactory;
         $this->_downloader = $fileFactory;
         $this->directory = $directory;
        parent::__construct($context);
    }

    public function execute()
    {
        $resultRedirect = $this->resultRedirectFactory->create();
        $id = $this->getRequest()->getParam('id');
        try {
            $blogModel = $this->blogFactory->create();
            $blogModel->load($id);
            $fileName = $blogModel->getResume();
            $file = $this->directory->getPath("media")."/thecoachsmb/".$fileName;
            return $this->_downloader->create(
                   $fileName,
                   @file_get_contents($file)
             );
            $this->messageManager->addSuccessMessage(__('You downloaded the pdf file.'));
        } catch (\Exception $e) {
            $this->messageManager->addErrorMessage($e->getMessage());
        }
        return $resultRedirect->setPath('*/*/');
    }
}

In this way, you can download the PDF file in Magento2.

Conclusion

In this way, we learned the complete process of the PDF uploading through form, saving PDF in the database and also download PDF from the Admin Grid in Magento2.

I hope this must have helped you. Do comment below giving feedback about the article.

4 thoughts on “Upload, Save and Download PDF in Magento2 Custom Module Frontend and Admin UI Grid

  1. I’m able to store the file name in DB but the created file and folder are not visible in my pub/media folder, also how can I download the file from the front end using a hyperlink or something like a button?
    Thank you!

  2. Class Thecoachsmb\Pdfmodule\Model\ViewFactory does not exist when I am using this module, I checked to generate folder permission. I run the di:compile command also but not working. Please check it. Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *