How to write a new hook plugin

In this tutorial we will show you how to write a new hook plugin for the Springbok framework.

We are going to create a DeleteHook that will be called after each bulk has been processed. This hook will be used to mark concrete products as deleted.


Step 1: Create a new DeleteHook

First we need to create a new Hook class which can implement multiple hook interfaces. In this example we are going to use a AfterBulkHookInterface to collect ProductConcreteIds and then a AfterPipelineHookInterface to mark those ids as deleted.

To do this we need to create a new class that implements the AfterBulkHookInterface and AfterPipelineHookInterface.

<?php

namespace Pyz\Zed\SpringbokCommon\Business\Hook;

use Antiloop\Zed\Springbok\Dependency\Plugin\AfterBulkHookInterface;
use Antiloop\Zed\Springbok\Dependency\Plugin\AfterPipelineHookInterface;
use Flow\ETL\Rows;
use Spryker\Zed\Product\Business\ProductFacadeInterface;

class DeleteHook implements AfterBulkHookInterface, AfterPipelineHookInterface
{
    /**
     * @var array<int, int>
     */
     protected array $productConcreteIds = [];

    /**
     * @var \Spryker\Zed\Product\Business\ProductFacadeInterface
     */
    protected ProductFacadeInterface $productFacade;

    /**
     * @var string
     */
    protected string $idColumn;

    /**
     * @param \Spryker\Zed\Product\Business\ProductFacadeInterface $productFacade
     * @param string $idColumn
     */
    public function __construct(ProductFacadeInterface $productFacade, string $idColumn)
    {
        $this->productFacade = $productFacade;
        $this->idColumn = $idColumn;
    }

    /**
     * Gets called after a bulk of rows is processed.
     *
     * @param \Flow\ETL\Rows $rows
     *
     * @return void
     */
    public function afterBulk(Rows $rows): void
    {
        foreach ($rows as $row) {
            $this->productConcreteIds[] = $row->get($this->idColumn)->value();
        }
    }

    /**
     * Gets called after the pipeline is executed.
     *
     * @return void
     */
    public function afterPipeline(): void
    {
        foreach ($this->productConcreteIds as $idProductConcrete) {
            $this->productFacade->touchProductConcreteDelete($idProductConcrete);
        }
    }
}

Step 2: Add the hook to the factory

Now that we have created the hook we need to add it to the factory so that we can instantiate it.

We are using the factory to create our actual Hook. We need to add a factory method to the SpringbokCommonCommunicationFactory class.

SpringbokCommonCommunicationFactory.php:

<?php

namespace Pyz\Zed\SpringbokCommon\Communication;

use Flow\ETL\Loader;
use Flow\ETL\Transformer;
use Pyz\Zed\SpringbokCommon\Business\Hook\DeleteHook;

class SpringbokCommonCommunicationFactory extends AbstractCommunicationFactory
{
    /**
     * @return \Pyz\Zed\SpringbokCommon\Business\Hook\DeleteHook
     */
    public function createDeleteHook(string $idColumn): DeleteHook
    {
        return new DeleteHook($this->getProductFacade(), $idColumn);
    }
}

Step 3: Create a plugin that will allow us to use the hook in a pipeline

To make springbok aware of the hook we need to create a plugin that will allow us to use the hook in a pipeline.

We need to create a new class that extends the AbstractPlugin class and implements the HookPluginInterface.

<?php

namespace Pyz\Zed\SpringbokCommon\Communication\Plugins;

use Antiloop\Zed\Springbok\Dependency\Plugin\HookInterface;
use Antiloop\Zed\Springbok\Dependency\Plugin\HookPluginInterface;
use Spryker\Zed\Kernel\Communication\AbstractPlugin;

/**
 * @method \Pyz\Zed\SpringbokCommon\Communication\SpringbokCommonCommunicationFactory getFactory()
 */
class DeleteHookPlugin extends AbstractPlugin implements HookPluginInterface
{
    /**
     * @var string
     */
    protected const NAME = 'delete-hook';

    /**
     * @return string
     */
    public function getName(): string
    {
        return static::NAME;
    }

    /**
     * @param array $xml
     * @param array $options
     *
     * @return \Antiloop\Zed\Springbok\Dependency\Plugin\HookInterface
     */
    public function build(array $xml, array $options): HookInterface
    {
        $idColumn = $xml['@idColumn'];

        return $this->getFactory()->createDeleteHook($idColumn);
    }
}

Step 4: Register the plugin

Finally, we need to register the plugin in the SpringbokDependencyProvider class.

<?php

namespace Pyz\Zed\Springbok;

use Antiloop\Zed\Springbok\SpringbokDependencyProvider as SpringbokSpringbokDependencyProvider;
use Pyz\Zed\SpringbokCommon\Communication\Plugins\DeleteHookPlugin;

class SpringbokDependencyProvider extends SpringbokSpringbokDependencyProvider
{
    /**
     * @return array<\Antiloop\Zed\Springbok\Dependency\Plugin\HookPluginInterface>
     */
    protected function getHookPlugins(): array
    {
        return [
            new DeleteHookPlugin(),
        ];
    }
}

Step 5: Use the plugin

Now you can use the plugin in your Springbok pipeline configuration.

<delete-hook />

What we have done in this tutorial?

  • We have created a DeleteHook

  • We added the hook to the factory so that we can instantiate.

  • We created a plugin that will allow us to use the hook in a pipeline.

  • We added the plugin to the dependency provider so that it can be used in the pipeline.

Now you can use the plugin in your pipeline configuration file. And this concludes the tutorial on how to write a new hook plugin for the Springbok framework.


Further reading: