Request Quote

How to Create Custom DataGrid using Akeneo

In Akeneo, If you want to display a list of item in a grid system with CRUD functionalities. You can use Akeneo Datagrid. the benefits of Akeneo grid component are filtering, sorting, pagination, and search item. Using Akeneo you can define the form to edit or display an item easily.  Let’s start with an example with multi credentials for a connector.

First, you need to create an entity for data grid items. As Akeneo relies heavily on standard tools like Doctrine,

 

# /src/Webkul/CustomBundle/Entity/CredentialsConfig.php

<?php

namespace Webkul\CustomBundle\Entity;

/**
 * CredentialsConfig
 */
class CredentialsConfig
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $url;

    /**
     * @var string
     */
    private $apiUser;

    /**
     * @var string
     */
    private $apiKey;

    /**
     * @var boolean
     */
    private $active = 0;


    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set url
     *
     * @param string $url
     *
     * @return CredentialsConfig
     */
    public function setUrl($url)
    {
        $this->url = $url;

        return $this;
    }

    /**
     * Get url
     *
     * @return string
     */
    public function getUrl()
    {
        return $this->url;
    }

    /**
     * Set apiUser
     *
     * @param string $apiUser
     *
     * @return CredentialsConfig
     */
    public function setApiUser($apiUser)
    {
        $this->apiUser = $apiUser;

        return $this;
    }

    /**
     * Get apiUser
     *
     * @return string
     */
    public function getApiUser()
    {
        return $this->apiUser;
    }

    /**
     * Set apiKey
     *
     * @param string $apiKey
     *
     * @return CredentialsConfig
     */
    public function setApiKey($apiKey)
    {
        $this->apiKey = $apiKey;

        return $this;
    }

    /**
     * Get apiKey
     *
     * @return string
     */
    public function getApiKey()
    {
        return $this->apiKey;
    }

    /**
     * Set active
     *
     * @param boolean $active
     *
     * @return CredentialsConfig
     */
    public function setActive($active)
    {
        $this->active = $active;

        return $this;
    }

    /**
     * Get active
     *
     * @return boolean
     */
    public function getActive()
    {
        return $this->active;
    }

    /**
     * Change the active value vice-versa
     */
    public function activation() 
    {
        $this->active = !$this->active;

        return $this;
    }
    /**
     * @var string
     */
    private $resources;


    /**
     * Set resources
     *
     * @param string $resources
     *
     * @return CredentialsConfig
     */
    public function setResources($resources)
    {
        $this->resources = $resources;

        return $this;
    }

    /**
     * Get resources
     *
     * @return string
     */
    public function getResources()
    {
        return $this->resources;
    }
}

 

Now create a Datagrid.

