The standard data sources in Frontastic are contained in what we call streams. For example, product-list and content are both stream types. If a Tastic is defined to retrieve a stream of a certain type, it'll be provided with the corresponding data automatically at the time of rendering. You can extend this mechanism with your own stream types to provide data to Tastics in a similar way.

You'll be using what's called the Tastic field handler. It's been known as custom field handler but the class is TasticFieldHandler.

To provide a Custom Stream type, you'll need to follow the steps below to register the handler in the Frontastic PHP stack:

Provide an implementation
In order to handle a Custom Stream, you'll need to provide an implementation of Frontastic\Catwalk\FrontendBundle\Domain\TasticFieldHandlerV2 which is the generalized interface for handling all field types and contains two methods:
namespace Frontastic\Catwalk\FrontendBundle\Domain;

use Frontastic\Catwalk\ApiCoreBundle\Domain\Context;

abstract class TasticFieldHandlerV2
     * @return string
    abstract public function getType(): string;

     * @param mixed $fieldValue
     * @return mixed Handled value
    abstract public function handle(Context $context, Node $node, Page $page, $fieldValue);

The getType() method should return the type identifier for your stream type.

You must prefix custom stream types with your project ID in the form<project-id>-<stream-type>, for example, awesomeshop-stores if your project is awesomeshop and your StreamType will provide information about local stores.

The second method handle() performs the actual work of handling a stream of your type. It's called by Frontastic as soon as a Tastic requires a stream of your type.

As parameters, it receives the current application Context, Node, Page, Tastic, and the $fieldValue which was assigned by the configuring user in the Frontastic Editor.

PLEASE NOTE: We're still working on this feature. It's not yet possible for users of the Frontastic Editor to assign values to Custom Stream fields. But even without this possibility, custom streams can be useful to provide data to a Tastic.

The handle() method is supposed to return the value of the stream that will then be given to the Tastic that required it. It can be an arbitrary value type except for one constraint: It must be serializable to JSON (that excludes, for example, resource types). Ideally, you will return either:

  • A simple data object
  • An array of scalar values of simple array objects
  • Null
  • A combination of the above

You might notice that this is also called TasticFieldHandlerV2. If you previously implemented the TasticFieldHandler and it's not using V2, you can use the TasticFieldHandlerAdapter if you don't want to update to using V2.

Register your Tastic field handler
Now that you've implemented your Tastic field handler for your custom stream, you need to register it in the Symfony service container and apply a tag to it so it knows what it is.

To do this, go to your service.xml in one of your project bundles (if there isn't a bundle yet, you can create one using bin/console frontastic:create:bundle MyDecorators, for example) and then add the tag frontend.tasticFieldHandler to it in a similar way to the below:

<service id="Frontastic\Customer\StorefinderBundle\Domain\StreamHandler">
     <argument type="service" id="Frontastic\Customer\StorefinderBundle\Domain\StorefinderService" />

     <tag name="frontend.tasticFieldHandler"/>

In this example, a Tastic field handler is registered for implementing a store finder. The field handler implementation itself is rather slim and dispatches all work to a service. This gives you the possibility to unleash the full power of Frontastic, Symfony, and your own microservice APIs within a field handler.

Use the stream in a Tastic
All you need to do now is add your Tastic field handler to a Tastic schema. You must set the  type to stream and then set the streamType to the type that you created in the first step, for example:
     "tasticType": "awesomeshop-store-finder",
     "name": "Storefinder",
     "category": "Awesome Shop",
     "icon": "store",
     "schema": [
	     "name": "General",
	     "fields": [
		     "label": "Stores",
		     "field": "stream",
		     "type": "stream",
		     "streamType": "awesomeshop-stores",
		     "default": null,
		     "required": false

Accessing the request

WARNING: We generally discourage accessing the request from a service, however, until we can offer a better way to access such information it can be used as a workaround.

Since a field handler is just a normal Symfony service you can get any service injected to dispatch work to. This also holds for the RequestStack which allows you to get hands on the currently processed request to access URL parameters and much more:

namespace Frontastic\Customer\StorefinderBundle\Domain;

use Symfony\Component\HttpFoundation\RequestStack;

use Frontastic\Catwalk\FrontendBundle\Domain\TasticFieldHandler;
use Frontastic\Catwalk\FrontendBundle\Domain\Stream;
use Frontastic\Catwalk\ApiCoreBundle\Domain\DataRepository;
use Frontastic\Catwalk\ApiCoreBundle\Domain\Context;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi\Locale;

class StoresFieldHandler 
extends TasticFieldHandlerV2
     private $service;

     private $requestStack;

     public function __construct(StorefinderService $service, RequestStack $requestStack)
	$this->service = $service;
	$this->requestStack = $requestStack;

     public function getType(): string
	return 'awesomeshop-stores';

     public function handle(Context $context, Node $node, Page $page, $fieldValue)
	$locationId = $this->requestStack->getCurrentRequest()->get('location', null);
	if (!$locationId) {
	     return null;

	$locale = Locale::createFromPosix($context->locale);
	return $this->service->getStores($locale->territory, $locationId);

In this example the RequestStack is asked for the current request to fetch the URL parameter location. If this isn't set, the stream simply contains nothing. Otherwise, the corresponding domain service is used to determine stores for the stream.

‹ Back to article list

Still need help? Contact us Contact us