deselect): ?>
-
- = $this->trans('MSC.reset') ?>
+
delete): ?>
-
- = $this->trans('MSC.delete') ?>
+
diff --git a/src/View/ActionHandler/CopyHandler.php b/src/View/ActionHandler/CopyHandler.php
index 589b83f..1cfb3fa 100644
--- a/src/View/ActionHandler/CopyHandler.php
+++ b/src/View/ActionHandler/CopyHandler.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2022 Contao Community Alliance.
+ * (c) 2015-2023 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -13,7 +13,7 @@
* @package contao-community-alliance/dc-general-contao-frontend
* @author Richard Henkenjohann
* @author Ingolf Steinhardt
- * @copyright 2015-2022 Contao Community Alliance.
+ * @copyright 2015-2023 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -24,7 +24,10 @@
use Contao\CoreBundle\Exception\RedirectResponseException;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminatorAwareTrait;
+use ContaoCommunityAlliance\DcGeneral\Controller\ControllerInterface;
+use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelId;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Event\ActionEvent;
@@ -32,11 +35,16 @@
use ContaoCommunityAlliance\DcGeneral\Event\PreDuplicateModelEvent;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
use ContaoCommunityAlliance\DcGeneral\Exception\NotCreatableException;
+use ContaoCommunityAlliance\DcGeneral\InputProviderInterface;
use ContaoCommunityAlliance\UrlBuilder\UrlBuilder;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
* This class handles the copy actions in the frontend.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CopyHandler
{
@@ -47,13 +55,12 @@ class CopyHandler
*
* @var RequestStack
*/
- private $requestStack;
+ private RequestStack $requestStack;
/**
* CopyHandler constructor.
*
* @param RequestScopeDeterminator $scopeDeterminator The request mode determinator.
- *
* @param RequestStack $requestStack The current request stack.
*/
public function __construct(RequestScopeDeterminator $scopeDeterminator, RequestStack $requestStack)
@@ -75,7 +82,10 @@ public function __construct(RequestScopeDeterminator $scopeDeterminator, Request
*/
public function handleEvent(ActionEvent $event): void
{
- if (!$this->scopeDeterminator->currentScopeIsFrontend()) {
+ if (
+ null === ($scopeDeterminator = $this->scopeDeterminator)
+ || !$scopeDeterminator->currentScopeIsFrontend()
+ ) {
return;
}
@@ -89,7 +99,7 @@ public function handleEvent(ActionEvent $event): void
}
// Only run when no response given yet.
- if (null !== $event->getResponse()) {
+ if ('' !== $event->getResponse()) {
return;
}
@@ -109,28 +119,46 @@ public function handleEvent(ActionEvent $event): void
*/
public function process(EnvironmentInterface $environment): void
{
- $dispatcher = $environment->getEventDispatcher();
- $definition = $environment->getDataDefinition();
+ $dispatcher = $environment->getEventDispatcher();
+ assert($dispatcher instanceof EventDispatcherInterface);
+
+ $definition = $environment->getDataDefinition();
+ assert($definition instanceof ContainerInterface);
+
$basicDefinition = $definition->getBasicDefinition();
- $currentUrl = $this->requestStack->getCurrentRequest()->getUri();
+
+ $currentRequest = $this->requestStack->getCurrentRequest() ;
+ assert($currentRequest instanceof Request);
+
+ $currentUrl = $currentRequest->getUri();
if (!$basicDefinition->isCreatable()) {
throw new NotCreatableException('DataContainer ' . $definition->getName() . ' is not creatable');
}
+
// We only support flat tables, sorry.
if (BasicDefinitionInterface::MODE_HIERARCHICAL === $basicDefinition->getMode()) {
return;
}
- $modelId = ModelId::fromSerialized($environment->getInputProvider()->getParameter('source'));
+
+ $inputProvider = $environment->getInputProvider();
+ assert($inputProvider instanceof InputProviderInterface);
+
+ $modelId = ModelId::fromSerialized((string) $inputProvider->getParameter('source'));
$dataProvider = $environment->getDataProvider();
- $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
+ assert($dataProvider instanceof DataProviderInterface);
+
+ $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
if (null === $model) {
throw new PageNotFoundException('Model not found: ' . $modelId->getSerialized());
}
- $copyModel = $environment->getController()->createClonedModel($model);
+ $controller = $environment->getController();
+ assert($controller instanceof ControllerInterface);
+
+ $copyModel = $controller->createClonedModel($model);
// Dispatch pre duplicate event.
$copyEvent = new PreDuplicateModelEvent($environment, $copyModel, $model);
@@ -138,6 +166,8 @@ public function process(EnvironmentInterface $environment): void
// Save the copy.
$provider = $environment->getDataProvider($copyModel->getProviderName());
+ assert($provider instanceof DataProviderInterface);
+
$provider->save($copyModel);
// Dispatch post duplicate event.
diff --git a/src/View/ActionHandler/CreateHandler.php b/src/View/ActionHandler/CreateHandler.php
index 0b3cc81..ae5c858 100644
--- a/src/View/ActionHandler/CreateHandler.php
+++ b/src/View/ActionHandler/CreateHandler.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2019 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -14,7 +14,7 @@
* @author Christian Schiffler
* @author Ingolf Steinhardt
* @author Richard Henkenjohann
- * @copyright 2015-2019 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -24,6 +24,8 @@
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminatorAwareTrait;
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\View\EditMask;
+use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Event\ActionEvent;
@@ -32,7 +34,7 @@
use ContaoCommunityAlliance\DcGeneral\Exception\NotCreatableException;
/**
- * This class handles the create actions in the frontend.
+ * This class handles the actions of create in the frontend.
*/
class CreateHandler
{
@@ -60,26 +62,25 @@ public function __construct(RequestScopeDeterminator $scopeDeterminator)
*/
public function handleEvent(ActionEvent $event): void
{
- if (!$this->scopeDeterminator->currentScopeIsFrontend()) {
+ if (
+ null === ($scopeDeterminator = $this->scopeDeterminator)
+ || !$scopeDeterminator->currentScopeIsFrontend()
+ ) {
return;
}
- $environment = $event->getEnvironment();
- $action = $event->getAction();
-
- // Only handle if we do not have a manual sorting or we know where to insert.
+ // Only handle if we do not have a manual sorting, or we know where to insert.
// Manual sorting is handled by clipboard.
- if ('create' !== $action->getName()) {
+ if ('create' !== $event->getAction()->getName()) {
return;
}
// Only run when no response given yet.
- if (null !== $event->getResponse()) {
+ if ('' !== $event->getResponse()) {
return;
}
- $response = $this->process($environment);
- if ($response !== false) {
+ if ('' !== ($response = $this->process($event->getEnvironment()))) {
$event->setResponse($response);
}
}
@@ -89,13 +90,15 @@ public function handleEvent(ActionEvent $event): void
*
* @param EnvironmentInterface $environment The environment.
*
- * @return string|bool
+ * @return string
*
* @throws NotCreatableException If the data container is not editable, closed.
*/
public function process(EnvironmentInterface $environment)
{
- $definition = $environment->getDataDefinition();
+ $definition = $environment->getDataDefinition();
+ assert($definition instanceof ContainerInterface);
+
$basicDefinition = $definition->getBasicDefinition();
if (!$basicDefinition->isCreatable()) {
@@ -103,22 +106,26 @@ public function process(EnvironmentInterface $environment)
}
// We only support flat tables, sorry.
if (BasicDefinitionInterface::MODE_HIERARCHICAL === $basicDefinition->getMode()) {
- return false;
+ return '';
}
$dataProvider = $environment->getDataProvider();
- $properties = $definition->getPropertiesDefinition()->getProperties();
- $model = $dataProvider->getEmptyModel();
- $clone = $dataProvider->getEmptyModel();
+ assert($dataProvider instanceof DataProviderInterface);
+
+ $properties = $definition->getPropertiesDefinition()->getProperties();
+ $model = $dataProvider->getEmptyModel();
+ $clone = $dataProvider->getEmptyModel();
// If some of the fields have a default value, set it.
foreach ($properties as $property) {
$propName = $property->getName();
- if ($property->getDefaultValue() !== null) {
- $model->setProperty($propName, $property->getDefaultValue());
- $clone->setProperty($propName, $property->getDefaultValue());
+ if ((null === $property->getDefaultValue()) || !$dataProvider->fieldExists($propName)) {
+ continue;
}
+
+ $clone->setProperty($propName, $property->getDefaultValue());
+ $model->setProperty($propName, $property->getDefaultValue());
}
return (new EditMask($environment, $model, $clone, null, null))->execute();
diff --git a/src/View/ActionHandler/DeleteHandler.php b/src/View/ActionHandler/DeleteHandler.php
index 946d144..22350ae 100644
--- a/src/View/ActionHandler/DeleteHandler.php
+++ b/src/View/ActionHandler/DeleteHandler.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2022 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -13,7 +13,7 @@
* @package contao-community-alliance/dc-general-contao-frontend
* @author Richard Henkenjohann
* @author Ingolf Steinhardt
- * @copyright 2015-2022 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -24,7 +24,9 @@
use Contao\CoreBundle\Exception\RedirectResponseException;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminatorAwareTrait;
+use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelId;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Event\ActionEvent;
@@ -32,10 +34,15 @@
use ContaoCommunityAlliance\DcGeneral\Event\PreDeleteModelEvent;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
use ContaoCommunityAlliance\DcGeneral\Exception\NotDeletableException;
+use ContaoCommunityAlliance\DcGeneral\InputProviderInterface;
+use Psr\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
- * This class handles the edit actions in the frontend.
+ * This class handles the actions of edit in the frontend.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class DeleteHandler
{
@@ -46,13 +53,12 @@ class DeleteHandler
*
* @var RequestStack
*/
- private $requestStack;
+ private RequestStack $requestStack;
/**
* DeleteHandler constructor.
*
* @param RequestScopeDeterminator $scopeDeterminator The request mode determinator.
- *
* @param RequestStack $requestStack The current request stack.
*/
public function __construct(RequestScopeDeterminator $scopeDeterminator, RequestStack $requestStack)
@@ -74,7 +80,10 @@ public function __construct(RequestScopeDeterminator $scopeDeterminator, Request
*/
public function handleEvent(ActionEvent $event): void
{
- if (!$this->scopeDeterminator->currentScopeIsFrontend()) {
+ if (
+ null === ($scopeDeterminator = $this->scopeDeterminator)
+ || !$scopeDeterminator->currentScopeIsFrontend()
+ ) {
return;
}
@@ -106,17 +115,24 @@ public function handleEvent(ActionEvent $event): void
*/
public function process(EnvironmentInterface $environment): void
{
- $definition = $environment->getDataDefinition();
+ $definition = $environment->getDataDefinition();
+ assert($definition instanceof ContainerInterface);
+
$basicDefinition = $definition->getBasicDefinition();
if (!$basicDefinition->isDeletable()) {
throw new NotDeletableException('DataContainer ' . $definition->getName() . ' is not deletable');
}
- $modelId = ModelId::fromSerialized($environment->getInputProvider()->getParameter('id'));
+ $inputProvider = $environment->getInputProvider();
+ assert($inputProvider instanceof InputProviderInterface);
+
+ $modelId = ModelId::fromSerialized($inputProvider->getParameter('id'));
$dataProvider = $environment->getDataProvider();
- $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
+ assert($dataProvider instanceof DataProviderInterface);
+
+ $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
if (null === $model) {
throw new PageNotFoundException('Model not found: ' . $modelId->getSerialized());
@@ -124,14 +140,20 @@ public function process(EnvironmentInterface $environment): void
// Trigger event before the model will be deleted.
$event = new PreDeleteModelEvent($environment, $model);
- $environment->getEventDispatcher()->dispatch($event, $event::NAME);
+ $eventDispatcher = $environment->getEventDispatcher();
+ assert($eventDispatcher instanceof EventDispatcherInterface);
+
+ $eventDispatcher->dispatch($event, $event::NAME);
$dataProvider->delete($model);
// Trigger event after the model is deleted.
$event = new PostDeleteModelEvent($environment, $model);
- $environment->getEventDispatcher()->dispatch($event, $event::NAME);
+ $eventDispatcher->dispatch($event, $event::NAME);
+
+ $currentRequest = $this->requestStack->getCurrentRequest();
+ assert($currentRequest instanceof Request);
- throw new RedirectResponseException($this->requestStack->getCurrentRequest()->headers->get('referer'));
+ throw new RedirectResponseException($currentRequest->headers->get('referer') ?? '');
}
}
diff --git a/src/View/ActionHandler/EditHandler.php b/src/View/ActionHandler/EditHandler.php
index 0527acc..b6bd869 100644
--- a/src/View/ActionHandler/EditHandler.php
+++ b/src/View/ActionHandler/EditHandler.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2022 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -15,7 +15,7 @@
* @author Richard Henkenjohann
* @author Sven Baumann
* @author Ingolf Steinhardt
- * @copyright 2015-2022 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -26,16 +26,21 @@
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator;
use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminatorAwareTrait;
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\View\EditMask;
+use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelId;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\BasicDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Event\ActionEvent;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
use ContaoCommunityAlliance\DcGeneral\Exception\NotEditableException;
+use ContaoCommunityAlliance\DcGeneral\InputProviderInterface;
/**
- * This class handles the edit actions in the frontend.
+ * This class handles the actions of edit in the frontend.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class EditHandler
{
@@ -64,14 +69,16 @@ public function __construct(RequestScopeDeterminator $scopeDeterminator)
*/
public function handleEvent(ActionEvent $event): void
{
- if (!$this->scopeDeterminator->currentScopeIsFrontend()) {
+ if (
+ null === ($scopeDeterminator = $this->scopeDeterminator)
+ || !$scopeDeterminator->currentScopeIsFrontend()
+ ) {
return;
}
- $action = $event->getAction();
// Only handle if we do not have a manual sorting or we know where to insert.
// Manual sorting is handled by clipboard.
- if ('edit' !== $action->getName()) {
+ if ('edit' !== $event->getAction()->getName()) {
return;
}
@@ -80,8 +87,7 @@ public function handleEvent(ActionEvent $event): void
return;
}
- $response = $this->process($event->getEnvironment());
- if (false !== $response) {
+ if ('' !== ($response = $this->process($event->getEnvironment()))) {
$event->setResponse($response);
}
}
@@ -91,14 +97,16 @@ public function handleEvent(ActionEvent $event): void
*
* @param EnvironmentInterface $environment The environment.
*
- * @return string|bool
+ * @return string
*
* @throws PageNotFoundException If item to edit was not found.
* @throws NotEditableException When the definition is not editable.
*/
public function process(EnvironmentInterface $environment)
{
- $definition = $environment->getDataDefinition();
+ $definition = $environment->getDataDefinition();
+ assert($definition instanceof ContainerInterface);
+
$basicDefinition = $definition->getBasicDefinition();
if (!$basicDefinition->isEditable()) {
@@ -107,13 +115,18 @@ public function process(EnvironmentInterface $environment)
// We only support flat tables, sorry.
if (BasicDefinitionInterface::MODE_HIERARCHICAL === $basicDefinition->getMode()) {
- return false;
+ return '';
}
- $modelId = ModelId::fromSerialized($environment->getInputProvider()->getParameter('id'));
+ $inputProvider = $environment->getInputProvider();
+ assert($inputProvider instanceof InputProviderInterface);
+
+ $modelId = ModelId::fromSerialized($inputProvider->getParameter('id'));
$dataProvider = $environment->getDataProvider();
- $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
+ assert($dataProvider instanceof DataProviderInterface);
+
+ $model = $dataProvider->fetch($dataProvider->getEmptyConfig()->setId($modelId->getId()));
if (null === $model) {
throw new PageNotFoundException('Model not found: ' . $modelId->getSerialized());
diff --git a/src/View/DefaultWidgetBuilder.php b/src/View/DefaultWidgetBuilder.php
index ec9594b..04ec1d6 100644
--- a/src/View/DefaultWidgetBuilder.php
+++ b/src/View/DefaultWidgetBuilder.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2022 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -14,13 +14,15 @@
* @author Christian Schiffler
* @author Richard Henkenjohann
* @author Ingolf Steinhardt
- * @copyright 2015-2022 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
namespace ContaoCommunityAlliance\DcGeneral\ContaoFrontend\View;
+use Contao\System;
+use Contao\Widget;
use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents;
use ContaoCommunityAlliance\Contao\Bindings\Events\Widget\GetAttributesFromDcaEvent;
use ContaoCommunityAlliance\DcGeneral\Contao\Compatibility\DcCompat;
@@ -30,30 +32,44 @@
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\ManipulateWidgetEvent;
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\Event\BuildWidgetEvent;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\Properties\PropertyInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
+use Psr\EventDispatcher\EventDispatcherInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Widget Builder to build Contao frontend widgets.
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class DefaultWidgetBuilder
{
-
/**
* The request scope determinator.
*
* @var RequestScopeDeterminator
*/
- private $scopeDeterminator;
+ private RequestScopeDeterminator $scopeDeterminator;
+
+ /**
+ * The translator.
+ *
+ * @var TranslatorInterface
+ */
+ private TranslatorInterface $translator;
/**
* DefaultWidgetBuilder constructor.
*
* @param RequestScopeDeterminator $scopeDeterminator The request scope determinator.
+ * @param TranslatorInterface $translator The translator.
*/
- public function __construct(RequestScopeDeterminator $scopeDeterminator)
+ public function __construct(RequestScopeDeterminator $scopeDeterminator, TranslatorInterface $translator)
{
$this->scopeDeterminator = $scopeDeterminator;
+ $this->translator = $translator;
}
/**
@@ -79,12 +95,10 @@ public function handleEvent(BuildWidgetEvent $event)
* Build a widget for a given property.
*
* @param EnvironmentInterface $environment The environment.
- *
* @param PropertyInterface $property The property.
- *
* @param ModelInterface $model The current model.
*
- * @return \Widget
+ * @return Widget|null
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
@@ -94,11 +108,17 @@ public function buildWidget(
PropertyInterface $property,
ModelInterface $model
) {
- $dispatcher = $environment->getEventDispatcher();
+ $dispatcher = $environment->getEventDispatcher();
+ assert($dispatcher instanceof EventDispatcherInterface);
+
$propertyName = $property->getName();
$propExtra = $property->getExtra();
- $defName = $environment->getDataDefinition()->getName();
- $strClass = $this->getWidgetClass($property);
+
+ $dataDefinition = $environment->getDataDefinition();
+ assert($dataDefinition instanceof ContainerInterface);
+
+ $defName = $dataDefinition->getName();
+ $strClass = $this->getWidgetClass($property);
if (null === $strClass) {
return null;
@@ -109,14 +129,16 @@ public function buildWidget(
->setProperty($propertyName)
->setValue($model->getProperty($propertyName));
- $dispatcher->dispatch($event,$event::NAME);
+ $dispatcher->dispatch($event, $event::NAME);
$varValue = $event->getValue();
- $propExtra['required'] = ($varValue == '') && !empty($propExtra['mandatory']);
+ $propExtra['required'] = ($varValue === '') && !empty($propExtra['mandatory']);
$propExtra['tableless'] = true;
- if (isset($propExtra['readonly'])
+ if (
+ isset($propExtra['readonly'])
&& $propExtra['readonly']
- && \in_array($property->getWidgetType(), ['checkbox', 'select'], true)) {
+ && \in_array($property->getWidgetType(), ['checkbox', 'select'], true)
+ ) {
$propExtra['disabled'] = true;
}
@@ -148,15 +170,21 @@ public function buildWidget(
$propExtra['class'] = $this->addCssClass($propExtra['class'], $propExtra['tl_class']);
}
- $arrConfig = array(
+ // If no description present, pass as string instead of array.
+ $label = $this->translator->trans($property->getLabel(), [], $defName);
+ if ('' !== $description = $property->getDescription()) {
+ $label = [
+ $label,
+ $this->translator->trans($description, [], $defName),
+ ];
+ }
+
+ $arrConfig = [
'inputType' => $property->getWidgetType(),
- 'label' => array(
- $property->getLabel(),
- $property->getDescription()
- ),
+ 'label' => $label,
'options' => $this->getOptionsForWidget($environment, $property, $model),
'eval' => $propExtra,
- );
+ ];
if (isset($propExtra['reference'])) {
$arrConfig['reference'] = $propExtra['reference'];
@@ -181,6 +209,7 @@ public function buildWidget(
}
$widget = new $strClass($preparedConfig, new DcCompat($environment, $model, $propertyName));
+ assert($widget instanceof Widget);
$widget->currentRecord = $model->getId();
@@ -195,7 +224,7 @@ public function buildWidget(
*
* @param PropertyInterface $property The property to get the widget class name for.
*
- * @return string
+ * @return class-string|null
*
* @SuppressWarnings(PHPMD.Superglobals)
* @SuppressWarnings(PHPMD.CamelCaseVariableName)
@@ -206,8 +235,8 @@ private function getWidgetClass(PropertyInterface $property)
return null;
}
- $className = $GLOBALS['TL_FFL'][$property->getWidgetType()];
- if (!class_exists($className)) {
+ $className = (string) $GLOBALS['TL_FFL'][$property->getWidgetType()];
+ if (!\class_exists($className)) {
return null;
}
@@ -218,12 +247,10 @@ private function getWidgetClass(PropertyInterface $property)
* Get special labels.
*
* @param EnvironmentInterface $environment The environment.
- *
* @param PropertyInterface $propInfo The property for which the options shall be retrieved.
- *
* @param ModelInterface $model The model.
*
- * @return string[]
+ * @return string[]|null
*/
private function getOptionsForWidget(
EnvironmentInterface $environment,
@@ -231,8 +258,10 @@ private function getOptionsForWidget(
ModelInterface $model
) {
$dispatcher = $environment->getEventDispatcher();
- $options = $propInfo->getOptions();
- $event = new GetPropertyOptionsEvent($environment, $model);
+ assert($dispatcher instanceof EventDispatcherInterface);
+
+ $options = $propInfo->getOptions();
+ $event = new GetPropertyOptionsEvent($environment, $model);
$event->setPropertyName($propInfo->getName());
$event->setOptions($options);
$dispatcher->dispatch($event, GetPropertyOptionsEvent::NAME);
@@ -255,7 +284,7 @@ private function getOptionsForWidget(
*/
private function addCssClass($classString, $class)
{
- if (null !== $classString) {
+ if ('' !== $classString) {
$classString .= ' ' . $class;
} else {
$classString = $class;
diff --git a/src/View/EditMask.php b/src/View/EditMask.php
index 50ff8b8..6a22693 100644
--- a/src/View/EditMask.php
+++ b/src/View/EditMask.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2023 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -15,7 +15,7 @@
* @author Richard Henkenjohann
* @author Sven Baumann
* @author Ingolf Steinhardt
- * @copyright 2015-2023 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -26,7 +26,9 @@
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\Event\HandleSubmitEvent;
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\DataProviderInformationInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\PropertiesDefinitionInterface;
use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PaletteInterface;
use ContaoCommunityAlliance\DcGeneral\Data\DataProviderInterface;
@@ -40,6 +42,7 @@
use ContaoCommunityAlliance\DcGeneral\Event\PrePersistModelEvent;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
+use ContaoCommunityAlliance\DcGeneral\InputProviderInterface;
use ContaoCommunityAlliance\Translator\TranslatorInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -47,6 +50,9 @@
* This class manages the displaying of the edit/create mask containing the widgets.
*
* It also handles the persisting of the model.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
*/
class EditMask
{
@@ -55,49 +61,49 @@ class EditMask
*
* @var EnvironmentInterface
*/
- private $environment;
+ private EnvironmentInterface $environment;
/**
* The event dispatcher.
*
* @var EventDispatcherInterface
*/
- private $dispatcher;
+ private EventDispatcherInterface $dispatcher;
/**
* Retrieve the translation manager to use.
*
* @var TranslatorInterface
*/
- private $translator;
+ private TranslatorInterface $translator;
/**
* The data definition from the environment.
*
* @var ContainerInterface
*/
- private $definition;
+ private ContainerInterface $definition;
/**
* The data provider of the model being edited.
*
- * @var DataProviderInterface
+ * @var DataProviderInformationInterface
*/
- private $modelProvider;
+ private DataProviderInformationInterface $modelProvider;
/**
* The model to be manipulated.
*
* @var ModelInterface
*/
- private $model;
+ private ModelInterface $model;
/**
* The original model from the database.
*
* @var ModelInterface
*/
- private $originalModel;
+ private ModelInterface $originalModel;
/**
* The method to be executed before the model is persisted.
@@ -118,29 +124,31 @@ class EditMask
*
* @var array
*/
- private $errors = [];
+ private array $errors = [];
/**
* Create the edit mask.
*
* @param EnvironmentInterface $environment The view in use.
- *
* @param ModelInterface $model The model with the current data.
- *
* @param ModelInterface $originalModel The data from the original data.
- *
- * @param callable $preFunction The function to call before saving an item.
- *
- * @param callable $postFunction The function to call after saving an item.
+ * @param callable|null $preFunction The function to call before saving an item.
+ * @param callable|null $postFunction The function to call after saving an item.
*/
public function __construct($environment, $model, $originalModel, $preFunction, $postFunction)
{
- $providerName = $model->getProviderName();
- $this->environment = $environment;
- $this->translator = $environment->getTranslator();
- $this->dispatcher = $environment->getEventDispatcher();
- $this->definition = $environment->getDataDefinition();
- $this->modelProvider = $this->definition->getDataProviderDefinition()->getInformation($providerName);
+ $providerName = $model->getProviderName();
+ $this->environment = $environment;
+ $translator = $environment->getTranslator();
+ assert($translator instanceof TranslatorInterface);
+ $this->translator = $translator;
+ $dispatcher = $environment->getEventDispatcher();
+ assert($dispatcher instanceof EventDispatcherInterface);
+ $this->dispatcher = $dispatcher;
+ $dataDefinition = $environment->getDataDefinition();
+ assert($dataDefinition instanceof ContainerInterface);
+ $this->definition = $dataDefinition;
+ $this->modelProvider = $dataDefinition->getDataProviderDefinition()->getInformation($providerName);
$this->model = $model;
$this->originalModel = $originalModel;
$this->preFunction = $preFunction;
@@ -153,12 +161,13 @@ public function __construct($environment, $model, $originalModel, $preFunction,
* @return string
*
* @throws DcGeneralRuntimeException If the data container is not editable, closed.
- *
* @throws DcGeneralInvalidArgumentException If an unknown property is encountered in the palette.
*/
public function execute()
{
- $inputProvider = $this->environment->getInputProvider();
+ $inputProvider = $this->environment->getInputProvider();
+ assert($inputProvider instanceof InputProviderInterface);
+
$palettesDefinition = $this->definition->getPalettesDefinition();
$isSubmitted = ($inputProvider->getValue('FORM_SUBMIT') === $this->definition->getName());
$isAutoSubmit = ($inputProvider->getValue('SUBMIT_TYPE') === 'auto');
@@ -172,12 +181,14 @@ public function execute()
$palette = $palettesDefinition->findPalette($this->model);
$propertyValues = $this->processInput($widgetManager);
- if ($isSubmitted && $propertyValues) {
+ if ($isSubmitted && null !== $propertyValues) {
// Pass 2: Determine the real palette we want to work on if we have some data submitted.
$palette = $palettesDefinition->findPalette($this->model, $propertyValues);
// Update the model - the model might add some more errors to the propertyValueBag via exceptions.
- $this->environment->getController()->updateModelFromPropertyBag($this->model, $propertyValues);
+ $controller = $this->environment->getController();
+ assert($controller instanceof ControllerInterface);
+ $controller->updateModelFromPropertyBag($this->model, $propertyValues);
}
$fieldSets = $this->buildFieldSet($widgetManager, $palette, $propertyValues);
@@ -210,7 +221,7 @@ public function execute()
*
* @return void
*/
- private function enforceModelRelationship()
+ private function enforceModelRelationship(): void
{
$event = new EnforceModelRelationshipEvent($this->environment, $this->model);
@@ -224,13 +235,14 @@ private function enforceModelRelationship()
*
* @return null|PropertyValueBag
*/
- private function processInput($widgetManager)
+ private function processInput($widgetManager): ?PropertyValueBag
{
$input = $this->environment->getInputProvider();
+ assert($input instanceof InputProviderInterface);
if ($input->getValue('FORM_SUBMIT') === $this->definition->getName()) {
$propertyValues = new PropertyValueBag();
- $propertyNames = array_intersect(
+ $propertyNames = \array_intersect(
$this->definition->getPropertiesDefinition()->getPropertyNames(),
(array) $input->getValue('FORM_INPUTS')
);
@@ -254,7 +266,7 @@ private function processInput($widgetManager)
*
* @return void
*/
- private function handlePrePersist()
+ private function handlePrePersist(): void
{
if (null !== $this->preFunction) {
\call_user_func($this->preFunction, $this->environment, $this->model, $this->originalModel);
@@ -271,7 +283,7 @@ private function handlePrePersist()
*
* @return void
*/
- private function handlePostPersist()
+ private function handlePostPersist(): void
{
if (null !== $this->postFunction) {
\call_user_func($this->postFunction, $this->environment, $this->model, $this->originalModel);
@@ -294,16 +306,19 @@ private function handlePostPersist()
*
* @return string
*/
- private function translateLabel($transString, $parameters = [])
+ private function translateLabel(string $transString, array $parameters = []): string
{
$translator = $this->translator;
- if ($transString !== ($label =
- $translator->translate($transString, $this->definition->getName(), $parameters))) {
+ if (
+ $transString !== ($label =
+ $translator->translate($transString, $this->definition->getName(), $parameters))
+ ) {
return $label;
}
- if ($transString !== ($label =
- $translator->translate('MSC.'.$transString, $this->definition->getName(), $parameters))
+ if (
+ $transString !== ($label =
+ $translator->translate('MSC.' . $transString, $this->definition->getName(), $parameters))
) {
return $label;
}
@@ -317,12 +332,12 @@ private function translateLabel($transString, $parameters = [])
*
* @return string[]
*/
- private function getEditButtons()
+ private function getEditButtons(): array
{
$button = '';
$buttons = [];
- $buttons['save'] = sprintf(
+ $buttons['save'] = \sprintf(
$button,
'save',
'save',
@@ -332,7 +347,7 @@ private function getEditButtons()
);
if ($this->definition->getBasicDefinition()->isCreatable()) {
- $buttons['saveNcreate'] = sprintf(
+ $buttons['saveNcreate'] = \sprintf(
$button,
'saveNcreate',
'saveNcreate',
@@ -353,11 +368,9 @@ private function getEditButtons()
/**
* Build the field sets.
*
- * @param WidgetManager $widgetManager The widget manager in use.
- *
- * @param PaletteInterface $palette The palette to use.
- *
- * @param PropertyValueBag $propertyValues The property values.
+ * @param WidgetManager $widgetManager The widget manager in use.
+ * @param PaletteInterface $palette The palette to use.
+ * @param PropertyValueBag|null $propertyValues The property values.
*
* @return array
*
@@ -366,10 +379,17 @@ private function getEditButtons()
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
- private function buildFieldSet($widgetManager, $palette, $propertyValues)
- {
+ private function buildFieldSet(
+ WidgetManager $widgetManager,
+ PaletteInterface $palette,
+ ?PropertyValueBag $propertyValues
+ ): array {
$propertyDefinitions = $this->definition->getPropertiesDefinition();
- $isAutoSubmit = ($this->environment->getInputProvider()->getValue('SUBMIT_TYPE') === 'auto');
+
+ $inputProvider = $this->environment->getInputProvider();
+ assert($inputProvider instanceof InputProviderInterface);
+
+ $isAutoSubmit = ($inputProvider->getValue('SUBMIT_TYPE') === 'auto');
$fieldSets = [];
$errors = [];
@@ -392,7 +412,8 @@ private function buildFieldSet($widgetManager, $palette, $propertyValues)
$this->ensurePropertyExists($propertyName, $propertyDefinitions);
// If this property is invalid, fetch the error.
- if ((!$isAutoSubmit)
+ if (
+ (!$isAutoSubmit)
&& $propertyValues
&& $propertyValues->hasPropertyValue($propertyName)
&& $propertyValues->isPropertyValueInvalid($propertyName)
@@ -401,12 +422,13 @@ private function buildFieldSet($widgetManager, $palette, $propertyValues)
}
$fields[] = $widgetManager->renderWidget($propertyName, $isAutoSubmit, $propertyValues);
- $hidden[] = sprintf('', $propertyName);
+ $hidden[] = \sprintf('', $propertyName);
}
+ $fieldSet = [];
$fieldSet['label'] = $legendName;
$fieldSet['class'] = $first ? 'tl_tbox' : 'tl_box';
- $fieldSet['palette'] = implode('', $hidden) . implode('', $fields);
+ $fieldSet['palette'] = \implode('', $hidden) . \implode('', $fields);
$fieldSet['legend'] = $legend->getName();
$fieldSets[] = $fieldSet;
@@ -424,18 +446,17 @@ private function buildFieldSet($widgetManager, $palette, $propertyValues)
* Ensure a property is defined in the data definition and raise an exception if it is unknown.
*
* @param string $property The property name to check.
- *
* @param PropertiesDefinitionInterface $propertyDefinitions The property definitions.
*
* @return void
*
* @throws DcGeneralInvalidArgumentException When the property is not registered in the definition.
*/
- private function ensurePropertyExists($property, $propertyDefinitions)
+ private function ensurePropertyExists(string $property, PropertiesDefinitionInterface $propertyDefinitions): void
{
if (!$propertyDefinitions->hasProperty($property)) {
throw new DcGeneralInvalidArgumentException(
- sprintf(
+ \sprintf(
'Property %s is mentioned in palette but not defined in propertyDefinition.',
$property
)
@@ -450,24 +471,31 @@ private function ensurePropertyExists($property, $propertyDefinitions)
*
* @return void
*/
- private function storeVersion(ModelInterface $model)
+ private function storeVersion(ModelInterface $model): void
{
if (!$this->modelProvider->isVersioningEnabled()) {
return;
}
- $environment = $this->environment;
- $modelId = $model->getId();
- $dataProvider = $environment->getDataProvider($this->model->getProviderName());
+ $environment = $this->environment;
+ $modelId = $model->getId();
+ $dataProvider = $environment->getDataProvider($this->model->getProviderName());
+ assert($dataProvider instanceof DataProviderInterface);
+
$currentVersion = $dataProvider->getActiveVersion($modelId);
+ $version = $dataProvider->getVersion($modelId, $currentVersion);
+ assert($version instanceof ModelInterface);
// Compare version and current record.
- if (!$currentVersion
- || !$dataProvider->sameModels($model, $dataProvider->getVersion($modelId, $currentVersion))
+ if (
+ !$currentVersion
+ || !$dataProvider->sameModels($model, $version)
) {
$user = \FrontendUser::getInstance();
$username = '(frontend anonymous)';
+
+ /** @psalm-suppress DeprecatedMethod */
if ($user->authenticate()) {
- $username = $user->username;
+ $username = $user->username ?? '';
}
$dataProvider->saveVersion($model, $username);
@@ -483,10 +511,12 @@ private function storeVersion(ModelInterface $model)
*
* @return void
*/
- private function handleSubmit($buttons)
+ private function handleSubmit(array $buttons): void
{
$inputProvider = $this->environment->getInputProvider();
- foreach (array_keys($buttons) as $button) {
+ assert($inputProvider instanceof InputProviderInterface);
+
+ foreach (\array_keys($buttons) as $button) {
if ($inputProvider->hasValue($button)) {
$event = new HandleSubmitEvent($this->environment, $this->model, $button);
@@ -500,25 +530,25 @@ private function handleSubmit($buttons)
/**
* Determine the headline to use.
*
- * @return string.
+ * @return string|null
*
* @deprecated This is deprecated since 2.3 and will be removed in 3.0.
*/
- private function getHeadline(): string
+ private function getHeadline(): ?string
{
// @codingStandardsIgnoreStart
@\trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated - use getSubHeadline()!', E_USER_DEPRECATED);
// @codingStandardsIgnoreEnd
- $this->getSubHeadline();
+ return $this->getSubHeadline();
}
/**
* Determine the headline to use.
*
- * @return string.
+ * @return string|null
*/
- private function getSubHeadline(): string
+ private function getSubHeadline(): ?string
{
$event = new GetEditMaskSubHeadlineEvent($this->environment, $this->model);
@@ -540,9 +570,10 @@ private function doPersist()
$this->handlePrePersist();
- // TO DO: manual sorting property handling is not enabled here as it originates from the backend defininiton.
+ // TO DO: manual sorting property handling is not enabled here as it originates from the backend definition.
// Save the model.
$dataProvider = $this->environment->getDataProvider($this->model->getProviderName());
+ assert($dataProvider instanceof DataProviderInterface);
$dataProvider->save($this->model);
diff --git a/src/View/ViewTemplate.php b/src/View/ViewTemplate.php
index ca30a94..2453630 100644
--- a/src/View/ViewTemplate.php
+++ b/src/View/ViewTemplate.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,27 +12,31 @@
*
* @package contao-community-alliance/dc-general-contao-frontend
* @author Christian Schiffler
- * @copyright 2015 Contao Community Alliance.
+ * @author Ingolf Steinhardt
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
namespace ContaoCommunityAlliance\DcGeneral\ContaoFrontend\View;
+use Contao\BackendTemplate;
use ContaoCommunityAlliance\DcGeneral\View\ViewTemplateInterface;
use ContaoCommunityAlliance\Translator\TranslatorInterface;
/**
* This class is used for the contao frontend view as template.
+ *
+ * @psalm-suppress PropertyNotSetInConstructor
*/
-class ViewTemplate extends \BackendTemplate implements ViewTemplateInterface, TranslatorInterface
+class ViewTemplate extends BackendTemplate implements ViewTemplateInterface, TranslatorInterface
{
/**
* The translator.
*
* @var TranslatorInterface
*/
- protected $translator;
+ protected TranslatorInterface $translator;
/**
* Get the translator.
@@ -61,9 +65,9 @@ public function setTranslator(TranslatorInterface $translator)
/**
* {@inheritDoc}
*/
- public function setData($data)
+ public function setData($arrData)
{
- parent::setData($data);
+ parent::setData($arrData);
return $this;
}
@@ -91,11 +95,7 @@ public function get($name)
*/
public function translate($string, $domain = null, array $parameters = [], $locale = null)
{
- if ($this->translator) {
- return $this->translator->translate($string, $domain, $parameters, $locale);
- }
-
- return $string;
+ return $this->translator->translate($string, $domain, $parameters, $locale);
}
/**
@@ -103,10 +103,33 @@ public function translate($string, $domain = null, array $parameters = [], $loca
*/
public function translatePluralized($string, $number, $domain = null, array $parameters = [], $locale = null)
{
- if ($this->translator) {
- return $this->translator->translatePluralized($string, $number, $domain, $parameters, $locale);
- }
+ return $this->translator->translatePluralized($string, $number, $domain, $parameters, $locale);
+ }
+
+ // @codingStandardsIgnoreStart
+ /**
+ * {@inheritDoc}
+ */
+ public function getData()
+ {
+ return parent::getData();
+ }
- return $string;
+ /**
+ * {@inheritDoc}
+ */
+ public function parse()
+ {
+ return parent::parse();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function output()
+ {
+ /** @psalm-suppress DeprecatedMethod */
+ parent::output();
}
+ // @codingStandardsIgnoreEnd
}
diff --git a/src/View/WidgetManager.php b/src/View/WidgetManager.php
index b3da44d..d42002e 100644
--- a/src/View/WidgetManager.php
+++ b/src/View/WidgetManager.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2015-2022 Contao Community Alliance.
+ * (c) 2015-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -14,7 +14,7 @@
* @author Christian Schiffler
* @author Richard Henkenjohann
* @author Ingolf Steinhardt
- * @copyright 2015-2022 Contao Community Alliance.
+ * @copyright 2015-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
* @filesource
*/
@@ -23,19 +23,25 @@
use Contao\FormTextArea;
use Contao\Input;
+use Contao\Widget;
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\Event\BuildWidgetEvent;
use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\EncodePropertyValueFromWidgetEvent;
use ContaoCommunityAlliance\DcGeneral\ContaoFrontend\Event\DcGeneralFrontendEvents;
+use ContaoCommunityAlliance\DcGeneral\Controller\ControllerInterface;
use ContaoCommunityAlliance\DcGeneral\Data\ModelInterface;
use ContaoCommunityAlliance\DcGeneral\Data\PropertyValueBag;
+use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface;
use ContaoCommunityAlliance\DcGeneral\EnvironmentInterface;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralInvalidArgumentException;
use ContaoCommunityAlliance\DcGeneral\Exception\DcGeneralRuntimeException;
+use Psr\EventDispatcher\EventDispatcherInterface;
/**
* Class WidgetManager.
*
* This class is responsible for creating widgets and processing data through them.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class WidgetManager
{
@@ -44,20 +50,19 @@ class WidgetManager
*
* @var EnvironmentInterface
*/
- protected $environment;
+ protected EnvironmentInterface $environment;
/**
* The model for which widgets shall be generated.
*
* @var ModelInterface
*/
- protected $model;
+ protected ModelInterface $model;
/**
* Create a new instance.
*
* @param EnvironmentInterface $environment The environment in use.
- *
* @param ModelInterface $model The model for which widgets shall be generated.
*/
public function __construct(EnvironmentInterface $environment, ModelInterface $model)
@@ -69,20 +74,23 @@ public function __construct(EnvironmentInterface $environment, ModelInterface $m
/**
* Retrieve the instance of a widget for the given property.
*
- * @param string $property Name of the property for which the widget shall be retrieved.
- *
- * @param PropertyValueBag $valueBag The input values to use (optional).
+ * @param string $property Name of the property for which the widget shall be retrieved.
+ * @param PropertyValueBag|null $valueBag The input values to use (optional).
*
- * @return \Widget
+ * @return \Widget|null
*
- * @throws DcGeneralRuntimeException When No widget could be build.
+ * @throws DcGeneralRuntimeException When No widget could be built.
* @throws DcGeneralInvalidArgumentException When property is not defined in the property definitions.
*/
public function getWidget($property, PropertyValueBag $valueBag = null)
{
- $environment = $this->getEnvironment();
- $dispatcher = $environment->getEventDispatcher();
- $propertyDefinitions = $environment->getDataDefinition()->getPropertiesDefinition();
+ $environment = $this->getEnvironment();
+ $dispatcher = $environment->getEventDispatcher();
+ assert($dispatcher instanceof EventDispatcherInterface);
+ $dataDefinition = $environment->getDataDefinition();
+ assert($dataDefinition instanceof ContainerInterface);
+
+ $propertyDefinitions = $dataDefinition->getPropertiesDefinition();
if (!$propertyDefinitions->hasProperty($property)) {
throw new DcGeneralInvalidArgumentException(
@@ -95,7 +103,11 @@ public function getWidget($property, PropertyValueBag $valueBag = null)
if ($valueBag) {
$values = new PropertyValueBag($valueBag->getArrayCopy());
- $this->environment->getController()->updateModelFromPropertyBag($model, $values);
+
+ $controller = $this->environment->getController();
+ assert($controller instanceof ControllerInterface);
+
+ $controller->updateModelFromPropertyBag($model, $values);
}
$propertyDefinition = $propertyDefinitions->getProperty($property);
@@ -104,7 +116,7 @@ public function getWidget($property, PropertyValueBag $valueBag = null)
$dispatcher->dispatch($event, DcGeneralFrontendEvents::BUILD_WIDGET);
if (!$event->getWidget()) {
throw new DcGeneralRuntimeException(
- sprintf('Widget was not build for property %s::%s.', $this->model->getProviderName(), $property)
+ \sprintf('Widget was not build for property %s::%s.', $this->model->getProviderName(), $property)
);
}
@@ -115,14 +127,12 @@ public function getWidget($property, PropertyValueBag $valueBag = null)
* Render the widget for the named property.
*
* @param string $property The name of the property for which the widget shall be rendered.
- *
* @param bool $ignoreErrors Flag if the error property of the widget shall get cleared prior rendering.
- *
* @param PropertyValueBag $valueBag The input values to use (optional).
*
* @return string
*
- * @throws DcGeneralRuntimeException For unknown properties.
+ * @throws DcGeneralRuntimeException or unknown properties.
*/
public function renderWidget($property, $ignoreErrors = false, PropertyValueBag $valueBag = null)
{
@@ -141,7 +151,8 @@ public function renderWidget($property, $ignoreErrors = false, PropertyValueBag
$reflection->setAccessible(true);
$reflection->setValue($widget, str_replace('error', '', $reflection->getValue($widget)));
} else {
- if ($valueBag && $valueBag->hasPropertyValue($property)
+ if (
+ $valueBag && $valueBag->hasPropertyValue($property)
&& $valueBag->isPropertyValueInvalid($property)
) {
foreach ($valueBag->getPropertyValueErrors($property) as $error) {
@@ -160,12 +171,12 @@ public function renderWidget($property, $ignoreErrors = false, PropertyValueBag
*
* @return void
*/
- public function processInput(PropertyValueBag $valueBag)
+ public function processInput(PropertyValueBag $valueBag): void
{
$post = $this->hijackPost($valueBag);
// Now get and validate the widgets.
- foreach (array_keys($valueBag->getArrayCopy()) as $property) {
+ foreach (\array_keys($valueBag->getArrayCopy()) as $property) {
$this->processProperty($valueBag, $property);
}
@@ -176,7 +187,6 @@ public function processInput(PropertyValueBag $valueBag)
* Process a single property.
*
* @param PropertyValueBag $valueBag The value bag to update.
- *
* @param string $property The property to process.
*
* @return void
@@ -184,12 +194,13 @@ public function processInput(PropertyValueBag $valueBag)
* @throws DcGeneralRuntimeException When No widget could be build.
* @throws DcGeneralInvalidArgumentException When property is not defined in the property definitions.
*/
- private function processProperty(PropertyValueBag $valueBag, $property)
+ private function processProperty(PropertyValueBag $valueBag, string $property): void
{
// NOTE: the passed input values are RAW DATA from the input provider - aka widget known values and not
// native data as in the model.
- // Therefore we do not need to decode them but MUST encode them.
+ // Therefore, we do not need to decode them but MUST encode them.
$widget = $this->getWidget($property, $valueBag);
+ assert($widget instanceof Widget);
$widget->validate();
if ($widget->hasErrors()) {
@@ -209,6 +220,7 @@ private function processProperty(PropertyValueBag $valueBag, $property)
try {
// See https://github.com/contao/contao/blob/7e6bacd4e/core-bundle/src/Resources/contao/forms/FormTextArea.php#L147
if ($widget instanceof FormTextArea) {
+ /** @psalm-suppress UndefinedMagicPropertyFetch */
$valueBag->setPropertyValue($property, $this->encodeValue($property, $widget->rawValue, $valueBag));
return;
}
@@ -233,7 +245,7 @@ private function processProperty(PropertyValueBag $valueBag, $property)
* @SuppressWarnings(PHPMD.Superglobals)
* @SuppressWarnings(PHPMD.CamelCaseVariableName)
*/
- private function hijackPost(PropertyValueBag $valueBag)
+ private function hijackPost(PropertyValueBag $valueBag): array
{
$post = $_POST;
$_POST = [];
@@ -257,7 +269,7 @@ private function hijackPost(PropertyValueBag $valueBag)
* @SuppressWarnings(PHPMD.Superglobals)
* @SuppressWarnings(PHPMD.CamelCaseVariableName)
*/
- private function restorePost($post)
+ private function restorePost(array $post): void
{
$_POST = $post;
Input::resetCache();
@@ -268,7 +280,7 @@ private function restorePost($post)
*
* @return EnvironmentInterface
*/
- private function getEnvironment()
+ private function getEnvironment(): EnvironmentInterface
{
return $this->environment;
}
@@ -282,7 +294,7 @@ private function getEnvironment()
*
* @return mixed
*/
- private function encodeValue($property, $value, PropertyValueBag $valueBag)
+ private function encodeValue(string $property, mixed $value, PropertyValueBag $valueBag): mixed
{
$environment = $this->getEnvironment();
@@ -291,7 +303,10 @@ private function encodeValue($property, $value, PropertyValueBag $valueBag)
->setProperty($property)
->setValue($value);
- $environment->getEventDispatcher()->dispatch($event, EncodePropertyValueFromWidgetEvent::NAME);
+ $dispatcher = $environment->getEventDispatcher();
+ assert($dispatcher instanceof EventDispatcherInterface);
+
+ $dispatcher->dispatch($event, EncodePropertyValueFromWidgetEvent::NAME);
return $event->getValue();
}
diff --git a/src/Widgets/UploadOnSteroids.php b/src/Widgets/UploadOnSteroids.php
index 0e234f6..780b83a 100644
--- a/src/Widgets/UploadOnSteroids.php
+++ b/src/Widgets/UploadOnSteroids.php
@@ -3,7 +3,7 @@
/**
* This file is part of contao-community-alliance/dc-general-contao-frontend.
*
- * (c) 2016-2023 Contao Community Alliance.
+ * (c) 2016-2024 Contao Community Alliance.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -13,7 +13,7 @@
* @package contao-community-alliance/dc-general-contao-frontend
* @author Sven Baumann
* @author Ingolf Steinhardt
- * @copyright 2016-2023 Contao Community Alliance.
+ * @copyright 2016-2024 Contao Community Alliance.
* @license https://github.com/contao-community-alliance/dc-general-contao-frontend/blob/master/LICENSE LGPL-3.0
*
* @filesource
@@ -22,6 +22,7 @@
namespace ContaoCommunityAlliance\DcGeneral\ContaoFrontend\Widgets;
use Contao\Controller;
+use Contao\CoreBundle\Image\ImageFactory;
use Contao\CoreBundle\Slug\Slug as SlugGenerator;
use Contao\CoreBundle\Framework\Adapter;
use Contao\Dbafs;
@@ -31,8 +32,12 @@
use Contao\Input;
use Contao\StringUtil;
use Contao\System;
+use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Exception;
use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@@ -60,6 +65,11 @@
* @property string sortBy
*
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ *
+ * @psalm-suppress PropertyNotSetInConstructor
+ * @psalm-suppress UndefinedThisPropertyFetch
+ * @psalm-suppress UndefinedThisPropertyAssignment
*/
class UploadOnSteroids extends FormFileUpload
{
@@ -85,92 +95,93 @@ class UploadOnSteroids extends FormFileUpload
protected $strPrefix = 'widget widget-upload widget-upload-on-steroids';
/**
- * Image sizes.
+ * Image sizes as serialisized string.
*
- * @var array
+ * @var string
*/
- protected $imageSize;
+ protected string $imageSize;
/**
* The translator.
*
- * @var TranslatorInterface
+ * @var TranslatorInterface|null
*/
- protected TranslatorInterface $translator;
+ protected ?TranslatorInterface $translator = null;
/**
* The input provider.
*
- * @var Adapter|Input
+ * @var Adapter
*/
- protected $inputProvider;
+ protected ?Adapter $inputProvider = null;
/**
* The file model.
*
- * @var Adapter|FilesModel
+ * @var Adapter|null
*/
- private $filesModel;
+ private ?Adapter $filesModel = null;
/**
* The filesystem.
*
- * @var Filesystem
+ * @var Filesystem|null
*/
- private $filesystem;
+ private ?Filesystem $filesystem = null;
/**
* The slug generator.
*
- * @var SlugGenerator
+ * @var SlugGenerator|null
*/
- private $slugGenerator;
+ private ?SlugGenerator $slugGenerator = null;
/**
* {@inheritDoc}
*/
- public function __set($key, $value)
+ public function __set($strKey, $varValue)
{
- if (\in_array(
- $key,
- [
- 'deselect',
- 'delete',
- 'extendFolder',
- 'normalizeExtendFolder',
- 'normalizeFilename',
- 'prefixFilename',
- 'postfixFilename',
- 'files',
- 'showThumbnail',
- 'multiple',
- 'imageSize',
- 'sortBy'
- ]
- )) {
- $this->arrConfiguration[$key] = $value;
+ if (
+ \in_array(
+ $strKey,
+ [
+ 'deselect',
+ 'delete',
+ 'extendFolder',
+ 'normalizeExtendFolder',
+ 'normalizeFilename',
+ 'prefixFilename',
+ 'postfixFilename',
+ 'files',
+ 'showThumbnail',
+ 'multiple',
+ 'imageSize',
+ 'sortBy'
+ ]
+ )
+ ) {
+ $this->arrConfiguration[$strKey] = $varValue;
return;
}
- parent::__set($key, $value);
+ parent::__set($strKey, $varValue);
}
/**
* {@inheritDoc}
*/
- public function parse($attributes = null)
+ public function parse($arrAttributes = null)
{
$this->addIsDeletable();
$this->addIsDeselectable();
$this->addIsMultiple();
$this->addShowThumbnail();
- $this->getImageSize();
$this->addFiles($this->sortBy);
$this->value = \implode(',', \array_map('\Contao\StringUtil::binToUuid', (array) $this->value));
- return parent::parse($attributes);
+ return parent::parse($arrAttributes);
}
/**
@@ -182,7 +193,7 @@ public function parse($attributes = null)
*/
public function parseFilename(string $filename): string
{
- if (empty($filename) || !\is_string($filename)) {
+ if (empty($filename)) {
return $filename;
}
@@ -192,7 +203,7 @@ public function parseFilename(string $filename): string
/**
* {@inheritDoc}
*/
- public function validate()
+ public function validate(): void
{
$inputName = $this->name;
@@ -201,8 +212,9 @@ public function validate()
}
if ($this->extendFolder) {
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
$uploadFolder = $this->filesModel()->findByUuid($this->uploadFolder);
- $uploadFolderPath = $uploadFolder->path . DIRECTORY_SEPARATOR . $this->extendFolder;
+ $uploadFolderPath = (string) $uploadFolder?->path . DIRECTORY_SEPARATOR . $this->extendFolder;
$newUploadFolder = null;
@@ -211,11 +223,12 @@ public function validate()
$newUploadFolder = Dbafs::addResource($uploadFolderPath);
}
- if (!$newUploadFolder) {
+ if (null === $newUploadFolder) {
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
$newUploadFolder = $this->filesModel()->findByPath($uploadFolderPath);
}
- $this->uploadFolder = $newUploadFolder->uuid;
+ $this->uploadFolder = $newUploadFolder?->uuid ?? '';
}
$this->validateSingleUpload();
@@ -229,6 +242,7 @@ public function validate()
*
* @return void
*
+ * @throws \Exception
* @SuppressWarnings(PHPMD.Superglobals)
*/
private function validateSingleUpload(): void
@@ -238,7 +252,7 @@ private function validateSingleUpload(): void
}
$inputName = $this->name;
- $_FILES[$inputName]['name'] = $this->parseFilename($_FILES[$inputName]['name']);
+ $_FILES[$inputName]['name'] = $this->parseFilename($_FILES[$inputName]['name'] ?? '');
parent::validate();
@@ -259,6 +273,7 @@ private function validateSingleUpload(): void
*
* @return void
*
+ * @throws \Exception
* @SuppressWarnings(PHPMD.Superglobals)
*/
private function validateMultipleUpload(): void
@@ -268,7 +283,7 @@ private function validateMultipleUpload(): void
}
$inputName = $this->name;
- $values = \array_map('\Contao\StringUtil::binToUuid', $this->value);
+ $values = \array_map('\Contao\StringUtil::binToUuid', (array) $this->value);
$files = [];
$inputFiles = $this->getMultipleUploadedFiles();
@@ -317,7 +332,7 @@ private function getMultipleUploadedFiles(): array
$files = [];
foreach ($_FILES[$this->name] as $propertyName => $values) {
- foreach ($values as $key => $value) {
+ foreach ((array) $values as $key => $value) {
$files[$key][$propertyName] = $value;
}
}
@@ -328,28 +343,29 @@ private function getMultipleUploadedFiles(): array
/**
* Deselect the file, if is mark for deselect.
*
- * @param string $inputName The input nanme.
+ * @param string $inputName The input name.
*
* @return void
*/
- private function deselectFile(string $inputName)
+ private function deselectFile(string $inputName): void
{
- if (!$this->deselect
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
+ if (
+ !$this->deselect
|| $this->hasErrors()
- || !($post = $this->inputProvider()->post($inputName))
- || !isset($post['reset'][0])
+ || [] === ($post = (array) ($this->getCurrentRequest()?->request->get($inputName . '__reset') ?? []))
) {
return;
}
- if (!$this->multiple && (StringUtil::binToUuid($this->value) === $post['reset'][0])) {
+ if (!$this->multiple && (StringUtil::binToUuid($this->value) === $post[0])) {
$this->value = '';
return;
}
- $values = \array_map('\Contao\StringUtil::binToUuid', $this->value);
- $diffValues = \array_values(\array_diff($values, $post['reset']));
+ $values = \array_map('\Contao\StringUtil::binToUuid', (array) $this->value);
+ $diffValues = \array_values(\array_diff($values, $post));
$this->value = \array_map('\Contao\StringUtil::uuidToBin', $diffValues);
}
@@ -363,36 +379,37 @@ private function deselectFile(string $inputName)
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
- private function deleteFile(string $inputName)
+ private function deleteFile(string $inputName): void
{
- if (!$this->delete
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
+ if (
+ !$this->delete
|| $this->hasErrors()
- || !($post = $this->inputProvider()->post($inputName))
- || !isset($post['delete'][0])
+ || [] === ($post = (array) ($this->getCurrentRequest()?->request->get($inputName . '__delete') ?? []))
) {
return;
}
- if (!$this->multiple && (StringUtil::binToUuid($this->value) === $post['delete'][0])) {
- $this->value = '';
-
+ if (!$this->multiple && (StringUtil::binToUuid($this->value) === $post[0])) {
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
$file = $this->filesModel()->findByUuid($this->value);
- if ($file) {
- $this->filesystem->remove($file->path);
+ if (null !== $file) {
+ $this->filesystem()->remove($file->path);
$file->delete();
+ Dbafs::deleteResource($file->path);
}
-
- Dbafs::deleteResource($file->path);
+ $this->value = '';
return;
}
- $values = \array_map('\Contao\StringUtil::binToUuid', $this->value);
- $diffValues = \array_values(\array_diff($values, $post['delete']));
+ $values = \array_map('\Contao\StringUtil::binToUuid', (array) $this->value);
+ $diffValues = \array_values(\array_diff($values, $post));
- foreach ($post['delete'] as $delete) {
- $file = $this->filesModel()->findByUuid(StringUtil::uuidToBin($delete));
- if (!$file) {
+ foreach ($post as $delete) {
+ /** @psalm-suppress InternalMethod - Class ContaoFramework is internal, not the getAdapter() method. */
+ $file = $this->filesModel()->findByUuid(StringUtil::uuidToBin((string) $delete));
+ if (null === $file) {
continue;
}
@@ -414,8 +431,8 @@ private function deleteFile(string $inputName)
private function convertFilename(string $filename): string
{
$fileInfo = \pathinfo($filename);
- $extension = $fileInfo['extension'];
- $filename = $fileInfo['filename'];
+ $extension = $fileInfo['extension'] ?? '';
+ $filename = $fileInfo['filename'] ?? '';
if ($this->normalizeFilename) {
$extension = $this->slugGenerator()->generate($extension, $this->getSlugOptions());
@@ -438,20 +455,20 @@ private function preOrPostFixFilename(string $filename): string
return $filename;
}
- // We save the default delimeter '-' at prefix and postfix
+ // We save the default delimiter '-' at prefix and postfix
// see https://github.com/ausi/slug-generator/issues/34.
$prefix = $this->prefixFilename;
if ($this->prefixFilename && $this->normalizeFilename) {
$prefix = \str_repeat('-', \strspn($this->prefixFilename, '-')) .
- $this->slugGenerator()->generate($this->prefixFilename, $this->getSlugOptions()) .
- \str_repeat('-', \strspn(\strrev($this->prefixFilename), '-'));
+ $this->slugGenerator()->generate($this->prefixFilename, $this->getSlugOptions()) .
+ \str_repeat('-', \strspn(\strrev($this->prefixFilename), '-'));
}
$postfix = $this->postfixFilename;
if ($this->postfixFilename && $this->normalizeFilename) {
$postfix = \str_repeat('-', \strspn($this->postfixFilename, '-')) .
- $this->slugGenerator()->generate($this->postfixFilename, $this->getSlugOptions()) .
- \str_repeat('-', \strspn(\strrev($this->postfixFilename), '-'));
+ $this->slugGenerator()->generate($this->postfixFilename, $this->getSlugOptions()) .
+ \str_repeat('-', \strspn(\strrev($this->postfixFilename), '-'));
}
return $prefix . $filename . $postfix;
@@ -464,9 +481,10 @@ private function preOrPostFixFilename(string $filename): string
*
* @return void
*
+ * @throws Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
- private function addFiles($sortBy)
+ private function addFiles($sortBy): void
{
$this->files = [];
@@ -476,10 +494,7 @@ private function addFiles($sortBy)
/** @var Connection $connection */
$connection = self::getContainer()->get('database_connection');
-
- $platform = $connection->getDatabasePlatform();
-
- $builder = $connection->createQueryBuilder();
+ $builder = $connection->createQueryBuilder();
switch ($sortBy) {
case 'name_desc':
@@ -501,25 +516,25 @@ private function addFiles($sortBy)
$builder
->select(
- $platform->quoteIdentifier('id'),
- $platform->quoteIdentifier('pid'),
- $platform->quoteIdentifier('tstamp'),
- $platform->quoteIdentifier('uuid'),
- $platform->quoteIdentifier('type'),
- $platform->quoteIdentifier('path'),
- $platform->quoteIdentifier('extension'),
- $platform->quoteIdentifier('hash'),
- $platform->quoteIdentifier('found'),
- $platform->quoteIdentifier('name'),
- $platform->quoteIdentifier('importantPartX'),
- $platform->quoteIdentifier('importantPartY'),
- $platform->quoteIdentifier('importantPartWidth'),
- $platform->quoteIdentifier('importantPartHeight'),
- $platform->quoteIdentifier('meta')
+ 't.id',
+ 't.pid',
+ 't.tstamp',
+ 't.uuid',
+ 't.type',
+ 't.path',
+ 't.extension',
+ 't.hash',
+ 't.found',
+ 't.name',
+ 't.importantPartX',
+ 't.importantPartY',
+ 't.importantPartWidth',
+ 't.importantPartHeight',
+ 't.meta'
)
- ->from($platform->quoteIdentifier('tl_files'))
- ->where($builder->expr()->in($platform->quoteIdentifier('uuid'), ':uuids'))
- ->setParameter('uuids', (array) $this->value, Connection::PARAM_STR_ARRAY);
+ ->from('tl_files', 't')
+ ->where($builder->expr()->in('t.uuid', ':uuids'))
+ ->setParameter('uuids', (array) $this->value, ArrayParameterType::STRING);
$statement = $builder->executeQuery();
if (!$statement->rowCount()) {
@@ -537,9 +552,14 @@ private function addFiles($sortBy)
$fileList = [];
$container = System::getContainer();
$projectDir = $container->getParameter('kernel.project_dir');
+ assert(\is_string($projectDir));
+ $imageFactory = $container->get('contao.image.image_factory');
+ assert($imageFactory instanceof ImageFactory);
foreach ($statement->fetchAllAssociative() as $file) {
- $objFile = FilesModel::findByUuid($file['uuid']);
- $src = $container->get('contao.image.image_factory')
+ if (null === ($objFile = FilesModel::findByUuid($file['uuid']))) {
+ continue;
+ }
+ $src = $imageFactory
->create($projectDir . '/' . rawurldecode($objFile->path), $this->imageSize)
->getUrl($projectDir);
$objThumbnailFile = new File(rawurldecode($src));
@@ -616,34 +636,31 @@ private function addIsMultiple(): void
return;
}
- $this->prefix .= $this->multiple ? ' is-multiple' : '';
+ $this->prefix .= ' is-multiple';
$this->addAttribute('multiple', 'multiple');
}
- /**
- * Get the input provider.
- *
- * @return Adapter|Input
- */
- private function inputProvider(): Adapter
+ private function getCurrentRequest(): ?Request
{
- if (!$this->inputProvider) {
- $this->inputProvider = self::getContainer()->get('contao.framework')->getAdapter(Input::class);
+ $requestStack = \Contao\System::getContainer()->get('request_stack');
+ if (!$requestStack instanceof RequestStack) {
+ return null;
}
-
- return $this->inputProvider;
+ return $requestStack->getCurrentRequest();
}
/**
* Get the files model.
*
- * @return Adapter|FilesModel
+ * @return Adapter
*/
private function filesModel(): Adapter
{
- if (!$this->filesModel) {
- $this->filesModel = self::getContainer()->get('contao.framework')->getAdapter(FilesModel::class);
+ if (null === $this->filesModel) {
+ $filesModel = self::getContainer()->get('contao.framework')?->getAdapter(FilesModel::class);
+ assert($filesModel instanceof Adapter);
+ $this->filesModel = $filesModel;
}
return $this->filesModel;
@@ -654,10 +671,12 @@ private function filesModel(): Adapter
*
* @return Filesystem
*/
- private function filesystem()
+ private function filesystem(): Filesystem
{
- if (!$this->filesystem) {
- $this->filesystem = self::getContainer()->get('filesystem');
+ if (null === $this->filesystem) {
+ $filesystem = self::getContainer()->get('filesystem');
+ assert($filesystem instanceof Filesystem);
+ $this->filesystem = $filesystem;
}
return $this->filesystem;
@@ -668,10 +687,12 @@ private function filesystem()
*
* @return SlugGenerator
*/
- private function slugGenerator()
+ private function slugGenerator(): SlugGenerator
{
- if (!$this->slugGenerator) {
- $this->slugGenerator = System::getContainer()->get('contao.slug');
+ if (null === $this->slugGenerator) {
+ $slugGenerator = System::getContainer()->get('contao.slug');
+ assert($slugGenerator instanceof SlugGenerator);
+ $this->slugGenerator = $slugGenerator;
}
return $this->slugGenerator;
@@ -694,20 +715,12 @@ protected function getSlugOptions(): array
*/
private function translator(): TranslatorInterface
{
- if (!$this->filesystem) {
- $this->filesystem = self::getContainer()->get('translator');
+ if (null === $this->translator) {
+ $translator = self::getContainer()->get('translator');
+ assert($translator instanceof TranslatorInterface);
+ $this->translator = $translator;
}
- return $this->filesystem;
- }
-
- /**
- * Get the image sizes.
- *
- * @return void
- */
- private function getImageSize(): void
- {
- $this->imageSize = StringUtil::deserialize($this->imageSize, true);
+ return $this->translator;
}
}