#src/Webkul/CustomBundle/Resources/config/datagrid
datagrid:
    webkul-custom-credentials-mapping-grid:
        extended_entity_name: Webkul\CustomBundle\Entity\CredentialsConfig
        options:
            entityHint: CredentialsConfig
            manageFilters: false
        source:
            acl_resource: webkul_custom_connector_configuration
            type: custom_datasource_credentials
            entity: 'Webkul\CustomBundle\Entity\CredentialsConfig'
            query:
                select:
                    - wem.id
                    - wem.url
                    - wem.apiUser
                    - wem.apiKey
                    - wem.active
                from:
                    - { table: 'Webkul\CustomBundle\Entity\CredentialsConfig', alias: wem }
        columns:
            url:
                label: webkul_custom.credentials.grid.export_mappings.columns.url
                frontend_type: label
            apiUser:
                label: webkul_custom.credentials.grid.export_mappings.columns.apiUser
            active:
                label: Activated
                type: twig
                template: PimDataGridBundle:Property:activated.html.twig
                frontend_type: html

        properties:
            id: ~
            edit_link:
                type: url
                route: webkul_custom_credentials_edit
                params:
                    - id
            toggle_link:
                type: url
                route: webkul_custom_credentials_change_status
                params:
                    - id
            delete_link:
                type: url
                route: webkul_custom_credentials_delete
                params:
                    - id
        sorters:
            columns:
                url:
                    data_name: wem.url
                apiUser:
                    data_name: wem.apiUser
                active:
                    data_name: wem.active
            default:
                url: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC'

        filters:
            columns:
                url:
                    type: search
                    data_name: wem.url
                    
                active:
                    type:      boolean
                    label:     Activated
                    data_name: wem.active

        actions:
            toggle:
                launcherOptions:
                    className: AknIconButton AknIconButton--small AknIconButton--switch
                type:         navigate
                label:        Change status
                link:         toggle_link
                acl_resource: webkul_custom_connector_configuration
            edit:
                launcherOptions:
                    className: AknIconButton AknIconButton--small AknIconButton--edit
                type:      navigate
                label:     Edit
                link:      edit_link
                acl_resource: webkul_custom_connector_configuration
                rowAction: true
            delete:
                launcherOptions:
                    className: AknIconButton AknIconButton--small AknIconButton--trash
                type:          delete
                label:         Delete
                link:          delete_link
                acl_resource:  webkul_custom_connector_configuration

 

you need to define the data source service for datagrid.

#src/Webkul/customBundle/Resources/config

services:    
    webkul_custom_datagrid.datasource.credentails:
        class: Webkul\customBundle\Datasource\CredentailsDatasource
        arguments:
            - '@webkul_custom.repository.credentials'
            - '@pim_datagrid.datasource.result_record.hydrator.default'
        tags:
            - { name: oro_datagrid.datasource, type: custom_datasource_credentials }

Define the Datasource class which is used in data source service.

<?php

namespace Webkul\CustomBundle\Datasource;

use Pim\Bundle\DataGridBundle\Datasource\Datasource;
use Webkul\CustomBundle\Repository\CustomCredentailsRepository;
use Pim\Bundle\DataGridBundle\Datasource\ResultRecord\HydratorInterface;


class CredentailsDatasource extends Datasource
{
    /** @var CustomCredentailsRepository */
    protected $repository;

    /** @var CustomObjectIdHydrator */
    protected $hydrator;

    /** @var array */
    protected $parameters = [];

    /**
     * @param CustomCredentailsRepository $om
     * @param HydratorInterface          $hydrator
     */
    public function __construct(CustomCredentailsRepository $repository, HydratorInterface $hydrator)
    {
        $this->repository = $repository;
        $this->hydrator = $hydrator;
    }

    /**
     * @param string $method the query builder creation method
     * @param array  $config the query builder creation config
     *
     * @return Datasource
     */
    protected function initializeQueryBuilder($method, array $config = [])
    {
        $this->qb = $this->repository->$method('wem');
        
        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getResults()
    {
        return $this->hydrator->hydrate($this->qb);
    }
}

Define the Access control list ( acl.yml )

#src/Webkul/CustomBundle/Resource/config/acl.yml

webkul_custom_connector_configuration:
    type: action
    label: Custom Connector
    group_name: ~


Define the following routes as used in datagrid for actions edit, change status, delete.

  • webkul_custom_credentials_edit
  • webkul_custom_credentials_change_status
  • webkul_custom_credentials_delete
#src/Webkul/customBundle/Resources/config/routing.yml

webkul_custom_credentials_edit:
    path: /custom-configuration/rest/edit/{id}
    requirements:
        id: \d+

webkul_custom_credentials_change_status:
    path: /custom-configuration/rest/toggle/{id}
    defaults: { _controller: customBundle:Rest\Configuration:toggle }
    requirements:
        id: \d+

webkul_custom_credentials_delete:
  path: /custom-configuration/rest/credentials/{id}
  defaults: { _controller: customBundle:Rest\Configuration:deleteCredentail }
  requirements:
  id: \d+
  methods: [DELETE]


Define the methods for changestatus, and delete
# Webkul\CustomBundle\Controller\Rest\ConfigurationController

