PHP-Code:
namespace {
/*
* This file is part of Contao.
*
* (c) Leo Feyer
*
* @license LGPL-3.0-or-later
*/
\Contao\System::loadLanguageFile('tl_content');
$GLOBALS['TL_DCA']['tl_news'] = array(
// Config
'config' => array('dataContainer' => 'Table', 'ptable' => 'tl_news_archive', 'ctable' => array('tl_content'), 'switchToEdit' => \true, 'enableVersioning' => \true, 'markAsCopy' => 'headline', 'onload_callback' => array(array('tl_news', 'checkPermission'), array('tl_news', 'generateFeed')), 'oncut_callback' => array(array('tl_news', 'scheduleUpdate')), 'ondelete_callback' => array(array('tl_news', 'scheduleUpdate')), 'onsubmit_callback' => array(array('tl_news', 'adjustTime'), array('tl_news', 'scheduleUpdate')), 'sql' => array('keys' => array('id' => 'primary', 'alias' => 'index', 'pid,start,stop,published' => 'index'))),
// List
'list' => array('sorting' => array('mode' => 4, 'fields' => array('date'), 'headerFields' => array('title', 'jumpTo', 'tstamp', 'protected', 'allowComments'), 'panelLayout' => 'filter;sort,search,limit', 'child_record_callback' => array('tl_news', 'listNewsArticles'), 'child_record_class' => 'no_padding'), 'global_operations' => array('all' => array('href' => 'act=select', 'class' => 'header_edit_all', 'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"')), 'operations' => array('edit' => array('href' => 'table=tl_content', 'icon' => 'edit.svg'), 'editheader' => array('href' => 'act=edit', 'icon' => 'header.svg'), 'copy' => array('href' => 'act=paste&mode=copy', 'icon' => 'copy.svg'), 'cut' => array('href' => 'act=paste&mode=cut', 'icon' => 'cut.svg'), 'delete' => array('href' => 'act=delete', 'icon' => 'delete.svg', 'attributes' => 'onclick="if(!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'), 'toggle' => array('icon' => 'visible.svg', 'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleVisibility(this,%s)"', 'button_callback' => array('tl_news', 'toggleIcon'), 'showInHeader' => \true), 'feature' => array('icon' => 'featured.svg', 'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleFeatured(this,%s)"', 'button_callback' => array('tl_news', 'iconFeatured')), 'show' => array('href' => 'act=show', 'icon' => 'show.svg'))),
// Palettes
'palettes' => array('__selector__' => array('source', 'addImage', 'addEnclosure', 'overwriteMeta'), 'default' => '{title_legend},headline,featured,alias,author;{date_legend},date,time;{source_legend:hide},source;{meta_legend},pageTitle,description,serpPreview;{teaser_legend},subheadline,teaser;{image_legend},addImage;{enclosure_legend:hide},addEnclosure;{expert_legend:hide},cssClass,noComments;{publish_legend},published,start,stop', 'internal' => '{title_legend},headline,featured,alias,author;{date_legend},date,time;{source_legend},source,jumpTo;{teaser_legend},subheadline,teaser;{image_legend},addImage;{enclosure_legend:hide},addEnclosure;{expert_legend:hide},cssClass,noComments;{publish_legend},published,start,stop', 'article' => '{title_legend},headline,featured,alias,author;{date_legend},date,time;{source_legend},source,articleId;{teaser_legend},subheadline,teaser;{image_legend},addImage;{enclosure_legend:hide},addEnclosure;{expert_legend:hide},cssClass,noComments;{publish_legend},published,start,stop', 'external' => '{title_legend},headline,featured,alias,author;{date_legend},date,time;{source_legend},source,url,target;{teaser_legend},subheadline,teaser;{image_legend},addImage;{enclosure_legend:hide},addEnclosure;{expert_legend:hide},cssClass,noComments;{publish_legend},published,start,stop'),
// Subpalettes
'subpalettes' => array('addImage' => 'singleSRC,size,floating,imagemargin,fullsize,overwriteMeta', 'addEnclosure' => 'enclosure', 'overwriteMeta' => 'alt,imageTitle,imageUrl,caption'),
// Fields
'fields' => array('id' => array('sql' => "int(10) unsigned NOT NULL auto_increment"), 'pid' => array('foreignKey' => 'tl_news_archive.title', 'sql' => "int(10) unsigned NOT NULL default 0", 'relation' => array('type' => 'belongsTo', 'load' => 'lazy')), 'tstamp' => array('sql' => "int(10) unsigned NOT NULL default 0"), 'headline' => array('exclude' => \true, 'search' => \true, 'sorting' => \true, 'flag' => 1, 'inputType' => 'text', 'eval' => array('mandatory' => \true, 'maxlength' => 255, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'featured' => array('exclude' => \true, 'filter' => \true, 'inputType' => 'checkbox', 'eval' => array('tl_class' => 'w50 m12'), 'sql' => "char(1) NOT NULL default ''"), 'alias' => array('exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('rgxp' => 'alias', 'doNotCopy' => \true, 'unique' => \true, 'maxlength' => 255, 'tl_class' => 'w50'), 'save_callback' => array(array('tl_news', 'generateAlias')), 'sql' => "varchar(255) BINARY NOT NULL default ''"), 'author' => array('default' => \Contao\BackendUser::getInstance()->id, 'exclude' => \true, 'search' => \true, 'filter' => \true, 'sorting' => \true, 'flag' => 11, 'inputType' => 'select', 'foreignKey' => 'tl_user.name', 'eval' => array('doNotCopy' => \true, 'chosen' => \true, 'mandatory' => \true, 'includeBlankOption' => \true, 'tl_class' => 'w50'), 'sql' => "int(10) unsigned NOT NULL default 0", 'relation' => array('type' => 'hasOne', 'load' => 'lazy')), 'date' => array('default' => \time(), 'exclude' => \true, 'filter' => \true, 'sorting' => \true, 'flag' => 8, 'inputType' => 'text', 'eval' => array('rgxp' => 'date', 'mandatory' => \true, 'doNotCopy' => \true, 'datepicker' => \true, 'tl_class' => 'w50 wizard'), 'load_callback' => array(array('tl_news', 'loadDate')), 'sql' => "int(10) unsigned NOT NULL default 0"), 'time' => array('default' => \time(), 'exclude' => \true, 'inputType' => 'text', 'eval' => array('rgxp' => 'time', 'mandatory' => \true, 'doNotCopy' => \true, 'tl_class' => 'w50'), 'load_callback' => array(array('tl_news', 'loadTime')), 'sql' => "int(10) NOT NULL default 0"), 'pageTitle' => array('exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'description' => array('exclude' => \true, 'search' => \true, 'inputType' => 'textarea', 'eval' => array('style' => 'height:60px', 'decodeEntities' => \true, 'tl_class' => 'clr'), 'sql' => "text NULL"), 'serpPreview' => array('label' => &$GLOBALS['TL_LANG']['MSC']['serpPreview'], 'exclude' => \true, 'inputType' => 'serpPreview', 'eval' => array('url_callback' => array('tl_news', 'getSerpUrl'), 'title_tag_callback' => array('tl_news', 'getTitleTag'), 'titleFields' => array('pageTitle', 'headline'), 'descriptionFields' => array('description', 'teaser')), 'sql' => \null), 'subheadline' => array('exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('maxlength' => 255, 'tl_class' => 'long'), 'sql' => "varchar(255) NOT NULL default ''"), 'teaser' => array('exclude' => \true, 'search' => \true, 'inputType' => 'textarea', 'eval' => array('rte' => 'tinyMCE', 'tl_class' => 'clr'), 'sql' => "text NULL"), 'addImage' => array('exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('submitOnChange' => \true), 'sql' => "char(1) NOT NULL default ''"), 'overwriteMeta' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['overwriteMeta'], 'exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('submitOnChange' => \true, 'tl_class' => 'w50 clr'), 'sql' => "char(1) NOT NULL default ''"), 'singleSRC' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['singleSRC'], 'exclude' => \true, 'inputType' => 'fileTree', 'eval' => array('fieldType' => 'radio', 'filesOnly' => \true, 'extensions' => \Contao\Config::get('validImageTypes'), 'mandatory' => \true), 'sql' => "binary(16) NULL"), 'alt' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['alt'], 'exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('maxlength' => 255, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'imageTitle' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['imageTitle'], 'exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('maxlength' => 255, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'size' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['size'], 'exclude' => \true, 'inputType' => 'imageSize', 'reference' => &$GLOBALS['TL_LANG']['MSC'], 'eval' => array('rgxp' => 'natural', 'includeBlankOption' => \true, 'nospace' => \true, 'helpwizard' => \true, 'tl_class' => 'w50'), 'options_callback' => static function () {
return \Contao\System::getContainer()->get('contao.image.image_sizes')->getOptionsForUser(\Contao\BackendUser::getInstance());
}, 'sql' => "varchar(64) NOT NULL default ''"), 'imagemargin' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['imagemargin'], 'exclude' => \true, 'inputType' => 'trbl', 'options' => $GLOBALS['TL_CSS_UNITS'], 'eval' => array('includeBlankOption' => \true, 'tl_class' => 'w50'), 'sql' => "varchar(128) NOT NULL default ''"), 'imageUrl' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['imageUrl'], 'exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('rgxp' => 'url', 'decodeEntities' => \true, 'maxlength' => 255, 'dcaPicker' => \true, 'addWizardClass' => \false, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'fullsize' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['fullsize'], 'exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('tl_class' => 'w50 m12'), 'sql' => "char(1) NOT NULL default ''"), 'caption' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['caption'], 'exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('maxlength' => 255, 'allowHtml' => \true, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'floating' => array('label' => &$GLOBALS['TL_LANG']['tl_content']['floating'], 'exclude' => \true, 'inputType' => 'radioTable', 'options' => array('above', 'left', 'right', 'below'), 'eval' => array('cols' => 4, 'tl_class' => 'w50'), 'reference' => &$GLOBALS['TL_LANG']['MSC'], 'sql' => "varchar(12) NOT NULL default 'above'"), 'addEnclosure' => array('exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('submitOnChange' => \true), 'sql' => "char(1) NOT NULL default ''"), 'enclosure' => array('exclude' => \true, 'inputType' => 'fileTree', 'eval' => array('multiple' => \true, 'fieldType' => 'checkbox', 'filesOnly' => \true, 'isDownloads' => \true, 'extensions' => \Contao\Config::get('allowedDownload'), 'mandatory' => \true, 'orderField' => 'orderEnclosure'), 'sql' => "blob NULL"), 'orderEnclosure' => array('label' => &$GLOBALS['TL_LANG']['MSC']['sortOrder'], 'sql' => "blob NULL"), 'source' => array('exclude' => \true, 'filter' => \true, 'inputType' => 'radio', 'options_callback' => array('tl_news', 'getSourceOptions'), 'reference' => &$GLOBALS['TL_LANG']['tl_news'], 'eval' => array('submitOnChange' => \true, 'helpwizard' => \true), 'sql' => "varchar(12) NOT NULL default 'default'"), 'jumpTo' => array('exclude' => \true, 'inputType' => 'pageTree', 'foreignKey' => 'tl_page.title', 'eval' => array('mandatory' => \true, 'fieldType' => 'radio'), 'sql' => "int(10) unsigned NOT NULL default 0", 'relation' => array('type' => 'belongsTo', 'load' => 'lazy')), 'articleId' => array('exclude' => \true, 'inputType' => 'select', 'options_callback' => array('tl_news', 'getArticleAlias'), 'eval' => array('chosen' => \true, 'mandatory' => \true, 'tl_class' => 'w50'), 'sql' => "int(10) unsigned NOT NULL default 0", 'relation' => array('table' => 'tl_article', 'type' => 'hasOne', 'load' => 'lazy')), 'url' => array('label' => &$GLOBALS['TL_LANG']['MSC']['url'], 'exclude' => \true, 'search' => \true, 'inputType' => 'text', 'eval' => array('mandatory' => \true, 'rgxp' => 'url', 'decodeEntities' => \true, 'maxlength' => 255, 'dcaPicker' => \true, 'addWizardClass' => \false, 'tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'target' => array('label' => &$GLOBALS['TL_LANG']['MSC']['target'], 'exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('tl_class' => 'w50 m12'), 'sql' => "char(1) NOT NULL default ''"), 'cssClass' => array('exclude' => \true, 'inputType' => 'text', 'eval' => array('tl_class' => 'w50'), 'sql' => "varchar(255) NOT NULL default ''"), 'noComments' => array('exclude' => \true, 'filter' => \true, 'inputType' => 'checkbox', 'eval' => array('tl_class' => 'w50 m12'), 'sql' => "char(1) NOT NULL default ''"), 'published' => array('exclude' => \true, 'filter' => \true, 'flag' => 1, 'inputType' => 'checkbox', 'eval' => array('doNotCopy' => \true), 'sql' => "char(1) NOT NULL default ''"), 'start' => array('exclude' => \true, 'inputType' => 'text', 'eval' => array('rgxp' => 'datim', 'datepicker' => \true, 'tl_class' => 'w50 wizard'), 'sql' => "varchar(10) NOT NULL default ''"), 'stop' => array('exclude' => \true, 'inputType' => 'text', 'eval' => array('rgxp' => 'datim', 'datepicker' => \true, 'tl_class' => 'w50 wizard'), 'sql' => "varchar(10) NOT NULL default ''")),
);
/**
* Provide miscellaneous methods that are used by the data configuration array.
*
* @property Contao\News $News
*
* @author Leo Feyer <https://github.com/leofeyer>
*/
class tl_news extends \Contao\Backend
{
/**
* Import the back end user object
*/
public function __construct()
{
parent::__construct();
$this->import('Contao\\BackendUser', 'User');
}
/**
* Check permissions to edit table tl_news
*
* @throws Contao\CoreBundle\Exception\AccessDeniedException
*/
public function checkPermission()
{
$bundles = \Contao\System::getContainer()->getParameter('kernel.bundles');
// HOOK: comments extension required
if (!isset($bundles['ContaoCommentsBundle'])) {
$key = \array_search('allowComments', $GLOBALS['TL_DCA']['tl_news']['list']['sorting']['headerFields']);
unset($GLOBALS['TL_DCA']['tl_news']['list']['sorting']['headerFields'][$key], $GLOBALS['TL_DCA']['tl_news']['fields']['noComments']);
}
if ($this->User->isAdmin) {
return;
}
// Set the root IDs
if (empty($this->User->news) || !\is_array($this->User->news)) {
$root = array(0);
} else {
$root = $this->User->news;
}
$id = \strlen(\Contao\Input::get('id')) ? \Contao\Input::get('id') : \CURRENT_ID;
// Check current action
switch (\Contao\Input::get('act')) {
case 'paste':
case 'select':
// Check CURRENT_ID here (see #247)
if (!\in_array(\CURRENT_ID, $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to access news archive ID ' . $id . '.');
}
break;
case 'create':
if (!\Contao\Input::get('pid') || !\in_array(\Contao\Input::get('pid'), $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to create news items in news archive ID ' . \Contao\Input::get('pid') . '.');
}
break;
case 'cut':
case 'copy':
if (\Contao\Input::get('act') == 'cut' && \Contao\Input::get('mode') == 1) {
$objArchive = $this->Database->prepare("SELECT pid FROM tl_news WHERE id=?")->limit(1)->execute(\Contao\Input::get('pid'));
if ($objArchive->numRows < 1) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Invalid news item ID ' . \Contao\Input::get('pid') . '.');
}
$pid = $objArchive->pid;
} else {
$pid = \Contao\Input::get('pid');
}
if (!\in_array($pid, $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to ' . \Contao\Input::get('act') . ' news item ID ' . $id . ' to news archive ID ' . $pid . '.');
}
// no break
case 'edit':
case 'show':
case 'delete':
case 'toggle':
case 'feature':
$objArchive = $this->Database->prepare("SELECT pid FROM tl_news WHERE id=?")->limit(1)->execute($id);
if ($objArchive->numRows < 1) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Invalid news item ID ' . $id . '.');
}
if (!\in_array($objArchive->pid, $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to ' . \Contao\Input::get('act') . ' news item ID ' . $id . ' of news archive ID ' . $objArchive->pid . '.');
}
break;
case 'editAll':
case 'deleteAll':
case 'overrideAll':
case 'cutAll':
case 'copyAll':
if (!\in_array($id, $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to access news archive ID ' . $id . '.');
}
$objArchive = $this->Database->prepare("SELECT id FROM tl_news WHERE pid=?")->execute($id);
/** @var Symfony\Component\HttpFoundation\Session\SessionInterface $objSession */
$objSession = \Contao\System::getContainer()->get('session');
$session = $objSession->all();
$session['CURRENT']['IDS'] = \array_intersect((array) $session['CURRENT']['IDS'], $objArchive->fetchEach('id'));
$objSession->replace($session);
break;
default:
if (\Contao\Input::get('act')) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Invalid command "' . \Contao\Input::get('act') . '".');
}
if (!\in_array($id, $root)) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to access news archive ID ' . $id . '.');
}
break;
}
}
/**
* Auto-generate the news alias if it has not been set yet
*
* @param mixed $varValue
* @param Contao\DataContainer $dc
*
* @return string
*
* @throws Exception
*/
public function generateAlias($varValue, \Contao\DataContainer $dc)
{
$aliasExists = function (string $alias) use($dc) : bool {
return $this->Database->prepare("SELECT id FROM tl_news WHERE alias=? AND id!=?")->execute($alias, $dc->id)->numRows > 0;
};
// Generate alias if there is none
if (!$varValue) {
$varValue = \Contao\System::getContainer()->get('contao.slug')->generate($dc->activeRecord->headline, \Contao\NewsArchiveModel::findByPk($dc->activeRecord->pid)->jumpTo, $aliasExists);
} elseif (\preg_match('/^[1-9]\\d*$/', $varValue)) {
throw new \Exception(\sprintf($GLOBALS['TL_LANG']['ERR']['aliasNumeric'], $varValue));
} elseif ($aliasExists($varValue)) {
throw new \Exception(\sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $varValue));
}
return $varValue;
}
/**
* Set the timestamp to 00:00:00 (see #26)
*
* @param integer $value
*
* @return integer
*/
public function loadDate($value)
{
return \strtotime(\date('Y-m-d', $value) . ' 00:00:00');
}
/**
* Set the timestamp to 1970-01-01 (see #26)
*
* @param integer $value
*
* @return integer
*/
public function loadTime($value)
{
return \strtotime('1970-01-01 ' . \date('H:i:s', $value));
}
/**
* Return the SERP URL
*
* @param Contao\NewsModel $model
*
* @return string
*/
public function getSerpUrl(\Contao\NewsModel $model)
{
return \Contao\News::generateNewsUrl($model, \false, \true);
}
/**
* Return the title tag from the associated page layout
*
* @param Contao\NewsModel $model
*
* @return string
*/
public function getTitleTag(\Contao\NewsModel $model)
{
/** @var Contao\NewsArchiveModel $archive */
if (!($archive = $model->getRelated('pid'))) {
return '';
}
/** @var Contao\PageModel $page */
if (!($page = $archive->getRelated('jumpTo'))) {
return '';
}
$page->loadDetails();
/** @var Contao\LayoutModel $layout */
if (!($layout = $page->getRelated('layout'))) {
return '';
}
$origObjPage = $GLOBALS['objPage'] ?? \null;
// Override the global page object, so we can replace the insert tags
$GLOBALS['objPage'] = $page;
$title = \implode('%s', \array_map(static function ($strVal) {
return \str_replace('%', '%%', self::replaceInsertTags($strVal));
}, \explode('{{page::pageTitle}}', $layout->titleTag ?: '{{page::pageTitle}} - {{page::rootPageTitle}}', 2)));
$GLOBALS['objPage'] = $origObjPage;
return $title;
}
/**
* List a news article
*
* @param array $arrRow
*
* @return string
*/
public function listNewsArticles($arrRow)
{
return '<div class="tl_content_left">' . $arrRow['headline'] . ' <span style="color:#999;padding-left:3px">[' . \Contao\Date::parse(\Contao\Config::get('datimFormat'), $arrRow['date']) . ']</span></div>';
}
/**
* Get all articles and return them as array
*
* @param Contao\DataContainer $dc
*
* @return array
*/
public function getArticleAlias(\Contao\DataContainer $dc)
{
$arrPids = array();
$arrAlias = array();
if (!$this->User->isAdmin) {
foreach ($this->User->pagemounts as $id) {
$arrPids[] = array($id);
$arrPids[] = $this->Database->getChildRecords($id, 'tl_page');
}
if (!empty($arrPids)) {
$arrPids = \array_merge(...$arrPids);
} else {
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")->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")->execute($dc->id);
}
if ($objAlias->numRows) {
\Contao\System::loadLanguageFile('tl_article');
while ($objAlias->next()) {
$arrAlias[$objAlias->parent][$objAlias->id] = $objAlias->title . ' (' . ($GLOBALS['TL_LANG']['COLS'][$objAlias->inColumn] ?: $objAlias->inColumn) . ', ID ' . $objAlias->id . ')';
}
}
return $arrAlias;
}
/**
* Add the source options depending on the allowed fields (see #5498)
*
* @param Contao\DataContainer $dc
*
* @return array
*/
public function getSourceOptions(\Contao\DataContainer $dc)
{
if ($this->User->isAdmin) {
return array('default', 'internal', 'article', 'external');
}
$arrOptions = array('default');
// Add the "internal" option
if ($this->User->hasAccess('tl_news::jumpTo', 'alexf')) {
$arrOptions[] = 'internal';
}
// Add the "article" option
if ($this->User->hasAccess('tl_news::articleId', 'alexf')) {
$arrOptions[] = 'article';
}
// Add the "external" option
if ($this->User->hasAccess('tl_news::url', 'alexf')) {
$arrOptions[] = 'external';
}
// Add the option currently set
if ($dc->activeRecord && $dc->activeRecord->source) {
$arrOptions[] = $dc->activeRecord->source;
$arrOptions = \array_unique($arrOptions);
}
return $arrOptions;
}
/**
* Adjust start end end time of the event based on date, span, startTime and endTime
*
* @param Contao\DataContainer $dc
*/
public function adjustTime(\Contao\DataContainer $dc)
{
// Return if there is no active record (override all)
if (!$dc->activeRecord) {
return;
}
$arrSet['date'] = \strtotime(\date('Y-m-d', $dc->activeRecord->date) . ' ' . \date('H:i:s', $dc->activeRecord->time));
$arrSet['time'] = $arrSet['date'];
$this->Database->prepare("UPDATE tl_news %s WHERE id=?")->set($arrSet)->execute($dc->id);
}
/**
* Check for modified news feeds and update the XML files if necessary
*/
public function generateFeed()
{
/** @var Symfony\Component\HttpFoundation\Session\SessionInterface $objSession */
$objSession = \Contao\System::getContainer()->get('session');
$session = $objSession->get('news_feed_updater');
if (empty($session) || !\is_array($session)) {
return;
}
$request = \Contao\System::getContainer()->get('request_stack')->getCurrentRequest();
if ($request) {
$origScope = $request->attributes->get('_scope');
$request->attributes->set('_scope', 'frontend');
}
$this->import('Contao\\News', 'News');
foreach ($session as $id) {
$this->News->generateFeedsByArchive($id);
}
$this->import('Contao\\Automator', 'Automator');
$this->Automator->generateSitemap();
if ($request) {
$request->attributes->set('_scope', $origScope);
}
$objSession->set('news_feed_updater', \null);
}
/**
* Schedule a news feed update
*
* This method is triggered when a single news item or multiple news
* 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.
*
* @param Contao\DataContainer $dc
*/
public function scheduleUpdate(\Contao\DataContainer $dc)
{
// Return if there is no ID
if (!$dc->activeRecord || !$dc->activeRecord->pid || \Contao\Input::get('act') == 'copy') {
return;
}
/** @var Symfony\Component\HttpFoundation\Session\SessionInterface $objSession */
$objSession = \Contao\System::getContainer()->get('session');
// Store the ID in the session
$session = $objSession->get('news_feed_updater');
$session[] = $dc->activeRecord->pid;
$objSession->set('news_feed_updater', \array_unique($session));
}
/**
* Return the "feature/unfeature element" button
*
* @param array $row
* @param string $href
* @param string $label
* @param string $title
* @param string $icon
* @param string $attributes
*
* @return string
*/
public function iconFeatured($row, $href, $label, $title, $icon, $attributes)
{
if (\Contao\Input::get('fid')) {
$this->toggleFeatured(\Contao\Input::get('fid'), \Contao\Input::get('state') == 1, \func_num_args() <= 12 ? \null : \func_get_arg(12));
$this->redirect($this->getReferer());
}
// Check permissions AFTER checking the fid, so hacking attempts are logged
if (!$this->User->hasAccess('tl_news::featured', 'alexf')) {
return '';
}
$href .= '&fid=' . $row['id'] . '&state=' . ($row['featured'] ? '' : 1);
if (!$row['featured']) {
$icon = 'featured_.svg';
}
return '<a href="' . $this->addToUrl($href) . '" title="' . \Contao\StringUtil::specialchars($title) . '"' . $attributes . '>' . \Contao\Image::getHtml($icon, $label, 'data-state="' . ($row['featured'] ? 1 : 0) . '"') . '</a> ';
}
/**
* Feature/unfeature a news item
*
* @param integer $intId
* @param boolean $blnVisible
* @param Contao\DataContainer $dc
*
* @throws Contao\CoreBundle\Exception\AccessDeniedException
*/
public function toggleFeatured($intId, $blnVisible, \Contao\DataContainer $dc = \null)
{
// Check permissions to edit
\Contao\Input::setGet('id', $intId);
\Contao\Input::setGet('act', 'feature');
if ($dc) {
$dc->id = $intId;
// see #8043
}
// Trigger the onload_callback
if (\is_array($GLOBALS['TL_DCA']['tl_news']['config']['onload_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['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 permissions to feature
if (!$this->User->hasAccess('tl_news::featured', 'alexf')) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to feature/unfeature news item ID ' . $intId . '.');
}
// Set the current record
if ($dc) {
$objRow = $this->Database->prepare("SELECT * FROM tl_news WHERE id=?")->limit(1)->execute($intId);
if ($objRow->numRows) {
$dc->activeRecord = $objRow;
}
}
$objVersions = new \Contao\Versions('tl_news', $intId);
$objVersions->initialize();
// Trigger the save_callback
if (\is_array($GLOBALS['TL_DCA']['tl_news']['fields']['featured']['save_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['fields']['featured']['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, $this);
}
}
}
$time = \time();
// Update the database
$this->Database->prepare("UPDATE tl_news SET tstamp=" . \time() . ", featured='" . ($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_news']['config']['onsubmit_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['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();
}
/**
* 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 (\Contao\Input::get('tid')) {
$this->toggleVisibility(\Contao\Input::get('tid'), \Contao\Input::get('state') == 1, \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_news::published', 'alexf')) {
return '';
}
$href .= '&tid=' . $row['id'] . '&state=' . ($row['published'] ? '' : 1);
if (!$row['published']) {
$icon = 'invisible.svg';
}
return '<a href="' . $this->addToUrl($href) . '" title="' . \Contao\StringUtil::specialchars($title) . '"' . $attributes . '>' . \Contao\Image::getHtml($icon, $label, 'data-state="' . ($row['published'] ? 1 : 0) . '"') . '</a> ';
}
/**
* Disable/enable a user group
*
* @param integer $intId
* @param boolean $blnVisible
* @param Contao\DataContainer $dc
*/
public function toggleVisibility($intId, $blnVisible, \Contao\DataContainer $dc = \null)
{
// Set the ID and action
\Contao\Input::setGet('id', $intId);
\Contao\Input::setGet('act', 'toggle');
if ($dc) {
$dc->id = $intId;
// see #8043
}
// Trigger the onload_callback
if (\is_array($GLOBALS['TL_DCA']['tl_news']['config']['onload_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['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_news::published', 'alexf')) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to publish/unpublish news item ID ' . $intId . '.');
}
$objRow = $this->Database->prepare("SELECT * FROM tl_news WHERE id=?")->limit(1)->execute($intId);
if ($objRow->numRows < 1) {
throw new \Contao\CoreBundle\Exception\AccessDeniedException('Invalid news item ID ' . $intId . '.');
}
// Set the current record
if ($dc) {
$dc->activeRecord = $objRow;
}
$objVersions = new \Contao\Versions('tl_news', $intId);
$objVersions->initialize();
// Trigger the save_callback
if (\is_array($GLOBALS['TL_DCA']['tl_news']['fields']['published']['save_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['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_news 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_news']['config']['onsubmit_callback'])) {
foreach ($GLOBALS['TL_DCA']['tl_news']['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();
// The onsubmit_callback has triggered scheduleUpdate(), so run generateFeed() now
$this->generateFeed();
if ($dc) {
$dc->invalidateCacheTags();
}
}
}
}
namespace {
/**
* Contao Open Source CMS
*
* Copyright (C) 2005-2013 Leo Feyer
*
* @copyright Tim Gatzky 2019
* @author Tim Gatzky <info@tim-gatzky.de>
* @package pct_theme_settings
* @link http://contao.org
*/
/**
* Load language files
*/
\Contao\System::loadLanguageFile('dca_theme_settings');
/**
* Selector
*/
$GLOBALS['TL_DCA']['tl_news']['palettes']['__selector__'][] = 'addFilter';
/**
* Subpalettes
*/
$GLOBALS['TL_DCA']['tl_news']['subpalettes']['addFilter'] = 'filters';
/**
* Palettes
*/
$GLOBALS['TL_DCA']['tl_news']['palettes'] = \str_replace('teaser;', 'teaser;{filter_settings:hide},addFilter;', $GLOBALS['TL_DCA']['tl_news']['palettes']);
/**
* Fields
*/
\array_insert($GLOBALS['TL_DCA']['tl_news']['fields'], 0, array(
// sorting
'sorting' => array('sql' => "int(10) unsigned NOT NULL default '0'"),
// news filter
'addFilter' => array('label' => &$GLOBALS['TL_LANG']['dca_theme_settings']['addFilter'], 'exclude' => \true, 'inputType' => 'checkbox', 'eval' => array('submitOnChange' => \true, 'tl_class' => 'clr'), 'sql' => "char(1) NOT NULL default ''"),
'filters' => array('label' => &$GLOBALS['TL_LANG']['dca_theme_settings']['filters'], 'exclude' => \true, 'inputType' => 'listWizard', 'eval' => array('tl_class' => 'clr'), 'sql' => "blob NULL"),
));
}
namespace {
$this->loadLanguageFile('hofff_st');
// Config
$GLOBALS['TL_DCA']['tl_news']['config']['onload_callback'][] = [\Hofff\Contao\SocialTags\EventListener\Dca\NewsDcaListener::class, 'initializePalette'];
// Palettes
$GLOBALS['TL_DCA']['tl_news']['palettes']['__selector__'][] = 'hofff_st';
$GLOBALS['TL_DCA']['tl_news']['palettes']['__selector__'][] = 'hofff_st_twitter_type';
$GLOBALS['TL_DCA']['tl_news']['subpalettes']['hofff_st'] = 'hofff_st_og_type' . ',hofff_st_og_title,hofff_st_og_site' . ',hofff_st_og_url' . ',hofff_st_og_image' . ',hofff_st_og_description' . ',hofff_st_twitter_type';
$GLOBALS['TL_DCA']['tl_news']['subpalettes']['hofff_st_twitter_type_hofff_st_twitter_summary'] = ',hofff_st_twitter_title' . ',hofff_st_twitter_image' . ',hofff_st_twitter_site' . ',hofff_st_twitter_description';
$GLOBALS['TL_DCA']['tl_news']['subpalettes']['hofff_st_twitter_type_hofff_st_twitter_summary_large_image'] = ',hofff_st_twitter_title' . ',hofff_st_twitter_image' . ',hofff_st_twitter_site' . ',hofff_st_twitter_creator' . ',hofff_st_twitter_description';
// Fields
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st'] = ['label' => &$GLOBALS['TL_LANG']['tl_news']['hofff_st'], 'exclude' => \true, 'inputType' => 'checkbox', 'eval' => ['submitOnChange' => \true, 'tl_class' => ''], 'sql' => 'char(1) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_type'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['type'], 'exclude' => \true, 'inputType' => 'select', 'default' => 'article', 'options_callback' => [\Hofff\Contao\SocialTags\EventListener\Dca\OpenGraphTypeOptions::class, '__invoke'], 'reference' => &$GLOBALS['TL_LANG']['hofff_st']['types'], 'eval' => ['mandatory' => \true, 'chosen' => \true, 'submitOnChange' => \true, 'tl_class' => 'w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_title'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_og_title'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'clr w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_site'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_og_site'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_url'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_og_url'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 1022, 'decodeEntities' => \true, 'rgxp' => 'url', 'tl_class' => 'clr long'], 'sql' => 'varchar(1022) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_image'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_og_image'], 'exclude' => \true, 'inputType' => 'fileTree', 'eval' => ['mandatory' => \false, 'files' => \true, 'fieldType' => 'radio', 'extensions' => 'gif,jpg,jpeg,png', 'filesOnly' => \true, 'tl_class' => 'clr'], 'sql' => 'binary(16) NULL'];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_og_description'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_og_description'], 'exclude' => \true, 'inputType' => 'textarea', 'eval' => ['style' => 'height: 60px;', 'tl_class' => 'clr'], 'sql' => 'varchar(1022) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_type'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_type'], 'exclude' => \true, 'inputType' => 'select', 'options' => ['hofff_st_twitter_summary', 'hofff_st_twitter_summary_large_image'], 'reference' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_types'], 'eval' => ['chosen' => \true, 'submitOnChange' => \true, 'includeBlankOption' => \true, 'tl_class' => 'w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_title'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_title'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'clr w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_description'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_description'], 'exclude' => \true, 'inputType' => 'textarea', 'eval' => ['style' => 'height: 60px;', 'tl_class' => 'clr'], 'sql' => 'varchar(1022) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_site'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_site'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'clr w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_creator'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_creator'], 'exclude' => \true, 'inputType' => 'text', 'eval' => ['maxlength' => 255, 'decodeEntities' => \true, 'tl_class' => 'w50'], 'sql' => 'varchar(255) NOT NULL default \'\''];
$GLOBALS['TL_DCA']['tl_news']['fields']['hofff_st_twitter_image'] = ['label' => &$GLOBALS['TL_LANG']['hofff_st']['hofff_st_twitter_image'], 'exclude' => \true, 'inputType' => 'fileTree', 'eval' => ['mandatory' => \false, 'files' => \true, 'fieldType' => 'radio', 'extensions' => 'gif,jpg,jpeg,png', 'filesOnly' => \true, 'tl_class' => 'clr'], 'sql' => 'binary(16) NULL'];
}
Lesezeichen