API
The configuratorware backend has a public API, usually having the name “…Api” included. These classes are not marked as @internal and are therefore part of our backward compatibility promise. All classes that are marked as internal might change at any time with a new release without deprecations.
Events
The most common way to extend the functionality of the API is by binding listeners to existing events and add functionality there. For example if you want to calculate the weight of your configured item
After those steps the calculation call will return the calculation result with an additional property “weight” to the frontend.
Modify the CalculationResult
Create a new structure for the calculation result inheriting the original structure from the ConfiguratorApiBundle
.
This way you can add a new weight property.
<?php declare(strict_types=1);
namespace App\Structure;
use JMS\Serializer\Annotation as Serializer;
use Redhotmagma\ConfiguratorApiBundle\Structure\Frontend\CalculationResult as ApiCalculationResult;
class CalculationResult extends ApiCalculationResult
{
/**
* @Serializer\Type("integer")
*/
public $weight;
}
Create an event listener class in your project
Create an event listener in your client project.
<?php declare(strict_types=1);
namespace App\EventListener;
use Redhotmagma\ConfiguratorApiBundle\Events\CalculationEvent;
use App\Service\WeightCalculation;
class WeightCalculationListener
{
/**
* Service to calculate the weight
* @var WeightCalculation
*/
private $weightCalculation;
/**
* WeightCalculationListener constructor.
* @param WeightCalculation $weightCalculation
*/
public function __construct(WeightCalculation $weightCalculation)
{
$this->weightCalculation = $weightCalculation;
}
/**
* @param CalculationEvent $event
*/
public function onCalculate(CalculationEvent $event)
{
$configuration = $event->getConfiguration();
$calculationResult = $event->getCalculationResult();
// use your own weight calculation class to calculate the weight
$calculationResult = $this->weightCalculation->calculate($calculationResult, $configuration);
$event->setCalculationResult($calculationResult);
}
}
Register the listener to the calculation event
Your event listener has to be bound to the event. In most cases you want your code to be executed after all core functionality has been executed. The core usually sets the priority of its listeners within +/- 100.
App\EventListener\WeightCalculationListener:
autowire: true
class: App\EventListener\WeightCalculationListener
tags:
- { name: kernel.event_listener, event: configuratorware.calculation.calculate, method: onCalculate, priority: -200 }
Finding all available events
Symfony provides a command to list all available events with the listeners bound to them
bin/console debug:event-dispatcher
Repositories
If you want to add functionality to existing repositories you can create a repository class in you client project for an existing entity and have custom queries to fetch those entities there. For example if you want to retrieve items by an attribute and attribute value to get all items that are made of steel.
Create a repository in your project
Create a repository in your client project and implement the custom query you need.
<?php declare(strict_types=1);
namespace App\Repository;
use Doctrine\ORM\Query;
use Redhotmagma\ConfiguratorApiBundle\Entity\Item;
class ItemRepository extends \Redhotmagma\ConfiguratorApiBundle\Repository\ItemRepository
{
/**
* @param string $attributeIdentifier
* @param string $attributeValue
* @return Item[]|null
*/
public function fetchItemsByAttribute(
string $attributeIdentifier,
string $attributeValue
): array {
$entityName = $this->getNormalizedEntityName();
$queryBuilder = $this->createQueryBuilder($entityName);
$queryBuilder->leftJoin('item.itemAttribute', 'itemAttribute')
->leftJoin('itemAttribute.attribute', 'attribute')
->leftJoin('itemAttribute.attributevalue', 'attributevalue')
->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('attribute.identifier', ':attributeIdentifier'),
$queryBuilder->expr()->eq('attributevalue.value', ':attributeValue')
)
);
$queryBuilder->setParameter(':attributeIdentifier', $attributeIdentifier);
$queryBuilder->setParameter(':attributeValue', $attributeValue);
$query = $queryBuilder->getQuery();
$items = $query->getResult();
return $items;
}
}
Register the custom repository for the item entity
To register your item repository you have to use the repository factory. By this whenever the item repository is used in the configurator it instead uses the one with your extended functions. The newly created method to get items can then be used wherever the item repository is available.
Redhotmagma\ConfiguratorApiBundle\Repository\ItemRepository:
class: App\Repository\ItemRepository
factory: ["@configuratorware.doctrine_extensions.repository_factory", createRepository]
arguments:
- Redhotmagma\ConfiguratorApiBundle\Entity\Item
- App\Repository\ItemRepository
Security
Configuratorware allows the security config only to be stored in 1 file. It’s valid to override the firewall settings in the project, but trying to
add a new firewall will cause an error. Because of this limitation it is possible to disable configuratorware default_security
. Change in
config/packages/redhotmagma_configurator_api.yaml
to:
redhotmagma_configurator_api:
default_security: false
This will disable all security configuration. Do this on your own risk. You will need to setup the complete security for the project. It is recommended to not depend on any internals like Authenticators in your security config because they might change without deprecation.
Rest APIs
The Rest APIs for the configurator are documented in swagger.
There are three sections admin area
, frontend
and connector
.
Configuration PDF
Change Template
To change the Template of the configuration PDF, create a new template in the following folder:
templates/bundles/RedhotmagmaConfiguratorApiBundle/configuration/main.html.twig
Note
The templates
directory needs to be configured as the twig default path, which is the default after install.
The template has access to the following data:
[
'calculationResult' => Redhotmagma\ConfiguratorApiBundle\Structure\Frontend\CalculationResult,
'cover' => Redhotmagma\ConfiguratorApiBundle\Service\ConfigurationDocument\Models\Cover,
'documentInfo' => [
'currentDate' => '',
'channelSettings' => [...],
'documentType' => 'user', // 'user' or 'production'
'logoPath' => 'logo.png',
'theme' => [...],
'contactName' => '', // specified per client/globally in adminarea
'contactStreet' => '',
'contactPostCode' => '',
'contactCity' => '',
'contactPhone' => '',
'contactEmail' => '',
'displayNetPrices' => false
],
'editedDesignAreas' => Redhotmagma\ConfiguratorApiBundle\Service\ConfigurationDocument\ModelsEditedDesignArea[],
'preview' => Redhotmagma\ConfiguratorApiBundle\Service\ConfigurationDocument\Models\Preview
];
Note
Twig is a powerful template engine to generate html. For more info see: https://twig.symfony.com/ In configuratorware the PDF is generated out of html via weasyprint, see https://weasyprint.org/
Change Contents
The data array (see Change Template) for the template can be changed by listening to the Event Redhotmagma\ConfiguratorApiBundle\Events\ConfigurationDocument\DataCollectionEvent
.
Be aware that configuratorware itself uses this event to populate the data and therefore the listener must be registered after the internal listeners to overwrite.
Weasyprint
Up to version 1.24 configuratorware depended on weasyprint as PDF generator. From 1.25 on the default pdf generator is Dompdf which is installed via composer automatically without any further infrastructure requirement. If you did not customize your template, there is nothing to do. Otherwise you have 2 options:
adapt your template to work with DomPDF
adapt your service config as follows to continue to use weasyprint:
Redhotmagma\ConfiguratorApiBundle\Vector\HtmlPdfConverterInterface:
alias: Redhotmagma\ConfiguratorApiBundle\Vector\WeasyprintHtmlPdfConverter
API classes
The api classes define the public interface to the configurator functionality.
Those services can be used in client projects to access functionality that is already provided by the configurator.
E.g. if you want to load a configuration by its code you can use the method loadByConfigurationCode
in the class ConfigurationApi
.
You can find a complete list here: