Skip to content

Commit

Permalink
Add new ValidateModelEvent
Browse files Browse the repository at this point in the history
The event can be used to check the entire model and pass error messages for one or more properties
  • Loading branch information
zonky2 committed Jan 22, 2025
1 parent 8edfeba commit a1234a8
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/Contao/Dca/Populator/ParentDefinitionPopulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
*/
class ParentDefinitionPopulator extends AbstractEventDrivenEnvironmentPopulator
{
/** @psalm-suppress MissingClassConstType */
public const PRIORITY = 0;

/**
Expand Down
14 changes: 10 additions & 4 deletions src/Contao/View/Contao2BackendView/ContaoWidgetManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\EncodePropertyValueFromWidgetEvent;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\ResolveWidgetErrorMessageEvent;
use ContaoCommunityAlliance\DcGeneral\Controller\ControllerInterface;
use ContaoCommunityAlliance\DcGeneral\Data\DefaultEditInformation;
use ContaoCommunityAlliance\DcGeneral\Data\EditInformationInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelId;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBag;
Expand Down Expand Up @@ -280,6 +282,7 @@ protected function getUniqueId($propertyName)
*
* @SuppressWarnings(PHPMD.Superglobals)
* @SuppressWarnings(PHPMD.CamelCaseVariableName)
* @SuppressWarnings(PHPMD.EmptyCatchBlock)
*/
public function getWidget($property, PropertyValueBagInterface $inputValues = null)
{
Expand All @@ -305,10 +308,13 @@ public function getWidget($property, PropertyValueBagInterface $inputValues = nu

$values = new PropertyValueBag();
foreach ($inputValues->getIterator() as $propertyName => $propertyValue) {
$values->setPropertyValue(
$propertyName,
$this->encodeValue($propertyName, $propertyValue, $inputValues)
);
try {
$values->setPropertyValue(
$propertyName,
$this->encodeValue($propertyName, $propertyValue, $inputValues)
);
} catch (\Exception $e) {
}
}

$controller->updateModelFromPropertyBag($model, $values);
Expand Down
35 changes: 24 additions & 11 deletions src/Contao/View/Contao2BackendView/EditMask.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general.
*
* (c) 2013-2024 Contao Community Alliance.
* (c) 2013-2025 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
Expand All @@ -18,17 +18,13 @@
* @author Stefan Heimes <[email protected]>
* @author Sven Baumann <[email protected]>
* @author Richard Henkenjohann <[email protected]>
* @copyright 2013-2024 Contao Community Alliance.
* @copyright 2013-2025 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later
* @filesource
*/

namespace ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView;

use Contao\BackendUser;
use Contao\CoreBundle\Intl\Locales;
use Contao\Image;
use Contao\System;
use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents;
use ContaoCommunityAlliance\Contao\Bindings\Events\Backend\AddToUrlEvent;
use ContaoCommunityAlliance\Contao\Bindings\Events\Controller\RedirectEvent;
Expand All @@ -38,29 +34,34 @@
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetEditMaskSubHeadlineEvent;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetEditModeButtonsEvent;
use ContaoCommunityAlliance\DcGeneral\Controller\ControllerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\PropertiesDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\LegendInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PaletteInterface;
use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
use ContaoCommunityAlliance\DcGeneral\Data\DefaultEditInformation;
use ContaoCommunityAlliance\DcGeneral\Data\EditInformationInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelId;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\MultiLanguageDataProviderInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBag;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\PropertiesDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\LegendInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PaletteInterface;
use ContaoCommunityAlliance\DcGeneral\DcGeneralEvents;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Event\EnforceModelRelationshipEvent;
use ContaoCommunityAlliance\DcGeneral\Event\PostPersistModelEvent;
use ContaoCommunityAlliance\DcGeneral\Event\PreEditModelEvent;
use ContaoCommunityAlliance\DcGeneral\Event\PrePersistModelEvent;
use ContaoCommunityAlliance\DcGeneral\Event\ValidateModelEvent;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
use ContaoCommunityAlliance\DcGeneral\InputProviderInterface;
use ContaoCommunityAlliance\DcGeneral\SessionStorageInterface;
use ContaoCommunityAlliance\Translator\TranslatorInterface;
use Contao\BackendUser;
use Contao\CoreBundle\Intl\Locales;
use Contao\Image;
use Contao\System;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
Expand Down Expand Up @@ -563,6 +564,12 @@ protected function buildFieldSet($widgetManager, $palette, $propertyValues)
$propName,
$widgetManager->decodeValue($propName, $propertyValues->getPropertyValue($propName))
);
if ($propertyValues->isPropertyValueInvalid($propName)) {
$rawValues->markPropertyValueAsInvalid(
$propName,
$propertyValues->getPropertyValueErrors($propName)
);
}
}
}
}
Expand Down Expand Up @@ -994,6 +1001,12 @@ public function execute()

