I try to override the maxSizeMessage atttribute from File in a Symfony 4.2 project however, it is the default message who is returned by the framework ("The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}").
This is my validator configuration for this FormType :
# config\validator\validator.yaml
App\Application\Form\Command\PropertyPicture\PropertyAddPictureCommand:
properties:
image:
- Image:
maxSize: 10M
maxSizeMessage: "Image size over 10M"
mimeTypes: [image/jpeg, image/png, image/gif, image/bmp]
mimeTypesMessage: "Image extension not valid"
uploadErrorMessage: "An error has been encounted during the process"
[EDIT for Michał Tomczuk commentary (2019/04/08)]
This is the "FormType" object in this project (it is a DDD architecture with POMM) :
class PropertyAddPictureCommand
{
/**
* #var string
*/
public $link;
/**
* #var string
*/
public $filename;
/**
* #var Property
*/
public $property;
/**
* #var string
*/
public $pathname;
/**
* #var string
*/
public $directory;
/**
* #var UploadedFile
*/
public $image;
}
[END EDIT for Michał Tomczuk commentary (2019/04/08)]
[EDIT for Michał Tomczuk commentary (2019/04/09)]
This is the FormType object use (the object get before is the values passed in $options array) in the project :
class CommandType extends AbstractType
{
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'name' => 'command_type',
]);
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
foreach (get_object_vars($options['data']) as $key => $value) {
$builder->add($key);
}
}
}
And this is how I call the form object in the controller :
$uploadedFile = $request->files->get('image');
$propertyId = $property->getIdValue();
$directory = 'group'.DIRECTORY_SEPARATOR.$this->getUser()->getGroupId().DIRECTORY_SEPARATOR.'property'.DIRECTORY_SEPARATOR.$propertyId;
$filename = $propertyId.'-'.uniqid().'.'.$uploadedFile->getClientOriginalExtension();
$command = new PropertyAddPictureCommand();
$command->link = $this->getParameter('amazon_s3.bucket_url').'images/'.$directory.DIRECTORY_SEPARATOR.$filename;
$command->filename = $filename;
$command->property = $property;
$command->pathname = $uploadedFile->getPathname();
$command->directory = $directory;
$form = $this->createForm(CommandType::class, $command, ['data_class' => PropertyAddPictureCommand::class]);
$form->submit($request->request->all() + ['image' => $uploadedFile], false);
if (!$form->isValid()) {
throw new NotValidFormException($form);
}
[END EDIT for Michał Tomczuk commentary (2019/04/09)]
I expected to show "Image size over 10M" message when the image size is over 10M.
I think it is a property path issue.
Your form has a name - command_type, which means that every input name is preceeded with it, so instead of appending image to the request, try appending command_type[image].
I think you could also simply map the image to the command object:
$command->image = $uploadedFile;
In this case you don't need to append the image property to the request.
Related
This is Laravel 8. I'm extending Illuminate\Mail\Transport\Transport class to create a custom mail transport in order to utilize the company's custom mail API with Illuminate\Mail\Mailable. I got most of it working, including file attachments, however the Swift_Mime_SimpleMimeEntity and the classes deriving from it contain getBody(), getFilename(), getSize(), and getContentType() but no methods to extract file extension.
<?php
namespace App\CustomMailDriver;
use GuzzleHttp\ClientInterface;
use Illuminate\Mail\Transport\Transport;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Swift_Mime_SimpleMessage;
class CustomTransport extends Transport
{
/**
* Guzzle client instance.
*
* #var \GuzzleHttp\ClientInterface
*/
protected $client;
/**
* API key.
*
* #var string
*/
protected $key;
/**
* The API URL to which to POST emails.
*
* #var string
*/
protected $url;
/**
* Create a new Custom transport instance.
*
* #param \GuzzleHttp\ClientInterface $client
* #param string|null $url
* #param string $key
* #return void
*/
public function __construct(ClientInterface $client, string $url, string $key)
{
$this->key = $key;
$this->client = $client;
$this->url = $url;
}
/**
* {#inheritdoc}
*/
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
{
$this->beforeSendPerformed($message);
$payload = $this->getPayload($message);
try {
// ignore ssl (esp when working in DEV/QA)
$response = Http::withoutVerifying()->withHeaders([
'X-Authorization' => $this->key
])->post($this->url, $payload);
Log::info($response->body());
} catch (\Exception $e) {
Log::error($e->getMessage());
}
$this->sendPerformed($message);
return $this->numberOfRecipients($message);
}
/**
* Get the HTTP payload for sending the message.
*
* #param \Swift_Mime_SimpleMessage $message
* #return array
*/
protected function getPayload(Swift_Mime_SimpleMessage $message): array
{
// to
if (!empty($message->getTo())) {
$payload['payload']['to']['email'] = key($message->getTo());
}
// cc
if (!empty($message->getCc())) {
$payload['payload']['cc']['email'] = key($message->getCc());
}
// bcc
if (!empty($message->getBcc())) {
$payload['payload']['bcc']['email'] = key($message->getBcc());
}
// subject
$payload['payload']['subject'] = $message->getSubject();
// html
$payload['payload']['message']['html'] = $message->getBody();
// message children contains plain text, attachments, etc
$children = $message->getChildren();
if (!empty($children)) {
foreach($children as $child) {
// attachments
if (get_class($child) === 'Swift_Attachment') {
$payload['payload']['attachments'][] = [
'content' => base64_encode($child->getBody()),
'filename' => $child->getFilename(),
];
}
// plain text
if (get_class($child) === 'Swift_MimePart') {
$payload['payload']['message']['text'] = $child->getBody();
}
}
}
return $payload;
}
}
I had to go different route. Instead of searching the extension inside Transport class using Swift_Mime_SimpleMessage, I passed the filename with the original extension to Transport class from Illuminate\Mail\Mailable
public function build()
{
$tempUpload = request()->file('file_attachment');
$filename = $tampUpload->getClientOriginalName() . "." . $tempUpload->getClientOriginalExtension();
return $this->from($this->from_email, $this->from_name)
->subject('subject line')
->attach($tempUpload, ['as' => $filename)
->view('emails.gce.supplier_supplier')
->with($this->data);
}
What I want to archive: I'd like to create a Zammad ticket using the Zammad-api but also parse markdown.
To do so, I created a custom channel to send a notification to the Zammad Helpdesk system using Zammad's API.
This is the specific class:
<?php
namespace App\Channels;
use Illuminate\Mail\Mailable;
class ZammadMessage extends Mailable
{
/**
* The issuer of the ticket.
*
* #var string
*/
public $from;
/**
* The text content of the message.
*
* #var string
*/
private $content;
public function __construct($from, $content = '')
{
$this->from = $from;
$this->content = $content;
}
public static function create($from = '', $content = '')
{
return new static($from, $content);
}
/**
* Set the text content of the message.
*
* #param $content
*
* #return $this
*/
public function content($content)
{
$this->content = $content;
return $this;
}
public function asMarkdown()
{
$this->build();
$this->body = $this->buildView();
return $this;
}
public function build()
{
return $this->from($this->from)
->markdown('emails.contact.submitted', ['data' => $this->content]);
}
/**
* Set the issuer of the ticket.
*
* #param $address
* #param string $name
*
* #return $this
*/
public function from($address, $name = 'null'): static
{
$this->from = $address;
return $this;
}
}
Using this class by my notification class
public function toTicket($notifiable)
{
$address = $notifiable instanceof AnonymousNotifiable
? collect($notifiable->routeNotificationFor('zammad'))->first()
: $notifiable->email;
return ZammadMessage::create()
->from($address)
->content($this->content)
->asMarkdown();
}
I am getting this error:
PHP Deprecated: Passing an $environment into the "League/CommonMark/CommonMarkConverter" constructor is deprecated in 1.6 and will not be supported in 2.0; use MarkdownConverter instead. See https://commonmark.thephpleague.com/2.0/upgrading/consumers/#commonmarkconverter-and-githubflavoredmarkdownconverter-constructors for more details. in /var/www/html/vendor/league/commonmark/src/CommonMarkConverter.php on line 43
That E_USER_DEPRECATED error is not stopping code execution so you should be able to ignore it. Double-check your error_reporting setting in php.ini and/or any similar settings in your framework and adjust as needed.
Normally TYPO3 assigns a variable in FrontEnd with the name validationResults and it looks like that.
Then we have to iterate through the Error objects and get a list with all the errors and their messages. But there is no way to take each one individually and assign it on the corresponding field where the error appears.
So the question is, how do i do it?
Best regards,
After some programming and a help from larry-pete (typo3.slack.com) i found a solution.
I created my own ViewHelper and it looks like this:
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['mytag'][] = 'Vendor\\ExtensionName\\ViewHelpers';
Classes/ViewHelpers/Form/ErrorViewHelper.php
namespace Vendor\ExtensionName\ViewHelpers\Form;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
class ErrorViewHelper extends AbstractFormFieldViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
$this->registerArgument('as', 'string', '', false, 'flattenedErrors');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$as = $arguments['as'];
$for = $arguments['for'];
$templateVariableContainer = $renderingContext->getVariableProvider();
$controllerContext = $renderingContext->getcontrollerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null){
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getErrors();
$output = $renderChildrenClosure();
$withKeys = [];
if (empty($output)) {
if ($flattenedErrors) {
foreach ($flattenedErrors as $error) {
$withKeys[$error->getTitle()] = $error;
}
}
}
$templateVariableContainer->add($as, $withKeys);
return $output;
}
}
Form.html
<mytag:form.error as="error" for="error"/>
And this returns:
So now, you can do something like that:
<f:if condition="{offer.firstName}"><span style="display: block">{offer.firstName.message}</span></f:if>
Best regards
I changed your Viewhelper a bit because it didn't worked in my version (typo3 9)
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class ErrorViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$for = $arguments['for'];
$controllerContext = $renderingContext->getControllerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null) {
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getFlattenedErrors();
return $flattenedErrors;
}
}
you can do:
{myExt:error() -> f:variable(name: 'errors')}}
or
{ff:error( for:"user" ) -> f:variable(name: 'errors')}}
What is the simple way to share partials between themes. Assets are possible but i am having issue with whole partials. I have a multi-theme site managed/activated by sub-domain policies/logic.
SOLUTIONS
/**
*
* Renders a requested partial in context of this component,
* see Cms\Classes\Controller#renderPartial for usage.
*/
/**
* #param $themeName
* #param $partialName
* #param $data
* #return mixed
* #throws \Cms\Classes\CmsException
*/
public function renderThemePartial($partialName, $themeName, $data)
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$controller = new Controller($theme);
return $controller->renderPartial($partialName, $data);
}
/**
*
* Renders a requested content in context of this component,
* see Cms\Classes\Controller#renderContent for usage.
*/
/**
* #param $themeName
* #param $contentName
* #param $data
* #return string
* #throws \Cms\Classes\CmsException
*/
public function renderThemeContent($contentName, $themeName, $data)
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$controller = new Controller($theme);
return $controller->renderContent($contentName, $data);
}
public function registerMarkupTags()
{
return [
'functions' => [
'partial_from_theme' => [$this, 'themePartial'],
'content_from_theme' => [$this, 'themeContent'],
],
'filters' => [
'theme_asset' => [$this, 'themeUrl']
]
];
}
/**
* #param $requested
* #return string
*/
public function themeUrl($requested)
{
$asset = $requested[0];
$theme = $requested[1];
$theme = Theme::load($theme);
$themeDir = $theme->getDirName();
if (is_array($asset)) {
$_url = Url::to(CombineAssets::combine($asset, themes_path().'/'.$themeDir));
}
else {
$_url = Config::get('cms.themesPath', '/themes').'/'.$themeDir;
if ($asset !== null) {
$_url .= '/'.$asset;
}
$_url = Url::asset($_url);
}
return $_url;
}
/**
* #param $partialName
* #param null $themeName
* #param array $parameters
* #return mixed
* #throws \Cms\Classes\CmsException
*/
public function themePartial($partialName, $themeName = null, $parameters = [])
{
return $this->renderThemePartial($partialName, $themeName, $parameters);
}
/**
* #param $contentName
* #param null $themeName
* #param array $parameters
* #return string
* #throws \Cms\Classes\CmsException
*/
public function themeContent($contentName, $themeName = null, $parameters = [])
{
return $this->renderThemeContent($contentName, $themeName, $parameters);
}
I guess you can use Plugin component here you can add component to page and use its partial.
You need to define partial [ you can add as many as you like ] in component.
And just use that partial like below in page , now this same thing you can do in other themes as well.
When you change partial it will affect in all other themes like its shared across multiple themes.
Down side will be that you can not change its content from backend, you need to manually change that file from ftp or other manner.
Partial from another theme
Hmm
you can add custom twig function for that may be
In any of your plugin you can add this code
public function registerMarkupTags()
{
return [
'functions' => [
'theme_partial' => [$this, 'themePartial'],
]
];
}
public function themePartial($partialName, $themeName = null, $vars = [])
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$template = call_user_func([Partial::class, 'load'], $theme, $partialName);
$partialContent = $template->getTwigContent();
$html = Twig::parse($partialContent, $vars);
return $html;
}
Now inside your theme when you want to use partial you can use
{{ theme_partial('call_from_other_theme', 'stemalo' ,{'name':'hardik'}) }}
^ Your theme name here.
themes/stemalo/partials/call_from_other_theme.htm content
description = "Shared Partial."
[viewBag]
==
<div id="shared_partial">
<h1>Another Theme Partial : {{name}}</h1>
</div>
this way you can use partial from another themes.
you aksed for access to theme directory here may be you can just you need to pass theme name, and `its dynamic you can pass variable as theme name so it can pick any thing you like.
If any doubt please comment.
I need to make functionality to validate JSON message, with particular validators, base on specific configuration.
I've got validator and constraints defined as services:
services:
validator.constraint.message.country_code:
class: RenamedBundle\Validator\Constraints\CountryCode
arguments: ...
validator.constraint.message.price_comma:
class: RenamedBundle\Validator\Constraints\PriceComma
arguments: ...
message.validator:
class: RenamedBundle\Service\Validator\MessageValidatorService
arguments: ['#validator']
calls:
- [addConstraint, ['#validator.constraint.message.country_code']]
- [addConstraint, ['#validator.constraint.message.price_comma']]
In DtoValidatorService I call validate()using constraints list.
The probl... challenge is that same JSON message can require validation only with few validators from list, depends on message properties ie. for Poland I want do validate all float values (in Poland separator is ',', not '.'). I've try to do this by config.yml.
renamed:
pritners:
warehouse_wa:
characteristic:
country: 'pl'
source: 'hq-pl'
validators:
- '#validator.constraint.message.country_code'
- '#validator.constraint.message.price_comma'
warehouse_ny:
characteristic:
country: 'us'
source: 'hq-us'
validators:
- '#validator.constraint.message.country_code'
I've added extension:
class Configuration implements ConfigurationInterface
{
/**
* {#inheritDoc}
*
* #throws \RuntimeException
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('renamed');
$rootNode
->children()
->arrayNode('printers')
->useAttributeAsKey('name')
->prototype('array')
->children()
->arrayNode('characteristic')
->children()
->scalarNode('country')->end()
->scalarNode('source')->end()
->end()
->end()
->end()
->children()
->arrayNode('validators')
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
class RenamedExtension extends Extension
{
/**
* {#inheritDoc}
* #throws \Exception
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('printers', $config['printers']);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
}
This configuration works, but problem is when i pass '%printers%' parameter into service, I recieve list of services names:
Array
(
[0] => #validator.constraint.message.country_code
)
but when I pass constraint I got object.
array(1) {
[0] =>
class RenamedBundle\Validator\Constraints\CountryCode#688 (5) {
...
}
}
I'm in dead end now. How can I parameterized printers configuration and avoid passing inline/hardcode validator class name. Calling services in paremeters section is not allowed. Calling them in configuration provide me additional controll and validation.
Maybe someone got better solution?
edit:
According to #Artur Vesker suggestion, I change extension load method implementation.
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$printers = [];
foreach ($config['printers'] as $printerName => $printerConfig) {
$constraints = [];
foreach($printerConfig['valdiators'] as $constraintName) {
$constraintName = ltrim($constraintName, '#');
$constraints[] = new Reference($constraintName);
}
$printerConfig['valdiators'] = $constraints;
$printers[$printerName] = $printerConfig;
}
$container->setParameter('printers', $printers);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
trying to build cache I got:
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
You cannot dump a container with parameters that contain references to other services
It looks my approach in not allowed in symfony world ;]
Use Reference
Set just ids in config:
validators:
- 'validator.constraint.message.country_code'
- 'validator.constraint.message.price_comma'
And create parameter with Reference in you Extension
$validators = array_map(function($id) {
return new Reference($id);
}, $config['pritners.warehouse_wa.validators']);
$messageValidatorDefinition = new Definition('RenamedBundle\Service\Validator\MessageValidatorService', [new Reference('validator)]);
foreach ($validators as $validator) {
messageValidatorDefinition->addMethodCall('addConstraint', [$validator])
}
Thanks Artur Vesker, Your solution works for me.
I tried to keep message.validator in services.yml (I want to have PHPStorm hints) and get them in extension by $container->getDefinition('message.validator'), but in this way addMethodCall not working. So anyone that will try this way, it will not work, you must create service dynamillacy as Artur suggest.
My full code:
- same class Configuration implements ConfigurationInterface
- same config.yml
- removed message.validator from services.yml
- in messageValidator I decide to group constraints by printer name
/**
* Class MessageValidatoService
* #package RenamedBundle\Service
*/
class MessageValidatoService
{
/** PrinterConfigurationDto[] */
protected $printersConfig;
/**
* array of constraints for preValidator grouped by printer name ex:
* [
* 'printer_name' => [Constraint1, Constraint2]
* ]
* #var array
*/
protected $constraints;
/**
* MessageValidatorService constructor.
*
* #param array $printersConfiguration
* #param Serializer $serializer
*
* #throws \RuntimeException
*/
public function __construct(array $printersConfiguration, Serializer $serializer)
{
$this->serializer = $serializer;
$this->constraints = [];
$this->printersConfig = [];
foreach ($printersConfiguration as $printerConfig) {
/** #var PrinterConfigurationDto $configDto */
$configDto = $this->serializer->fromArray(
$printerConfig,
'RenamedBundle\Dto\PrinterConfiguration\PrinterConfigurationDto'
);
$this->printersConfig[] = $configDto;
}
}
/**
* #param string $printerName
* #param Constraint $constraint
*
* #return $this
*/
public function addConstraint($printerName, Constraint $constraint)
{
$this->constraints[$printerName][] = $constraint;
return $this;
}
/**
* Return PrinterConfigurationDto, or throw RuntimeException if none configuration fir to ReceiptDto parameters.
*
* #param ReceiptDto $receiptDto
*
* #return PrinterConfigurationDto
*
* #throws \RuntimeException
* #throws \OutOfRangeException
*/
protected function getPrinterConfig($receiptDto)
{
$countryCodes = $receiptDto->getCountryCodes();
if (array_key_exists($receiptDto->getCountryId(), $countryCodes) === false) {
throw new \OutOfRangeException('Missing country code for country id:' . $receiptDto->getCountryId());
}
/** #var PrinterConfigurationDto $printerConfig */
foreach ($this->printersConfig as $printerConfig) {
if ($printerConfig->getSourceApp() === $receiptDto->getSourceApp()
&& $printerConfig->getCountry() === $countryCodes[$receiptDto->getCountryId()]
) {
return $printerConfig;
}
}
throw new \RuntimeException(
'No printer configuration found for app:' . $receiptDto->getSourceApp()
. ', country id: ' . $receiptDto->getCountryId()
);
}
/**
* #param ReceiptDto $receiptDto
*
* #return Constraint[]
*
* #throws \RuntimeException
* #throws \OutOfRangeException
*/
public function getValidatorConstraints(ReceiptDto $receiptDto)
{
$printerConfig = $this->getPrinterConfig($receiptDto);
if (array_key_exists($printerConfig->getName(), $this->constraints) === false) {
return [];
}
return $this->constraints[$printerConfig->getName()];
}
}
/**
* Class RenamedExtension
* #package RenamedBundle\DependencyInjection
*/
class RenamedExtension extends Extension
{
/**
* {#inheritDoc}
* #throws \Exception
* #throws ServiceNotFoundException
* #throws InvalidArgumentException
* #throws BadMethodCallException
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
//set parameters before load services
//rewrite printers configuration from RenamedBundle\Resources\printers.yml
//structure changes must be implemented also in RenamedBundle\Dto\PrinterConfiguration\PrinterConfigurationDto
$printers = [];
foreach ($config['printers'] as $printerName => $printerConfig) {
$printers[] = [
'name' => $printerName,
'country' => $printerConfig['characteristic']['country'],
'source_app' => $printerConfig['characteristic']['source_app'],
];
}
$container->setParameter('printers', $printers);
//load services, add constraints
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$definition = new Definition(PrinterManagerService::class);
$definition->addArgument('%printers%');
$definition->addArgument(new Reference('serializer'));
foreach ($config['validators'] as $printerName => $printerConfig) {
if (array_key_exists('validators', $printerConfig)
&& is_array($printerConfig['validators'])
) {
foreach ($printerConfig['validators'] as $constraintName) {
$constraint = new Reference(ltrim($constraintName, '#'));
$definition->addMethodCall('addConstraint', [$printerName, $constraint]);
}
}
}
$container->setDefinition('message.validator', $definition);
}
}