Magento – Magento 2 Import CSV File to Custom Module Table

csvimportmagento2

As per my requirement, I want to import CSV into my custom table, for that i have reviewed the following URL http://www.blogtreat.com/how-to-import-csv-file-to-custom-module-table-in-magento-2/

In this, while uploading the CSV file and hit the check data, the file is validating after that it's showing an import button, but when i hit the import button, nothing is happening.

enter image description here

class Imageimport extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
{
    const ID = 'id';
    const PRODUCT_SKU = 'product_sku';
    const PRODUCT_MAIN_IMAGE = 'product_main_image';
    const TIME = 'time';
    const TABLE_ENTITY = 'product_image_import';
    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $_messageTemplates = [
        ValidatorInterface::ERROR_ID_IS_EMPTY => 'Empty',
    ];

    protected $_permanentAttributes = [self::ID];

    /**
     * If we should check column names
     *
     * @var bool
     */
    protected $needColumnCheck = true;

    /**
     * Valid column names
     *
     * @array
     */
    protected $validColumnNames = [
        self::ID,
        self::PRODUCT_SKU,
        self::PRODUCT_MAIN_IMAGE,
    ];

    /**
     * Need to log in import history
     *
     * @var bool
     */
    protected $logInHistory = true;

    protected $_validators = [];

    /**
     * @var \Magento\Framework\Stdlib\DateTime\DateTime
     */
    protected $_connection;

    protected $_resource;

    /**
     * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
     */
    public function __construct(
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        \Magento\ImportExport\Helper\Data $importExportData,
        \Magento\ImportExport\Model\ResourceModel\Import\Data $importData,
        \Magento\Framework\App\ResourceConnection $resource,
        \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper,
        \Magento\Framework\Stdlib\StringUtils $string,
        ProcessingErrorAggregatorInterface $errorAggregator
    ) {
        $this->jsonHelper = $jsonHelper;
        $this->_importExportData = $importExportData;
        $this->_resourceHelper = $resourceHelper;
        $this->_dataSourceModel = $importData;
        $this->_resource = $resource;
        $this->_connection = $resource->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION);
        $this->errorAggregator = $errorAggregator;
    }

    public function getValidColumnNames() {
        return $this->validColumnNames;
    }

    /**
     * Entity type code getter.
     *
     * @return string
     */
    public function getEntityTypeCode() {
        return 'product_image_import';
    }

    /**
     * Row validation.
     *
     * @param array $rowData
     * @param int $rowNum
     * @return bool
     */
    public function validateRow(array $rowData, $rowNum) {
        $title = false;
        if (isset($this->_validatedRows[$rowNum])) {
            return !$this->getErrorAggregator()->isRowInvalid($rowNum);
        }

        $this->_validatedRows[$rowNum] = true;

        if (!isset($rowData[self::ID]) || empty($rowData[self::ID])) {
            $this->addRowError(ValidatorInterface::ERROR_MESSAGE_IS_EMPTY, $rowNum);
            return false;
        }
        return !$this->getErrorAggregator()->isRowInvalid($rowNum);
    }

    /**
     * Create advanced question data from raw data.
     *
     * @throws \Exception
     * @return bool Result of operation.
     */
    protected function _importData() {
        if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) {
            $this->deleteEntity();
        } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $this->getBehavior()) {
            $this->replaceEntity();
        } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $this->getBehavior()) {
            $this->saveEntity();
        }
        return true;
    }

    /**
     * Save question
     *
     * @return $this
     */
    public function saveEntity() {
        $this->saveAndReplaceEntity();
        return $this;
    }

    /**
     * Replace question
     *
     * @return $this
     */
    public function replaceEntity() {
        $this->saveAndReplaceEntity();
        return $this;
    }

    /**
     * Deletes question data from raw data.
     *
     * @return $this
     */
    public function deleteEntity() {
        $ids = [];
        while ($bunch = $this->_dataSourceModel->getNextBunch()) {
            foreach ($bunch as $rowNum => $rowData) {
                $this->validateRow($rowData, $rowNum);
                if (!$this->getErrorAggregator()->isRowInvalid($rowNum)) {
                    $rowId = $rowData[self::ID];
                    $ids[] = $rowId;
                }
                if ($this->getErrorAggregator()->hasToBeTerminated()) {
                    $this->getErrorAggregator()->addRowToSkip($rowNum);
                }
            }
        }
        if ($ids) {
            $this->deleteEntityFinish(array_unique($ids),self::TABLE_ENTITY);
        }
        return $this;
    }

    /**
     * Save and replace question
     *
     * @return $this
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */
    protected function saveAndReplaceEntity() {
        $behavior = $this->getBehavior();
        $ids = [];
        while ($bunch = $this->_dataSourceModel->getNextBunch()) {
            $entityList = [];
            $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/templog.log');
            $logger = new \Zend\Log\Logger();
            $logger->addWriter($writer);

            $logger->info(print_r($bunch,1));
            foreach ($bunch as $rowNum => $rowData) {
                if (!$this->validateRow($rowData, $rowNum)) {
                    $this->addRowError(ValidatorInterface::ERROR_MESSAGE_IS_EMPTY, $rowNum);
                    continue;
                }
                if ($this->getErrorAggregator()->hasToBeTerminated()) {
                    $this->getErrorAggregator()->addRowToSkip($rowNum);
                    continue;
                }
                $rowId= $rowData[self::ID];
                $ids[] = $rowId;
                $entityList[$rowId][] = [
                  self::ID => $rowData[self::ID],
                  self::PRODUCT_SKU => $rowData[self::PRODUCT_SKU],
                  self::PRODUCT_MAIN_IMAGE => $rowData[self::PRODUCT_MAIN_IMAGE],
                ];
            }
            $logger->info(print_r($entityList,1));
            if (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $behavior) {
                if ($ids) {
                    if ($this->deleteEntityFinish(array_unique(  $ids), self::TABLE_ENTITY)) {
                        $this->saveEntityFinish($entityList, self::TABLE_ENTITY);
                    }
                }
            } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $behavior) {
                $this->saveEntityFinish($entityList, self::TABLE_ENTITY);
            }

        }
        return $this;
    }

    /**
     * Save question
     *
     * @param array $priceData
     * @param string $table
     * @return $this
     */
    protected function saveEntityFinish(array $entityData, $table) {
        if ($entityData) {
            $tableName = $this->_connection->getTableName($table);
            $entityIn = [];
            foreach ($entityData as $id => $entityRows) {
                    foreach ($entityRows as $row) {
                        $entityIn[] = $row;
                    }
            }
            if ($entityIn) {
                $this->_connection->insertOnDuplicate($tableName, $entityIn,[
                self::ID,
                self::PRODUCT_SKU,
                self::PRODUCT_MAIN_IMAGE
            ]);
            }
        }
        return $this;
    }

    protected function deleteEntityFinish(array $ids, $table) {

        if ($table && $ids) {
            try {
                $this->countItemsDeleted += $this->_connection->delete(
                    $this->_connection->getTableName($table),
                    $this->_connection->quoteInto('id IN (?)', $ids)
                );
                return true;
            } catch (\Exception $e) {
                return false;
            }
        } else {
            return false;
        }
    }