 /**
     * Remove url
     *
     * @AclAncestor("webkul_custom_connector_configuration")
     *
     * @return JsonResponse
     */
    public function deleteCredentailAction($id)
    {
        $mapping = $this->get('webkul_custom.repository.credentials')->find($id);
        if(!$mapping) {
            throw new NotFoundHttpException(
                    sprintf('Instance with id "%s" not found', $id)
                );
        }
        $em = $this->getDoctrine()->getManager();
        $em->remove($mapping);
        $em->flush();

        return new Response(null, Response::HTTP_NO_CONTENT);
    }



    /**
     * Activate/Deactivate a credential instance
     *
     * @param CredentialsConfig $configValue
     *
     * @AclAncestor("webkul_custom_connector_configuration")
     *
     * @return JsonResponse
     */
    public function toggleAction(CredentialsConfig $configValue)
    {
        try{
            $em = $this->getDoctrine()->getManager();

            //change current active value
            $configValue->activation();
            $em->persist($configValue);
            $em->flush();
            
        } catch(Exception $e) {
            return new JsonResponse(['route' => 'webkul_custom_connector_configuration']);
        }
        
        return new JsonResponse(['route' => 'webkul_custom_connector_configuration']);
    }
Model form to create credential Instance
extensions:
    # Attribute Mapping Model
    webkul-custom-connector-create-instance-modal:
        module: custom/form/configuration/create/modal
        config:
            labels:
                title: webkul_custom_connector.create_popin.title
                subTitle: webkul_custom_connector.item.credential
            picture: illustrations/Groups.svg
            successMessage: pim_enrich.entity.group_type.message.created
            editRoute: webkul_custom_credentials_edit
            postUrl: webkul_custom_credentials_create
            routerKey: id

    webkul-custom-connector-create-instance-modal-host:
        module: custom/form/configuration/create/form
        parent: webkul-custom-connector-create-instance-modal
        targetZone: fields
        position: 10
        config:
            labels:
                title: webkul_custom_connector.create_popin.title
                subTitle: webkul_custom_connector.item.export_mapping
            identifier: host
            label: webkul_custom_connector.hostName
Create the js module and registered in requirejs.yml
#src/Webkul/customBundle/Resources/config/requirejs.yml
config:
    paths:
        custom/form/configuration/create/modal: custom/js/form/configuration/create/modal
        custom/form/configuration/create/form: custom/js/form/configuration/create/form

