diff --git a/README.md b/README.md
index 625111b..178bc8a 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
---
-> Working with **Contao 4.9** and up to **Contao 4.13** (PHP ^7.4 and PHP 8)
+> Working with **Contao 4.13** and **Contao 5.1** (PHP ^8.1)
---
diff --git a/composer.json b/composer.json
index 2c86749..c92520a 100644
--- a/composer.json
+++ b/composer.json
@@ -4,13 +4,13 @@
"description": "A glossary extension for the Contao Open Source CMS. Glossaries are organized in archives similar to news and events and can be displayed via a list and reader module.",
"license": "AGPL-3.0-or-later",
"authors": [
- {
- "name": "Fabian Ekert",
- "homepage": "https://github.com/eki89"
- },
{
"name": "Sebastian Zoglowek",
"homepage": "https://github.com/zoglo"
+ },
+ {
+ "name": "Fabian Ekert",
+ "homepage": "https://github.com/eki89"
}
],
"require": {
@@ -43,7 +43,7 @@
},
"extra": {
"branch-alias": {
- "dev-main": "2.1.x-dev"
+ "dev-main": "2.2.x-dev"
},
"contao-manager-plugin": "Oveleon\\ContaoGlossaryBundle\\ContaoManager\\Plugin"
},
diff --git a/contao/classes/Glossary.php b/contao/classes/Glossary.php
index 57c1188..4ba37a1 100644
--- a/contao/classes/Glossary.php
+++ b/contao/classes/Glossary.php
@@ -25,8 +25,8 @@
use Contao\PageModel;
use Contao\StringUtil;
use Contao\System;
+use Contao\Validator;
use Oveleon\ContaoGlossaryBundle\Model\GlossaryItemModel;
-use Oveleon\ContaoGlossaryBundle\Model\GlossaryModel;
use function Symfony\Component\String\u;
/**
@@ -41,95 +41,6 @@ class Glossary extends Frontend
*/
private static array $arrUrlCache = [];
- /**
- * Add glossary items to the indexer.
- */
- public function getSearchablePages(array $arrPages, $intRoot = 0, bool $blnIsSitemap = false): array
- {
- $arrRoot = [];
-
- if ($intRoot > 0)
- {
- $arrRoot = $this->Database->getChildRecords($intRoot, PageModel::getTable());
- }
-
- $arrProcessed = [];
- $time = time();
-
- // Get all glossaries
- $objGlossary = GlossaryModel::findByProtected('');
-
- // Walk through each glossary
- if (null !== $objGlossary)
- {
- while ($objGlossary->next())
- {
- // Skip glossaries without target page
- if (!$objGlossary->jumpTo)
- {
- continue;
- }
-
- // Skip glossaries outside the root nodes
- if (!empty($arrRoot) && !\in_array($objGlossary->jumpTo, $arrRoot))
- {
- continue;
- }
-
- // Get the URL of the jumpTo page
- if (!isset($arrProcessed[$objGlossary->jumpTo]))
- {
- $objParent = PageModel::findWithDetails($objGlossary->jumpTo);
-
- // The target page does not exist
- if (null === $objParent)
- {
- continue;
- }
-
- // The target page has not been published (see #5520)
- if (!$objParent->published || ($objParent->start && $objParent->start > $time) || ($objParent->stop && $objParent->stop <= $time))
- {
- continue;
- }
-
- if ($blnIsSitemap)
- {
- // The target page is protected (see #8416)
- if ($objParent->protected)
- {
- continue;
- }
-
- // The target page is exempt from the sitemap (see #6418)
- if ('noindex,nofollow' === $objParent->robots)
- {
- continue;
- }
- }
-
- // Generate the URL
- $arrProcessed[$objGlossary->jumpTo] = $objParent->getAbsoluteUrl(Config::get('useAutoItem') ? '/%s' : '/items/%s');
- }
-
- $strUrl = $arrProcessed[$objGlossary->jumpTo];
-
- // Get the items
- $objArticle = GlossaryItemModel::findPublishedDefaultByPid($objGlossary->id);
-
- if (null !== $objArticle)
- {
- while ($objArticle->next())
- {
- $arrPages[] = $this->getLink($objArticle, $strUrl);
- }
- }
- }
- }
-
- return $arrPages;
- }
-
/**
* Generate a URL and return it as string.
*/
@@ -156,7 +67,14 @@ public static function generateUrl(GlossaryItemModel $objItem, bool $blnAbsolute
}
else
{
- self::$arrUrlCache[$strCacheKey] = StringUtil::ampersand($objItem->url);
+ $url = $objItem->url;
+
+ if (Validator::isRelativeUrl($url))
+ {
+ $url = Environment::get('path') . '/' . $url;
+ }
+
+ self::$arrUrlCache[$strCacheKey] = StringUtil::ampersand($url);
}
break;
@@ -188,7 +106,7 @@ public static function generateUrl(GlossaryItemModel $objItem, bool $blnAbsolute
if (!$objPage instanceof PageModel)
{
- self::$arrUrlCache[$strCacheKey] = StringUtil::ampersand(Environment::get('request'));
+ self::$arrUrlCache[$strCacheKey] = StringUtil::ampersand(Environment::get('requestUri'));
}
else
{
@@ -256,8 +174,8 @@ public static function parseGlossaryItem(GlossaryItemModel $objGlossaryItem, str
$objTemplate->teaser = StringUtil::encodeEmail($objTemplate->teaser);
// Replace insert tags within teaser when fetching items via controller (see #13)
- // ToDo: rewrite
- //$objTemplate->teaser = Controller::replaceInsertTags($objTemplate->teaser);
+ $parser = System::getContainer()->get('contao.insert_tag.parser');
+ $objTemplate->teaser = $parser->replace((string) $objTemplate->teaser);
}
// Display the "read more" button for external/article links
@@ -293,15 +211,16 @@ public static function parseGlossaryItem(GlossaryItemModel $objGlossaryItem, str
$objTemplate->addImage = false;
// Add an image
- if ($objGlossaryItem->addImage && $objGlossaryItem->singleSRC)
+ if ($objGlossaryItem->addImage)
{
$objModel = FilesModel::findByUuid($objGlossaryItem->singleSRC);
- if (null !== $objModel && is_file(System::getContainer()->getParameter('kernel.project_dir') . 'Glossary.php/' .$objModel->path))
+ if (null !== $objModel)
{
// Do not override the field now that we have a model registry
$arrGlossaryItem = $objGlossaryItem->row();
+ // ToDo: Move method into src
// Override the default image size
if ($imgSize)
{
@@ -309,33 +228,37 @@ public static function parseGlossaryItem(GlossaryItemModel $objGlossaryItem, str
if ($size[0] > 0 || $size[1] > 0 || is_numeric($size[2]) || ($size[2][0] ?? null) === '_')
{
- $arrGlossaryItem['size'] = $imgSize;
+ $imgSize = $imgSize;
}
}
- $arrGlossaryItem['singleSRC'] = $objModel->path;
- Controller::addImageToTemplate($objTemplate, $arrGlossaryItem, null, null, $objModel);
+ $figureBuilder = System::getContainer()
+ ->get('contao.image.studio')
+ ->createFigureBuilder()
+ ->from($objModel->path)
+ ->setSize($imgSize)
+ ->enableLightbox((bool) $objGlossaryItem->fullsize);
- // Link to the glossary item if no image link has been defined
- if (!$objTemplate->fullsize && !$objTemplate->imageUrl)
+ // If the external link is opened in a new window, open the image link in a new window as well (see #210)
+ if ('external' === $objTemplate->source && $objTemplate->target)
{
- // Load language for 'read more' link
- System::loadLanguageFile('default');
-
- // Unset the image title attribute
- $picture = $objTemplate->picture;
- unset($picture['title']);
- $objTemplate->picture = $picture;
-
- // Link to the glossary item
- $objTemplate->href = $objTemplate->link;
- $objTemplate->linkTitle = StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['readMore'], $objGlossaryItem->keyword), true);
+ $figureBuilder->setLinkAttribute('target', '_blank');
+ }
- // If the external link is opened in a new window, open the image link in a new window, too
- if ('external' === $objTemplate->source && $objTemplate->target && false === strpos($objTemplate->attributes, 'target="_blank"'))
+ if (null !== ($figure = $figureBuilder->buildIfResourceExists()))
+ {
+ // ToDo: intCount (see contao #5708/#5851).
+ if (!$figure->getLinkHref())
{
- $objTemplate->attributes .= ' target="_blank"';
+ $linkTitle = StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['readMore'], $objGlossaryItem->keyword), true);
+
+ $figure = $figureBuilder
+ ->setLinkHref($objTemplate->link)
+ ->setLinkAttribute('title', $linkTitle)
+ ->build();
}
+
+ $figure->applyLegacyTemplateData($objTemplate, $objGlossaryItem->imagemargin, $objGlossaryItem->floating);
}
}
}
diff --git a/contao/config/config.php b/contao/config/config.php
index c77549c..57b8fa0 100644
--- a/contao/config/config.php
+++ b/contao/config/config.php
@@ -35,9 +35,6 @@
$GLOBALS['TL_MODELS']['tl_glossary'] = GlossaryModel::class;
$GLOBALS['TL_MODELS']['tl_glossary_item'] = GlossaryItemModel::class;
-// Register hooks
-$GLOBALS['TL_HOOKS']['getSearchablePages'][] = ['Oveleon\ContaoGlossaryBundle\Glossary', 'getSearchablePages'];
-
// Add permissions
$GLOBALS['TL_PERMISSIONS'][] = 'glossarys';
$GLOBALS['TL_PERMISSIONS'][] = 'glossaryp';
diff --git a/contao/dca/tl_glossary.php b/contao/dca/tl_glossary.php
index c2ef51a..3a859e4 100644
--- a/contao/dca/tl_glossary.php
+++ b/contao/dca/tl_glossary.php
@@ -12,21 +12,12 @@
* @copyright Oveleon
*/
-use Contao\Backend;
use Contao\BackendUser;
use Contao\Controller;
-use Contao\CoreBundle\Exception\AccessDeniedException;
-use Contao\CoreBundle\Security\ContaoCorePermissions;
use Contao\DataContainer;
use Contao\DC_Table;
-use Contao\Image;
-use Contao\Input;
-use Contao\PageModel;
-use Contao\StringUtil;
use Contao\System;
-use Oveleon\ContaoGlossaryBundle\Security\ContaoGlossaryPermissions;
-use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
-use Symfony\Component\HttpFoundation\Session\SessionInterface;
+use Oveleon\ContaoGlossaryBundle\EventListener\DataContainer\GlossaryListener;
$GLOBALS['TL_DCA']['tl_glossary'] = [
// Config
@@ -36,17 +27,14 @@
'switchToEdit' => true,
'enableVersioning' => true,
'markAsCopy' => 'title',
- 'onload_callback' => [
- ['tl_glossary', 'checkPermission'],
- ],
'oncreate_callback' => [
- ['tl_glossary', 'adjustPermissions'],
+ [GlossaryListener::class, 'adjustPermissions'],
],
'oncopy_callback' => [
- ['tl_glossary', 'adjustPermissions'],
+ [GlossaryListener::class, 'adjustPermissions'],
],
'oninvalidate_cache_tags_callback' => [
- ['tl_glossary', 'addSitemapCacheInvalidationTag'],
+ [GlossaryListener::class, 'addSitemapCacheInvalidationTag'],
],
'sql' => [
'keys' => [
@@ -83,18 +71,18 @@
'editheader' => [
'href' => 'act=edit',
'icon' => 'header.svg',
- 'button_callback' => ['tl_glossary', 'editHeader'],
+ 'button_callback' => [GlossaryListener::class, 'editHeader'],
],
'copy' => [
'href' => 'act=copy',
'icon' => 'copy.svg',
- 'button_callback' => ['tl_glossary', 'copyArchive'],
+ 'button_callback' => [GlossaryListener::class, 'copyArchive'],
],
'delete' => [
'href' => 'act=delete',
'icon' => 'delete.svg',
'attributes' => 'onclick="if(!confirm(\''.($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null).'\'))return false;Backend.getScrollOffset()"',
- 'button_callback' => ['tl_glossary', 'deleteArchive'],
+ 'button_callback' => [GlossaryListener::class, 'deleteArchive'],
],
'show' => [
'href' => 'act=show',
@@ -155,7 +143,7 @@
'inputType' => 'imageSize',
'reference' => &$GLOBALS['TL_LANG']['MSC'],
'eval' => ['rgxp' => 'natural', 'includeBlankOption' => true, 'nospace' => true, 'helpwizard' => true, 'tl_class' => 'w50'],
- 'options_callback' => static fn () => System::getContainer()->get('contao.image.image_sizes')->getOptionsForUser(BackendUser::getInstance()),
+ 'options_callback' => static fn () => System::getContainer()->get('contao.image.sizes')->getOptionsForUser(BackendUser::getInstance()),
'sql' => "varchar(64) NOT NULL default ''",
],
'protected' => [
@@ -177,233 +165,3 @@
],
],
];
-
-/**
- * Provide miscellaneous methods that are used by the data configuration array.
- *
- * @author Fabian Ekert
- */
-class tl_glossary extends Backend
-{
- /**
- * Import the back end user object.
- */
- public function __construct()
- {
- parent::__construct();
- $this->import(BackendUser::class, 'User');
- }
-
- /**
- * Check permissions to edit table tl_glossary.
- *
- * @throws AccessDeniedException
- */
- public function checkPermission(): void
- {
- if ($this->User->isAdmin)
- {
- return;
- }
-
- // Set root IDs
- if (empty($this->User->glossarys) || !is_array($this->User->glossarys))
- {
- $root = [0];
- }
- else
- {
- $root = $this->User->glossarys;
- }
-
- $GLOBALS['TL_DCA']['tl_glossary']['list']['sorting']['root'] = $root;
-
- // Check permissions to add archives
- if (!$this->User->hasAccess('create', 'glossaryp'))
- {
- $GLOBALS['TL_DCA']['tl_glossary']['config']['closed'] = true;
- }
-
- /** @var SessionInterface $objSession */
- $objSession = System::getContainer()->get('session');
-
- // Check current action
- switch (Input::get('act'))
- {
- case 'select':
- // Allow
- break;
-
- case 'create':
- if (!$this->User->hasAccess('create', 'glossaryp'))
- {
- throw new AccessDeniedException('Not enough permissions to create glossaries.');
- }
- break;
-
- case 'edit':
- case 'copy':
- case 'delete':
- case 'show':
- if (!in_array(Input::get('id'), $root) || ('delete' === Input::get('act') && !$this->User->hasAccess('delete', 'glossaryp')))
- {
- throw new AccessDeniedException('Not enough permissions to '.Input::get('act').' glossary ID '.Input::get('id').'.');
- }
- break;
-
- case 'editAll':
- case 'deleteAll':
- case 'overrideAll':
- case 'copyAll':
- $session = $objSession->all();
-
- if ('deleteAll' === Input::get('act') && !$this->User->hasAccess('delete', 'glossaryp'))
- {
- $session['CURRENT']['IDS'] = [];
- }
- else
- {
- $session['CURRENT']['IDS'] = array_intersect((array) $session['CURRENT']['IDS'], $root);
- }
- $objSession->replace($session);
- break;
-
- default:
- if (Input::get('act'))
- {
- throw new AccessDeniedException('Not enough permissions to '.Input::get('act').' glossary.');
- }
- break;
- }
- }
-
- /**
- * Add the glossary to the permissions.
- *
- * @param $insertId
- */
- public function adjustPermissions($insertId): void
- {
- // The oncreate_callback passes $insertId as second argument
- if (4 === func_num_args())
- {
- $insertId = func_get_arg(1);
- }
-
- if ($this->User->isAdmin)
- {
- return;
- }
-
- // Set root IDs
- if (empty($this->User->glossarys) || !is_array($this->User->glossarys))
- {
- $root = [0];
- }
- else
- {
- $root = $this->User->glossarys;
- }
-
- // The glossary is enabled already
- if (in_array($insertId, $root))
- {
- return;
- }
-
- /** @var AttributeBagInterface $objSessionBag */
- $objSessionBag = System::getContainer()->get('session')->getBag('contao_backend');
-
- $arrNew = $objSessionBag->get('new_records');
-
- if (is_array($arrNew['tl_glossary']) && in_array($insertId, $arrNew['tl_glossary']))
- {
- // Add the permissions on group level
- if ('custom' !== $this->User->inherit)
- {
- $objGroup = $this->Database->execute('SELECT id, glossarys, glossaryp FROM tl_user_group WHERE id IN('.implode(',', array_map('\intval', $this->User->groups)).')');
-
- while ($objGroup->next())
- {
- $arrGlossaryp = StringUtil::deserialize($objGroup->glossaryp);
-
- if (is_array($arrGlossaryp) && in_array('create', $arrGlossaryp))
- {
- $arrGlossarys = StringUtil::deserialize($objGroup->glossarys, true);
- $arrGlossarys[] = $insertId;
-
- $this->Database->prepare('UPDATE tl_user_group SET glossarys=? WHERE id=?')
- ->execute(serialize($arrGlossarys), $objGroup->id)
- ;
- }
- }
- }
-
- // Add the permissions on user level
- if ('group' !== $this->User->inherit)
- {
- $objUser = $this->Database->prepare('SELECT glossarys, glossaryp FROM tl_user WHERE id=?')
- ->limit(1)
- ->execute($this->User->id)
- ;
-
- $arrGlossaryp = StringUtil::deserialize($objUser->glossaryp);
-
- if (is_array($arrGlossaryp) && in_array('create', $arrGlossaryp))
- {
- $arrGlossarys = StringUtil::deserialize($objUser->glossarys, true);
- $arrGlossarys[] = $insertId;
-
- $this->Database->prepare('UPDATE tl_user SET glossarys=? WHERE id=?')
- ->execute(serialize($arrGlossarys), $this->User->id)
- ;
- }
- }
-
- // Add the new element to the user object
- $root[] = $insertId;
- $this->User->glossarys = $root;
- }
- }
-
- /**
- * Return the edit header button.
- */
- public function editHeader(array $row, string $href, string $label, string $title, string $icon, string $attributes): string
- {
- return System::getContainer()->get('security.helper')->isGranted(ContaoCorePermissions::USER_CAN_EDIT_FIELDS_OF_TABLE, 'tl_glossary') ? '' . Image::getHtml($icon, $label) . ' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
- }
-
- /**
- * Return the copy archive button.
- */
- public function copyArchive(array $row, string $href, string $label, string $title, string $icon, string $attributes): string
- {
- return System::getContainer()->get('security.helper')->isGranted(ContaoGlossaryPermissions::USER_CAN_CREATE_ARCHIVES) ? '' . Image::getHtml($icon, $label) . ' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
- }
-
- /**
- * Return the delete archive button.
- */
- public function deleteArchive(array $row, string $href, string $label, string $title, string $icon, string $attributes): string
- {
- return System::getContainer()->get('security.helper')->isGranted(ContaoGlossaryPermissions::USER_CAN_DELETE_ARCHIVES) ? '' . Image::getHtml($icon, $label) . ' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)) . ' ';
- }
-
- /**
- * @param DataContainer $dc
- *
- * @return array
- */
- public function addSitemapCacheInvalidationTag($dc, array $tags)
- {
- $pageModel = PageModel::findWithDetails($dc->activeRecord->jumpTo);
-
- if (null === $pageModel)
- {
- return $tags;
- }
-
- return array_merge($tags, ['contao.sitemap.'.$pageModel->rootId]);
- }
-}
diff --git a/contao/dca/tl_glossary_item.php b/contao/dca/tl_glossary_item.php
index 0a49f13..4545237 100644
--- a/contao/dca/tl_glossary_item.php
+++ b/contao/dca/tl_glossary_item.php
@@ -12,23 +12,18 @@
* @copyright Oveleon
*/
-use Contao\Automator;
use Contao\Backend;
use Contao\BackendUser;
use Contao\Config;
-use Contao\CoreBundle\Exception\AccessDeniedException;
use Contao\DataContainer;
-use Contao\Image;
-use Contao\Input;
+use Contao\DC_Table;
use Contao\LayoutModel;
use Contao\PageModel;
-use Contao\StringUtil;
use Contao\System;
-use Contao\Versions;
+use Oveleon\ContaoGlossaryBundle\EventListener\DataContainer\GlossaryItemListener;
use Oveleon\ContaoGlossaryBundle\Glossary;
use Oveleon\ContaoGlossaryBundle\Model\GlossaryItemModel;
use Oveleon\ContaoGlossaryBundle\Model\GlossaryModel;
-use Symfony\Component\HttpFoundation\Session\SessionInterface;
System::loadLanguageFile('tl_content');
@@ -42,21 +37,21 @@
'enableVersioning' => true,
'markAsCopy' => 'keyword',
'onload_callback' => [
- ['tl_glossary_item', 'checkPermission'],
- ['tl_glossary_item', 'generateSitemap'],
+ [GlossaryItemListener::class, 'checkPermission'],
+ [GlossaryItemListener::class, 'generateSitemap'],
],
'oncut_callback' => [
- ['tl_glossary_item', 'scheduleUpdate'],
+ [GlossaryItemListener::class, 'scheduleUpdate'],
],
'ondelete_callback' => [
- ['tl_glossary_item', 'scheduleUpdate'],
+ [GlossaryItemListener::class, 'scheduleUpdate'],
],
'onsubmit_callback' => [
- ['tl_glossary_item', 'setGlossaryItemGroup'],
- ['tl_glossary_item', 'scheduleUpdate'],
+ [GlossaryItemListener::class, 'setGlossaryItemGroup'],
+ [GlossaryItemListener::class, 'scheduleUpdate'],
],
'oninvalidate_cache_tags_callback' => [
- ['tl_glossary_item', 'addSitemapCacheInvalidationTag'],
+ [GlossaryItemListener::class, 'addSitemapCacheInvalidationTag'],
],
'sql' => [
'keys' => [
@@ -70,12 +65,12 @@
// List
'list' => [
'sorting' => [
- 'mode' => 4,
+ 'mode' => DataContainer::MODE_PARENT,
'fields' => ['keyword'],
'headerFields' => ['title', 'jumpTo', 'tstamp', 'protected'],
'panelLayout' => 'filter;sort,search,limit',
- 'child_record_callback' => ['tl_glossary_item', 'listGlossaryItems'],
- 'child_record_class' => 'no_padding',
+ 'child_record_callback' => [GlossaryItemListener::class, 'listItems'],
+ 'child_record_class' => 'no_padding'
],
'global_operations' => [
'all' => [
@@ -107,9 +102,8 @@
'attributes' => 'onclick="if(!confirm(\''.($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null).'\'))return false;Backend.getScrollOffset()"',
],
'toggle' => [
+ 'href' => 'act=toggle&field=published',
'icon' => 'visible.svg',
- 'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleVisibility(this,%s)"',
- 'button_callback' => ['tl_glossary_item', 'toggleIcon'],
'showInHeader' => true,
],
'show' => [
@@ -278,7 +272,7 @@
'inputType' => 'imageSize',
'reference' => &$GLOBALS['TL_LANG']['MSC'],
'eval' => ['rgxp' => 'natural', 'includeBlankOption' => true, 'nospace' => true, 'helpwizard' => true, 'tl_class' => 'w50'],
- 'options_callback' => static fn () => System::getContainer()->get('contao.image.image_sizes')->getOptionsForUser(BackendUser::getInstance()),
+ 'options_callback' => static fn () => System::getContainer()->get('contao.image.sizes')->getOptionsForUser(BackendUser::getInstance()),
'sql' => "varchar(64) NOT NULL default ''",
],
'imagemargin' => [
@@ -372,6 +366,7 @@
'sql' => "varchar(255) NOT NULL default ''",
],
'published' => [
+ 'toggle' => true,
'label' => &$GLOBALS['TL_LANG']['tl_glossary_item']['published'],
'exclude' => true,
'filter' => true,
@@ -400,147 +395,6 @@ public function __construct()
$this->import(BackendUser::class, 'User');
}
- /**
- * Check permissions to edit table tl_glossary_item.
- *
- * @throws AccessDeniedException
- */
- public function checkPermission(): void
- {
- if ($this->User->isAdmin)
- {
- return;
- }
-
- // Set the root IDs
- if (empty($this->User->glossarys) || !is_array($this->User->glossarys))
- {
- $root = [0];
- }
- else
- {
- $root = $this->User->glossarys;
- }
-
- $id = strlen(Input::get('id')) ? Input::get('id') : CURRENT_ID;
-
- // Check current action
- switch (Input::get('act'))
- {
- case 'paste':
- case 'select':
- // Check CURRENT_ID here (see #247)
- if (!in_array(CURRENT_ID, $root))
- {
- throw new AccessDeniedException('Not enough permissions to access glossary ID '.$id.'.');
- }
- break;
-
- case 'create':
- if (!Input::get('pid') || !in_array(Input::get('pid'), $root))
- {
- throw new AccessDeniedException('Not enough permissions to create glossary items in glossary ID '.Input::get('pid').'.');
- }
- break;
-
- case 'cut':
- case 'copy':
- if ('cut' === Input::get('act') && 1 === (int) Input::get('mode'))
- {
- $objGlossary = $this->Database->prepare('SELECT pid FROM tl_glossary_item WHERE id=?')
- ->limit(1)
- ->execute(Input::get('pid'))
- ;
-
- if ($objGlossary->numRows < 1)
- {
- throw new AccessDeniedException('Invalid glossary item ID '.Input::get('pid').'.');
- }
-
- $pid = $objGlossary->pid;
- }
- else
- {
- $pid = Input::get('pid');
- }
-
- if (!in_array($pid, $root))
- {
- throw new AccessDeniedException('Not enough permissions to '.Input::get('act').' glossary item ID '.$id.' to glossary ID '.$pid.'.');
- }
- // no break
-
- case 'edit':
- case 'show':
- case 'delete':
- case 'toggle':
- $objGlossary = $this->Database->prepare('SELECT pid FROM tl_glossary_item WHERE id=?')
- ->limit(1)
- ->execute($id)
- ;
-
- if ($objGlossary->numRows < 1)
- {
- throw new AccessDeniedException('Invalid glossary item ID '.$id.'.');
- }
-
- if (!in_array($objGlossary->pid, $root))
- {
- throw new AccessDeniedException('Not enough permissions to '.Input::get('act').' glossary item ID '.$id.' of glossary ID '.$objGlossary->pid.'.');
- }
- break;
-
- case 'editAll':
- case 'deleteAll':
- case 'overrideAll':
- case 'cutAll':
- case 'copyAll':
- if (!in_array($id, $root))
- {
- throw new AccessDeniedException('Not enough permissions to access glossary ID '.$id.'.');
- }
-
- $objGlossary = $this->Database->prepare('SELECT id FROM tl_glossary_item WHERE pid=?')
- ->execute($id)
- ;
-
- /** @var SessionInterface $objSession */
- $objSession = System::getContainer()->get('session');
-
- $session = $objSession->all();
- $session['CURRENT']['IDS'] = array_intersect((array) $session['CURRENT']['IDS'], $objGlossary->fetchEach('id'));
- $objSession->replace($session);
- break;
-
- default:
- if (Input::get('act'))
- {
- throw new AccessDeniedException('Invalid command "'.Input::get('act').'".');
- }
-
- if (!in_array($id, $root))
- {
- throw new AccessDeniedException('Not enough permissions to access glossary ID '.$id.'.');
- }
- break;
- }
- }
-
- /**
- * Set group by keyword.
- */
- public function setGlossaryItemGroup(DataContainer $dc): void
- {
- $newGroup = mb_strtoupper(mb_substr($dc->activeRecord->keyword, 0, 1, 'UTF-8'));
-
- if ($dc->activeRecord->letter !== $newGroup)
- {
- $this->Database->prepare('UPDATE tl_glossary_item SET letter=? WHERE id=?')
- ->execute($newGroup, $dc->id)
- ;
- }
- }
-
/**
* Auto-generate the glossary item alias if it has not been set yet.
*
@@ -552,7 +406,9 @@ public function setGlossaryItemGroup(DataContainer $dc): void
*/
public function generateAlias($varValue, DataContainer $dc)
{
- $aliasExists = fn (string $alias): bool => $this->Database->prepare('SELECT id FROM tl_glossary_item WHERE alias=? AND id!=?')->execute($alias, $dc->id)->numRows > 0;
+ $aliasExists = function (string $alias) use ($dc): bool {
+ return $this->Database->prepare("SELECT id FROM tl_glossary_item WHERE alias=? AND id!=?")->execute($alias, $dc->id)->numRows > 0;
+ };
// Generate alias if there is none
if (!$varValue)
@@ -628,64 +484,6 @@ static function ($strVal) {
return $title;
}
- /**
- * List a glossary item.
- *
- * @param array $arrRow
- *
- * @return string
- */
- public function listGlossaryItems($arrRow)
- {
- return ''.$arrRow['keyword'].'
';
- }
-
- /**
- * Check for modified glossary items and update the XML files if necessary.
- */
- public function generateSitemap(): void
- {
- /** @var SessionInterface $objSession */
- $objSession = System::getContainer()->get('session');
-
- $session = $objSession->get('glossaryitems_updater');
-
- if (empty($session) || !is_array($session))
- {
- return;
- }
-
- $this->import(Automator::class, 'Automator');
- $this->Automator->generateSitemap();
-
- $objSession->set('glossaryitems_updater', null);
- }
-
- /**
- * Schedule a glossary item update.
- *
- * This method is triggered when a single glossary item or multiple glossary items
- * are modified (edit/editAll), moved (cut/cutAll) or deleted (delete/deleteAll).
- * Since duplicated items are unpublished by default, it is not necessary to
- * schedule updates on copyAll as well.
- */
- public function scheduleUpdate(DataContainer $dc): void
- {
- // Return if there is no ID
- if (!$dc->activeRecord || !$dc->activeRecord->pid || 'copy' === Input::get('act'))
- {
- return;
- }
-
- /** @var SessionInterface $objSession */
- $objSession = System::getContainer()->get('session');
-
- // Store the ID in the session
- $session = $objSession->get('glossaryitems_updater');
- $session[] = $dc->activeRecord->pid;
- $objSession->set('glossaryitems_updater', array_unique($session));
- }
-
/**
* Get all articles and return them as array.
*
@@ -713,13 +511,13 @@ public function getArticleAlias(DataContainer $dc)
return $arrAlias;
}
- $objAlias = $this->Database->prepare('SELECT a.id, a.title, a.inColumn, p.title AS parent FROM tl_article a LEFT JOIN tl_page p ON p.id=a.pid WHERE a.pid IN('.implode(',', array_map('\intval', array_unique($arrPids))).') ORDER BY parent, a.sorting')
+ $objAlias = $this->Database->prepare("SELECT a.id, a.title, a.inColumn, p.title AS parent FROM tl_article a LEFT JOIN tl_page p ON p.id=a.pid WHERE a.pid IN('.implode(',', array_map('\intval', array_unique($arrPids))).') ORDER BY parent, a.sorting")
->execute($dc->id)
;
}
else
{
- $objAlias = $this->Database->prepare('SELECT a.id, a.title, a.inColumn, p.title AS parent FROM tl_article a LEFT JOIN tl_page p ON p.id=a.pid ORDER BY parent, a.sorting')
+ $objAlias = $this->Database->prepare("SELECT a.id, a.title, a.inColumn, p.title AS parent FROM tl_article a LEFT JOIN tl_page p ON p.id=a.pid ORDER BY parent, a.sorting")
->execute($dc->id)
;
}
@@ -778,183 +576,4 @@ public function getSourceOptions(DataContainer $dc)
return $arrOptions;
}
-
- /**
- * Add a link to the list items import wizard.
- *
- * @return string
- */
- public function listImportWizard()
- {
- return ' '.Image::getHtml('tablewizard.svg', $GLOBALS['TL_LANG']['MSC']['tw_import'][0]).'';
- }
-
- /**
- * Return the "toggle visibility" button.
- *
- * @param array $row
- * @param string $href
- * @param string $label
- * @param string $title
- * @param string $icon
- * @param string $attributes
- *
- * @return string
- */
- public function toggleIcon($row, $href, $label, $title, $icon, $attributes)
- {
- if (Input::get('tid'))
- {
- $this->toggleVisibility(Input::get('tid'), 1 === (int) Input::get('state'), (func_num_args() <= 12 ? null : func_get_arg(12)));
- $this->redirect($this->getReferer());
- }
-
- // Check permissions AFTER checking the tid, so hacking attempts are logged
- if (!$this->User->hasAccess('tl_glossary_item::published', 'alexf'))
- {
- return '';
- }
-
- $href .= '&tid='.$row['id'].'&state='.($row['published'] ? '' : 1);
-
- if (!$row['published'])
- {
- $icon = 'invisible.svg';
- }
-
- return ''.Image::getHtml($icon, $label, 'data-state="'.($row['published'] ? 1 : 0).'"').' ';
- }
-
- /**
- * Disable/enable a user group.
- *
- * @param int $intId
- * @param bool $blnVisible
- * @param DataContainer $dc
- */
- public function toggleVisibility($intId, $blnVisible, DataContainer $dc = null): void
- {
- // Set the ID and action
- Input::setGet('id', $intId);
- Input::setGet('act', 'toggle');
-
- if ($dc)
- {
- $dc->id = $intId;
- }
-
- // Trigger the onload_callback
- if (is_array($GLOBALS['TL_DCA']['tl_glossary_item']['config']['onload_callback'] ?? null))
- {
- foreach ($GLOBALS['TL_DCA']['tl_glossary_item']['config']['onload_callback'] as $callback)
- {
- if (is_array($callback))
- {
- $this->import($callback[0]);
- $this->{$callback[0]}->{$callback[1]}($dc);
- }
- elseif (is_callable($callback))
- {
- $callback($dc);
- }
- }
- }
-
- // Check the field access
- if (!$this->User->hasAccess('tl_glossary_item::published', 'alexf'))
- {
- throw new AccessDeniedException('Not enough permissions to publish/unpublish glossary item ID '.$intId.'.');
- }
-
- // Set the current record
- $objRow = $this->Database->prepare('SELECT * FROM tl_glossary_item WHERE id=?')
- ->limit(1)
- ->execute($intId)
- ;
-
- if ($objRow->numRows < 1)
- {
- throw new AccessDeniedException('Invalid glossary item ID '.$intId.'.');
- }
-
- if ($dc)
- {
- $dc->activeRecord = $objRow;
- }
-
- $objVersions = new Versions('tl_glossary_item', $intId);
- $objVersions->initialize();
-
- // Trigger the save_callback
- if (is_array($GLOBALS['TL_DCA']['tl_glossary_item']['fields']['published']['save_callback'] ?? null))
- {
- foreach ($GLOBALS['TL_DCA']['tl_glossary_item']['fields']['published']['save_callback'] as $callback)
- {
- if (is_array($callback))
- {
- $this->import($callback[0]);
- $blnVisible = $this->{$callback[0]}->{$callback[1]}($blnVisible, $dc);
- }
- elseif (is_callable($callback))
- {
- $blnVisible = $callback($blnVisible, $dc);
- }
- }
- }
-
- $time = time();
-
- // Update the database
- $this->Database->prepare("UPDATE tl_glossary_item SET tstamp=$time, published='".($blnVisible ? '1' : '')."' WHERE id=?")
- ->execute($intId)
- ;
-
- if ($dc)
- {
- $dc->activeRecord->tstamp = $time;
- $dc->activeRecord->published = ($blnVisible ? '1' : '');
- }
-
- // Trigger the onsubmit_callback
- if (is_array($GLOBALS['TL_DCA']['tl_glossary_item']['config']['onsubmit_callback'] ?? null))
- {
- foreach ($GLOBALS['TL_DCA']['tl_glossary_item']['config']['onsubmit_callback'] as $callback)
- {
- if (is_array($callback))
- {
- $this->import($callback[0]);
- $this->{$callback[0]}->{$callback[1]}($dc);
- }
- elseif (is_callable($callback))
- {
- $callback($dc);
- }
- }
- }
-
- $objVersions->create();
-
- if ($dc)
- {
- $dc->invalidateCacheTags();
- }
- }
-
- /**
- * @param DataContainer $dc
- *
- * @return array
- */
- public function addSitemapCacheInvalidationTag($dc, array $tags)
- {
- $archiveModel = GlossaryModel::findByPk($dc->activeRecord->pid);
- $pageModel = PageModel::findWithDetails($archiveModel->jumpTo);
-
- if (null === $pageModel)
- {
- return $tags;
- }
-
- return array_merge($tags, ['contao.sitemap.'.$pageModel->rootId]);
- }
}
diff --git a/src/EventListener/DataContainer/GlossaryItemListener.php b/src/EventListener/DataContainer/GlossaryItemListener.php
index 199e3e3..e5c1b50 100644
--- a/src/EventListener/DataContainer/GlossaryItemListener.php
+++ b/src/EventListener/DataContainer/GlossaryItemListener.php
@@ -3,13 +3,11 @@
namespace Oveleon\ContaoGlossaryBundle\EventListener\DataContainer;
use Contao\Automator;
-use Contao\Config;
use Contao\Controller;
use Contao\CoreBundle\Exception\AccessDeniedException;
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\Database;
use Contao\DataContainer;
-use Contao\Date;
use Contao\Input;
use Contao\PageModel;
use Contao\System;
diff --git a/src/EventListener/DataContainer/GlossaryListener.php b/src/EventListener/DataContainer/GlossaryListener.php
index 670f1bd..0c89bdf 100644
--- a/src/EventListener/DataContainer/GlossaryListener.php
+++ b/src/EventListener/DataContainer/GlossaryListener.php
@@ -135,7 +135,7 @@ public function adjustPermissions(int|string $insertId): void
// Add the new element to the user object
$root[] = $insertId;
- $objUser->recommendations = $root;
+ $objUser->glossarys = $root;
}
}
diff --git a/src/EventListener/SitemapListener.php b/src/EventListener/SitemapListener.php
index ee2fd35..010dffe 100644
--- a/src/EventListener/SitemapListener.php
+++ b/src/EventListener/SitemapListener.php
@@ -53,16 +53,16 @@ public function __invoke(SitemapEvent $event): void
return;
}
- // Walk through each recommendation archive
+ // Walk through each glossary
foreach ($objGlossaries as $objGlossary)
{
- // Skip recommendation archives without target page
+ // Skip glossaries without target page
if (!$objGlossary->jumpTo)
{
continue;
}
- // Skip recommendation archives outside the root nodes
+ // Skip glossaries outside the root nodes
if (!\in_array($objGlossary->jumpTo, $arrRoot, true))
{
continue;