Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds messagehandling for form outputs #13

Merged
merged 4 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions src/Controller/FormController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Symfony\Component\Serializer\Exception\ExceptionInterface as SerializerException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Valantic\PimcoreFormsBundle\Http\ApiResponse;
use Valantic\PimcoreFormsBundle\Model\Message;
use Valantic\PimcoreFormsBundle\Service\FormService;

class FormController extends AbstractController
Expand Down Expand Up @@ -80,21 +81,27 @@ public function apiAction(string $name, FormService $formService, Request $reque
if ($form->isValid()) {
$data = $form->getData();

$outputSuccess = $formService->outputs($form);
$outputResponse = $formService->outputs($form);

$redirectUrl = $formService->getRedirectUrl($form, $outputSuccess);
$redirectUrl = $formService->getRedirectUrl($form, $outputResponse->getOverallStatus());

$messages = $outputSuccess
$messages = $outputResponse->getOverallStatus()
? [
'type' => ApiResponse::MESSAGE_TYPE_SUCCESS,
'message' => $translator->trans('valantic.pimcoreForms.formSubmitSuccess'),
(new Message())
->setType(ApiResponse::MESSAGE_TYPE_SUCCESS)
->setMessage($translator->trans('valantic.pimcoreForms.formSubmitSuccess')),
]
: [
'type' => ApiResponse::MESSAGE_TYPE_ERROR,
'message' => $translator->trans('valantic.pimcoreForms.formSubmitError'),
(new Message())
->setType(ApiResponse::MESSAGE_TYPE_ERROR)
->setMessage($translator->trans('valantic.pimcoreForms.formSubmitError')),
];

$statusCode = $outputSuccess
if (!empty($outputResponse->getMessages())) {
$messages = $outputResponse->getMessages();
}

$statusCode = $outputResponse->getOverallStatus()
? JsonResponse::HTTP_OK
: JsonResponse::HTTP_PRECONDITION_FAILED;

Expand Down
212 changes: 107 additions & 105 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Valantic\PimcoreFormsBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
Expand All @@ -17,81 +19,81 @@
*/
class Configuration implements ConfigurationInterface
{
const SYMFONY_CONSTRAINTS_NAMESPACE = 'Symfony\\Component\\Validator\\Constraints\\';
const SYMFONY_FORMTYPES_NAMESPACE = 'Symfony\\Component\\Form\\Extension\\Core\\Type\\';
public const SYMFONY_CONSTRAINTS_NAMESPACE = 'Symfony\\Component\\Validator\\Constraints\\';
public const SYMFONY_FORMTYPES_NAMESPACE = 'Symfony\\Component\\Form\\Extension\\Core\\Type\\';

/**
* {@inheritdoc}
* {@inheritDoc}
*/
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('valantic_pimcore_forms');
$treeBuilder->getRootNode()
->children()
->arrayNode('forms')
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->scalarNode('api_error_message_template')
->info('Custom error message sprintf() based template. Example like "(%2$s) %1$s". (Params: %1$s = error message, %2$s = localized field label')
->defaultValue(null)
->end()
->booleanNode('csrf')
->defaultValue(true)
->info('Whether to enable CSRF protection for this form')
->end()
->arrayNode('translate')
->children()
->booleanNode('field_labels')
->defaultValue(false)
->info('Whether to pass field labels through the Symfony Translator')
->end()
->booleanNode('inline_choices')
->defaultValue(false)
->info('Whether to pass choices defined inline (i.e. not using a choice provider) through the Symfony Translator')
->end()
->end()
->end()
->scalarNode('method')
->defaultValue('POST')
->info('HTTP method (POST/GET) to submit this form')
->validate()
->ifNotInArray(['GET', 'POST'])
->thenInvalid('Must be GET or POST')
->end()
->end()
->scalarNode('redirect_handler')
->defaultNull()
->info('Service to handle redirecting the form')
->validate()
->ifTrue(function (?string $handler): bool {
->arrayNode('forms')
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->scalarNode('api_error_message_template')
->info('Custom error message sprintf() based template. Example like "(%2$s) %1$s". (Params: %1$s = error message, %2$s = localized field label')
->defaultValue(null)
->end()
->booleanNode('csrf')
->defaultValue(true)
->info('Whether to enable CSRF protection for this form')
->end()
->arrayNode('translate')
->children()
->booleanNode('field_labels')
->defaultValue(false)
->info('Whether to pass field labels through the Symfony Translator')
->end()
->booleanNode('inline_choices')
->defaultValue(false)
->info('Whether to pass choices defined inline (i.e. not using a choice provider) through the Symfony Translator')
->end()
->end()
->end()
->scalarNode('method')
->defaultValue('POST')
->info('HTTP method (POST/GET) to submit this form')
->validate()
->ifNotInArray(['GET', 'POST'])
->thenInvalid('Must be GET or POST')
->end()
->end()
->scalarNode('redirect_handler')
->defaultNull()
->info('Service to handle redirecting the form')
->validate()
->ifTrue(function(?string $handler): bool {
if ($handler === null) {
return false;
}

return !in_array(RedirectHandlerInterface::class, class_implements($handler) ?: [], true);
})
->thenInvalid('Invalid redirect handler class found. If not null, the service must implement ' . RedirectHandlerInterface::class)
->end()
->end()
->scalarNode('input_handler')
->defaultNull()
->info('Service to handle inputs for the form')
->validate()
->ifTrue(function (?string $handler): bool {
->thenInvalid('Invalid redirect handler class found. If not null, the service must implement ' . RedirectHandlerInterface::class)
->end()
->end()
->scalarNode('input_handler')
->defaultNull()
->info('Service to handle inputs for the form')
->validate()
->ifTrue(function(?string $handler): bool {
if ($handler === null) {
return false;
}

return !in_array(InputHandlerInterface::class, class_implements($handler) ?: [], true);
})
->thenInvalid('Invalid input handler class found. If not null, the service must implement ' . InputHandlerInterface::class)
->end()
->end()
->append($this->buildOutputsNode())
->append($this->buildFieldsNode())
->end()
->end()
->thenInvalid('Invalid input handler class found. If not null, the service must implement ' . InputHandlerInterface::class)
->end()
->end()
->append($this->buildOutputsNode())
->append($this->buildFieldsNode())
->end()
->end()
->end();

// Here you should define the parameters that are allowed to
Expand All @@ -108,21 +110,21 @@ protected function buildFieldsNode(): ArrayNodeDefinition
return $treeBuilder->getRootNode()
->children()
->arrayNode('fields')->isRequired()->requiresAtLeastOneElement()->arrayPrototype()
->children()
->scalarNode('type')
->cannotBeEmpty()
->info('The type of this FormType')
->validate()
->ifTrue(fn (string $type): bool => !(class_exists($type) || class_exists(self::SYMFONY_FORMTYPES_NAMESPACE . $type)))
->thenInvalid('Invalid type class found. The type should either be a FQN or a subclass of ' . self::SYMFONY_FORMTYPES_NAMESPACE)
->end()
->example('TextType')
->end()
->variableNode('constraints')
->defaultValue([])
->info('Define the Symfony Constraints for this field')
->validate()
->ifTrue(function (array $constraints): bool {
->children()
->scalarNode('type')
->cannotBeEmpty()
->info('The type of this FormType')
->validate()
->ifTrue(fn(string $type): bool => !(class_exists($type) || class_exists(self::SYMFONY_FORMTYPES_NAMESPACE . $type)))
->thenInvalid('Invalid type class found. The type should either be a FQN or a subclass of ' . self::SYMFONY_FORMTYPES_NAMESPACE)
->end()
->example('TextType')
->end()
->variableNode('constraints')
->defaultValue([])
->info('Define the Symfony Constraints for this field')
->validate()
->ifTrue(function(array $constraints): bool {
$hasError = false;
foreach ($constraints as $constraint) {
$classExists = fn(string $name): bool => class_exists($name) || class_exists(self::SYMFONY_CONSTRAINTS_NAMESPACE . $name);
Expand All @@ -139,22 +141,22 @@ protected function buildFieldsNode(): ArrayNodeDefinition

return $hasError;
})
->thenInvalid('Invalid constraint class found. The constraint should either be a FQN or a subclass of ' . self::SYMFONY_CONSTRAINTS_NAMESPACE)
->end()
->end()
->variableNode('options')
->defaultValue([])
->info('Any of the valid field options for this FormType')
->end()
->scalarNode('provider')
->defaultValue(null)
->info('A class to provide the options for this FormType')
->validate()
->ifTrue(fn(?string $name): bool => $name === null || !class_exists($name) || !in_array(ChoicesInterface::class, class_implements($name) ?: [], true))
->thenInvalid('Provider class must exist and implement ' . ChoicesInterface::class)
->end()
->end()
->end()
->thenInvalid('Invalid constraint class found. The constraint should either be a FQN or a subclass of ' . self::SYMFONY_CONSTRAINTS_NAMESPACE)
->end()
->end()
->variableNode('options')
->defaultValue([])
->info('Any of the valid field options for this FormType')
->end()
->scalarNode('provider')
->defaultValue(null)
->info('A class to provide the options for this FormType')
->validate()
->ifTrue(fn(?string $name): bool => $name === null || !class_exists($name) || !in_array(ChoicesInterface::class, class_implements($name) ?: [], true))
->thenInvalid('Provider class must exist and implement ' . ChoicesInterface::class)
->end()
->end()
->end()
->end();
}

Expand All @@ -165,41 +167,41 @@ protected function buildOutputsNode(): ArrayNodeDefinition
return $treeBuilder->getRootNode()
->children()
->arrayNode('outputs')
->isRequired()->requiresAtLeastOneElement()->arrayPrototype()
->children()
->variableNode('type')
->cannotBeEmpty()
->info('The type of this output channel, e.g. log, email, http, data_object, asset; or anything implementing ' . OutputInterface::class)
->end()
->variableNode('options')
->defaultValue([])
->info('This depends on the output channel')
->end()
->end()
->validate()
->ifTrue(function ($config): bool {
->isRequired()->requiresAtLeastOneElement()->arrayPrototype()
->children()
->variableNode('type')
->cannotBeEmpty()
->info('The type of this output channel, e.g. log, email, http, data_object, asset; or anything implementing ' . OutputInterface::class)
->end()
->variableNode('options')
->defaultValue([])
->info('This depends on the output channel')
->end()
->end()
->validate()
->ifTrue(function($config): bool {
$hasError = false;

if ($config['type'] === 'http') {
$hasError = $hasError || (filter_var($config['options']['url'] ?? '', FILTER_VALIDATE_URL) === false);
$hasError = $hasError || (filter_var($config['options']['url'] ?? '', \FILTER_VALIDATE_URL) === false);
}

if ($config['type'] === 'email') {
$hasError = $hasError || (filter_var($config['options']['to'] ?? '', FILTER_VALIDATE_EMAIL) === false);
$hasError = $hasError || (filter_var($config['options']['to'] ?? '', \FILTER_VALIDATE_EMAIL) === false);
}

if ($config['type'] === 'data_object') {
$hasError = $hasError || !array_key_exists('class', $config['options']) || !array_key_exists('path', $config['options']);
}

if ($config['type'] === 'asset') {
$hasError = $hasError || !array_key_exists('fields', $config['options'])|| !is_array($config['options']['fields']) || !array_key_exists('path', $config['options']);
$hasError = $hasError || !array_key_exists('fields', $config['options']) || !is_array($config['options']['fields']) || !array_key_exists('path', $config['options']);
}

return $hasError;
})
->thenInvalid('There are missing/invalid configuration options')
->end()
->end();
->thenInvalid('There are missing/invalid configuration options')
->end()
->end();
}
}
5 changes: 3 additions & 2 deletions src/Form/Output/AssetOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Pimcore\Model\Asset\Folder;
use Ramsey\Uuid\Uuid;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Valantic\PimcoreFormsBundle\Model\OutputResponse;
use voku\helper\ASCII;

class AssetOutput extends AbstractOutput
Expand All @@ -18,7 +19,7 @@ public static function name(): string
return 'asset';
}

public function handle(): bool
public function handle(OutputResponse $outputResponse): OutputResponse
{
$path = Folder::getByPath($this->getPath());

Expand Down Expand Up @@ -50,7 +51,7 @@ public function handle(): bool

OutputScratchpad::set($this->key, ['path' => $subfolder->getFullPath(), 'count' => $count]);

return true;
return $outputResponse->addStatus(true);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/Form/Output/DataObjectOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use InvalidArgumentException;
use Pimcore\Model\DataObject\Concrete;
use Valantic\PimcoreFormsBundle\Model\OutputResponse;

class DataObjectOutput extends AbstractOutput
{
Expand All @@ -14,7 +15,7 @@ public static function name(): string
return 'data_object';
}

public function handle(): bool
public function handle(OutputResponse $outputResponse): OutputResponse
{
$objClass = 'Pimcore\\Model\\DataObject\\' . $this->config['class'];

Expand Down Expand Up @@ -46,7 +47,7 @@ public function handle(): bool
$obj->setParentId($pathId);
$obj->save();

return true;
return $outputResponse->addStatus(true);
}

/**
Expand Down
Loading