Support Form: Extensibility
Support Form for Sylius - rejecting requests through an event before storing, extending the form with a FormTypeExtension, replaceable services, plus hooks and templates of the admin interface
Support Form: Extensibility
Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net
The plugin provides two places where your own code can hook in without modifying the plugin. Both are meant for spam protection, but they work for any check before storing.
Rejecting requests before they are stored
Before a request is stored, the processing dispatches the event mmd_sylius_support_form_plugin.support_request.pre_persist. The constant for it is SupportRequestEvents::PRE_PERSIST. This happens on both paths, in the shop and through the Shop API. A listener receives a SupportRequestPrePersistEvent with the request and the current Request and can reject the request.
<?php
declare(strict_types=1);
namespace App\EventListener;
use Mmd\SyliusSupportFormPlugin\Event\SupportRequestEvents;
use Mmd\SyliusSupportFormPlugin\Event\SupportRequestPrePersistEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: SupportRequestEvents::PRE_PERSIST)]
final class RejectBlockedSubjects
{
public function __invoke(SupportRequestPrePersistEvent $event): void
{
$subject = $event->getSupportRequest()->getSubject() ?? '';
if (str_contains(strtolower($subject), 'casino')) {
$event->reject('app.support_form.rejected');
}
}
}
reject() accepts an optional reason:
| Path | Effect of reject() |
|---|---|
| Storefront | The customer sees the reason as an error message. The reason is a translation key. Without a reason the default message "Your submission could not be processed. Please try again." appears. |
| Shop API | The API answers with 422. The reason appears unchanged in the error message, without a reason it says "Submission rejected." |
If a listener rejects the request, it is neither stored nor sent. This applies to both mails.
The listener runs after the request is valid. It therefore only sees requests that already meet all required fields. Checks on the
Requestinclude rate limiting, a honeypot field or evaluating a proof-of-work token.
Extending the form with fields
SupportRequestType is an ordinary Symfony form type and not final. A FormTypeExtension targeting SupportRequestType::class can therefore add its own fields, for example for a spam protection widget.
<?php
declare(strict_types=1);
namespace App\Form\Extension;
use Mmd\SyliusSupportFormPlugin\Form\Type\SupportRequestType;
use Symfony\Component\Form\AbstractTypeExtension;
final class SupportRequestTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return [SupportRequestType::class];
}
}
In addition, the storefront template provides the hook mmd_altcha.widget.support_form before the submit button (see Storefront).
A form type extension only takes effect in the storefront. The Shop API doesn't build any form fields. A check that should apply to both paths therefore belongs in a listener on
PRE_PERSIST.
Replaceable services
These services are registered as aliases through an interface. You can replace them in your application with your own implementation by redirecting the alias:
| Interface | Purpose |
|---|---|
SupportRequestSubmissionHandlerInterface |
Dispatches PRE_PERSIST, stores and notifies |
SupportRequestMailerInterface |
Sends notification and confirmation |
SupportFormSubjectResolverInterface |
Provides the subject choices of a channel and resolves a code into its label |
SupportFormPrivacyPolicyLinkProviderInterface |
Provides the privacy link for the consent |
SupportRequestAnswersApplierInterface |
Validates the Shop API answers and applies them to the request |
The entities (SupportRequest, SupportFormField, SupportFormChannelConfiguration, plus SupportFormFieldTranslation for the translations of a field) are Sylius resources. You can replace them with your own classes through the Sylius resource configuration, as with any other Sylius resource.
# config/services.yaml
services:
Mmd\SyliusSupportFormPlugin\Mailer\SupportRequestMailerInterface:
alias: App\Mailer\MySupportRequestMailer
Customizing the admin interface
The plugin attaches its admin pages to the Sylius interface through Twig hooks. You can register your own entries on the same hooks or override the templates.
Hooks:
sylius_admin.support_request.show.contentsylius_admin.support_request.index.content.header.title_blocksylius_admin.support_request.index.content.header.title_block.actionssylius_admin.support_form_field.index.content.header.title_blocksylius_admin.support_form_field.index.content.header.title_block.actionssylius_admin.support_form_field.create.content.form.sectionssylius_admin.support_form_field.update.content.form.sectionssylius_admin.support_form_channel_configuration.index.content.header.title_blocksylius_admin.support_form_channel_configuration.index.content.header.title_block.actionssylius_admin.support_form_channel_configuration.create.content.form.sectionssylius_admin.support_form_channel_configuration.update.content.form.sections
Templates (put a copy under templates/bundles/MmdSyliusSupportFormPlugin/, using the same path without the leading templates/):
templates/admin/common/title_block/title.html.twigtemplates/admin/support_request/show/content/details.html.twigtemplates/admin/support_request/title_block/actions/channel_configuration.html.twigtemplates/admin/support_form_field/form/sections/general.html.twigtemplates/admin/support_form_field/form/sections/translations.html.twigtemplates/admin/support_form_field/title_block/actions/channel_configuration.html.twigtemplates/admin/support_form_channel_configuration/form/sections/general.html.twigtemplates/admin/support_form_channel_configuration/title_block/actions/support_form_fields.html.twigtemplates/admin/support_form_channel_configuration/title_block/actions/support_requests.html.twig