Hallo zusammen,
ich arbeite zurzeit an einer Quiz-Erweiterung und schlage mich mit einem seltsamen Problem herum. Ich habe eine Tabelle mit 3 Kindtabellen.
- tl_quiz
- tl_quiz_question
- tl_quiz_result
Wenn ich in tl_quiz_answer einen Eintrag erzeuge und dann den Quiz-Bereich verlasse, wird der Eintrag in tl_quiz_answer automatisch gelöscht. Der Eintrag ist nach dem Anlegen in der Datenbank vorhanden und kann auch per Toggle ein und ausgeblendet werden.
Wenn ich über "zurück" die Tabelle "tl_quiz_question" aufrufe und dann zu "tl_quiz_answer" zurück kehre, ist der Eintrag auch weiterhin vorhanden. Wenn ich aber zwei Mal auf "zurück" klicke, also bei "tl_quiz" lande, wird der Eintrag in "tl_quiz_answer" automatisch gelöscht.
Hat jemand dafür eine Erklärung?
PHP-Code:
// src/Resources/contao/config.php
...
// Back end modules
$GLOBALS['BE_MOD']['content']['quiz'] = [
'tables' => ['tl_quiz', 'tl_quiz_question', 'tl_quiz_answer', 'tl_quiz_result']
];
...
PHP-Code:
// src/Resources/contao/dca/tl_quiz.php
$GLOBALS['TL_DCA']['tl_quiz'] = [
// Config
'config' => [
'dataContainer' => 'Table',
'ctable' => ['tl_quiz_question', 'tl_quiz_result', 'tl_quiz_answer'],
'enableVersioning' => true,
'sql' => [
'keys' => [
'id' => 'primary'
]
]
],
// List
'list' => [
'sorting' => [
'mode' => 1,
'fields' => ['title'],
'flag' => 1,
'panelLayout' => 'filter;search,limit'
],
'label' => [
'fields' => ['title'],
'format' => '%s'
],
'global_operations' => [
'all' => [
'href' => 'act=select',
'class' => 'header_edit_all',
'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
]
],
'operations' => [
'edit' => [
'href' => 'table=tl_quiz_question',
'icon' => 'edit.svg'
],
'editheader' => [
'href' => 'act=edit',
'icon' => 'header.svg'
],
'quizresult' => array
(
'href' => 'table=tl_quiz_result',
'icon' => '/bundles/quiz/text.svg'
),
'copy' => [
'href' => 'act=copy',
'icon' => 'copy.svg'
],
'delete' => [
'href' => 'act=delete',
'icon' => 'delete.svg',
'attributes' => 'onclick="if(!confirm(\'' . ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null) . '\'))return false;Backend.getScrollOffset()"'
],
'show' => [
'href' => 'act=show',
'icon' => 'show.svg'
]
]
],
// Palettes
'palettes' => [
'default' => '{quiz_legend},title,description,resulttext'
],
// Fields
'fields' => [
'id' => [
'sql' => "int(10) unsigned NOT NULL auto_increment"
],
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default 0"
],
'title' => [
'exclude' => true,
'search' => true,
'inputType' => 'text',
'eval' => ['mandatory'=>true, 'maxlength'=>255, 'tl_class'=>'w50'],
'sql' => "varchar(255) NOT NULL default ''"
],
'description' => [
'exclude' => true,
'search' => true,
'inputType' => 'textarea',
'eval' => ['style'=>'height:60px', 'tl_class'=>'clr'],
'sql' => "text NULL"
],
'resulttext' => [
'exclude' => true,
'search' => true,
'inputType' => 'textarea',
'eval' => ['style'=>'height:60px', 'tl_class'=>'clr'],
'sql' => "text NULL"
]
]
];
PHP-Code:
// src/Resources/contao/dca/tl_quiz_question.php
use Contao\Backend;
use Contao\CoreBundle\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
$GLOBALS['TL_DCA']['tl_quiz_question'] = [
// Config
'config' => [
'dataContainer' => 'Table',
'ptable' => 'tl_quiz',
'ctable' => ['tl_quiz_answer'],
'switchToEdit' => true,
'enableVersioning' => true,
'sql' => [
'keys' => [
'id' => 'primary',
'pid' => 'index'
]
]
],
// List
'list' => [
'sorting' => [
'mode' => 4,
'panelLayout' => 'filter;search,limit',
'headerFields' => ['title','description'],
'fields' => ['sorting'],
'child_record_callback' => ['tl_quiz_question', 'child_record_callback'],
'disableGrouping' => true
],
'global_operations' => [
'all' => [
'href' => 'act=select',
'class' => 'header_edit_all',
'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
]
],
'operations' => [
'edit' => [
'href' => 'table=tl_quiz_answer',
'icon' => 'edit.svg'
],
'editheader' => [
'href' => 'act=edit',
'icon' => 'header.svg'
],
'copy' => [
'href' => 'act=paste&mode=copy',
'icon' => 'copy.svg'
],
'cut' => [
'href' => 'act=paste&mode=cut',
'icon' => 'cut.svg'
],
'delete' => [
'href' => 'act=delete',
'icon' => 'delete.svg',
'attributes' => 'onclick="if(!confirm(\'' . ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null) . '\'))return false;Backend.getScrollOffset()"'
],
'toggle' => [
'icon' => 'visible.svg',
'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleVisibility(this,%s)"',
'button_callback' => ['tl_quiz_question', 'toggleIcon'],
'showInHeader' => true
],
'show' => [
'href' => 'act=show',
'icon' => 'show.svg'
]
]
],
// Palettes
'palettes' => [
'__selector__' => ['addImage'],
'default' => '{question_legend},question;{image_legend},addImage;{publish_legend},published',
],
// Subpalettes
'subpalettes' => [
'addImage' => 'singleSRC,size'
],
// Fields
'fields' => [
'id' => [
'sql' => "int(10) unsigned NOT NULL auto_increment"
],
'pid' => [
'foreignKey' => 'tl_news_archive.title',
'sql' => "int(10) unsigned NOT NULL default 0",
'relation' => ['type'=>'belongsTo', 'load'=>'lazy']
],
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default 0"
],
'sorting' => array
(
'sql' => "int(10) unsigned NOT NULL default 0"
),
'question' => [
'exclude' => true,
'search' => true,
'inputType' => 'textarea',
'eval' => ['style'=>'height:60px', 'decodeEntities'=>true, 'tl_class'=>'clr'],
'sql' => "text NULL"
],
'addImage' => [
'exclude' => true,
'inputType' => 'checkbox',
'eval' => array('submitOnChange'=>true),
'sql' => "char(1) NOT NULL default ''"
],
'singleSRC' => [
'exclude' => true,
'inputType' => 'fileTree',
'eval' => ['filesOnly'=>true, 'fieldType'=>'radio', 'mandatory'=>true, 'tl_class'=>'clr'],
'sql' => "binary(16) NULL"
],
'size' => [
'exclude' => true,
'inputType' => 'imageSize',
'reference' => &$GLOBALS['TL_LANG']['MSC'],
'eval' => ['rgxp'=>'natural', 'includeBlankOption'=>true, 'nospace'=>true, 'helpwizard'=>true, 'tl_class'=>'w50'],
'options_callback' => static function () {
return System::getContainer()->get('contao.image.image_sizes')->getOptionsForUser(BackendUser::getInstance());
},
'sql' => "varchar(255) NOT NULL default ''"
],
'published' => [
'exclude' => true,
'filter' => true,
'flag' => 1,
'inputType' => 'checkbox',
'eval' => ['doNotCopy'=>true],
'sql' => "char(1) NOT NULL default ''"
]
]
];
class tl_quiz_question extends Backend
{
public function __construct()
{
parent::__construct();
$this->import(BackendUser::class, 'User');
}
public function toggleIcon($row, $href, $label, $title, $icon, $attributes)
{
if (Input::get('table') === 'tl_quiz_question' && Input::get('tid'))
{
$this->toggleVisibility(Input::get('tid'), (Input::get('state') == 1), (@func_get_arg(12) ?: null));
$this->redirect($this->getReferer());
}
$href .= '&tid=' . $row['id'] . '&state=' . ($row['published'] ? '' : 1);
if (!$row['published'])
{
$icon = 'invisible.svg';
}
return '<a href="' . $this->addToUrl($href) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label, 'data-state="' . ($row['published'] ? 1 : 0) . '"') . '</a> ';
}
/**
* Disable/enable question
*
* @param integer $intId
* @param boolean $blnVisible
* @param DataContainer $dc
*
* @throws AccessDeniedException
*/
public function toggleVisibility($intId, $blnVisible, DataContainer $dc=null)
{
if ($dc->table !== 'tl_quiz_question') return;
// Set the ID and action
Input::setGet('id', $intId);
Input::setGet('act', 'toggle');
if ($dc)
{
$dc->id = $intId; // see #8043
}
// Check the field access
if (!$this->User->hasAccess('tl_quiz_question::published', 'alexf'))
{
throw new AccessDeniedException('Not enough permissions to publish/unpublish quiz result recipient ID ' . $intId . '.');
}
$objRow = $this->Database->prepare("SELECT * FROM tl_quiz_question WHERE id=?")
->limit(1)
->execute($intId);
if ($objRow->numRows < 1)
{
throw new AccessDeniedException('Invalid quiz question ID ' . $intId . '.');
}
// Set the current record
if ($dc)
{
$dc->activeRecord = $objRow;
}
$objVersions = new Versions('tl_quiz_question', $intId);
$objVersions->initialize();
$time = time();
// Update the database
$this->Database->prepare("UPDATE tl_quiz_question SET tstamp=$time, published='" . ($blnVisible ? '1' : '') . "' WHERE id=?")
->execute($intId);
if ($dc)
{
$dc->activeRecord->tstamp = $time;
$dc->activeRecord->published = ($blnVisible ? '1' : '');
}
$objVersions->create();
if ($dc)
{
$dc->invalidateCacheTags();
}
}
public function child_record_callback($row)
{
return $row['question'];
}
}
PHP-Code:
// src/Resources/contao/dca/tl_quiz_answer.php
use Contao\Backend;
use Contao\CoreBundle\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
$GLOBALS['TL_DCA']['tl_quiz_answer'] = [
// Config
'config' => [
'dataContainer' => 'Table',
'ptable' => 'tl_quiz_question',
'switchToEdit' => true,
'enableVersioning' => true,
'sql' => [
'keys' => [
'id' => 'primary',
'pid' => 'index'
]
]
],
// List
'list' => [
'sorting' => [
'mode' => 4,
'panelLayout' => 'filter;search,limit',
'headerFields' => ['question'],
'fields' => ['sorting'],
'child_record_callback' => ['tl_quiz_answer', 'child_record_callback'],
'disableGrouping' => true
],
'global_operations' => [
'all' => [
'href' => 'act=select',
'class' => 'header_edit_all',
'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"'
]
],
'operations' => [
'edit' => [
'href' => 'act=edit',
'icon' => 'edit.svg'
],
'copy' => [
'href' => 'act=paste&mode=copy',
'icon' => 'copy.svg'
],
'cut' => [
'href' => 'act=paste&mode=cut',
'icon' => 'cut.svg'
],
'delete' => [
'href' => 'act=delete',
'icon' => 'delete.svg',
'attributes' => 'onclick="if(!confirm(\'' . ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null) . '\'))return false;Backend.getScrollOffset()"'
],
'answer' => [
'icon' => 'visible.svg',
'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleVisibility(this,%s)"',
'button_callback' => ['tl_quiz_answer', 'toggleIcon'],
'showInHeader' => true
],
'show' => [
'href' => 'act=show',
'icon' => 'show.svg'
]
]
],
// Palettes
'palettes' => [
'__selector__' => ['addImage'],
'default' => '{answer_legend},answer,correct;{image_legend},addImage;{publish_legend},published',
],
// Subpalettes
'subpalettes' => [
'addImage' => 'singleSRC,size'
],
// Fields
'fields' => [
'id' => [
'sql' => "int(10) unsigned NOT NULL auto_increment"
],
'pid' => [
'foreignKey' => 'tl_news_archive.title',
'sql' => "int(10) unsigned NOT NULL default 0",
'relation' => ['type'=>'belongsTo', 'load'=>'lazy']
],
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default 0"
],
'sorting' => array
(
'sql' => "int(10) unsigned NOT NULL default 0"
),
'answer' => [
'exclude' => true,
'search' => true,
'inputType' => 'textarea',
'eval' => ['style'=>'height:60px', 'decodeEntities'=>true, 'tl_class'=>'clr'],
'sql' => "text NULL"
],
'correct' => [
'exclude' => true,
'filter' => true,
'flag' => 1,
'inputType' => 'checkbox',
'sql' => "char(1) NOT NULL default ''"
],
'addImage' => [
'exclude' => true,
'inputType' => 'checkbox',
'eval' => array('submitOnChange'=>true),
'sql' => "char(1) NOT NULL default ''"
],
'singleSRC' => [
'exclude' => true,
'inputType' => 'fileTree',
'eval' => ['filesOnly'=>true, 'fieldType'=>'radio', 'mandatory'=>true, 'tl_class'=>'clr'],
'sql' => "binary(16) NULL"
],
'size' => [
'exclude' => true,
'inputType' => 'imageSize',
'reference' => &$GLOBALS['TL_LANG']['MSC'],
'eval' => ['rgxp'=>'natural', 'includeBlankOption'=>true, 'nospace'=>true, 'helpwizard'=>true, 'tl_class'=>'w50'],
'options_callback' => static function () {
return System::getContainer()->get('contao.image.image_sizes')->getOptionsForUser(BackendUser::getInstance());
},
'sql' => "varchar(255) NOT NULL default ''"
],
'published' => [
'exclude' => true,
'filter' => true,
'flag' => 1,
'inputType' => 'checkbox',
'eval' => ['doNotCopy'=>true],
'sql' => "char(1) NOT NULL default ''"
]
]
];
class tl_quiz_answer extends Backend
{
public function __construct()
{
parent::__construct();
$this->import(BackendUser::class, 'User');
}
public function toggleIcon($row, $href, $label, $title, $icon, $attributes)
{
if (Input::get('table') === 'tl_quiz_answer' && Input::get('tid'))
{
$this->toggleVisibility(Input::get('tid'), (Input::get('state') == 1), (@func_get_arg(12) ?: null));
$this->redirect($this->getReferer());
}
$href .= '&tid=' . $row['id'] . '&state=' . ($row['published'] ? '' : 1);
if (!$row['published'])
{
$icon = 'invisible.svg';
}
return '<a href="' . $this->addToUrl($href) . '" title="' . StringUtil::specialchars($title) . '"' . $attributes . '>' . Image::getHtml($icon, $label, 'data-state="' . ($row['published'] ? 1 : 0) . '"') . '</a> ';
}
/**
* Disable/enable answer
*
* @param integer $intId
* @param boolean $blnVisible
* @param DataContainer $dc
*
* @throws AccessDeniedException
*/
public function toggleVisibility($intId, $blnVisible, DataContainer $dc=null)
{
// Set the ID and action
Input::setGet('id', $intId);
Input::setGet('act', 'toggle');
if ($dc)
{
$dc->id = $intId; // see #8043
}
// Check the field access
if (!$this->User->hasAccess('tl_quiz_answer::published', 'alexf'))
{
throw new AccessDeniedException('Not enough permissions to publish/unpublish quiz answer recipient ID ' . $intId . '.');
}
$objRow = $this->Database->prepare("SELECT * FROM tl_quiz_answer WHERE id=?")
->limit(1)
->execute($intId);
if ($objRow->numRows < 1)
{
throw new AccessDeniedException('Invalid quiz answer ID ' . $intId . '.');
}
// Set the current record
if ($dc)
{
$dc->activeRecord = $objRow;
}
$objVersions = new Versions('tl_quiz_answer', $intId);
$objVersions->initialize();
$time = time();
// Update the database
$this->Database->prepare("UPDATE tl_quiz_answer SET tstamp=$time, published='" . ($blnVisible ? '1' : '') . "' WHERE id=?")
->execute($intId);
if ($dc)
{
$dc->activeRecord->tstamp = $time;
$dc->activeRecord->published = ($blnVisible ? '1' : '');
}
$objVersions->create();
if ($dc)
{
$dc->invalidateCacheTags();
}
}
public function child_record_callback($row)
{
return $row['answer'];
}
}
Besten Dank und
viele Grüße
Dennis
Lesezeichen