diff --git a/Classes/AssetHandler/Connector/AssetHandlerConnectorManager.php b/Classes/AssetHandler/Connector/AssetHandlerConnectorManager.php
index 028ce5f..a2f1998 100644
--- a/Classes/AssetHandler/Connector/AssetHandlerConnectorManager.php
+++ b/Classes/AssetHandler/Connector/AssetHandlerConnectorManager.php
@@ -122,7 +122,7 @@ public function getFormzGeneratedFilePath($prefix = '')
0,
22
);
- $identifier .= '-' . md5($formObject->getHash());
+ $identifier .= '-' . md5($formObject->getHash() . $formObject->getName());
return CacheService::GENERATED_FILES_PATH . $identifier;
}
diff --git a/Classes/Condition/ConditionFactory.php b/Classes/Condition/ConditionFactory.php
index 8bcec3f..545d8ec 100644
--- a/Classes/Condition/ConditionFactory.php
+++ b/Classes/Condition/ConditionFactory.php
@@ -14,9 +14,11 @@
namespace Romm\Formz\Condition;
use Romm\Formz\Condition\Items\ConditionItemInterface;
+use Romm\Formz\Condition\Items\FieldCountValuesCondition;
use Romm\Formz\Condition\Items\FieldHasErrorCondition;
use Romm\Formz\Condition\Items\FieldHasValueCondition;
use Romm\Formz\Condition\Items\FieldIsEmptyCondition;
+use Romm\Formz\Condition\Items\FieldIsFilledCondition;
use Romm\Formz\Condition\Items\FieldIsValidCondition;
use Romm\Formz\Exceptions\ClassNotFoundException;
use Romm\Formz\Exceptions\EntryNotFoundException;
@@ -134,6 +136,12 @@ public function registerDefaultConditions()
)->registerCondition(
FieldIsEmptyCondition::CONDITION_NAME,
FieldIsEmptyCondition::class
+ )->registerCondition(
+ FieldIsFilledCondition::CONDITION_IDENTIFIER,
+ FieldIsFilledCondition::class
+ )->registerCondition(
+ FieldCountValuesCondition::CONDITION_IDENTIFIER,
+ FieldCountValuesCondition::class
);
}
}
diff --git a/Classes/Condition/Exceptions/InvalidConditionException.php b/Classes/Condition/Exceptions/InvalidConditionException.php
index 09000a2..55660f8 100644
--- a/Classes/Condition/Exceptions/InvalidConditionException.php
+++ b/Classes/Condition/Exceptions/InvalidConditionException.php
@@ -149,6 +149,23 @@ final public static function conditionFieldIsEmptyFieldNotFound($fieldName)
return $exception;
}
+ /**
+ * @code 1518016343128
+ *
+ * @param string $fieldName
+ * @return InvalidConditionException
+ */
+ final public static function conditionFieldIsFilledFieldNotFound($fieldName)
+ {
+ /** @var self $exception */
+ $exception = self::getNewExceptionInstance(
+ self::FIELD_DOES_NOT_EXIST,
+ [$fieldName]
+ );
+
+ return $exception;
+ }
+
/**
* @code 1488183577
*
@@ -165,4 +182,21 @@ final public static function conditionFieldIsValidFieldNotFound($fieldName)
return $exception;
}
+
+ /**
+ * @code 1519909297
+ *
+ * @param string $fieldName
+ * @return InvalidConditionException
+ */
+ final public static function conditionFieldCountValuesFieldNotFound($fieldName)
+ {
+ /** @var self $exception */
+ $exception = self::getNewExceptionInstance(
+ self::FIELD_DOES_NOT_EXIST,
+ [$fieldName]
+ );
+
+ return $exception;
+ }
}
diff --git a/Classes/Condition/Items/FieldCountValuesCondition.php b/Classes/Condition/Items/FieldCountValuesCondition.php
new file mode 100644
index 0000000..c0b82d2
--- /dev/null
+++ b/Classes/Condition/Items/FieldCountValuesCondition.php
@@ -0,0 +1,108 @@
+
+ *
+ * This file is part of the TYPO3 FormZ project.
+ * It is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, either
+ * version 3 of the License, or any later version.
+ *
+ * For the full copyright and license information, see:
+ * http://www.gnu.org/licenses/gpl-3.0.html
+ */
+
+namespace Romm\Formz\Condition\Items;
+
+use Romm\Formz\Condition\Exceptions\InvalidConditionException;
+use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
+use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
+
+/**
+ * This condition will match when a field has a number of selected items between
+ * a given minimum and maximum.
+ */
+class FieldCountValuesCondition extends AbstractConditionItem
+{
+ const CONDITION_IDENTIFIER = 'fieldCountValues';
+
+ /**
+ * @inheritdoc
+ * @var array
+ */
+ protected static $javaScriptFiles = [
+ 'EXT:formz/Resources/Public/JavaScript/Conditions/Formz.Condition.FieldCountValues.js'
+ ];
+
+ /**
+ * @var string
+ * @validate NotEmpty
+ */
+ protected $fieldName;
+
+ /**
+ * @var int
+ */
+ protected $minimum;
+
+ /**
+ * @var int
+ */
+ protected $maximum;
+
+ /**
+ * @param string $fieldName
+ * @param int $minimum
+ * @param int $maximum
+ */
+ public function __construct($fieldName, $minimum = null, $maximum = null)
+ {
+ $this->fieldName = $fieldName;
+ $this->minimum = $minimum;
+ $this->maximum = $maximum;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getJavaScriptResult()
+ {
+ return $this->getDefaultJavaScriptCall([
+ 'fieldName' => $this->fieldName,
+ 'minimum' => $this->minimum,
+ 'maximum' => $this->maximum
+ ]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getPhpResult(PhpConditionDataObject $dataObject)
+ {
+ $value = ObjectAccess::getProperty($dataObject->getForm(), $this->fieldName);
+
+ return !($this->minimum && count($value) < (int)$this->minimum)
+ && !($this->maximum && count($value) > (int)$this->maximum);
+ }
+
+ /**
+ * @inheritdoc
+ *
+ * @throws InvalidConditionException
+ */
+ protected function checkConditionConfiguration()
+ {
+ $configuration = $this->formObject->getConfiguration();
+
+ if (false === $configuration->hasField($this->fieldName)) {
+ throw InvalidConditionException::conditionFieldCountValuesFieldNotFound($this->fieldName);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getCssResult()
+ {
+ return '';
+ }
+}
diff --git a/Classes/Condition/Items/FieldIsEmptyCondition.php b/Classes/Condition/Items/FieldIsEmptyCondition.php
index 4ed9179..113f9c1 100644
--- a/Classes/Condition/Items/FieldIsEmptyCondition.php
+++ b/Classes/Condition/Items/FieldIsEmptyCondition.php
@@ -45,7 +45,10 @@ class FieldIsEmptyCondition extends AbstractConditionItem
*/
public function getCssResult()
{
- return '[' . DataAttributesAssetHandler::getFieldDataValueKey($this->fieldName) . '=""]';
+ return [
+ '[' . DataAttributesAssetHandler::getFieldDataValueKey($this->fieldName) . '=""]',
+ ':not([' . DataAttributesAssetHandler::getFieldDataValueKey($this->fieldName) . '])'
+ ];
}
/**
diff --git a/Classes/Condition/Items/FieldIsFilledCondition.php b/Classes/Condition/Items/FieldIsFilledCondition.php
new file mode 100644
index 0000000..14d4981
--- /dev/null
+++ b/Classes/Condition/Items/FieldIsFilledCondition.php
@@ -0,0 +1,95 @@
+
+ *
+ * This file is part of the TYPO3 FormZ project.
+ * It is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, either
+ * version 3 of the License, or any later version.
+ *
+ * For the full copyright and license information, see:
+ * http://www.gnu.org/licenses/gpl-3.0.html
+ */
+
+namespace Romm\Formz\Condition\Items;
+
+use Romm\Formz\AssetHandler\Html\DataAttributesAssetHandler;
+use Romm\Formz\Condition\Exceptions\InvalidConditionException;
+use Romm\Formz\Condition\Processor\DataObject\PhpConditionDataObject;
+use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
+
+/**
+ * This condition will match when a field is filled with any value.
+ */
+class FieldIsFilledCondition extends AbstractConditionItem
+{
+ const CONDITION_IDENTIFIER = 'fieldIsFilled';
+
+ /**
+ * @inheritdoc
+ * @var array
+ */
+ protected static $javaScriptFiles = [
+ 'EXT:formz/Resources/Public/JavaScript/Conditions/Formz.Condition.FieldIsFilled.js'
+ ];
+
+ /**
+ * @var string
+ * @validate NotEmpty
+ */
+ protected $fieldName;
+
+ /**
+ * @param string $fieldName
+ */
+ public function __construct($fieldName)
+ {
+ $this->fieldName = $fieldName;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getCssResult()
+ {
+ $valueKey = DataAttributesAssetHandler::getFieldDataValueKey($this->fieldName);
+
+ return '[' . $valueKey . ']:not([' . $valueKey . '=""])';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getJavaScriptResult()
+ {
+ return $this->getDefaultJavaScriptCall(['fieldName' => $this->fieldName]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getPhpResult(PhpConditionDataObject $dataObject)
+ {
+ $value = ObjectAccess::getProperty($dataObject->getForm(), $this->fieldName);
+
+ return !empty($value);
+ }
+
+ /**
+ * Checks the condition configuration/options.
+ *
+ * If any syntax/configuration error is found, an exception of type
+ * `InvalidConditionException` must be thrown.
+ *
+ * @throws InvalidConditionException
+ */
+ protected function checkConditionConfiguration()
+ {
+ $configuration = $this->formObject->getConfiguration();
+
+ if (false === $configuration->hasField($this->fieldName)) {
+ throw InvalidConditionException::conditionFieldIsFilledFieldNotFound($this->fieldName);
+ }
+ }
+}
diff --git a/Classes/Condition/Parser/Node/NodeInterface.php b/Classes/Condition/Parser/Node/NodeInterface.php
index bfb830d..f06666c 100644
--- a/Classes/Condition/Parser/Node/NodeInterface.php
+++ b/Classes/Condition/Parser/Node/NodeInterface.php
@@ -27,9 +27,9 @@ interface NodeInterface
public function getParent();
/**
- * @param NodeInterface $parent
+ * @param self $parent
*/
- public function setParent(NodeInterface $parent);
+ public function setParent(self $parent);
/**
* @return ConditionTree
diff --git a/Classes/Configuration/ConfigurationFactory.php b/Classes/Configuration/ConfigurationFactory.php
index 44ecc19..46076d9 100644
--- a/Classes/Configuration/ConfigurationFactory.php
+++ b/Classes/Configuration/ConfigurationFactory.php
@@ -69,7 +69,7 @@ public function getFormzConfiguration()
/**
* Will fetch the configuration from cache, and build it if not found. It
- * wont be stored in cache if any error is found. This is done this way to
+ * won't be stored in cache if any error is found. This is done this way to
* avoid the integrator to be forced to flush caches when errors are found.
*
* @param string $cacheIdentifier
diff --git a/Classes/Controller/AjaxValidationController.php b/Classes/Controller/AjaxValidationController.php
index f8af88b..4fce7e7 100644
--- a/Classes/Controller/AjaxValidationController.php
+++ b/Classes/Controller/AjaxValidationController.php
@@ -30,7 +30,6 @@
use Romm\Formz\Service\ExtensionService;
use Romm\Formz\Service\MessageService;
use Romm\Formz\Validation\DataObject\ValidatorDataObject;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Error\Error;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
@@ -201,7 +200,7 @@ public function runAction($name, $className, $fieldName, $validatorName)
$validatorDataObject = new ValidatorDataObject($this->formObject, $this->validation);
/** @var ValidatorInterface $validator */
- $validator = GeneralUtility::makeInstance(
+ $validator = Core::instantiate(
$this->validation->getClassName(),
$this->validation->getOptions(),
$validatorDataObject
diff --git a/Classes/Form/FormObjectFactory.php b/Classes/Form/FormObjectFactory.php
index cfae228..fe8aa6a 100644
--- a/Classes/Form/FormObjectFactory.php
+++ b/Classes/Form/FormObjectFactory.php
@@ -177,6 +177,14 @@ protected function getCacheIdentifier($className, $name)
]
);
}
+
+ /**
+ * @return FormObject[]
+ */
+ public function getInstances()
+ {
+ return $this->instances;
+ }
/**
* @param ConfigurationFactory $configurationFactory
diff --git a/Classes/Service/FormService.php b/Classes/Service/FormService.php
index 4ff51c0..2e34675 100644
--- a/Classes/Service/FormService.php
+++ b/Classes/Service/FormService.php
@@ -24,10 +24,6 @@
*
* - Access to the last submitted form which validation failed:
* `$myFailedForm = FormUtility::getFormWithErrors(MyForm::class);`
- *
- * - Automatic redirect if required argument is missing:
- *
- * @see `onRequiredArgumentIsMissing()`
*/
class FormService implements SingletonInterface
{
diff --git a/Classes/Service/ViewHelper/Field/FieldViewHelperService.php b/Classes/Service/ViewHelper/Field/FieldViewHelperService.php
index 5543760..b40420c 100644
--- a/Classes/Service/ViewHelper/Field/FieldViewHelperService.php
+++ b/Classes/Service/ViewHelper/Field/FieldViewHelperService.php
@@ -108,14 +108,23 @@ public function getView(Layout $layout)
$identifier = $layout->getTemplateFile();
if (null === $this->view[$identifier]) {
- /** @var StandaloneView $view */
- $view = Core::instantiate(StandaloneView::class);
- $view->setTemplatePathAndFilename($layout->getTemplateFile());
-
- $this->view[$identifier] = $view;
+ $this->view[$identifier] = $this->getViewInstance($layout);
}
- return $this->view[$identifier];
+ return clone $this->view[$identifier];
+ }
+
+ /**
+ * @param Layout $layout
+ * @return StandaloneView
+ */
+ protected function getViewInstance(Layout $layout)
+ {
+ /** @var StandaloneView $view */
+ $view = Core::instantiate(StandaloneView::class);
+ $view->setTemplatePathAndFilename($layout->getTemplateFile());
+
+ return $view;
}
/**
diff --git a/Classes/Validation/Validator/AbstractValidator.php b/Classes/Validation/Validator/AbstractValidator.php
index 5865aee..c6b72f7 100644
--- a/Classes/Validation/Validator/AbstractValidator.php
+++ b/Classes/Validation/Validator/AbstractValidator.php
@@ -20,6 +20,7 @@
use Romm\Formz\Form\FormInterface;
use Romm\Formz\Service\MessageService;
use Romm\Formz\Validation\DataObject\ValidatorDataObject;
+use TYPO3\CMS\Extbase\Error\Result;
abstract class AbstractValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator
{
@@ -96,11 +97,31 @@ final public function __construct(array $options = [], ValidatorDataObject $data
$this->dataObject = $dataObject;
$this->form = $dataObject->getFormObject()->getForm();
+ }
+
+ /**
+ * @param mixed $value
+ * @return Result
+ */
+ public function validate($value)
+ {
+ /*
+ * Messages are initialized just before the validation actually runs,
+ * and not in the constructor.
+ *
+ * This allows more flexibility for the messages initialization; for
+ * instance you can dynamically build the messages list in the method
+ * `initializeObject()` of your validator (and not only in the class
+ * variable declaration), then the messages will be processed just
+ * below.
+ */
$this->messages = MessageService::get()->filterMessages(
$this->dataObject->getValidation()->getMessages(),
$this->supportedMessages,
(bool)$this->supportsAllMessages
);
+
+ return parent::validate($value);
}
/**
diff --git a/Classes/Validation/Validator/Form/AbstractFormValidator.php b/Classes/Validation/Validator/Form/AbstractFormValidator.php
index 70d74d3..0dfba09 100644
--- a/Classes/Validation/Validator/Form/AbstractFormValidator.php
+++ b/Classes/Validation/Validator/Form/AbstractFormValidator.php
@@ -131,7 +131,7 @@ final public function validate($form)
}
/**
- * Validates the form, but wont save form data in the form object.
+ * Validates the form, but won't save form data in the form object.
*
* @param FormInterface $form
* @param bool $initialize
diff --git a/Classes/Validation/Validator/RequiredValidator.php b/Classes/Validation/Validator/RequiredValidator.php
index 9b9d4f8..b509454 100644
--- a/Classes/Validation/Validator/RequiredValidator.php
+++ b/Classes/Validation/Validator/RequiredValidator.php
@@ -45,6 +45,7 @@ class RequiredValidator extends AbstractValidator
public function isValid($value)
{
if (null === $value
+ || false === $value
|| '' === $value
|| (is_array($value) && empty($value))
|| (is_object($value) && $value instanceof \Countable && $value->count() === 0)
diff --git a/Classes/ViewHelpers/ClassViewHelper.php b/Classes/ViewHelpers/ClassViewHelper.php
index ef4ea62..a775702 100644
--- a/Classes/ViewHelpers/ClassViewHelper.php
+++ b/Classes/ViewHelpers/ClassViewHelper.php
@@ -89,6 +89,8 @@ class ClassViewHelper extends AbstractViewHelper
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('name', 'string', 'Name of the class which will be managed.', true);
$this->registerArgument('field', 'string', 'Name of the field which will be managed. By default, it is the field from the current `FieldViewHelper`.');
}
diff --git a/Classes/ViewHelpers/FieldViewHelper.php b/Classes/ViewHelpers/FieldViewHelper.php
index dd9a680..d47385a 100644
--- a/Classes/ViewHelpers/FieldViewHelper.php
+++ b/Classes/ViewHelpers/FieldViewHelper.php
@@ -68,16 +68,13 @@ class FieldViewHelper extends AbstractViewHelper
*/
protected $slotService;
- /**
- * @var array
- */
- protected $originalArguments = [];
-
/**
* @inheritdoc
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('name', 'string', 'Name of the field which should be rendered.', true);
$this->registerArgument('layout', 'string', 'Path of the TypoScript layout which will be used.', true);
$this->registerArgument('arguments', 'array', 'Arbitrary arguments which will be sent to the field template.', false, []);
@@ -88,8 +85,6 @@ public function initializeArguments()
*/
public function render()
{
- $viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
-
/*
* First, we check if this view helper is called from within the
* `FormViewHelper`, because it would not make sense anywhere else.
@@ -116,21 +111,11 @@ public function render()
*/
$this->renderChildren();
- /*
- * We need to store original arguments declared for the current view
- * context, because we may override them during the rendering of this
- * view helper.
- */
- $this->storeOriginalArguments();
-
- /*
- * We merge the arguments with the ones registered with the
- * `OptionViewHelper`.
- */
- $templateArguments = $this->arguments['arguments'] ?: [];
- ArrayUtility::mergeRecursiveWithOverrule($templateArguments, $this->fieldService->getFieldOptions());
+ if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '<')) {
+ $restoreCallback = $this->storeViewDataLegacy();
+ }
- $currentView = $viewHelperVariableContainer->getView();
+ $templateArguments = $this->getTemplateArguments();
$result = $this->renderLayoutView($templateArguments);
@@ -140,14 +125,16 @@ public function render()
$this->fieldService->removeCurrentField();
$this->slotService->resetState();
- $viewHelperVariableContainer->setView($currentView);
- $this->restoreOriginalArguments($templateArguments);
+ if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '<')) {
+ /** @noinspection PhpUndefinedVariableInspection */
+ $restoreCallback($templateArguments);
+ }
return $result;
}
/**
- * Will render the associated Fluid view for this field (configured with the
+ * Will return the associated Fluid view for this field (configured with the
* `layout` argument).
*
* @param array $templateArguments
@@ -166,32 +153,120 @@ protected function renderLayoutView(array $templateArguments)
$templateArguments['fieldName'] = $fieldName;
$templateArguments['fieldId'] = ($templateArguments['fieldId']) ?: StringService::get()->sanitizeString('formz-' . $formObject->getName() . '-' . $fieldName);
+ $currentView = $this->viewHelperVariableContainer->getView();
+ $currentVariables = [];
+
$view = $this->fieldService->getView($layout);
+ /*
+ * Warning: we need to store the layouts/partials paths before
+ * manipulating the rendering context!
+ */
$layoutPaths = $this->getPaths('layout');
$partialPaths = $this->getPaths('partial');
if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '<')) {
$view->setRenderingContext($this->renderingContext);
} else {
- $view->setControllerContext($this->controllerContext);
+ $currentVariables = $this->renderingContext->getVariableProvider()->getAll();
- $variableProvider = $this->getVariableProvider();
+ /*
+ * Updating the view dependencies: the variable container as well as
+ * the controller context must be injected in the view.
+ */
+ $this->viewHelperVariableContainer->setView($view);
- foreach ($templateArguments as $key => $value) {
- if ($variableProvider->exists($key)) {
- $variableProvider->remove($key);
- }
+ $view->getRenderingContext()->setViewHelperVariableContainer($this->viewHelperVariableContainer);
- $variableProvider->add($key, $value);
- }
+ $view->setControllerContext($this->controllerContext);
+
+ /*
+ * Adding current variables to the field view variables.
+ */
+ $tmpVariables = $currentVariables;
+ ArrayUtility::mergeRecursiveWithOverrule($tmpVariables, $templateArguments);
+ $templateArguments = $tmpVariables;
}
$view->setLayoutRootPaths($layoutPaths);
$view->setPartialRootPaths($partialPaths);
$view->assignMultiple($templateArguments);
- return $view->render();
+ $result = $view->render();
+
+ if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '>=')) {
+ /*
+ * Because the view can be used several times in nested fields, we
+ * need to restore the variables after the view was rendered.
+ */
+ $viewVariableProvider = $view->getRenderingContext()->getVariableProvider();
+
+ foreach ($viewVariableProvider->getAllIdentifiers() as $identifier) {
+ $viewVariableProvider->remove($identifier);
+ }
+
+ foreach ($currentVariables as $key => $value) {
+ $viewVariableProvider->add($key, $value);
+ }
+
+ /*
+ * Resetting the view of the variable container with the original
+ * view.
+ */
+ $this->viewHelperVariableContainer->setView($currentView);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Temporary solution for TYPO3 6.2 to 7.6 that will store the current view
+ * variables, to be able to restore them later.
+ *
+ * A callback function is returned; it will be called once the field layout
+ * view was processed, and will restore all the view data.
+ *
+ * @return \Closure
+ *
+ * @deprecated Will be deleted when TYPO3 7.6 is not supported anymore.
+ */
+ protected function storeViewDataLegacy()
+ {
+ $originalArguments = [];
+
+ $variableProvider = $this->getVariableProvider();
+
+ foreach (self::$reservedVariablesNames as $key) {
+ if ($variableProvider->exists($key)) {
+ $originalArguments[$key] = $variableProvider->get($key);
+ }
+ }
+
+ $viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
+ $currentView = $viewHelperVariableContainer->getView();
+
+ return function (array $templateArguments) use ($originalArguments, $variableProvider, $viewHelperVariableContainer, $currentView) {
+ $viewHelperVariableContainer->setView($currentView);
+
+ /*
+ * Cleaning up the variables in the provider: the original
+ * values are restored to make the provider like it was before
+ * the field rendering started.
+ */
+ foreach ($variableProvider->getAllIdentifiers() as $identifier) {
+ if (array_key_exists($identifier, $templateArguments)) {
+ $variableProvider->remove($identifier);
+ }
+ }
+
+ foreach ($originalArguments as $key => $value) {
+ if ($variableProvider->exists($key)) {
+ $variableProvider->remove($key);
+ }
+
+ $variableProvider->add($key, $value);
+ }
+ };
}
/**
@@ -257,43 +332,17 @@ protected function getLayout(View $viewConfiguration)
}
/**
- * Stores some arguments which may already have been initialized, and could
- * be overridden in the local scope.
- */
- protected function storeOriginalArguments()
- {
- $this->originalArguments = [];
- $variableProvider = $this->getVariableProvider();
-
- foreach (self::$reservedVariablesNames as $key) {
- if ($variableProvider->exists($key)) {
- $this->originalArguments[$key] = $variableProvider->get($key);
- }
- }
- }
-
- /**
- * Will restore original arguments in the template variable container.
+ * Merging the arguments with the ones registered with the
+ * `OptionViewHelper`.
*
- * @param array $templateArguments
+ * @return array
*/
- protected function restoreOriginalArguments(array $templateArguments)
+ protected function getTemplateArguments()
{
- $variableProvider = $this->getVariableProvider();
-
- foreach ($variableProvider->getAllIdentifiers() as $identifier) {
- if (array_key_exists($identifier, $templateArguments)) {
- $variableProvider->remove($identifier);
- }
- }
-
- foreach ($this->originalArguments as $key => $value) {
- if ($variableProvider->exists($key)) {
- $variableProvider->remove($key);
- }
+ $templateArguments = $this->arguments['arguments'] ?: [];
+ ArrayUtility::mergeRecursiveWithOverrule($templateArguments, $this->fieldService->getFieldOptions());
- $variableProvider->add($key, $value);
- }
+ return $templateArguments;
}
/**
@@ -323,7 +372,11 @@ protected function getPaths($type)
: $viewConfiguration->getAbsoluteLayoutRootPaths();
if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '>=')) {
- return $paths;
+ $templatePaths = $this->renderingContext->getTemplatePaths();
+
+ $currentPaths = $type === 'partial'
+ ? $templatePaths->getPartialRootPaths()
+ : $templatePaths->getLayoutRootPaths();
} else {
$currentView = $this->renderingContext->getViewHelperVariableContainer()->getView();
$propertyName = $type === 'partial'
@@ -334,10 +387,10 @@ protected function getPaths($type)
$method = $reflectionClass->getMethod($propertyName);
$method->setAccessible(true);
- $value = $method->invoke($currentView);
-
- return array_unique(array_merge($paths, $value));
+ $currentPaths = $method->invoke($currentView);
}
+
+ return array_unique(array_merge($paths, $currentPaths));
}
/**
diff --git a/Classes/ViewHelpers/FormatMessageViewHelper.php b/Classes/ViewHelpers/FormatMessageViewHelper.php
index a48baca..30d7aa1 100644
--- a/Classes/ViewHelpers/FormatMessageViewHelper.php
+++ b/Classes/ViewHelpers/FormatMessageViewHelper.php
@@ -60,6 +60,8 @@ class FormatMessageViewHelper extends AbstractViewHelper
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('message', 'object', 'The message which will be formatted.', true);
$this->registerArgument('field', 'string', 'Name of the field which will be managed. By default, it is the field from the current `FieldViewHelper`.');
}
diff --git a/Classes/ViewHelpers/OptionViewHelper.php b/Classes/ViewHelpers/OptionViewHelper.php
index dec4c4d..6f0be5a 100644
--- a/Classes/ViewHelpers/OptionViewHelper.php
+++ b/Classes/ViewHelpers/OptionViewHelper.php
@@ -60,6 +60,8 @@ class OptionViewHelper extends AbstractViewHelper implements CompilableInterface
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('name', 'string', 'Name of the option.', true);
$this->registerArgument('value', 'string', 'Value of the option.', true);
}
diff --git a/Classes/ViewHelpers/Slot/HasViewHelper.php b/Classes/ViewHelpers/Slot/HasViewHelper.php
index 0569bd7..8f67f75 100644
--- a/Classes/ViewHelpers/Slot/HasViewHelper.php
+++ b/Classes/ViewHelpers/Slot/HasViewHelper.php
@@ -32,6 +32,8 @@ class HasViewHelper extends AbstractConditionViewHelper implements CompilableInt
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('slot', 'string', 'Name of the slot.', true);
}
diff --git a/Classes/ViewHelpers/Slot/RenderViewHelper.php b/Classes/ViewHelpers/Slot/RenderViewHelper.php
index a11c610..1a57fe8 100644
--- a/Classes/ViewHelpers/Slot/RenderViewHelper.php
+++ b/Classes/ViewHelpers/Slot/RenderViewHelper.php
@@ -19,6 +19,8 @@
use Romm\Formz\Service\ViewHelper\Field\FieldViewHelperService;
use Romm\Formz\Service\ViewHelper\Slot\SlotViewHelperService;
use Romm\Formz\ViewHelpers\AbstractViewHelper;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\VersionNumberUtility;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
@@ -48,6 +50,8 @@ public function initializeArguments()
*/
public function render()
{
+ parent::initializeArguments();
+
return self::renderStatic($this->arguments, $this->buildRenderChildrenClosure(), $this->renderingContext);
}
@@ -71,7 +75,13 @@ public static function renderStatic(array $arguments, Closure $renderChildrenClo
$result = '';
if ($slotService->hasSlot($slotName)) {
- $slotService->addTemplateVariables($slotName, $arguments['arguments']);
+ $currentVariables = version_compare(VersionNumberUtility::getCurrentTypo3Version(), '8.0.0', '<')
+ ? $renderingContext->getTemplateVariableContainer()->getAll()
+ : $renderingContext->getVariableProvider()->getAll();
+
+ ArrayUtility::mergeRecursiveWithOverrule($currentVariables, $arguments['arguments']);
+
+ $slotService->addTemplateVariables($slotName, $currentVariables);
$slotClosure = $slotService->getSlotClosure($slotName);
$result = $slotClosure();
diff --git a/Classes/ViewHelpers/SlotViewHelper.php b/Classes/ViewHelpers/SlotViewHelper.php
index 1de0540..46678a3 100644
--- a/Classes/ViewHelpers/SlotViewHelper.php
+++ b/Classes/ViewHelpers/SlotViewHelper.php
@@ -35,6 +35,8 @@ class SlotViewHelper extends AbstractViewHelper implements CompilableInterface
*/
public function initializeArguments()
{
+ parent::initializeArguments();
+
$this->registerArgument('name', 'string', 'Name of the slot.', true);
$this->registerArgument('arguments', 'array', 'Arguments sent to the slot.', false, []);
}
diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/tt_content.php
similarity index 100%
rename from Configuration/TCA/Overrides/sys_template.php
rename to Configuration/TCA/Overrides/tt_content.php
diff --git a/Configuration/TypoScript/Validators/ValidatorsConfiguration.ts b/Configuration/TypoScript/Validators/ValidatorsConfiguration.ts
index a5e390a..9ac6265 100644
--- a/Configuration/TypoScript/Validators/ValidatorsConfiguration.ts
+++ b/Configuration/TypoScript/Validators/ValidatorsConfiguration.ts
@@ -150,7 +150,7 @@ config.tx_formz {
className = Romm\Formz\Validation\Validator\RegexValidator
options {
# Pattern used by the regex (you don't need separators).
- pattern = ^[\w-\' àáâãäåçèéêëìíîïðòóôõöùúûüýÿ]*$
+ pattern = ^[\w-\' àáâãäåçèéêëìíîïðòóôõöùúûüýÿßÄÖÜ]*$
# Options for the regex, e.g. "i" for insensitive case.
options = i
}
@@ -164,7 +164,7 @@ config.tx_formz {
className = Romm\Formz\Validation\Validator\RegexValidator
options {
# Pattern used by the regex (you don't need separators).
- pattern = ^[A-Za-z0-9àáâãäåçèéêëìíîïðòóôõöùúûüýÿ]*$
+ pattern = ^[A-Za-z0-9àáâãäåçèéêëìíîïðòóôõöùúûüýÿßÄÖÜ]*$
# Options for the regex, e.g. "i" for insensitive case.
options = i
}
diff --git a/Documentation/01-Introduction/FieldsActivation.rst b/Documentation/01-Introduction/FieldsActivation.rst
index a7a8071..f97dec6 100644
--- a/Documentation/01-Introduction/FieldsActivation.rst
+++ b/Documentation/01-Introduction/FieldsActivation.rst
@@ -51,7 +51,7 @@ You can find the different existing conditions and their configuration at the ch
The expression
^^^^^^^^^^^^^^
-The boolean expression allows to use several condition thanks to logical operators: the logical “and”, the logical “or”. It also allows to gather expressions thanks to parenthesis.
+The boolean expression allows to use several conditions thanks to logical operators: the logical “and”, the logical “or”. It also allows to gather expressions thanks to parenthesis.
**Example:**
diff --git a/Documentation/01-Introduction/Index.rst b/Documentation/01-Introduction/Index.rst
index 0105c28..f543e23 100644
--- a/Documentation/01-Introduction/Index.rst
+++ b/Documentation/01-Introduction/Index.rst
@@ -23,7 +23,7 @@ FormZ helps with the following topics:
What is this for?
-----------------
-The goal of FormZ it to accelerate forms development, from a simple contact form to a complex subscription form. The extension provides a set of tools: developers, integrators and administrators will have access to ready-to-run and simple features.
+The goal of FormZ is to accelerate forms development, from a simple contact form to a complex subscription form. The extension provides a set of tools: developers, integrators and administrators will have access to ready-to-run and simple features.
A form manipulation can be divided into three principal axes: its **composition**, its **validation on submission**, and its **data exploitation** when it is validated. The last part is specific to each form, while composition and validation will always have similarities between forms: identical fields with same validation rules, same display, etc.
diff --git a/Documentation/03-Tutorial/Index.rst b/Documentation/03-Tutorial/Index.rst
index 4401c01..d9b893e 100644
--- a/Documentation/03-Tutorial/Index.rst
+++ b/Documentation/03-Tutorial/Index.rst
@@ -91,7 +91,7 @@ TypoScript configuration
The handling of the validation rules is done with TypoScript.
-You must follow the explanations of the chapter “:ref:`usersManual`” to configure correctly you validation rules.
+You must follow the explanations of the chapter “:ref:`usersManual`” to configure correctly your validation rules.
**Configuration example:**
diff --git a/Documentation/04-DeveloperManual/JavaScript/Field.rst b/Documentation/04-DeveloperManual/JavaScript/Field.rst
index 7914272..233c663 100644
--- a/Documentation/04-DeveloperManual/JavaScript/Field.rst
+++ b/Documentation/04-DeveloperManual/JavaScript/Field.rst
@@ -11,7 +11,7 @@
Field
=====
-You can find below the list of available function for a **field instance**:
+You can find below the list of available functions for a **field instance**:
=========================================================================================================================== ====================================================================
Function Description
diff --git a/Documentation/04-DeveloperManual/JavaScript/Form.rst b/Documentation/04-DeveloperManual/JavaScript/Form.rst
index d188cab..cd7ab2b 100644
--- a/Documentation/04-DeveloperManual/JavaScript/Form.rst
+++ b/Documentation/04-DeveloperManual/JavaScript/Form.rst
@@ -154,7 +154,7 @@ Bind a function on the form submission
Parameters
- ``callback``: function called when the form is submitted. If it returns false, the form submission is cancelled.
Description
- Binds a function on the form submission. Note that the function wont be called if the form submission is blocked (for instance because of an invalid field).
+ Binds a function on the form submission. Note that the function won't be called if the form submission is blocked (for instance because of an invalid field).
The function can return ``false`` if the submission must be blocked for any reason.
diff --git a/Documentation/04-DeveloperManual/PHP/FormValidator.rst b/Documentation/04-DeveloperManual/PHP/FormValidator.rst
index e86aa2b..630f4f8 100644
--- a/Documentation/04-DeveloperManual/PHP/FormValidator.rst
+++ b/Documentation/04-DeveloperManual/PHP/FormValidator.rst
@@ -67,7 +67,7 @@ Pre-validation process
.. container:: table-row
- Fonction
+ Function
.. code-block:: php
protected function beforeValidationProcess()
@@ -86,7 +86,7 @@ During-validation process
.. container:: table-row
- Fonction
+ Function
.. code-block:: php
protected function *field*Validated()
@@ -107,7 +107,7 @@ Post-validation process
.. container:: table-row
- Fonction
+ Function
.. code-block:: php
protected function afterValidationProcess()
diff --git a/Documentation/04-DeveloperManual/PHP/Misc.rst b/Documentation/04-DeveloperManual/PHP/Misc.rst
index 98e55d1..303693b 100644
--- a/Documentation/04-DeveloperManual/PHP/Misc.rst
+++ b/Documentation/04-DeveloperManual/PHP/Misc.rst
@@ -21,33 +21,6 @@ Where :php:`$formClassName` is the name of the class of the form model (for inst
-----
-Redirect if the form is not sent
---------------------------------
-
-You have access to a function to **redirect the current action** if a **required argument for an action is not filled**: :php:`\Romm\Formz\Utility\FormUtility::onRequiredArgumentIsMissing()`
-
-This is useful when a user tries to access the submit action of the form controller. Indeed, this action is called only when the submitted form is valid. But a user can still access a URL which calls this action, without even submitting the form. In a normal scope, it can throw a fatal error. You may then use the action initialization function, which looks like ``initializeActionName()``, and call the function above.
-
-.. code-block:: php
-
- public function initializeSubmitFormAction()
- {
- FormUtility::onRequiredArgumentIsMissing(
- $this->arguments,
- $this->request,
- function($missingArgumentName) {
- $this->redirect('myIndex');
- }
- );
- }
-
- public function submitFormAction(FormExample $myForm)
- {
- // ...
- }
-
------
-
Create a custom activation condition
------------------------------------
diff --git a/Documentation/04-DeveloperManual/PHP/Validator.rst b/Documentation/04-DeveloperManual/PHP/Validator.rst
index 23c2c29..5b3e0f5 100644
--- a/Documentation/04-DeveloperManual/PHP/Validator.rst
+++ b/Documentation/04-DeveloperManual/PHP/Validator.rst
@@ -98,7 +98,7 @@ Supported messages list
],
'test' => [
// If you fill "value", the value will be directly used and
- // the process wont try to fetch a translation.
+ // the process won't try to fetch a translation.
'value' => 'Test message!'
]
];
diff --git a/Documentation/05-UsersManual/TypoScript/ConfigurationActivation/FieldIsEmptyCondition.rst b/Documentation/05-UsersManual/TypoScript/ConfigurationActivation/FieldIsEmptyCondition.rst
index b94800d..c81ba70 100644
--- a/Documentation/05-UsersManual/TypoScript/ConfigurationActivation/FieldIsEmptyCondition.rst
+++ b/Documentation/05-UsersManual/TypoScript/ConfigurationActivation/FieldIsEmptyCondition.rst
@@ -5,7 +5,7 @@
« FieldIsEmpty»
================
-This condition is verified when a given field was not filled. Works witch multiple checkboxes.
+This condition is verified when a given field was not filled. Works with multiple checkboxes.
Properties
----------
diff --git a/Documentation/05-UsersManual/TypoScript/ConfigurationFields.rst b/Documentation/05-UsersManual/TypoScript/ConfigurationFields.rst
index e35e885..b6e677f 100644
--- a/Documentation/05-UsersManual/TypoScript/ConfigurationFields.rst
+++ b/Documentation/05-UsersManual/TypoScript/ConfigurationFields.rst
@@ -249,7 +249,7 @@ Message list selector
Required?
No
Description
- Contains the CSS selector which will be used to fetch the block containing the field messages. It's a second selection layout for the message container (``settings.messageContainerSelector``): it allows adding static HTML contents which wont be cleaned up by JavaScript during the message refreshing.
+ Contains the CSS selector which will be used to fetch the block containing the field messages. It's a second selection layout for the message container (``settings.messageContainerSelector``): it allows adding static HTML contents which won't be cleaned up by JavaScript during the message refreshing.
Note that the marker ``#FIELD#`` is dynamically replaced by the name of the field.
diff --git a/Documentation/05-UsersManual/TypoScript/ConfigurationValidators.rst b/Documentation/05-UsersManual/TypoScript/ConfigurationValidators.rst
index fbc07d4..985c277 100644
--- a/Documentation/05-UsersManual/TypoScript/ConfigurationValidators.rst
+++ b/Documentation/05-UsersManual/TypoScript/ConfigurationValidators.rst
@@ -114,7 +114,7 @@ Validator messages
}
test {
# If you fill `value`, the value will be directly used
- # and the system wont try to fetch a translation.
+ # and the system won't try to fetch a translation.
value = Message test!
}
}
@@ -168,7 +168,7 @@ Use Ajax validation
Description
If this property is defined, an Ajax request is sent by JavaScript when it needs to test this validator.
- Note that if a JavaScript version of this validator exists (see “:ref:`developerManual-javaScript-validation-registerValidator`”), then filling this property wont have any effect and the JavaScript validator will be used instead of Ajax.
+ Note that if a JavaScript version of this validator exists (see “:ref:`developerManual-javaScript-validation-registerValidator`”), then filling this property won't have any effect and the JavaScript validator will be used instead of Ajax.
.. code-block:: typoscript
diff --git a/Documentation/06-IntegratorManual/ViewHelpers/SlotViewHelper.rst b/Documentation/06-IntegratorManual/ViewHelpers/SlotViewHelper.rst
index fa791dd..b0775d1 100644
--- a/Documentation/06-IntegratorManual/ViewHelpers/SlotViewHelper.rst
+++ b/Documentation/06-IntegratorManual/ViewHelpers/SlotViewHelper.rst
@@ -21,7 +21,7 @@ Argument Description
======================= ================================================================================================================
\* ``name`` Name of the slot.
- Note that if you use the name of a slot which is not used in the field layout, this slot wont be rendered.
+ Note that if you use the name of a slot which is not used in the field layout, this slot won't be rendered.
``arguments`` Array of arbitrary arguments that will be passed to the slot and can be used within it as Fluid variables.
======================= ================================================================================================================
diff --git a/Documentation/07-CheatSheets/PhpCheatSheet.rst b/Documentation/07-CheatSheets/PhpCheatSheet.rst
index ecf2483..568e9e1 100644
--- a/Documentation/07-CheatSheets/PhpCheatSheet.rst
+++ b/Documentation/07-CheatSheets/PhpCheatSheet.rst
@@ -287,59 +287,3 @@ The function :php:`getFormWithErrors` returns a form submitted during the last r
}
}
}
-
-Redirect an action if an argument is missing
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Using Extbase, a user can try to access to the submission action, without actually submitting the form. For instance, he submits the form, then pastes the result URL in a new tab: Extbase will think the user submitted the form, but he didn't. In normal time, it would throw a fatal error.
-
-FormZ provides the function :php:`onRequiredArgumentIsMissing`, which will check that a required argument is missing, and run actions otherwise.
-
-**Example:**
-
-.. code-block:: php
- :emphasize-lines: 22
-
- arguments,
- $this->request,
- function() {
- // If the argument `$exForm` is missing, we redirect to the
- // action "showForm".
- $this->redirect('showForm');
- }
- );
- }
-
- /**
- * Action called when the Example form is submitted.
- *
- * @param ExampleForm $exForm
- * @validate $exForm MyVendor.MyExtension:Form\ExampleFormValidator
- */
- public function submitFormAction(ExampleForm $exForm)
- {
- // The form is valid: should you save it? Process it? Your call!
- }
- }
diff --git a/Documentation/11-Changelog/Legacy/v0.3.2/Notes.md b/Documentation/11-Changelog/Legacy/v0.3.2/Notes.md
index 0c6fcb4..50c8d11 100644
--- a/Documentation/11-Changelog/Legacy/v0.3.2/Notes.md
+++ b/Documentation/11-Changelog/Legacy/v0.3.2/Notes.md
@@ -3,7 +3,7 @@
This release introduces partial backend support for FormZ, meaning you can use FormZ in any backend module.
-The last remaining known issue is ajax calls, which wont work for now.
+The last remaining known issue is ajax calls, which won't work for now.
----
diff --git a/Documentation/11-Changelog/Legacy/v1.0.0/Notes.md b/Documentation/11-Changelog/Legacy/v1.0.0/Notes.md
index 91aa1c6..2a14bce 100644
--- a/Documentation/11-Changelog/Legacy/v1.0.0/Notes.md
+++ b/Documentation/11-Changelog/Legacy/v1.0.0/Notes.md
@@ -11,7 +11,7 @@ After months of work on making the extension as reliable as possible (core refac
This commit adds a more reliable handling of the warning and notice message types in validation rules.
- These messages wont block a validation (an error will), but can be used to deliver more information to the final user about actions done during the validation.
+ These messages won't block a validation (an error will), but can be used to deliver more information to the final user about actions done during the validation.
Ajax requests are supported.
diff --git a/Documentation/Index.rst b/Documentation/Index.rst
index 5839e29..bce90c8 100644
--- a/Documentation/Index.rst
+++ b/Documentation/Index.rst
@@ -43,7 +43,7 @@ FormZ • Modern form handler
The content of this document is related to TYPO3,
a GNU/GPL CMS/Framework available from `www.typo3.org