// Update the model - the model might add some more errors to the propertyValueBag via exceptions.
$controller->updateModelFromPropertyBag($model, $propertyValues);

// Validate whole model.
$dispatcher->dispatch(
new ValidateModelEvent($environment, $model, $propertyValues),
ValidateModelEvent::NAME
);
}

$fieldSets = $this->buildFieldSet($widgetManager, $palette, $propertyValues);
Expand Down
55 changes: 55 additions & 0 deletions src/Event/ValidateModelEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/**
* This file is part of contao-community-alliance/dc-general.
*
* (c) 2013-2025 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* This project is provided in good faith and hope to be usable by anyone.
*
* @package contao-community-alliance/dc-general
* @author Ingolf Steinhardt <[email protected]>
* @copyright 2013-2025 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later
* @filesource
*/

namespace ContaoCommunityAlliance\DcGeneral\Event;

use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBagInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;

/**
* This event is emitted when a submitted and updated model has to be validated.
*
* This is triggered after the model has been updated but before rendering the edit mask and pre-persist.
*/
class ValidateModelEvent extends AbstractModelAwareEvent
{
/** @psalm-suppress MissingClassConstType */
public const NAME = 'dc-general.model.validate';

/**
* Create a new model aware event.
*
* @param EnvironmentInterface $environment The environment.
* @param ModelInterface $model The model being validated.
* @param PropertyValueBagInterface $propertyValueBag The property values.
*/
public function __construct(
EnvironmentInterface $environment,
ModelInterface $model,
private readonly PropertyValueBagInterface $propertyValueBag
) {
parent::__construct($environment, $model);
}

public function getPropertyValueBag(): PropertyValueBagInterface
{
return $this->propertyValueBag;
}
}
32 changes: 17 additions & 15 deletions src/Resources/contao/templates/dcbe_general_edit.html5
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,19 @@ $this->insert(
<input type="hidden" name="FORM_SUBMIT" value="<?= StringUtil::specialchars($this->table) ?>" />
<input type="hidden" name="REQUEST_TOKEN" value="<?= $requestToken ?>" />
<?php if($this->error): ?>
<?php if(5 < \count($this->error)): ?>
<div class="limit_height h128">
<?php endif; ?>

<p class="tl_error"><?= \implode('<br />', $this->error) ?></p>
<script>
window.addEvent('domready', function() {
Backend.vScrollTo(($('<?= $this->table ?>').getElement('label.error').getPosition().y - 20));
});
</script>

<?php if(5 < \count($this->error)): ?>
</div>
<?php endif; ?>
<div class="error_wrapper<?php if(5 < \count($this->error)): ?> limit_height h128<?php endif; ?>">
<p class="tl_error"><?= \implode('<br />', $this->error) ?></p>
<script>
window.addEvent('domready', function() {
var firstErrorElement = $('<?= $this->table ?>').getElement('label.error');
if (firstErrorElement) {
Backend.vScrollTo((firstErrorElement.getPosition().y - 20));
} else {
Backend.vScrollTo(($('<?= $this->table ?>').getElement('.error_wrapper p.tl_error').getPosition().y - 20));
}
});
</script>
</div>
<?php endif; ?>

<?php foreach($this->fieldsets as $arrFieldset):
Expand All @@ -102,7 +101,10 @@ $this->insert(
var e = $$("#" + <?= \json_encode($this->table) ?> + ' input[type="text"]')[0];
e && e.focus();
<?php if($this->noReload): ?>
Backend.vScrollTo(($('<?= $this->table ?>').getElement('label.error').getPosition().y - 20));
var firstErrorElement = $('<?= $this->table ?>').getElement('label.error');
if (firstErrorElement) {
Backend.vScrollTo((firstErrorElement.getPosition().y - 20));
}
<?php endif; ?>
});
</script>
Expand Down

0 comments on commit a1234a8

Please sign in to comment.