Kindly check and let me know your thoughts and ideab, it will help me to resolve the issue

Best Answer

First create a Import Button in your Ui-component File

[vendor_name] \ [module_name] \view\adminhtml\ui_component

uiComponenetFileName.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Ui/etc/ui_configuration.xsd">

            <!-- main part of the grid -->
                <argument name="data" xsi:type="array">
                   <!-- define  date source -->
                <item name="js_config" xsi:type="array">
                    <item name="provider" xsi:type="string">locator_record_locator_list.locator_record_locator_list_data_source</item>
                    <item name="deps" xsi:type="string">locator_record_locator_list.locator_record_locator_list_data_source</item>
                </item>
                <!-- for columns -->
                <item name="spinner" xsi:type="string">locator_records_columns</item>
                <!--  for Add new record button  -->
                <item name="buttons" xsi:type="array">
                    <item name="add" xsi:type="array">
                        <item name="name" xsi:type="string">add</item>
                        <item name="label" xsi:type="string" translate="true">Add New Location</item>
                        <item name="class" xsi:type="string">primary</item>
                        <item name="url" xsi:type="string">*/*/addlocation</item>
                        <item name="sortOrder" xsi:type="number">10</item>
                    </item>
                    <item name="import" xsi:type="array">
                        <item name="name" xsi:type="string">import</item>
                        <item name="label" xsi:type="string" translate="true">Import Locatore</item>
                        <item name="class" xsi:type="string">secondary</item>
                        <item name="url" xsi:type="string">*/dataimport/importdata</item>
                        <item name="sortOrder" xsi:type="number">20</item>
                    </item>
                    <item name="export" xsi:type="array">
                        <item name="name" xsi:type="string">export</item>
                        <item name="label" xsi:type="string" translate="true">Export locatore</item>
                        <item name="class" xsi:type="string">secondary</item>
                        <item name="url" xsi:type="string">*/*/exportdata</item>
                        <item name="sortOrder" xsi:type="number">30</item>
                    </item>
                </item>
            </argument>
.........................
.........................
.........................

Now this Import Button Call Import Data Form

[vendor_name] \ [module_name] \Controller\Adminhtml\Dataimport

Importdata.php

<?php

namespace [vendor_name]\ [module_name] \Controller\Adminhtml\Dataimport;

use Magento\Framework\Controller\ResultFactory;

class Importdata extends \Magento\Backend\App\Action
{
    private $coreRegistry;

    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Registry $coreRegistry
    ) {                                 

       parent::__construct($context);
       $this->coreRegistry = $coreRegistry;
    }

    public function execute()
    {
        $rowData = $this->_objectManager->create('[vendor_name] \ [module_name] \Model\Locator');
        $this->coreRegistry->register('row_data', $rowData);
        $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE);
        $resultPage->getConfig()->getTitle()->prepend(__('Import Locator Data'));
        return $resultPage;
    }

    // used for acl.xml
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('[vendor_name]_[module_name]::add_datalocation');
    }
}

create a Layout File which Call your Block File

[vendor_name] \ [module_name] \view\adminhtml\layout

[controller_name]_dataimport_importdata.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
           <block class="[vendor_name] \ [module_name] \Block\Adminhtml\Dataimport\Importdata" name="importdata_locator" />
        </referenceContainer>
    </body>
</page>

create a block File for Import Data Form

[vendor_name] \ [module_name] \Block\Adminhtml\Dataimport

Importdata.php

<?php 

namespace [vendor_name] \ [module_name] \Block\Adminhtml\Dataimport;

class Importdata extends \Magento\Backend\Block\Widget\Form\Container
{
    protected $_coreRegistry = null;

    public function __construct(
        \Magento\Backend\Block\Widget\Context $context,
        \Magento\Framework\Registry $registry,
        array $data = []
    ) {
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }

    protected function _construct()
    {
        $this->_objectId = 'row_id';
        $this->_blockGroup = '[module_name]_[vendor_name]';
        $this->_controller = 'adminhtml_dataimport';
        parent::_construct();
        $this->buttonList->remove('back');
        $this->buttonList->update('save', 'label', __('Import'));
        $this->buttonList->remove('reset');

        $this->addButton(
                    'backhome',
                    [
                        'label' => __('Back'),
                        'on_click' => sprintf("location.href = '%s';", $this->getUrl('[route_name] / [controller_name] /index')),
                        'class' => 'back',
                        'level' => -2
                    ]
                );


    }


    public function getHeaderText()
    {
        return __('Import Location Data');
    }

    protected function _isAllowedAction($resourceId)
    {
        return $this->_authorization->isAllowed($resourceId);
    }


    public function getFormActionUrl()
    {
        if ($this->hasFormActionUrl()) {
            return $this->getData('form_action_url');
        }
        return $this->getUrl('[route_name] / dataimport/save');
    }
}

the above file call import form

[vendor_name] \ [module_name] \Block\Adminhtml\Dataimport\Edit

Form.php

<?php

namespace [vendor_name] \ [module_name] \Block\Adminhtml\Dataimport\Edit;

use Magento\Framework\View\Asset\Repository; 

class Form extends \Magento\Backend\Block\Widget\Form\Generic
{
    protected $_assetRepo;

    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Framework\View\Asset\Repository $assetRepo,
        array $data = []
    ) {   
        parent::__construct($context, $registry, $formFactory, $data);
    }


    protected function _prepareForm()
    {   
        $path = $this->_assetRepo->getUrl("[vendor_name]_[module_name]::img/[vendor_name]_[module_name]_Sample_File.csv");

        $model = $this->_coreRegistry->registry('row_data');

        $form = $this->_formFactory->create(
            ['data' => [
                            'id' => 'edit_form',
                            'enctype' => 'multipart/form-data',
                            'action' => $this->getData('action'),
                            'method' => 'post'
                        ]
            ]
        );

        $form->setHtmlIdPrefix('datalocation_');

           $fieldset = $form->addFieldset(
                'base_fieldset',
                ['legend' => __('Import Location '), 'class' => 'fieldset-wide']
            );

       $importdata_script =  $fieldset->addField(
            'importdata',
            'file', 
                array(
                        'label'     => 'Upload File',
                        'required'  => true,
                        'name'      => 'importdata',  
                        'note' => 'Allow File type: .csv and .xls', 
                     )
        );

        $importdata_script->setAfterElementHtml("   

        <span id='sample-file-span' ><a id='sample-file-link' href='".$path."'  >Download Sample File</a></span>

            <script type=\"text/javascript\">

            document.getElementById('[route_name]_importdata').onchange = function () { 

                var fileInput = document.getElementById('[route_name]_importdata');

                var filePath = fileInput.value;

                var allowedExtensions = /(\.csv|\.xls)$/i; 

                if(!allowedExtensions.exec(filePath))
                {
                    alert('Please upload file having extensions .csv or .xls only.');
                    fileInput.value = '';
                }

            };

            </script>"
        );


        $form->setValues($model->getData());
        $form->setUseContainer(true);
        $this->setForm($form);

        return parent::_prepareForm();
    }

}

this import form check whether file is valid or not, now create file which read your uploaded file and insert into table .

[vendor_name] \ [module_name] \Controller\Adminhtml\Dataimport*

Save.php

<?php

namespace [vendor_name]\[module_name]\Controller\Adminhtml\Dataimport;

use Magento\Backend\App\Action;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Framework\Image\AdapterFactory;
use Magento\Store\Model\ScopeInterface; 


class Save extends \Magento\Backend\App\Action
{

    protected $fileSystem;

    protected $uploaderFactory;

    protected $request;

    protected $adapterFactory;


    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Filesystem $fileSystem,
        \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        AdapterFactory $adapterFactory

    ) {
        parent::__construct($context);
        $this->fileSystem = $fileSystem;
        $this->request = $request;
        $this->scopeConfig = $scopeConfig;
        $this->adapterFactory = $adapterFactory;
        $this->uploaderFactory = $uploaderFactory;
    }

    public function execute()
    { 

         if ( (isset($_FILES['importdata']['name'])) && ($_FILES['importdata']['name'] != '') ) 
         {
            try 
           {    
                $uploaderFactory = $this->uploaderFactory->create(['fileId' => 'importdata']);
                $uploaderFactory->setAllowedExtensions(['csv', 'xls']);
                $uploaderFactory->setAllowRenameFiles(true);
                $uploaderFactory->setFilesDispersion(true);

                $mediaDirectory = $this->fileSystem->getDirectoryRead(DirectoryList::MEDIA);
                $destinationPath = $mediaDirectory->getAbsolutePath('[vendor_name]_[module_name]_IMPORTDATA');

                $result = $uploaderFactory->save($destinationPath);

                if (!$result) 
                   {
                     throw new LocalizedException
                     (
                        __('File cannot be saved to path: $1', $destinationPath)
                     );

                   }
                else
                    {   
                        $imagePath = '[vendor_name]_[module_name]_IMPORTDATA'.$result['file'];

                        $mediaDirectory = $this->fileSystem->getDirectoryRead(DirectoryList::MEDIA);

                        $destinationfilePath = $mediaDirectory->getAbsolutePath($imagePath);

                        /* file read operation */

                        $f_object = fopen($destinationfilePath, "r");

                        $column = fgetcsv($f_object);

                        // column name must be same as the Sample file name 

                        if($f_object)
                        {
                            if( ($column[0] == 'Col_name_1') && ($column[1] == 'Col_name_2') && ($column[2] == 'Col_name_3') && ($column[3] == 'Col_name_4') && ($column[4] == 'Col_name_5') )
                            {   

                                $count = 0;

                                while (($columns = fgetcsv($f_object)) !== FALSE) 
                                {

                                    $rowData = $this->_objectManager->create('Dolphin\Storelocator\Model\Storelocator');

                                    if($columns[0] != 'Col_name_1')// unique Name like Primary key
                                    {   
                                        $count++;

                                    /// here this are all the Getter Setter Method which are call to set value 
                                    // the auto increment column name not used to set value 

                                        $rowData->setCol_name_1($columns[1]);

                                        $rowData->setCol_name_2($columns[2]);

                                        $rowData->setCol_name_3($columns[3]);

                                        $rowData->setCol_name_4($columns[4]);

                                        $rowData->setCol_name_5($columns[5]);

                                        $rowData->save();   

                                    }

                                } 

                            $this->messageManager->addSuccess(__('A total of %1 record(s) have been Added.', $count));
                            $this->_redirect('[route_name]/[controller_name]/index');
                            }
                            else
                            {
                                $this->messageManager->addError(__("invalid Formated File"));
                                $this->_redirect('[route_name]/dataimport/importdata');
                            }

                        } 
                        else
                        {
                            $this->messageManager->addError(__("File hase been empty"));
                            $this->_redirect('[route_name]/dataimport/importdata');
                        }

                    }                   

           } 
           catch (\Exception $e) 
          {   
               $this->messageManager->addError(__($e->getMessage()));
               $this->_redirect('[controller_name]/dataimport/importdata');
          }

         }
         else
         {
            $this->messageManager->addError(__("Please try again."));
            $this->_redirect('[controller_name]/dataimport/importdata');
         }
    }
}

Now you can Click on the Import Button and upload .csv file and import data.

I Hope This Helps You.

Related Topic