Add Product Grid In Customer Admin Section And Save The Checkbox Values To Database - Magento 2
In one of my project i want to add product grid in Magento 2 admin customer section with a separate tab. And also want to save selected product checkbox value to my custom database. After spending 2 days i found solution after merging few codes that i found.
So i have created my custom magento 2 module that will do this all thing. It will add new tab in customer admin section and also save checkbox value to custom database.
Here is the quick steps to create module.
OR
You can download module here,
Note: This module also include code to show selected product in front-end.
Download
Step1: HK/Productattach/registration.php
Step2: HK/Productattach/Block/Adminhtml/Edit/Tab/Products.php
Step3: HK/Productattach/Controller/Adminhtml/Index/Products.php
Step4: HK/Productattach/Controller/Adminhtml/Index/ProductsGrid.php
Step5: HK/Productattach/etc/module.xml
Step6: HK/Productattach/etc/adminhtml/routes.xml
Step7: HK/Productattach/etc/adminhtml/events.xml
Step8: HK/Productattach/Model/Productattach.php
Step9: HK/Productattach/Model/ProductattachFactory.php
Step10: HK/Productattach/Model/ResourceModel/Productattach.php
Step11: HK/Productattach/Model/ResourceModel/Productattach/Collection.php
Step12: HK/Productattach/Observer/Customersaveafter.php
Step13: HK/Productattach/Setup/InstallSchema.php
Step14: HK/Productattach/view/adminhtml/layout/customer_index_edit.xml
Step15: HK/Productattach/view/adminhtml/layout/productattach_index_products.xml
Step16: HK/Productattach/view/adminhtml/layout/productattach_index_productsgrid.xml
Step17: HK/Productattach/view/adminhtml/templates/scriptjs.phtml
Now run following commands and you are done.
I hope this will help someone.
Thanks
So i have created my custom magento 2 module that will do this all thing. It will add new tab in customer admin section and also save checkbox value to custom database.
Here is the quick steps to create module.
OR
You can download module here,
Note: This module also include code to show selected product in front-end.
Download
Step1: HK/Productattach/registration.php
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'HK_Productattach', __DIR__ );
Step2: HK/Productattach/Block/Adminhtml/Edit/Tab/Products.php
<?php namespace HK\Productattach\Block\Adminhtml\Edit\Tab; use HK\Productattach\Model\ProductattachFactory; class Products extends \Magento\Backend\Block\Widget\Grid\Extended { /** * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory */ private $productCollectionFactory; //private $attachModel; /** * @var ProductattachFactory */ private $contactFactory; /** * @var \Magento\Framework\Registry */ private $registry; /** * Products constructor. * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Backend\Helper\Data $backendHelper * @param \Magento\Framework\Registry $registry * @param ProductattachFactory $contactFactory * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory * @param array $data */ public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Backend\Helper\Data $backendHelper, \Magento\Framework\Registry $registry, ProductattachFactory $contactFactory, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory, array $data = [] ) { $this->contactFactory = $contactFactory; $this->productCollectionFactory = $productCollectionFactory; $this->registry = $registry; //$this->attachModel = $attachModel; parent::__construct($context, $backendHelper, $data); } /** * _construct * @return void */ public function _construct() { parent::_construct(); $this->setId('productsGrid'); $this->setDefaultSort('entity_id'); $this->setDefaultDir('DESC'); $this->setSaveParametersInSession(true); $this->setUseAjax(true); if ($this->getRequest()->getParam('productattach_id')) { //if ($this->getRequest()->getParam('id')) { $this->setDefaultFilter(['in_product' => 1]); } } /** * @param \Magento\Backend\Block\Widget\Grid\Column $column * @return $this */ public function _addColumnFilterToCollection($column) { if ($column->getId() == 'in_product') { $productIds = $this->_getSelectedProducts(); if (empty($productIds)) { $productIds = 0; } if ($column->getFilter()->getValue()) { $this->getCollection()->addFieldToFilter('entity_id', ['in' => $productIds]); } else { if ($productIds) { $this->getCollection()->addFieldToFilter('entity_id', ['nin' => $productIds]); } } } else { parent::_addColumnFilterToCollection($column); } return $this; } /** * prepare collection */ public function _prepareCollection() { $collection = $this->productCollectionFactory->create(); $collection->addAttributeToSelect('name'); $collection->addAttributeToSelect('sku'); $collection->addAttributeToSelect('price'); $this->setCollection($collection); return parent::_prepareCollection(); } /** * @return $this */ public function _prepareColumns() { //$model = $this->attachModel; $this->addColumn( 'in_product', [ 'header_css_class' => 'a-center', 'type' => 'checkbox', 'name' => 'in_product', 'align' => 'center', 'index' => 'entity_id', 'values' => $this->_getSelectedProducts(), ] ); $this->addColumn( 'entity_id', [ 'header' => __('Product ID'), 'type' => 'number', 'index' => 'entity_id', 'header_css_class' => 'col-id', 'column_css_class' => 'col-id', ] ); $this->addColumn( 'names', [ 'header' => __('Name'), 'index' => 'name', 'class' => 'xxx', 'width' => '50px', ] ); $this->addColumn( 'sku', [ 'header' => __('Sku'), 'index' => 'sku', 'class' => 'xxx', 'width' => '50px', ] ); $this->addColumn( 'price', [ 'header' => __('Price'), 'type' => 'currency', 'index' => 'price', 'width' => '50px', ] ); return parent::_prepareColumns(); } /** * @return string */ public function getGridUrl() { return $this->getUrl('*/*/productsgrid', ['_current' => true]); } public function getTabUrl() { $id = 0; $customerId = $this->getRequest()->getParam('id'); $_objectManager = \Magento\Framework\App\ObjectManager::getInstance(); $hkproductCollection = $_objectManager->create('HK\Productattach\Model\Productattach'); $hkproductCollection = $hkproductCollection->getCollection()->addFieldToFilter('customer_id', $customerId); if($hkproductCollection->count() > 0){ $id = $hkproductCollection->getFirstItem()->getId(); } return $this->getUrl('productattach/*/products', ['productattach_id' => $id, '_current' => true]); } /** * @param object $row * @return string */ public function getRowUrl($row) { return ''; } public function _getSelectedProducts() { $contact = $this->getContact(); return $contact->getProducts($contact); } /** * Retrieve selected products * * @return array */ public function getSelectedProducts() { $contact = $this->getContact(); $selected = $contact->getProducts($contact); if (!is_array($selected)) { $selected = []; } return $selected; } public function getContact() { $contactId = $this->getRequest()->getParam('productattach_id'); $contact = $this->contactFactory->create(); if ($contactId) { $contact->load($contactId); } return $contact; } /** * {@inheritdoc} */ public function canShowTab() { return true; } /** * {@inheritdoc} */ public function isHidden() { return true; } public function isAjaxLoaded() { return true; } public function getTabLabel() { return __('Customer Products'); } /** * @return \Magento\Framework\Phrase */ public function getTabTitle() { return __('Customer Products'); } }
Step3: HK/Productattach/Controller/Adminhtml/Index/Products.php
<?php namespace HK\Productattach\Controller\Adminhtml\Index; use Magento\Backend\App\Action; class Products extends \Magento\Backend\App\Action { /** * @var \Magento\Framework\View\Result\LayoutFactory */ private $resultLayoutFactory; /** * Products constructor. * @param Action\Context $context * @param \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory */ public function __construct( Action\Context $context, \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory ) { parent::__construct($context); $this->resultLayoutFactory = $resultLayoutFactory; } /** * @return bool */ public function _isAllowed() { return true; } /** * Save action * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { $resultLayout = $this->resultLayoutFactory->create(); $resultLayout->getLayout()->getBlock('productattach.edit.tab.products') ->setInProducts($this->getRequest()->getPost('index_products', null)); return $resultLayout; } }
Step4: HK/Productattach/Controller/Adminhtml/Index/ProductsGrid.php
<?php namespace HK\Productattach\Controller\Adminhtml\Index; use Magento\Backend\App\Action; class ProductsGrid extends \Magento\Backend\App\Action { /** * @var \Magento\Framework\View\Result\LayoutFactory */ private $resultLayoutFactory; /** * ProductsGrid constructor. * @param Action\Context $context * @param \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory */ public function __construct( Action\Context $context, \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory ) { parent::__construct($context); $this->resultLayoutFactory = $resultLayoutFactory; } /** * @return bool */ public function _isAllowed() { return true; } /** * Save action * * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { $resultLayout = $this->resultLayoutFactory->create(); $resultLayout->getLayout()->getBlock('productattach.edit.tab.products') ->setInBanner($this->getRequest()->getPost('index_products', null)); return $resultLayout; } }
Step5: HK/Productattach/etc/module.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> <module name="HK_Productattach" setup_version="1.0.2"> <sequence> <module name="Magento_Backend"/> <module name="Magento_Sales"/> <module name="Magento_Quote"/> <module name="Magento_Checkout"/> <module name="Magento_Catalog"/> </sequence> </module> </config>
Step6: HK/Productattach/etc/adminhtml/routes.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="admin"> <route id="productattach" frontName="productattach"> <module name="HK_Productattach" /> </route> </router> </config>
Step7: HK/Productattach/etc/adminhtml/events.xml
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="adminhtml_customer_save_after"> <observer name="customer_save_after" instance="HK\Productattach\Observer\Customersaveafter" /> </event> </config>
Step8: HK/Productattach/Model/Productattach.php
<?php namespace HK\Productattach\Model; class Productattach extends \Magento\Framework\Model\AbstractModel { /** * Return unique ID(s) for each object in system * * @return array */ public function getIdentities() { return [self::CACHE_TAG . '_' . $this->getId()]; } /** * Initialize resource model * * @return void */ protected function _construct() { $this->_init('HK\Productattach\Model\ResourceModel\Productattach'); } public function getProducts(\HK\Productattach\Model\Productattach $object) { $id = $object->getId(); $tbl = $this->getResource()->getTable("hk_productattach"); $select = $this->getResource()->getConnection()->select()->from( $tbl, ['products'] ) ->where( 'productattach_id = ?', (int)$id ); $products = $this->getResource()->getConnection()->fetchCol($select); if ($products) { $products = explode('&', $products[0]); } return $products; } }
Step9: HK/Productattach/Model/ProductattachFactory.php
<?php namespace HK\Productattach\Model; class ProductattachFactory { /** * @var \Magento\Framework\ObjectManagerInterface */ protected $_objectManager; /** * @param \Magento\Framework\ObjectManagerInterface $objectManager */ public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager) { $this->_objectManager = $objectManager; } /** * Create new country model * * @param array $arguments * @return \Magento\Directory\Model\Country */ public function create(array $arguments = []) { return $this->_objectManager->create('HK\Productattach\Model\Productattach', $arguments, false); } }
Step10: HK/Productattach/Model/ResourceModel/Productattach.php
<?php namespace HK\Productattach\Model\ResourceModel; class Productattach extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { /** * Initialize resource model * * @return void */ protected function _construct() { $this->_init('hk_productattach', 'productattach_id'); } }
Step11: HK/Productattach/Model/ResourceModel/Productattach/Collection.php
<?php namespace HK\Productattach\Model\ResourceModel\Productattach; class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection { /** * Define resource model * * @return void */ protected function _construct() { $this->_init('HK\Productattach\Model\Productattach', 'HK\Productattach\Model\ResourceModel\Productattach'); //$this->_map['fields']['page_id'] = 'main_table.page_id'; } }
Step12: HK/Productattach/Observer/Customersaveafter.php
<?php namespace HK\Productattach\Observer; use Magento\Framework\Event\Observer as EventObserver; use Magento\Framework\Event\ObserverInterface; class Customersaveafter implements ObserverInterface { protected $objectManager; public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager ) { $this->objectManager = $objectManager; } public function execute(EventObserver $observer) { $customer = $observer->getEvent()->getData('customer'); $products = $observer->getRequest()->getPost('products'); $_objectManager = \Magento\Framework\App\ObjectManager::getInstance(); $hkproductModel = $this->objectManager->create('HK\Productattach\Model\Productattach'); $hkproductCollection = $hkproductModel->getCollection()->addFieldToFilter('customer_id', $customer->getId()); if($hkproductCollection->count() > 0){ $hkproductCollection = $hkproductCollection->getFirstItem(); $hkproductCollection->setProducts($products); $hkproductCollection->save(); }else{ if($products){ $hkproductModel->setData(array('products'=>$products, 'customer_id' => $customer->getId())); $hkproductModel->save(); } } } }
Step13: HK/Productattach/Setup/InstallSchema.php
<?php namespace HK\Productattach\Setup; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\DB\Adapter\AdapterInterface; class InstallSchema implements InstallSchemaInterface { public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $installer = $setup; $installer->startSetup(); $installer->getConnection()->dropTable($installer->getTable('hk_productattach')); $hk_productattach = $installer->getConnection()->newTable($installer->getTable('hk_productattach')); $hk_productattach->addColumn( 'productattach_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 'Entity Id' ); $hk_productattach->addColumn( 'customer_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['nullable' => true,'default' => null], 'Customer ID' ); $hk_productattach->addColumn( 'products', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, null, ['nullable' => true,'default' => null], 'Assigned Products' ); $hk_productattach->addColumn( 'created_at', \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, null, ['nullable' => false], 'Created At' ); $installer->getConnection()->createTable($hk_productattach); $installer->endSetup(); $installer->endSetup(); } }
Step14: HK/Productattach/view/adminhtml/layout/customer_index_edit.xml
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="customer_form"> <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="customer_edit_tab_products"> <action method="setTabLabel"> <argument name="label" xsi:type="string">Customer Products</argument> </action> </block> </referenceBlock> </body> </page>
Step15: HK/Productattach/view/adminhtml/layout/productattach_index_products.xml
<?xml version="1.0" encoding="UTF-8"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> <container name="root" label="Root"> <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="productattach.edit.tab.products"/> <block class="Magento\Backend\Block\Widget\Grid\Serializer" name="products_grid_serializer"> <arguments> <argument name="grid_block" xsi:type="string">productattach.edit.tab.products</argument> <argument name="callback" xsi:type="string">getSelectedProducts</argument> <argument name="input_element_name" xsi:type="string">products</argument> <argument name="reload_param_name" xsi:type="string">index_products</argument> </arguments> </block> <block class="Magento\Framework\View\Element\Template" name="grid_scriptjs" template="HK_Productattach::scriptjs.phtml"/> </container> </layout>
Step16: HK/Productattach/view/adminhtml/layout/productattach_index_productsgrid.xml
<?xml version="1.0" encoding="UTF-8"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> <container name="root" label="Root"> <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="productattach.edit.tab.products"/> </container> </layout>
Step17: HK/Productattach/view/adminhtml/templates/scriptjs.phtml
<script> require([ "jquery", ], function($){ $("input[name='products']").attr('data-form-part','customer_form'); }); </script>
Now run following commands and you are done.
php bin/magento setup:upgrade php bin/magento setup:static-content:deploy
I hope this will help someone.
Thanks
Please support us, Like us on Facebook.
Subscribe to:
Post Comments (Atom)
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'magento2_magento2.hk_productattach' doesn't exist, query was: SELECT `main_table`.* FROM `hk_productattach` AS `main_table` WHERE (`customer_id` = '5')
ReplyDeleteI've got this error can help me to solve it ?? its in the customer edit page
Thanx, hellped a lot.
ReplyDelete