Create Gui tables

Edit on GitHub

This document describes how to create a new Gui table in Merchant Portal. With this step by step instructions you will create a new Gui table with filters, search, sorting and an http data source type from scratch.

Prerequisites

To install the Marketplace Merchant Portal Core feature providing the GuiTable module, follow the Marketplace Merchant Portal Core feature integration guide.

1) Add GuiTable services to dependencies

<?php

namespace Spryker\Zed\ProductMerchantPortalGui;

class ProductMerchantPortalGuiDependencyProvider extends AbstractBundleDependencyProvider
{
    public const SERVICE_GUI_TABLE_HTTP_DATA_REQUEST_EXECUTOR = 'gui_table_http_data_request_executor';

    public const SERVICE_GUI_TABLE_FACTORY = 'gui_table_factory';

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    public function provideCommunicationLayerDependencies(Container $container): Container
    {
        $container = $this->addGuiTableHttpDataRequestHandler($container);
        $container = $this->addGuiTableFactory($container);

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addGuiTableHttpDataRequestHandler(Container $container): Container
    {
        $container->set(static::SERVICE_GUI_TABLE_HTTP_DATA_REQUEST_EXECUTOR, function (Container $container) {
            return $container->getApplicationService(static::SERVICE_GUI_TABLE_HTTP_DATA_REQUEST_EXECUTOR);
        });

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addGuiTableFactory(Container $container): Container
    {
        $container->set(static::SERVICE_GUI_TABLE_FACTORY, function (Container $container) {
            return $container->getApplicationService(static::SERVICE_GUI_TABLE_FACTORY);
        });

        return $container;
    }
}

2) Create factory methods for GuiTable services

<?php

namespace Spryker\Zed\ProductMerchantPortalGui\Communication;

use Spryker\Shared\GuiTable\GuiTableFactoryInterface;
use Spryker\Shared\GuiTable\Http\GuiTableDataRequestExecutorInterface;

class ProductMerchantPortalGuiCommunicationFactory extends AbstractCommunicationFactory
{
    /**
     * @return \Spryker\Shared\GuiTable\Http\GuiTableDataRequestExecutorInterface
     */
    public function getGuiTableHttpDataRequestExecutor(): GuiTableDataRequestExecutorInterface
    {
        return $this->getProvidedDependency(ProductMerchantPortalGuiDependencyProvider::SERVICE_GUI_TABLE_HTTP_DATA_REQUEST_EXECUTOR);
    }

    /**
     * @return \Spryker\Shared\GuiTable\GuiTableFactoryInterface
     */
    public function getGuiTableFactory(): GuiTableFactoryInterface
    {
        return $this->getProvidedDependency(ProductMerchantPortalGuiDependencyProvider::SERVICE_GUI_TABLE_FACTORY);
    }
}

3) Create a configuration provider

Create GuiTableConfigurationBuilder calling GuiTableFactoryInterface::createConfigurationBuilder() (gui_table_factory service) and then create GuiTableConfigurationTransfer by calling GuiTableConfigurationBuilder::createConfiguration().

class ProductAbstractGuiTableConfigurationProvider
{
    public const COL_KEY_SKU = 'sku';
    public const COL_KEY_IMAGE = 'image';
    public const COL_KEY_NAME = 'name';
    public const COL_KEY_SUPER_ATTRIBUTES = 'superAttributes';
    public const COL_KEY_VARIANTS = 'variants';
    public const COL_KEY_CATEGORIES = 'categories';
    public const COL_KEY_STORES = 'stores';
    public const COL_KEY_VISIBILITY = 'visibility';

    /**
     * @var \Spryker\Shared\GuiTable\GuiTableFactoryInterface
     */
    protected $guiTableFactory;

    /**
     * @param \Spryker\Shared\GuiTable\GuiTableFactoryInterface $guiTableFactory
     */
    public function __construct(GuiTableFactoryInterface $guiTableFactory)
    {
        $this->guiTableFactory = $guiTableFactory;
    }

    /**
     * @return \Generated\Shared\Transfer\GuiTableConfigurationTransfer
     */
    public function getConfiguration(): GuiTableConfigurationTransfer
    {
        $guiTableConfigurationBuilder = $this->guiTableFactory->createConfigurationBuilder();

        $guiTableConfigurationBuilder = $this->addColumns($guiTableConfigurationBuilder);
        $guiTableConfigurationBuilder = $this->addFilters($guiTableConfigurationBuilder);
        $guiTableConfigurationBuilder = $this->addRowActions($guiTableConfigurationBuilder);

        $guiTableConfigurationBuilder
            ->setDataSourceUrl('/product-merchant-portal-gui/products/table-data')
            ->setSearchPlaceholder('Search by SKU, Name')
            ->setDefaultPageSize(25);

        return $guiTableConfigurationBuilder->createConfiguration();
    }

    /**
     * @param \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder
     *
     * @return \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface
     */
    protected function addColumns(GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder): GuiTableConfigurationBuilderInterface
    {
        $guiTableConfigurationBuilder->addColumnText(static::COL_KEY_SKU, 'SKU', true, false)
            ->addColumnImage(static::COL_KEY_IMAGE, 'Image', false, true)
            ->addColumnText(static::COL_KEY_NAME, 'Name', true, false)
            ->addColumnListChip(static::COL_KEY_SUPER_ATTRIBUTES, 'Super Attributes', false, true, 2, 'gray')
            ->addColumnChip(static::COL_KEY_VARIANTS, 'Variants', true, true, 'gray')
            ->addColumnListChip(static::COL_KEY_CATEGORIES, 'Categories', false, true, 2, 'gray')
            ->addColumnListChip(static::COL_KEY_STORES, 'Stores', false, true, 2, 'gray')
            ->addColumnChip(static::COL_KEY_VISIBILITY, 'Visibility', true, true, 'gray', [
                'Online' => 'green',
            ]);

        return $guiTableConfigurationBuilder;
    }

