Magento 2 – Form Creation for Custom Tab in Customer Dashboard

customerlayoutmagento-2.0magento2

I added custom tab in customer dashboard, using customer_account.xml and i need to create form to this custom tab, if I click this custom tab, form will open in content area based on customer dashboard. So, which xml file I need to use to write a content.

Best Answer

I have done it like this , hope it will help you , i have extracted the script from my full module just to explain the flow of adding form and saving form data to database.

It is bit lengthy , but tried to explain in detail

For adding custom tab to customer dashboard

created a file view/frontend/layout/customer_account.xml with script

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" label="Customer My Account (All Pages)" design_abstraction="custom">
    <body>        
        <referenceBlock name="customer_account_navigation">
            <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-customtab-link">
                <arguments>
                    <argument name="label" xsi:type="string" translate="true">Profile</argument>
                    <argument name="path" xsi:type="string">customtab/profile</argument>
                </arguments>
            </block>
        </referenceBlock>
    </body>
</page>

Then created the controller Controller/Profile/Index.php that will work for path customtab/profile with script

namespace Sample\Customtab\Controller\Profile;

class Index extends \Sample\Customtab\Controller\Profile
{
    /**
     * Managing newsletter subscription page
     *
     * @return void
     */
    public function execute()
    {
        $this->_view->loadLayout();

        /*if ($block = $this->_view->getLayout()->getBlock('customer_newsletter')) {
            $block->setRefererUrl($this->_redirect->getRefererUrl());
        }*/
        $this->_view->getPage()->getConfig()->getTitle()->set(__('Custom Profile'));
        $this->_view->renderLayout();
    }
}

Now created the layout file at view/frontend/layout/customtab_profile_index.xml with script

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="customer_account"/>
    <body>
        <referenceContainer name="content">
            <block class="Sample\Customtab\Block\Store\Profile" name="customtab.store.profile" template="Sample_Customtab::store/profile.phtml"  />
        </referenceContainer>
    </body>
</page>

Now i have to create the block Block/Store/Profile.php

namespace Sample\Customtab\Block\Store;

/**
 * Sales order history block
 */
class Profile extends \Magento\Framework\View\Element\Template
{
    /**
     * @var string
     */
    //protected $_template = 'order/history.phtml';

    /**
     * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory
     */
    protected $collectionFactory;

    /**
     * @var \Magento\Customer\Model\Session
     */
    protected $_customerSession;

    /**
     * @var \Magento\Sales\Model\Order\Config
     */
    protected $_orderConfig;

    /** @var \Magento\Sales\Model\ResourceModel\Order\Collection */
    protected $orders;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderCollectionFactory
     * @param \Magento\Customer\Model\Session $customerSession
     * @param \Magento\Sales\Model\Order\Config $orderConfig
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Sample\Customtab\Model\ResourceModel\Stores\CollectionFactory $collectionFactory,
        \Magento\Customer\Model\Session $customerSession,
        array $data = []
    ) {
        $this->collectionFactory = $collectionFactory;
        $this->_customerSession = $customerSession;
        parent::__construct($context, $data);
    }

    /**
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $this->pageConfig->getTitle()->set(__('Store Profile'));

        $customerId     = $this->_customerSession->getCustomerId();   

        if($customerId)
        {
           $profiledata = $this->collectionFactory->create()->addFieldToSelect('*')
            ->addFieldToFilter('customer_id',$customerId);

           foreach($profiledata as $profile)
           {        
                $this->setProfileData($profile);
           }
        }
    }
}

And now the called phtml file view/frontend/templates/store/profile.phtml

$storeProfile = $block->getProfileData();

And in the form you have to put form action like

action="<?php echo $this->getUrl('customtab/profile/save'); ?>"

I have just place the code to fetch the data , in this phtml file you can put your html code with your required fields.

Now for \Sample\Customtab\Model\ResourceModel\Stores\CollectionFactory used in block we have to create collection for it

Create a model Model/Stores.php with

namespace Sample\Customtab\Model;

/**
 * Megamenutab megamenu model
 */
class Stores extends \Magento\Framework\Model\AbstractModel
{

    /**
     * @param \Magento\Framework\Model\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
     * @param \Magento\Framework\Data\Collection\Db $resourceCollection
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = []
    ) {
        parent::__construct($context, $registry, $resource, $resourceCollection, $data);
    }

    /**
     * @return void
     */
    public function _construct()
    {
        $this->_init('Sample\Customtab\Model\ResourceModel\Stores');
    }   
}

The ResourceModel Model/ResourceModel/Stores.php with

namespace Sample\Customtab\Model\ResourceModel;

class Stores extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{

    public function _construct()
    {
        $this->_init('yourtablename', 'id');   // with id primery key 
    }  
}

Then Collection Model Model/ResourceModel/Stores/Collection.php with

namespace Sample\Customtab\Model\ResourceModel\Stores;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    public function _construct()
    {
        $this->_init('Sample\Customtab\Model\Stores', 'Sample\Customtab\Model\ResourceModel\Stores');
    }
}

Now have to create abstract class for save profile controller Controller/Profile.php

namespace Sample\Customtab\Controller;

use Magento\Framework\App\RequestInterface;

abstract class Profile extends \Magento\Framework\App\Action\Action
{   
    protected $_customerSession;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Customer\Model\Session $customerSession
    ) {
        parent::__construct($context);
        $this->_customerSession = $customerSession;
    }

    public function dispatch(RequestInterface $request)
    {
        if (!$this->_customerSession->authenticate()) {
            $this->_actionFlag->set('', 'no-dispatch', true);
        }
        return parent::dispatch($request);
    }
}

Now have to create profile save controller that will work on profile save form action Controller/Profile/Save.php

namespace Sample\Customtab\Controller\Profile;

use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository;

class Save extends \Sample\Customtab\Controller\Profile
{
    protected $formKeyValidator;

    protected $storeManager;

    protected $customerRepository;

    protected $subscriberFactory;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Customer\Model\Session $customerSession,
        \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        CustomerRepository $customerRepository,
        \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory
    ) {
        $this->storeManager = $storeManager;
        $this->formKeyValidator = $formKeyValidator;
        $this->customerRepository = $customerRepository;
        $this->subscriberFactory = $subscriberFactory;
        parent::__construct($context, $customerSession);
    }

    /**
     * Save newsletter subscription preference action
     *
     * @return void|null
     */
    public function execute()
    {
        if (!$this->formKeyValidator->validate($this->getRequest())) {
            return $this->_redirect('customer/account/');
        }

        $customerId = $this->_customerSession->getCustomerId();

        if ($customerId === null) {
            $this->messageManager->addError(__('Something went wrong while saving your subscription.'));
        } else {
            try {                   
                    $data = $this->getRequest()->getParams();

                    $model = $this->_objectManager->create('Sample\Customtab\Model\Stores');

                    $data['customer_id'] = $customerId; // customer_id is one of the field from custom database table

                    $id = $this->getRequest()->getParam('id');

                    if ($id) {
                    $model->load($id);
                    }

                    $model->setData($data);

                    $model->save();

                    $this->messageManager->addSuccess(__('Profile has beem saved successfully.'));

                    $this->_redirect('*/*/');

                    return;

                } catch (\Exception $e) {
                    $this->messageManager->addError(__('Something went wrong while saving your profile.'));
                }
        }
        $this->_redirect('customer/account/');
    }
}

Hope i have included all the things. And it will work for you.

Related Topic