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']); }
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
#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()); } }); } );
// 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(); }, }); });
Be the first to comment.