    /**
     * @param \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder
     *
     * @return \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface
     */
    protected function addFilters(GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder): GuiTableConfigurationBuilderInterface
    {
        $guiTableConfigurationBuilder->addFilterSelect('isVisible', 'Visibility', false, [
            '1' => 'Online',
            '0' => 'Offline',
        ])

        return $guiTableConfigurationBuilder;
    }

    /**
     * @param \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder
     *
     * @return \Spryker\Shared\GuiTable\Configuration\Builder\GuiTableConfigurationBuilderInterface
     */
    protected function addRowActions(GuiTableConfigurationBuilderInterface $guiTableConfigurationBuilder): GuiTableConfigurationBuilderInterface
    {
        $guiTableConfigurationBuilder->addRowActionDrawerAjaxForm(
            'update-product',
            'Manage Product',
            sprintf(
                '/product-merchant-portal-gui/update-product-abstract?product-abstract-id=${row.%s}',
                ProductAbstractTransfer::ID_PRODUCT_ABSTRACT
            )
        )->setRowClickAction('update-product');

        return $guiTableConfigurationBuilder;
    }
}

4) Introduce criteria transfer

<?xml version="1.0"?>
<transfers xmlns="spryker:transfer-01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="spryker:transfer-01 http://static.spryker.com/transfer-01.xsd">

    <transfer name="MerchantProductTableCriteria">
        <property name="searchTerm" type="string"/>
        <property name="page" type="int"/>
        <property name="pageSize" type="int"/>
        <property name="orderBy" type="string"/>
        <property name="orderDirection" type="string"/>
        <property name="filterIsVisible" type="bool"/>
    </transfer>

</transfers>

5) Create a table data provider

Create a table data provider extending Spryker\Shared\GuiTable\DataProvider\AbstractGuiTableDataProvider. In the createCriteria() method, create and return an instance of MerchantProductTableCriteriaTransfer. The properties will be filled and should be used for pagination, search, sorting and filtering. Return GuiTableDataResponseTransfer with table data in the fetchData() method using the newly introduced transfer properties from $criteriaTransfer (MerchantProductTableCriteriaTransfer introduced in AbstractGuiTableDataProvider::createCriteria()).

    /**
     * @param \Generated\Shared\Transfer\MerchantProductTableCriteriaTransfer $criteriaTransfer
     *
     * @return \Generated\Shared\Transfer\GuiTableDataResponseTransfer
     */
    protected function fetchData(AbstractTransfer $criteriaTransfer): GuiTableDataResponseTransfer
    {
        $productAbstractCollectionTransfer = $this->productMerchantPortalGuiRepository
            ->getProductAbstractTableData($criteriaTransfer);
        $guiTableDataResponseTransfer = new GuiTableDataResponseTransfer();

        foreach ($productAbstractCollectionTransfer->getProductAbstracts() as $productAbstractTransfer) {
            $responseData = [
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_SKU => $productAbstractTransfer->getSku(),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_IMAGE => $this->getImageUrl($productAbstractTransfer),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_NAME => $productAbstractTransfer->getName(),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_SUPER_ATTRIBUTES => $this->getSuperAttributesColumnData($productAbstractTransfer, $localeTransfer),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_VARIANTS => $productAbstractTransfer->getConcreteProductCount(),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_CATEGORIES => $productAbstractTransfer->getCategoryNames(),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_STORES => $productAbstractTransfer->getStoreNames(),
                ProductAbstractGuiTableConfigurationProvider::COL_KEY_VISIBILITY => $this->getVisibilityColumnData($productAbstractTransfer),
            ];

            $guiTableDataResponseTransfer->addRow((new GuiTableRowDataResponseTransfer())->setResponseData($responseData));
        }

        $paginationTransfer = $productAbstractCollectionTransfer->getPagination();

        if (!$paginationTransfer) {
            return $guiTableDataResponseTransfer;
        }

        return $guiTableDataResponseTransfer
            ->setPage($paginationTransfer->getPage())
            ->setPageSize($paginationTransfer->getMaxPerPage())
            ->setTotal($paginationTransfer->getNbResults());
    }

6) Create a page with a table

Create a controller that displays a table and make use of the newly created configuration provider to pass table configuration to the Twig template:

namespace Spryker\Zed\ProductMerchantPortalGui\Communication\Controller;

use Spryker\Zed\Kernel\Communication\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ProductsController extends AbstractController
{
    /**
     * @return mixed[]
     */
    public function indexAction(): array
    {
        return $this->viewResponse([
            'productAbstractTableConfiguration' => $this->getFactory()
                ->createProductAbstractGuiTableConfigurationProvider()
                ->getConfiguration(),
        ]);
    }
}

Create a corresponding Twig template, pass configuration to frontend component.

To learn more about table components, see Table Design.

7) Data source

Add a new action for fetching data (based on the URL set in GuiTableConfigurationBuilder::setDataSourceUrl()), pass newly introduced data provider and configuration to GuiTableHttpDataRequestExecutor::execute() and request to create a response with the table data.

    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function tableDataAction(Request $request): Response
    {
        return $this->getFactory()->getGuiTableHttpDataRequestExecutor()->execute(
            $request,
            $this->getFactory()->createProductAbstractTableDataProvider(),
            $this->getFactory()->createProductAbstractGuiTableConfigurationProvider()->getConfiguration()
        );
    }