    config:
        pim/controller-registry:
            controllers:
                webkul_custom_credentials_change_status:
                    module: pim/controller/redirect
                webkul_custom_credentials_edit:
                    module: custom/form/configuration/credentials/edit

Create instance js module.

// src/Webkul/customBundle/Resources/public/js/form/configuration/create/modal.js

'use strict';

define(
    [
        'jquery',
        'underscore',
        'oro/translator',
        'routing',
        'pim/form/common/creation/modal',
        'oro/loading-mask',
        'pim/router',
    ],
    function (
        $,
        _,
        __,
        Routing,
        BaseModal,
        LoadingMask,
        router,
    ) {
        return BaseModal.extend({
            validationErrors: {},
            
            /**
             * {@inheritdoc}
             */
            save() {
                this.validationErrors = {};

                const loadingMask = new LoadingMask();
                this.$el.empty().append(loadingMask.render().$el.show());

                let data = this.getFormData();

                return $.ajax({
                    url: Routing.generate(this.config.postUrl),
                    type: 'POST',
                    data: JSON.stringify(data)
                }).fail(function (response) {
                    this.validationErrors = response.responseJSON;
                    this.render();
                }.bind(this))
                .always(() => loadingMask.remove());
            }
        });
    }
);
Create the form for the above module.
// src/Webkul/customBundle/Resources/public/js/form/configuration/create
define([
    'jquery',
    'underscore',
    'custom/form/configuration/create/modal',
    'pim/user-context',
    'oro/translator',
    'pim/fetcher-registry',
    'pim/initselect2',
    'custom/template/configuration/tab/credential',
    'routing',
    'oro/messenger',
    'oro/loading-mask'
], function(
    $,
    _,
    BaseModal,
    UserContext,
    __,
    FetcherRegistry,
    initSelect2,
    template,
    Routing,
    messenger,
    LoadingMask
    ) {

    return BaseModal.extend({
        loadingMask: null,
            updateFailureMessage: __('error to fetch token'),
            updateSuccessMessage: __('pim_enrich.entity.info.update_successful'),
            label: __('pim_enrich.entity.save.label'),
            isGroup: true,
            label: __('custom.credential.tab'),
            template: _.template(template),
            code: 'custom_connector_credential',
            controls: [{
                'label' : 'custom.form.properties.host_name.title',
                'name': 'hostName',
                'type': 'text'
            }, {
                'label' : 'custom.form.properties.apiUser.title',
                'name': 'apiUser',
                'type': 'text'
            }, {
                'label' : 'custom.form.properties.apiKey.title',
                'name': 'apiKey',
                'type': 'password'
            }],

            errors: [],
            events: {
                'change .AknFormContainer-Credential input': 'updateModel',
            },
           
             /**
             * {@inheritdoc}
             */
            render: function () {
                $('#container .AknButtonList[data-drop-zone="buttons"] div:nth-of-type(1)').hide();
                
                self = this;
                var controls;
                var controls2;
                
                this.$el.html(this.template({
                    controls: self.controls,
                    controls2: self.controls2,
                    model: self.getFormData(),
                    errors: this.parent.validationErrors
                }));
                this.delegateEvents();
            },
            /**
             * Update model after value change
             *
             * @param {Event} event
             */
            updateModel: function (event) {
                var data = this.getFormData();
                switch(event.target.id) {
                    case 'pim_enrich_entity_form_hostName':
                        data['hostName'] = event.target.value
                        break;
                    case 'pim_enrich_entity_form_apiUser':
                        data['apiUser'] = event.target.value
                        break;
                    case 'pim_enrich_entity_form_apiKey':
                        data['apiKey'] = event.target.value
                }
                
                this.setData(data);
            },
            
            stringify: function(formData) {
                if('undefined' != typeof(formData['mapping']) && formData['mapping'] instanceof Array) {
                    formData['mapping'] = $.extend({}, formData['mapping']);
                }

                return JSON.stringify(formData);                
            },

            /**
             * {@inheritdoc}
             */
            getSaveUrl: function () {
                var route = Routing.generate('webkul_custom_connector_configuration_post');
                return route;
            },
            /**
             * Sets errors
             *
             * @param {Object} errors
             */
            setValidationErrors: function (errors) {
                this.parent.validationErrors = errors.response;
                this.render();
            },

            /**
             * Resets errors
             */
            resetValidationErrors: function () {
                this.parent.validationErrors = {};
                this.render();
            },

                        /**
             * Show the loading mask
             */
            showLoadingMask: function () {
                this.loadingMask = new LoadingMask();
                this.loadingMask.render().$el.appendTo(this.getRoot().$el).show();
            },

            /**
             * Hide the loading mask
             */
            hideLoadingMask: function () {
                this.loadingMask.hide().$el.remove();
            },
         
    });
});
Now grid is ready to render.
Additionally, you can add mass edit, delete options for items in the datagrid.
.
Referances:
https://docs.akeneo.com/1.3/cookbook/custom_entity/creating_a_custom_entity.html
  
https://docs.akeneo.com/1.6/cookbook/ui_customization/create_a_reference_data_crud.html
 .
Thanks
. . .

Comment

Add Your Comment

Be the first to comment.

css.php