diff --git a/src/DataContainer/ProductArchiveContainer.php b/src/DataContainer/ProductArchiveContainer.php
index 3af1bbc..7e734b7 100644
--- a/src/DataContainer/ProductArchiveContainer.php
+++ b/src/DataContainer/ProductArchiveContainer.php
@@ -10,28 +10,37 @@
use Contao\BackendUser;
use Contao\Controller;
+use Contao\CoreBundle\Exception\AccessDeniedException;
+use Contao\CoreBundle\Security\ContaoCorePermissions;
+use Contao\Database;
+use Contao\DataContainer;
+use Contao\Image;
+use Contao\Input;
+use Contao\RequestToken;
+use Contao\StringUtil;
use Contao\System;
use HeimrichHannot\UtilsBundle\File\FileUtil;
use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
+use Symfony\Component\HttpFoundation\Session\SessionInterface;
+use Symfony\Component\Security\Core\Security;
class ProductArchiveContainer
{
- /**
- * @var FileUtil
- */
- protected $fileUtil;
+ protected FileUtil $fileUtil;
- /**
- * @var ModelUtil
- */
- protected $modelUtil;
+ protected ModelUtil $modelUtil;
+
+ protected Security $security;
public function __construct(
FileUtil $fileUtil,
- ModelUtil $modelUtil
+ ModelUtil $modelUtil,
+ Security $security
) {
$this->fileUtil = $fileUtil;
$this->modelUtil = $modelUtil;
+ $this->security = $security;
}
/**
@@ -61,8 +70,8 @@ public function getImageSizes()
public function checkPermission()
{
- $user = \Contao\BackendUser::getInstance();
- $database = \Contao\Database::getInstance();
+ $user = BackendUser::getInstance();
+ $database = Database::getInstance();
if ($user->isAdmin) {
return;
@@ -82,11 +91,11 @@ public function checkPermission()
$GLOBALS['TL_DCA']['tl_ml_product_archive']['config']['closed'] = true;
}
- /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $objSession */
- $objSession = \Contao\System::getContainer()->get('session');
+ /** @var SessionInterface $objSession */
+ $objSession = System::getContainer()->get('session');
// Check current action
- switch (\Contao\Input::get('act')) {
+ switch (Input::get('act')) {
case 'create':
case 'select':
// Allow
@@ -94,33 +103,29 @@ public function checkPermission()
case 'edit':
// Dynamically add the record to the user profile
- if (!\in_array(\Contao\Input::get('id'), $root, true)) {
- /** @var \Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface $sessionBag */
+ if (!\in_array(Input::get('id'), $root, true)) {
+ /** @var AttributeBagInterface $sessionBag */
$sessionBag = $objSession->getBag('contao_backend');
$arrNew = $sessionBag->get('new_records');
- if (\is_array($arrNew['tl_ml_product_archive']) && \in_array(\Contao\Input::get('id'),
+ if (\is_array($arrNew['tl_ml_product_archive']) && \in_array(Input::get('id'),
$arrNew['tl_ml_product_archive'], true)) {
// Add the permissions on group level
- if ('custom' != $user->inherit) {
- $objGroup = $database->execute(
- 'SELECT id, contao_media_library_bundles, contao_media_library_bundlep FROM tl_user_group WHERE id IN('.implode(
- ',',
- array_map(
- 'intval',
- $user->groups
- )
- ).')'
- );
+ if ('custom' != $user->inherit)
+ {
+ $sql = "SELECT id, contao_media_library_bundles, contao_media_library_bundlep FROM tl_user_group WHERE id IN(%s);";
+ $sql = sprintf($sql, implode(',', array_map('intval', $user->groups)));
+
+ $objGroup = $database->execute($sql);
while ($objGroup->next()) {
- $arrModulep = \StringUtil::deserialize($objGroup->contao_media_library_bundlep);
+ $arrModulep = StringUtil::deserialize($objGroup->contao_media_library_bundlep);
if (\is_array($arrModulep) && \in_array('create', $arrModulep, true)) {
- $arrModules = \StringUtil::deserialize($objGroup->contao_media_library_bundles,
+ $arrModules = StringUtil::deserialize($objGroup->contao_media_library_bundles,
true);
- $arrModules[] = \Contao\Input::get('id');
+ $arrModules[] = Input::get('id');
$database->prepare('UPDATE tl_user_group SET contao_media_library_bundles=? WHERE id=?')->execute(
serialize($arrModules),
@@ -136,21 +141,19 @@ public function checkPermission()
->limit(1)
->execute($user->id);
- $arrModulep = \StringUtil::deserialize($user->contao_media_library_bundlep);
+ $arrModulep = StringUtil::deserialize($user->contao_media_library_bundlep);
if (\is_array($arrModulep) && \in_array('create', $arrModulep, true)) {
- $arrModules = \StringUtil::deserialize($user->contao_media_library_bundles, true);
- $arrModules[] = \Contao\Input::get('id');
+ $arrModules = StringUtil::deserialize($user->contao_media_library_bundles, true);
+ $arrModules[] = Input::get('id');
- $database->prepare('UPDATE tl_user SET contao_media_library_bundles=? WHERE id=?')->execute(
- serialize($arrModules),
- $user->id
- );
+ $database->prepare('UPDATE tl_user SET contao_media_library_bundles=? WHERE id=?')
+ ->execute(serialize($arrModules), $user->id);
}
}
// Add the new element to the user object
- $root[] = \Contao\Input::get('id');
+ $root[] = Input::get('id');
$user->contao_media_library_bundles = $root;
}
}
@@ -159,14 +162,14 @@ public function checkPermission()
case 'copy':
case 'delete':
case 'show':
- if (!\in_array(\Contao\Input::get('id'), $root, true)
- || ('delete' == \Contao\Input::get('act')
+ if (!\in_array(Input::get('id'), $root, true)
+ || ('delete' == Input::get('act')
&& !$user->hasAccess(
'delete',
'contao_media_library_bundlep'
))
) {
- throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to '.\Contao\Input::get('act').' ml_product_archive ID '.\Contao\Input::get('id').'.');
+ throw new AccessDeniedException('Not enough permissions to '. Input::get('act').' ml_product_archive ID '. Input::get('id').'.');
}
break;
@@ -176,7 +179,7 @@ public function checkPermission()
case 'overrideAll':
$session = $objSession->all();
- if ('deleteAll' == \Contao\Input::get('act') && !$user->hasAccess('delete',
+ if ('deleteAll' == Input::get('act') && !$user->hasAccess('delete',
'contao_media_library_bundlep')) {
$session['CURRENT']['IDS'] = [];
} else {
@@ -187,43 +190,71 @@ public function checkPermission()
break;
default:
- if (\strlen(\Contao\Input::get('act'))) {
- throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to '.\Contao\Input::get('act').' ml_product_archives.');
+ if (\strlen(Input::get('act'))) {
+ throw new AccessDeniedException('Not enough permissions to '. Input::get('act').' ml_product_archives.');
}
break;
}
}
+ public function checkIncludeDelete(DataContainer $dc)
+ {
+ $record = Database::getInstance()
+ ->prepare('SELECT * FROM tl_ml_product_archive WHERE id=?')
+ ->limit(1)
+ ->execute($dc->id)
+ ;
+
+ if (!$record->numRows) {
+ return;
+ }
+
+ if ($record->includeDelete ?? false) {
+ $GLOBALS['TL_DCA']['tl_ml_product_archive']['fields']['redirectAfterDelete']['eval']['mandatory'] = true;
+ } else {
+ unset($GLOBALS['TL_DCA']['tl_ml_product_archive']['fields']['redirectAfterDelete']);
+ }
+ }
+
public function editHeader($row, $href, $label, $title, $icon, $attributes)
{
- return \Contao\BackendUser::getInstance()->canEditFieldsOf('tl_ml_product_archive') ? ''.\Image::getHtml(
- $icon,
- $label
- ).' ' : \Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' ';
+ if ($this->security->isGranted(ContaoCorePermissions::USER_CAN_EDIT_FIELDS_OF_TABLE, 'tl_ml_product_archive'))
+ {
+ $anchor = sprintf(
+ '%s ',
+ Controller::addToUrl("$href&id={$row['id']}"),
+ RequestToken::get(),
+ StringUtil::specialchars($title),
+ $attributes,
+ Image::getHtml($icon, $label)
+ );
+
+ return $anchor;
+ }
+
+ return Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
}
public function copyArchive($row, $href, $label, $title, $icon, $attributes)
{
- return \Contao\BackendUser::getInstance()->hasAccess('create',
+ return BackendUser::getInstance()->hasAccess('create',
'contao_media_library_bundlep') ? ''.\Image::getHtml(
+ ).'&rt='.RequestToken::get().'" title="'. StringUtil::specialchars($title).'"'.$attributes.'>'.Image::getHtml(
$icon,
$label
- ).' ' : \Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' ';
+ ).' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' ';
}
public function deleteArchive($row, $href, $label, $title, $icon, $attributes)
{
- return \Contao\BackendUser::getInstance()->hasAccess('delete',
+ return BackendUser::getInstance()->hasAccess('delete',
'contao_media_library_bundlep') ? ''.\Image::getHtml(
+ ).'&rt='.RequestToken::get().'" title="'.StringUtil::specialchars($title).'"'.$attributes.'>'.Image::getHtml(
$icon,
$label
- ).' ' : \Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' ';
+ ).' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' ';
}
}
diff --git a/src/EventListener/DeleteProductListener.php b/src/EventListener/DeleteProductListener.php
new file mode 100644
index 0000000..734eb0e
--- /dev/null
+++ b/src/EventListener/DeleteProductListener.php
@@ -0,0 +1,92 @@
+requestStack = $requestStack;
+ $this->translator = $translator;
+ $this->session = $session;
+ }
+
+ #[AsEventListener('huh.reader.event.reader_before_render')]
+ public function deleteProduct(ReaderBeforeRenderEvent $event): void
+ {
+ $item = $event->getItem();
+
+ if ($item->getDataContainer() !== 'tl_ml_product') {
+ return;
+ }
+
+ $request = $this->requestStack->getCurrentRequest();
+
+ if (!$request->isMethod(Request::METHOD_DELETE)
+ && Input::post('_method') !== 'DELETE')
+ {
+ return;
+ }
+
+ /** @var class-string $modelClass */
+ $modelClass = Model::getClassFromTable('tl_ml_product');
+ $product = $modelClass::findByPk($item->getRawValue('id'));
+ if ($product === null) {
+ throw new BadRequestHttpException('Invalid product id');
+ }
+
+ /** @var ProductArchiveModel|null $productArchive */
+ $productArchive = $product->getRelated('pid');
+
+ if ($productArchive === null) {
+ throw new InternalServerErrorHttpException('Product archive not found');
+ }
+
+ if (!$productArchive->includeDelete) {
+ throw new MethodNotAllowedHttpException([Request::METHOD_DELETE], 'Delete not allowed');
+ }
+
+ if (!$product->delete()) {
+ throw new InternalServerErrorHttpException('Could not delete product');
+ }
+
+ $pageId = $productArchive->redirectAfterDelete;
+ $page = PageModel::findByPk($pageId);
+
+ if ($page === null) {
+ throw new InternalServerErrorHttpException('No redirect page found');
+ }
+
+ $this->session
+ ->getFlashBag()
+ ->add('success', $this->translator->trans('huh.mediaLibrary.product.delete.success', ['title' => $product->title]))
+ ;
+
+ throw new RedirectResponseException($page->getAbsoluteUrl());
+ }
+}
\ No newline at end of file
diff --git a/src/FormType/MediaLibraryType.php b/src/FormType/MediaLibraryType.php
index a5c7ea7..71325c8 100644
--- a/src/FormType/MediaLibraryType.php
+++ b/src/FormType/MediaLibraryType.php
@@ -106,11 +106,15 @@ public function onPrepareFormData(PrepareFormDataEvent $event): void
$event->getForm()->storeValues = '1';
$event->getForm()->targetTable = ProductModel::getTable();
}
+
+ parent::onPrepareFormData($event);
}
public function onStoreFormData(StoreFormDataEvent $event): void
{
- if ($event->getForm()->ml_archive && ($archiveModel = ProductArchiveModel::findByPk($event->getForm()->ml_archive))) {
+ if ($event->getForm()->ml_archive
+ && ($archiveModel = ProductArchiveModel::findByPk($event->getForm()->ml_archive)))
+ {
$data = $event->getData();
$data = array_intersect_key($data, array_flip(Database::getInstance()->getFieldNames(ProductModel::getTable())));
$data['pid'] = $event->getForm()->ml_archive;
@@ -140,10 +144,14 @@ public function onStoreFormData(StoreFormDataEvent $event): void
$event->setData($data);
}
+
+ parent::onStoreFormData($event);
}
public function onProcessFormData(ProcessFormDataEvent $event): void
{
+ parent::onProcessFormData($event);
+
if (!class_exists(HeimrichHannotFileCreditsBundle::class)) {
return;
}
diff --git a/src/Model/ProductArchiveModel.php b/src/Model/ProductArchiveModel.php
index 7ef6ee4..36ef975 100644
--- a/src/Model/ProductArchiveModel.php
+++ b/src/Model/ProductArchiveModel.php
@@ -18,6 +18,8 @@
* @property string $type
* @property string $additionalFields
* @property bool $keepProductTitleForDownloadItems
+ * @property bool $includeDelete
+ * @property bool $redirectAfterDelete
* @property bool $protected
*/
class ProductArchiveModel extends Model
diff --git a/src/Resources/contao/dca/tl_ml_product_archive.php b/src/Resources/contao/dca/tl_ml_product_archive.php
index fdc101d..23d23fe 100644
--- a/src/Resources/contao/dca/tl_ml_product_archive.php
+++ b/src/Resources/contao/dca/tl_ml_product_archive.php
@@ -1,12 +1,16 @@
[
@@ -14,7 +18,8 @@
'ctable' => ['tl_ml_product'],
'enableVersioning' => true,
'onload_callback' => [
- [\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductArchiveContainer::class, 'checkPermission'],
+ [ProductArchiveContainer::class, 'checkPermission'],
+ [ProductArchiveContainer::class, 'checkIncludeDelete'],
],
'onsubmit_callback' => [
['huh.utils.dca', 'setDateAdded'],
@@ -57,13 +62,13 @@
'label' => &$GLOBALS['TL_LANG']['tl_ml_product_archive']['editheader'],
'href' => 'act=edit',
'icon' => 'header.svg',
- 'button_callback' => [\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductArchiveContainer::class, 'editHeader'],
+ 'button_callback' => [ProductArchiveContainer::class, 'editHeader'],
],
'copy' => [
'label' => &$GLOBALS['TL_LANG']['tl_ml_product_archive']['copy'],
'href' => 'act=copy',
'icon' => 'copy.svg',
- 'button_callback' => [\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductArchiveContainer::class, 'copyArchive'],
+ 'button_callback' => [ProductArchiveContainer::class, 'copyArchive'],
],
'delete' => [
'label' => &$GLOBALS['TL_LANG']['tl_ml_product_archive']['delete'],
@@ -71,7 +76,7 @@
'icon' => 'delete.svg',
'attributes' => 'onclick="if(!confirm(\''.($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? '')
.'\'))return false;Backend.getScrollOffset()"',
- 'button_callback' => [\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductArchiveContainer::class, 'deleteArchive'],
+ 'button_callback' => [ProductArchiveContainer::class, 'deleteArchive'],
],
'show' => [
'label' => &$GLOBALS['TL_LANG']['tl_ml_product_archive']['show'],
@@ -82,10 +87,10 @@
],
'palettes' => [
'__selector__' => ['type', 'protected', 'useExifDataForTags'],
- 'default' => '{general_legend},title;{config_legend},type,additionalFields,keepProductTitleForDownloadItems;{protected_legend},protected;',
+ 'default' => '{general_legend},title;{config_legend},type,additionalFields,keepProductTitleForDownloadItems,includeDelete,redirectAfterDelete;{protected_legend},protected;',
],
'subpalettes' => [
- 'type_'.\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductContainer::TYPE_IMAGE => 'imageSizes',
+ 'type_'. ProductContainer::TYPE_IMAGE => 'imageSizes',
'protected' => 'groups',
],
'fields' => [
@@ -119,7 +124,7 @@
'exclude' => true,
'filter' => true,
'inputType' => 'select',
- 'options' => \HeimrichHannot\MediaLibraryBundle\DataContainer\ProductContainer::TYPES,
+ 'options' => ProductContainer::TYPES,
'reference' => &$GLOBALS['TL_LANG']['tl_ml_product']['reference'],
'eval' => ['tl_class' => 'w50', 'mandatory' => true, 'includeBlankOption' => true, 'submitOnChange' => true],
'sql' => "varchar(64) NOT NULL default ''",
@@ -130,7 +135,7 @@
'filter' => true,
'inputType' => 'checkboxWizard',
'options_callback' => function (Contao\DataContainer $dc) {
- return \Contao\System::getContainer()->get('huh.utils.choice.field')->getCachedChoices(
+ return System::getContainer()->get('huh.utils.choice.field')->getCachedChoices(
[
'dataContainer' => 'tl_ml_product',
'evalConditions' => [
@@ -148,7 +153,7 @@
'exclude' => true,
'flag' => 1,
'inputType' => 'checkboxWizard',
- 'options_callback' => [\HeimrichHannot\MediaLibraryBundle\DataContainer\ProductArchiveContainer::class, 'getImageSizes'],
+ 'options_callback' => [ProductArchiveContainer::class, 'getImageSizes'],
'eval' => ['includeBlankOption' => true, 'multiple' => true, 'tl_class' => 'clr w50 autoheight'],
'sql' => 'blob NULL',
],
@@ -176,5 +181,29 @@
'eval' => ['tl_class' => 'clr'],
'sql' => "char(1) NOT NULL default ''",
],
+ 'includeDelete' => [
+ 'exclude' => true,
+ 'filter' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => [
+ 'tl_class' => 'clr',
+ 'submitOnChange' => true,
+ ],
+ 'sql' => "char(1) NOT NULL default ''",
+ ],
+ 'redirectAfterDelete' => [
+ 'inputType' => 'pageTree',
+ 'foreignKey' => 'tl_page.id',
+ 'eval' => [
+ 'fieldType' => 'radio',
+ 'tl_class' => 'clr'
+ ],
+ 'sql' => "int(10) unsigned NOT NULL default 0",
+ 'relation' => [
+ 'type' => 'hasOne',
+ 'load' => 'lazy'
+ ]
+ ]
],
];
diff --git a/src/Resources/contao/languages/de/tl_ml_product_archive.php b/src/Resources/contao/languages/de/tl_ml_product_archive.php
index 85a90a0..68d4ce8 100644
--- a/src/Resources/contao/languages/de/tl_ml_product_archive.php
+++ b/src/Resources/contao/languages/de/tl_ml_product_archive.php
@@ -21,7 +21,10 @@
$lang['groups'][1] = 'Wählen Sie hier die gewünschten Mitgliedergruppen für den geschützten Zugriff aus.';
$lang['keepProductTitleForDownloadItems'][0] = 'Produktnamen im Downloadtitel behalten';
$lang['keepProductTitleForDownloadItems'][1] = 'Wählen Sie diese Option, wenn der Titel des Produktes in den Titeln der Downloadelementen bestehen bleiben soll.';
-
+$lang['includeDelete'][0] = 'Produkte können gelöscht werden';
+$lang['includeDelete'][1] = 'Wählen Sie diese Option, wenn dem Nutzer die Möglichkeit gegeben werden soll, das Produkt zu löschen.';
+$lang['redirectAfterDelete'][0] = 'Weiterleitungsseite nach dem Löschen';
+$lang['redirectAfterDelete'][1] = 'Wählen Sie hier die Seite aus, zu der der Nutzer nach dem Löschen des Produktes weitergeleitet werden soll.';
/**
* Legends
diff --git a/src/Resources/translations/messages.de.yml b/src/Resources/translations/messages.de.yml
index e057c09..c7d7cde 100644
--- a/src/Resources/translations/messages.de.yml
+++ b/src/Resources/translations/messages.de.yml
@@ -6,4 +6,6 @@ huh.mediaLibrary.btn.abort.label: 'abbrechen'
huh.mediaLibrary.alert.download.title: 'Option wählen'
huh.mediaLibrary.downloadTitle.original: 'Originalgröße'
-huh.mediaLibrary.downloadTitle.sizeWithProductTitle: '{title} ({size})'
\ No newline at end of file
+huh.mediaLibrary.downloadTitle.sizeWithProductTitle: '{title} ({size})'
+
+huh.mediaLibrary.product.delete.success: 'Bild "{title}" wurde erfolgreich gelöscht'