Initial release
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\CoreBundle\DataContainer\PaletteManipulator;
|
||||
use Contao\DataContainer;
|
||||
use Contao\Database;
|
||||
use Contao\StringUtil;
|
||||
|
||||
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['location']);
|
||||
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['address']);
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['config']['onload_callback'][] = static function (): void {
|
||||
if (!isset($GLOBALS['TL_DCA']['tl_calendar_events']['palettes']) || !is_array($GLOBALS['TL_DCA']['tl_calendar_events']['palettes'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (array_keys($GLOBALS['TL_DCA']['tl_calendar_events']['palettes']) as $paletteName) {
|
||||
if ($paletteName === '__selector__') {
|
||||
continue;
|
||||
}
|
||||
|
||||
PaletteManipulator::create()
|
||||
->addLegend('organization_legend', 'details_legend', PaletteManipulator::POSITION_AFTER)
|
||||
->addField(['location_id', 'type', 'organizations'], 'organization_legend', PaletteManipulator::POSITION_APPEND)
|
||||
->applyToPalette((string) $paletteName, 'tl_calendar_events');
|
||||
|
||||
PaletteManipulator::create()
|
||||
->addField('photographer', 'image_legend', PaletteManipulator::POSITION_APPEND)
|
||||
->applyToPalette((string) $paletteName, 'tl_calendar_events');
|
||||
|
||||
PaletteManipulator::create()
|
||||
->addField(['source', 'url', 'target'], 'details_legend', PaletteManipulator::POSITION_APPEND)
|
||||
->addField(['termsAccepted', 'isSoldOut', 'isCanceled'], 'publish_legend', PaletteManipulator::POSITION_APPEND)
|
||||
->applyToPalette((string) $paletteName, 'tl_calendar_events');
|
||||
}
|
||||
};
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['config']['onbeforesubmit_callback'][] = static function (array $values): array {
|
||||
unset($values['organizations']);
|
||||
|
||||
return $values;
|
||||
};
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['location_id'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['location_id'],
|
||||
'exclude' => true,
|
||||
'filter' => true,
|
||||
'sorting' => true,
|
||||
'inputType' => 'select',
|
||||
'foreignKey' => 'tl_location.title',
|
||||
'options_callback' => static function (): array {
|
||||
$result = Database::getInstance()
|
||||
->query('SELECT id, title FROM tl_location ORDER BY title ASC');
|
||||
|
||||
$options = [];
|
||||
|
||||
foreach ($result->fetchAllAssoc() as $row) {
|
||||
$options[(int) $row['id']] = (string) $row['title'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
},
|
||||
'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'],
|
||||
'relation' => [
|
||||
'type' => 'hasOne',
|
||||
'load' => 'eager',
|
||||
'table' => 'tl_location',
|
||||
'field' => 'id',
|
||||
],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['type'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['type'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'select',
|
||||
'options' => ['accommodation', 'shopping', 'culture'],
|
||||
'reference' => &$GLOBALS['TL_LANG']['tl_calendar_events']['type_options'],
|
||||
'eval' => ['multiple' => true, 'chosen' => true, 'includeBlankOption' => false, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'blob', 'notnull' => false],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['organizations'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['organizations'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'select',
|
||||
'foreignKey' => 'tl_organization.title',
|
||||
'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'],
|
||||
'relation' => [
|
||||
'type' => 'hasMany',
|
||||
'load' => 'lazy',
|
||||
'table' => 'tl_organization',
|
||||
'field' => 'id',
|
||||
],
|
||||
'load_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = Database::getInstance()
|
||||
->prepare('SELECT organization_id FROM tl_calendar_events_organization WHERE event_id=? ORDER BY organization_id')
|
||||
->execute($dc->id);
|
||||
|
||||
return array_map(static fn (array $row): int => (int) $row['organization_id'], $result->fetchAllAssoc());
|
||||
},
|
||||
],
|
||||
'save_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$eventId = (int) $dc->id;
|
||||
$organizationIds = array_values(array_unique(array_map('intval', StringUtil::deserialize($value, true))));
|
||||
$db = Database::getInstance();
|
||||
$time = time();
|
||||
|
||||
$db->prepare('DELETE FROM tl_calendar_events_organization WHERE event_id=?')
|
||||
->execute($eventId);
|
||||
|
||||
foreach ($organizationIds as $organizationId) {
|
||||
$db->prepare('INSERT INTO tl_calendar_events_organization (tstamp, event_id, organization_id) VALUES (?, ?, ?)')
|
||||
->execute($time, $eventId, $organizationId);
|
||||
}
|
||||
|
||||
return $organizationIds;
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['photographer'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['photographer'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['isSoldOut'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['isSoldOut'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['isCanceled'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['isCanceled'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['termsAccepted'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_calendar_events']['termsAccepted'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
];
|
||||
|
||||
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source'])) {
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval'] ??= [];
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval']['tl_class'] = 'w50';
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target'])) {
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']['eval'] ??= [];
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']['eval']['tl_class'] = 'w50';
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url'])) {
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval'] ??= [];
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['tl_class'] = 'clr';
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['mandatory'] = false;
|
||||
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['rgxp']);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\DC_Table;
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_calendar_events_organization'] = [
|
||||
'config' => [
|
||||
'dataContainer' => DC_Table::class,
|
||||
'sql' => [
|
||||
'keys' => [
|
||||
'id' => 'primary',
|
||||
'event_id' => 'index',
|
||||
'organization_id' => 'index',
|
||||
],
|
||||
],
|
||||
],
|
||||
'fields' => [
|
||||
'id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'autoincrement' => true, 'notnull' => true],
|
||||
],
|
||||
'tstamp' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
'event_id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
'organization_id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\DataContainer;
|
||||
use Contao\Database;
|
||||
use Contao\DC_Table;
|
||||
use Contao\StringUtil;
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_location'] = [
|
||||
'config' => [
|
||||
'dataContainer' => DC_Table::class,
|
||||
'enableVersioning' => true,
|
||||
'sql' => [
|
||||
'keys' => [
|
||||
'id' => 'primary',
|
||||
'alias' => 'index',
|
||||
'published' => 'index',
|
||||
'title' => 'index',
|
||||
],
|
||||
],
|
||||
],
|
||||
'list' => [
|
||||
'sorting' => [
|
||||
'mode' => 1,
|
||||
'fields' => ['title'],
|
||||
'flag' => 1,
|
||||
'panelLayout' => 'search,limit',
|
||||
],
|
||||
'label' => [
|
||||
'fields' => ['title', 'city'],
|
||||
'format' => '%s (%s)',
|
||||
],
|
||||
'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=copy',
|
||||
'icon' => 'copy.svg',
|
||||
],
|
||||
'delete' => [
|
||||
'href' => 'act=delete',
|
||||
'icon' => 'delete.svg',
|
||||
'attributes' => 'onclick="if(!confirm(\'' . (string) ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? '') . '\'))return false;Backend.getScrollOffset()"',
|
||||
],
|
||||
'toggle' => [
|
||||
'href' => 'act=toggle&field=published',
|
||||
'icon' => 'visible.svg',
|
||||
],
|
||||
'show' => [
|
||||
'href' => 'act=show',
|
||||
'icon' => 'show.svg',
|
||||
],
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'__selector__' => [],
|
||||
'default' => '{title_legend},title,alias,image;{address_legend},street,street2,postal,city,state,country;{geo_legend},lat,lng;{description_legend},description;{publish_legend},published',
|
||||
],
|
||||
'fields' => [
|
||||
'id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'autoincrement' => true],
|
||||
],
|
||||
'tstamp' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
],
|
||||
'dateAdded' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
],
|
||||
'title' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['title'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'sorting' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'alias' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['alias'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['rgxp' => 'alias', 'unique' => true, 'maxlength' => 128, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 128, 'default' => ''],
|
||||
],
|
||||
'description' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['description'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'textarea',
|
||||
'eval' => ['rte' => 'tinyMCE', 'tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'text', 'notnull' => false],
|
||||
],
|
||||
'street' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['street'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'street2' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['street2'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'postal' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['postal'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'city' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['city'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'sorting' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'state' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['state'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'country' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['country'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 2, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 2, 'default' => 'de'],
|
||||
],
|
||||
'lat' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['lat'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 10, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'decimal', 'precision' => 10, 'scale' => 8, 'default' => '0.00000000'],
|
||||
],
|
||||
'lng' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['lng'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 11, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'decimal', 'precision' => 11, 'scale' => 8, 'default' => '0.00000000'],
|
||||
],
|
||||
'image' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['image'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'fileTree',
|
||||
'eval' => ['filesOnly' => true, 'fieldType' => 'radio', 'tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'binary', 'length' => 16, 'notnull' => false],
|
||||
],
|
||||
'published' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_location']['published'],
|
||||
'exclude' => true,
|
||||
'filter' => true,
|
||||
'toggle' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['doNotCopy' => true],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_location']['fields']['alias']['save_callback'][] = static function (string $value, DataContainer $dc): string {
|
||||
if ($value !== '') {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = StringUtil::generateAlias($dc->activeRecord?->title ?? '');
|
||||
|
||||
$exists = Database::getInstance()
|
||||
->prepare('SELECT id FROM tl_location WHERE alias=? AND id!=?')
|
||||
->execute($value, (int) ($dc->id ?? 0));
|
||||
|
||||
if ($exists->numRows > 0) {
|
||||
throw new \RuntimeException(sprintf((string) ($GLOBALS['TL_LANG']['tl_location']['aliasExists'] ?? '%s'), $value));
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\CoreBundle\DataContainer\PaletteManipulator;
|
||||
use Contao\DataContainer;
|
||||
use Contao\Database;
|
||||
use Contao\Input;
|
||||
use Contao\StringUtil;
|
||||
|
||||
if (isset($GLOBALS['TL_DCA']['tl_member']['palettes']) && is_array($GLOBALS['TL_DCA']['tl_member']['palettes'])) {
|
||||
foreach (array_keys($GLOBALS['TL_DCA']['tl_member']['palettes']) as $paletteName) {
|
||||
if ($paletteName === '__selector__') {
|
||||
continue;
|
||||
}
|
||||
|
||||
PaletteManipulator::create()
|
||||
->addLegend('organization_legend', 'contact_legend', PaletteManipulator::POSITION_AFTER)
|
||||
->addField('organizations', 'organization_legend', PaletteManipulator::POSITION_APPEND)
|
||||
->applyToPalette((string) $paletteName, 'tl_member');
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_member']['config']['onbeforesubmit_callback'][] = static function (array $values): array {
|
||||
unset($values['organizations']);
|
||||
|
||||
return $values;
|
||||
};
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'][] = static function (DataContainer $dc): void {
|
||||
if (!$dc->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$postedValues = Input::post('organizations');
|
||||
|
||||
if (null === $postedValues) {
|
||||
return;
|
||||
}
|
||||
|
||||
$organizationIds = array_values(array_unique(array_map('intval', is_array($postedValues) ? $postedValues : [$postedValues])));
|
||||
$memberId = (int) $dc->id;
|
||||
$db = Database::getInstance();
|
||||
$time = time();
|
||||
|
||||
$db->prepare('DELETE FROM tl_member_organization WHERE member_id=?')
|
||||
->execute($memberId);
|
||||
|
||||
foreach ($organizationIds as $organizationId) {
|
||||
$db->prepare('INSERT INTO tl_member_organization (tstamp, member_id, organization_id) VALUES (?, ?, ?)')
|
||||
->execute($time, $memberId, $organizationId);
|
||||
}
|
||||
};
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_member']['fields']['organizations'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_member']['organizations'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'select',
|
||||
'foreignKey' => 'tl_organization.title',
|
||||
'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'],
|
||||
'relation' => [
|
||||
'type' => 'hasMany',
|
||||
'load' => 'lazy',
|
||||
'table' => 'tl_organization',
|
||||
'field' => 'id',
|
||||
],
|
||||
'load_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = Database::getInstance()
|
||||
->prepare('SELECT organization_id FROM tl_member_organization WHERE member_id=? ORDER BY organization_id')
|
||||
->execute($dc->id);
|
||||
|
||||
return array_map(static fn (array $row): int => (int) $row['organization_id'], $result->fetchAllAssoc());
|
||||
},
|
||||
],
|
||||
'save_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$memberId = (int) $dc->id;
|
||||
$organizationIds = array_values(array_unique(array_map('intval', StringUtil::deserialize($value, true))));
|
||||
$db = Database::getInstance();
|
||||
$time = time();
|
||||
|
||||
$db->prepare('DELETE FROM tl_member_organization WHERE member_id=?')
|
||||
->execute($memberId);
|
||||
|
||||
foreach ($organizationIds as $organizationId) {
|
||||
$db->prepare('INSERT INTO tl_member_organization (tstamp, member_id, organization_id) VALUES (?, ?, ?)')
|
||||
->execute($time, $memberId, $organizationId);
|
||||
}
|
||||
|
||||
return $organizationIds;
|
||||
},
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\DC_Table;
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_member_organization'] = [
|
||||
'config' => [
|
||||
'dataContainer' => DC_Table::class,
|
||||
'sql' => [
|
||||
'keys' => [
|
||||
'id' => 'primary',
|
||||
'member_id' => 'index',
|
||||
'organization_id' => 'index',
|
||||
],
|
||||
],
|
||||
],
|
||||
'fields' => [
|
||||
'id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'autoincrement' => true, 'notnull' => true],
|
||||
],
|
||||
'tstamp' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
'member_id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
'organization_id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0, 'notnull' => true],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['palettes']['member_organizations'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
||||
$GLOBALS['TL_DCA']['tl_module']['palettes']['member_events'] = '{title_legend},name,headline,type;{eventmanager_legend},editPage;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
||||
$GLOBALS['TL_DCA']['tl_module']['palettes']['organization_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,logoFolder;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
||||
$GLOBALS['TL_DCA']['tl_module']['palettes']['event_edit'] = '{title_legend},name,headline,type;{eventmanager_legend},listPage,eventFolder,termsPage,frontendAuthorId,frontendArchiveId;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['editPage'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['editPage'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'pageTree',
|
||||
'eval' => ['fieldType' => 'radio', 'mandatory' => true, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['listPage'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['listPage'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'pageTree',
|
||||
'eval' => ['fieldType' => 'radio', 'mandatory' => true, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['logoFolder'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['logoFolder'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'fileTree',
|
||||
'eval' => ['fieldType' => 'radio', 'files' => false, 'mandatory' => true, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'binary', 'length' => 16, 'notnull' => false],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['eventFolder'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['eventFolder'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'fileTree',
|
||||
'eval' => ['fieldType' => 'radio', 'files' => false, 'mandatory' => true, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'binary', 'length' => 16, 'notnull' => false],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['termsPage'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['termsPage'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'pageTree',
|
||||
'eval' => ['fieldType' => 'radio', 'mandatory' => false, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['frontendAuthorId'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['frontendAuthorId'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['mandatory' => true, 'rgxp' => 'digit', 'maxlength' => 10, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_module']['fields']['frontendArchiveId'] = [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_module']['frontendArchiveId'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['mandatory' => true, 'rgxp' => 'digit', 'maxlength' => 10, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
];
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Contao\DataContainer;
|
||||
use Contao\Database;
|
||||
use Contao\DC_Table;
|
||||
use Contao\StringUtil;
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_organization'] = [
|
||||
'config' => [
|
||||
'dataContainer' => DC_Table::class,
|
||||
'enableVersioning' => true,
|
||||
'onbeforesubmit_callback' => [
|
||||
static function (array $values): array {
|
||||
unset($values['members']);
|
||||
|
||||
return $values;
|
||||
},
|
||||
],
|
||||
'sql' => [
|
||||
'keys' => [
|
||||
'id' => 'primary',
|
||||
'alias' => 'index',
|
||||
'published' => 'index',
|
||||
],
|
||||
],
|
||||
],
|
||||
'list' => [
|
||||
'sorting' => [
|
||||
'mode' => 1,
|
||||
'fields' => ['title'],
|
||||
'flag' => 1,
|
||||
'panelLayout' => 'search,limit',
|
||||
],
|
||||
'label' => [
|
||||
'fields' => ['title', 'city'],
|
||||
'format' => '%s (%s)',
|
||||
],
|
||||
'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=copy',
|
||||
'icon' => 'copy.svg',
|
||||
],
|
||||
'delete' => [
|
||||
'href' => 'act=delete',
|
||||
'icon' => 'delete.svg',
|
||||
'attributes' => 'onclick="if(!confirm(\'' . (string) ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? '') . '\'))return false;Backend.getScrollOffset()"',
|
||||
],
|
||||
'toggle' => [
|
||||
'href' => 'act=toggle&field=published',
|
||||
'icon' => 'visible.svg',
|
||||
],
|
||||
'show' => [
|
||||
'href' => 'act=show',
|
||||
'icon' => 'show.svg',
|
||||
],
|
||||
],
|
||||
],
|
||||
'palettes' => [
|
||||
'__selector__' => [],
|
||||
'default' => '{title_legend},title,alias,type,isExternal,logo;{address_legend},street,street2,postal,city,state,country;{contact_legend},phone,email,website;{geo_legend},lat,lng;{description_legend},description;{relation_legend},members;{publish_legend},published',
|
||||
],
|
||||
'fields' => [
|
||||
'id' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'autoincrement' => true],
|
||||
],
|
||||
'pid' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
],
|
||||
'tstamp' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
],
|
||||
'dateAdded' => [
|
||||
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
|
||||
],
|
||||
'title' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['title'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'sorting' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'alias' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['alias'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['rgxp' => 'alias', 'unique' => true, 'maxlength' => 128, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 128, 'default' => ''],
|
||||
],
|
||||
'logo' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['logo'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'fileTree',
|
||||
'eval' => ['filesOnly' => true, 'fieldType' => 'radio', 'tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'binary', 'length' => 16, 'notnull' => false],
|
||||
],
|
||||
'street' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['street'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'street2' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['street2'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'postal' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['postal'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'city' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['city'],
|
||||
'exclude' => true,
|
||||
'search' => true,
|
||||
'sorting' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'state' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['state'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'country' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['country'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 2, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 2, 'default' => ''],
|
||||
],
|
||||
'phone' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['phone'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 64, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 64, 'default' => ''],
|
||||
],
|
||||
'email' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['email'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['rgxp' => 'email', 'maxlength' => 255, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'website' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['website'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['rgxp' => 'url', 'maxlength' => 255, 'tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
|
||||
],
|
||||
'lat' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['lat'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 10, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'decimal', 'precision' => 10, 'scale' => 8, 'default' => '0.00000000'],
|
||||
],
|
||||
'lng' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['lng'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'text',
|
||||
'eval' => ['maxlength' => 11, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'decimal', 'precision' => 11, 'scale' => 8, 'default' => '0.00000000'],
|
||||
],
|
||||
'description' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['description'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'textarea',
|
||||
'eval' => ['rte' => 'tinyMCE', 'tl_class' => 'clr'],
|
||||
'sql' => ['type' => 'text', 'notnull' => false],
|
||||
],
|
||||
'published' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['published'],
|
||||
'exclude' => true,
|
||||
'filter' => true,
|
||||
'toggle' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['doNotCopy' => true],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
],
|
||||
'isExternal' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['isExternal'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'checkbox',
|
||||
'eval' => ['tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''],
|
||||
],
|
||||
'type' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['type'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'select',
|
||||
'options' => ['accommodation', 'shopping', 'culture'],
|
||||
'reference' => &$GLOBALS['TL_LANG']['tl_organization']['type_options'],
|
||||
'eval' => ['multiple' => true, 'chosen' => true, 'includeBlankOption' => false, 'tl_class' => 'w50'],
|
||||
'sql' => ['type' => 'blob', 'notnull' => false],
|
||||
],
|
||||
'members' => [
|
||||
'label' => &$GLOBALS['TL_LANG']['tl_organization']['members'],
|
||||
'exclude' => true,
|
||||
'inputType' => 'select',
|
||||
'options_callback' => static function (): array {
|
||||
$result = Database::getInstance()
|
||||
->query('SELECT id, firstname, lastname FROM tl_member ORDER BY lastname ASC, firstname ASC');
|
||||
|
||||
$options = [];
|
||||
|
||||
foreach ($result->fetchAllAssoc() as $row) {
|
||||
$name = trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? ''));
|
||||
$options[(int) $row['id']] = $name !== ''
|
||||
? $name
|
||||
: sprintf((string) ($GLOBALS['TL_LANG']['tl_organization']['memberFallback'] ?? '%s'), $row['id']);
|
||||
}
|
||||
|
||||
return $options;
|
||||
},
|
||||
'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'],
|
||||
'relation' => [
|
||||
'type' => 'hasMany',
|
||||
'load' => 'lazy',
|
||||
'table' => 'tl_member',
|
||||
'field' => 'id',
|
||||
],
|
||||
'load_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = Database::getInstance()
|
||||
->prepare('SELECT member_id FROM tl_member_organization WHERE organization_id=? ORDER BY member_id')
|
||||
->execute($dc->id);
|
||||
|
||||
return array_map(static fn (array $row): int => (int) $row['member_id'], $result->fetchAllAssoc());
|
||||
},
|
||||
],
|
||||
'save_callback' => [
|
||||
static function ($value, DataContainer $dc): array {
|
||||
if (!$dc->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$organizationId = (int) $dc->id;
|
||||
$memberIds = array_values(array_unique(array_map('intval', StringUtil::deserialize($value, true))));
|
||||
$db = Database::getInstance();
|
||||
$time = time();
|
||||
|
||||
$db->prepare('DELETE FROM tl_member_organization WHERE organization_id=?')
|
||||
->execute($organizationId);
|
||||
|
||||
foreach ($memberIds as $memberId) {
|
||||
$db->prepare('INSERT INTO tl_member_organization (tstamp, member_id, organization_id) VALUES (?, ?, ?)')
|
||||
->execute($time, $memberId, $organizationId);
|
||||
}
|
||||
|
||||
return $memberIds;
|
||||
},
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$GLOBALS['TL_DCA']['tl_organization']['fields']['alias']['save_callback'][] = static function (string $value, DataContainer $dc): string {
|
||||
if ($value !== '') {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = StringUtil::generateAlias($dc->activeRecord?->title ?? '');
|
||||
|
||||
$exists = Database::getInstance()
|
||||
->prepare('SELECT id FROM tl_organization WHERE alias=? AND id!=?')
|
||||
->execute($value, (int) ($dc->id ?? 0));
|
||||
|
||||
if ($exists->numRows > 0) {
|
||||
throw new \RuntimeException(sprintf((string) ($GLOBALS['TL_LANG']['tl_organization']['aliasExists'] ?? '%s'), $value));
|
||||
}
|
||||
|
||||
return $value;
|
||||
};
|
||||
Reference in New Issue
Block a user