Ergebnis 1 bis 5 von 5

Thema: Mehrere Parent-Tables für ein DCA?

  1. #1
    Contao-Nutzer Avatar von chatjack
    Registriert seit
    02.09.2012.
    Ort
    Essen
    Beiträge
    162

    Standard Mehrere Parent-Tables für ein DCA?

    Hallo zusammen,

    ich stehe zurzeit vor einem kleinen Problem, das sich aus Sicht der Datenbank relativ einfach realisieren lässt, weiß aber nicht wie ich es in der Contao-Logik abbilden kann.

    Ich habe das Event-Modul um ein Bestellsystem für kostenlose Eintrittskarten erweitert. Diese werden jetzt in einer Kind-Tabelle von 'tl_calendar_events' gespeichert. Sie heißt 'tl_calendar_tickets' und beinhaltet folgende Felder.

    • id
    • pid
    • tstamp
    • member
    • amount


    Dargestellt wird das Ganze nun im Mode 4.

    PHP-Code:
    $GLOBALS['TL_DCA']['tl_calendar_tickets'] = array
    (

        
    // Config
        
    'config' => array
        (
            
    'dataContainer'               => 'Table',
            
    'ptable'                      => 'tl_calendar_events',
            
    'sql' => array
            (
                
    'keys' => array
                (
                    
    'id' => 'primary',
                    
    'pid' => 'index',
                    
    'member' => 'index'
                
    )
            )
        ),
        
        
    // List
        
    'list' => array
        (
            
    'sorting' => array
            (
                
    'mode'                    => 4,
                
    'disableGrouping'          => true,
                
    'headerFields'            => array('title''startDate''availableSeats'),
                
    'header_callback'          => array('tl_calendar_tickets''header_callback'),
                
    'panelLayout'             => 'filter;sort,search,limit',
                
    'child_record_callback'   => array('tl_calendar_tickets''child_record_callback')
            ),
            
    'global_operations' => array
            (
                
    'all' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['MSC']['all'],
                    
    'href'                => 'act=select',
                    
    'class'               => 'header_edit_all',
                    
    'attributes'          => 'onclick="Backend.getScrollOffset()" accesskey="e"'
                
    )
            ),
            
    'operations' => array
            (
                
    'edit' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['edit'],
                    
    'href'                => 'act=edit',
                    
    'icon'                => 'edit.gif'
                
    ),
                
    'delete' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['delete'],
                    
    'href'                => 'act=delete',
                    
    'icon'                => 'delete.gif',
                    
    'attributes'          => 'onclick="if(!confirm(\'' $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'
                
    ),
                
    'pdf' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['pdf'],
                    
    'href'                => 'key=pdf',
                    
    'icon'                => '/system/modules/tickettool/assets/pdf.png'
                
    ),
            )
        ),

        
    // Palettes
        
    'palettes' => array
        (
            
    'default'                     => '{tickets_legend},pid,member,amount'
        
    ),
        
        
    // Fields
        
    'fields' => array
        (
            
    'id' => array
            (
                
    'sql'                     => "int(10) unsigned NOT NULL auto_increment"
            
    ),
            
    'pid' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['pid'],
                
    'foreignKey'              => 'tl_calendar_events.id',
                
    'options_callback'        => array('tl_calendar_tickets','pid_options_callback'),
                
    'inputType'                  => 'select',
                
    'sql'                     => "int(10) unsigned NOT NULL default '0'",
                
    'eval'                      => array('mandatory'=>true,'chosen'=>true,'includeBlankOption'=>true,'tl_class'=>'w50'),
                
    'relation'                => array('type'=>'belongsTo''load'=>'eager')
            ),
            
    'tstamp' => array
            (
                
    'sql'                     => "int(10) unsigned NOT NULL default '0'"
            
    ),
            
    'member' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['member'],
                
    'options_callback'        => array('tl_calendar_tickets','member_options_callback'),
                
    'inputType'                  => 'select',
                
    'eval'                      => array('mandatory'=>true,'chosen'=>true,'includeBlankOption'=>true,'tl_class'=>'w50'),
                
    'sql'                     => "int(10) unsigned NOT NULL"
            
    ),
            
    'amount' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['amount'],
                
    'inputType'                  => 'text',
                
    'eval'                      => array('mandatory'=>true,'rgxp'=>'natural','tl_class'=>'w50'),
                
    'sql'                     => "int(4) unsigned NULL"
            
    )
        )
    ); 
    Das funktioniert auch soweit wunderbar. Anhand der Event-Id kann ich mir eine Liste ausgeben lassen, die die bestellten Tickets ausgibt.

    Nun möchte ich zusätzlich eine Liste in Contao ausgeben, die alle Tickets anhand einer Mitglieds-ID ausgibt, die ebenfalls in der Tabelle 'tl_calendar_tickets' gespeichert wird. Nun ist mir nicht ganz klar, wie ich den bestehenden DCA anpasse bzw. einen neuen DCA anlege, ohne extra eine zusätzliche Tabelle zu erzeugen zu müssen, die die umgekehrte Zuordnung beinhaltet.

    Ich habe schon etwas mit 'filter' experimentiert, habe es aber nicht geschafft, 'pid' zu entfernen, sodass ich lediglich nach 'member' suche.

    PHP-Code:
    'filter'                  => array(array('member=?',Input::get('member'))) 
    Wie generiere ich mir hier am besten die Liste, in der die Tickets anhand der Member-ID aufgeführt werden?

    Vielen Dank und beste Grüße,
    Dennis
    Geändert von chatjack (15.07.2017 um 13:58 Uhr)

  2. #2
    Contao-Nutzer Avatar von chatjack
    Registriert seit
    02.09.2012.
    Ort
    Essen
    Beiträge
    162

    Standard Bisher kein Erfolg

    Bisher bin ich leider noch nicht weiter gekommen. In dem Szenario geht es um eine Darstellung im Mode '4' in zwei Fällen.

    Fall 1:
    Zeige alle Tickets zu einer Veranstaltung und liste die Namen der Ticketkäufer auf. Die Veranstaltung steckt in der Tabelle 'tl_calendar_events' und das Ticket in der Tabelle 'tl_calender_tickets'. Das Feld 'pid' in der Ticket-Tabelle entspricht dem Feld 'id' in der Event-Tabelle. Die 'headerFields' beinhalten die Informationen des Events.

    Fall 2:
    Zeige alle Tickets zu einem Ticketkäufer und liste die Namen der Events auf. Der Ticketkäufer steckt in der Tabelle 'tl_member' und das Ticket in der Tabelle 'tl_calender_tickets'. Das Feld 'member' in der Ticket-Tabelle entspricht dem Feld 'id' in der Mitglieder-Tabelle. Die 'headerFields' beinhalten die Informationen des Ticketkäufers.

    Leider kann ich für Fall 2 den Ticketkäufer nicht in 'pid' schreiben, da dieses Feld schon für die Event-ID reserviert ist.

    Ist es tatsächlich so schwer, beide Fälle in Contao abzubilden oder habe ich es bisher noch nicht geschafft, das Problem klar zu umschreiben?

    Ich bin für jeden Hinweis dankbar.

    Viele Grüße,
    Dennis

  3. #3
    Contao-Fan Avatar von Fehrmann
    Registriert seit
    04.07.2009.
    Ort
    Wismar
    Beiträge
    581
    Contao-Projekt unterstützen

    Support Contao

    Standard

    Ich denke, das ich das Problem verstanden habe. Auf die schnelle fällt mir nur ein, die zweite Ansicht (member) in ein eigenes Backendmodul zu packen und die Ansicht entsprechend nachzubauen.

    Ich bin aber auch gespannt, ob es bessere Wege gibt.
    Software-Entwickler Backend/Frontend

  4. #4
    Contao-Nutzer Avatar von chatjack
    Registriert seit
    02.09.2012.
    Ort
    Essen
    Beiträge
    162

    Standard

    Das Ganze nachzubauen habe ich auch schon überlegt, wäre dann aber die absolute Notlösung, da ich auf den ganzen Komfort, den Contao bietet natürlich nicht verzichten möchte.

    Inzwischen bin ich schon einen kleinen Schritt weiter. Der Datenbank-Query, der in der DC_Table-Klasse erzeugt wird, hängt die 'pid=?' hinter das Statement, das man im DCA über 'filter' übergeben hat.

    Bisher habe ich es mit folgendem Filter probiert.

    PHP-Code:
    'filter' => array(array('member=?',Input::get('member'))) 
    Der Query-String sah dementsprechend wie folgt aus.

    Code:
    SELECT * FROM tl_calendar_tickets WHERE member=? AND pid=?
    Das Ganze kann ich jedoch durch eine kleine Anpassung auflösen.

    PHP-Code:
    'filter' => array(array('member=? OR id IS NULL',Input::get('member'))) 
    Der Query-String sieht danach wie folgt aus.

    Code:
    SELECT * FROM tl_calendar_tickets WHERE member=? OR id IS NULL AND pid=?
    Indem ich nun nach 'pid=?' und 'id IS NULL' suche, bekomme ich für 'pid' kein Ergebnis mehr zurück, da 'id' niemals NULL ist. Dank der Oder-Verknüpfung greift aber weiterhin 'member'.

    Über 'header_callback' und 'child_record_callback' kann ich mir alles nun so anpassen, dass ich zum gewünschten Ergebnis komme. Nur dass man über "zurück" in die Eventliste anstatt zur Mitgliederliste kommt ist noch etwas unschön, aber hier findet sich sicher noch eine Lösung.
    Geändert von chatjack (16.07.2017 um 14:04 Uhr)

  5. #5
    Contao-Nutzer Avatar von chatjack
    Registriert seit
    02.09.2012.
    Ort
    Essen
    Beiträge
    162

    Standard

    Ich habe es inzwischen einigermaßen hinbekommen. Die Lösung ist aber jetzt dermaßen gebastelt, dass sie mir doch einige Bauchschmerzen bereitet.

    Der DCA sieht jetzt wie folgt aus.

    tl_calendar_tickets.php
    PHP-Code:
    <?php

    $GLOBALS
    ['TL_DCA']['tl_calendar_tickets'] = array
    (

        
    // Config
        
    'config' => array
        (
            
    'dataContainer'               => 'Table',
            
    'ptable'                      => 'tl_calendar_events',
            
    'sql' => array
            (
                
    'keys' => array
                (
                    
    'id' => 'primary',
                    
    'pid' => 'index',
                    
    'member' => 'index'
                
    )
            )
        ),
        
        
    // List
        
    'list' => array
        (
            
    'sorting' => array
            (
                
    'mode'                    => 4,
                
    'disableGrouping'          => true,
                
    'headerFields'            => array('title''startDate''availableSeats'),
                
    'header_callback'          => array('tl_calendar_tickets', (Input::get('type') == "member") ? 'header_callback_member' 'header_callback'),
                
    'panelLayout'             => 'filter;sort,search,limit',
                
    'filter'                  => (Input::get('type') == "member") ? array(array('member=? OR id IS NULL',Input::get('id'))) : null,
                
    'child_record_callback'   => array('tl_calendar_tickets', (Input::get('type') == "member") ? 'child_record_callback_member' 'child_record_callback')
            ),
            
    'global_operations' => array
            (
                
    'all' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['MSC']['all'],
                    
    'href'                => 'act=select',
                    
    'class'               => 'header_edit_all',
                    
    'attributes'          => 'onclick="Backend.getScrollOffset()" accesskey="e"'
                
    )
            ),
            
    'operations' => array
            (
                
    'edit' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['edit'],
                    
    'href'                => 'act=edit',
                    
    'icon'                => 'edit.gif'
                
    ),
                
    'delete' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['delete'],
                    
    'href'                => 'act=delete',
                    
    'icon'                => 'delete.gif',
                    
    'attributes'          => 'onclick="if(!confirm(\'' $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'
                
    ),
                
    'pdf' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_calendar_events']['pdf'],
                    
    'href'                => 'key=pdf',
                    
    'icon'                => '/system/modules/tickettool/assets/pdf.png'
                
    ),
            )
        ),

        
    // Palettes
        
    'palettes' => array
        (
            
    'default'                     => '{tickets_legend},pid,member,amount'
        
    ),
        
        
    // Fields
        
    'fields' => array
        (
            
    'id' => array
            (
                
    'sql'                     => "int(10) unsigned NOT NULL auto_increment"
            
    ),
            
    'pid' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['pid'],
                
    'foreignKey'              => 'tl_calendar_events.id',
                
    'options_callback'        => array('tl_calendar_tickets','pid_options_callback'),
                
    'inputType'                  => 'select',
                
    'sql'                     => "int(10) unsigned NOT NULL default '0'",
                
    'eval'                      => array('mandatory'=>true,'chosen'=>true,'includeBlankOption'=>true,'tl_class'=>'w50'),
                
    'relation'                => array('type'=>'belongsTo''load'=>'eager')
            ),
            
    'tstamp' => array
            (
                
    'sql'                     => "int(10) unsigned NOT NULL default '0'"
            
    ),
            
    'member' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['member'],
                
    'options_callback'        => array('tl_calendar_tickets','member_options_callback'),
                
    'inputType'                  => 'select',
                
    'eval'                      => array('mandatory'=>true,'chosen'=>true,'includeBlankOption'=>true,'tl_class'=>'w50'),
                
    'sql'                     => "int(10) unsigned NOT NULL"
            
    ),
            
    'amount' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_calendar_tickets']['amount'],
                
    'inputType'                  => 'text',
                
    'eval'                      => array('mandatory'=>true,'rgxp'=>'natural','tl_class'=>'w50'),
                
    'sql'                     => "int(4) unsigned NULL"
            
    )
        )
    );

    class 
    tl_calendar_tickets extends Backend {
        
        public function 
    header_callback($headerArr,$headerObj)
        {
            
    $pid $this->Input->get('id');
            
    $guests $this->Database->prepare("SELECT SUM(amount) AS g FROM tl_calendar_tickets WHERE pid=?")->execute($pid)->g;
            
    $headerArr["Gäste"] = $guests number_format($guests,0,",",".") : "0";
            return 
    $headerArr;
        }
        
        public function 
    header_callback_member($headerArr,$headerObj)
        {
            
    $member MemberModel::findById($this->Input->get('id'));
            
    $headerArr = Array(
                
    "Name" => $member->firstname " " $member->lastname,
                
    "Adresse" => $member->street ", " $member->postal " " $member->city
            
    );
            if ( 
    $member->email ) { $headerArr["E-Mail"] = '<a href="mailto:'.$member->email.'">'.$member->email.'</a>'; }
            if ( 
    $member->phone ) { $headerArr["Telefon"] = $member->phone; }
            
            
    $headerArr["Vorstellungen"] = 0;
            
    $headerArr["Tickets"] = 0;
            
    $tickets CalendarTicketsModel::findByMember($member->id);
            while ( 
    $tickets && $tickets->next() ) {
                
    $headerArr["Vorstellungen"] += 1;
                
    $headerArr["Tickets"] += (int)$tickets->amount;
            }
            
            return 
    $headerArr;
        }
        
        public function 
    child_record_callback($arrRow)
        {
            
    $member MemberModel::findById($arrRow['member']);
            return 
    sprintf(
                
    "%s %s <span style=\"color:#b3b3b3;padding-left:3px\">[%s Ticket%s]</span>",
                
    $member->firstname,
                
    $member->lastname,
                
    $arrRow['amount'],
                (
    $arrRow['amount']==="1")?'':'s'
            
    );
        }
        
        public function 
    child_record_callback_member($arrRow)
        {
            
    $event CalendarEventsModel::findById($arrRow['pid']);
            
    $calendar CalendarModel::findById($event->pid);
            return 
    sprintf(
                
    "%s: %s <span style=\"color:#b3b3b3;padding-left:3px\">[%s Ticket%s]</span>",
                
    date("d.m.Y",$event->startTime),
                
    $calendar->title,
                
    $arrRow['amount'],
                (
    $arrRow['amount']==="1")?'':'s'
            
    );
        }
        
        public function 
    pid_options_callback()
        {
            
    $options = Array();
            
    $events CalendarEventsModel::findAll(['order'=>'startTime DESC']);
            while ( 
    $events && $events->next() ) {
                
    $options[$events->id] = sprintf('%s: %s',date('d.m.Y',$events->startTime), $events->title);
            }
            return 
    $options;
        }
        
        public function 
    member_options_callback()
        {
            
    $options = Array();
            
    $members MemberModel::findAll(['order'=>'lastName']);
            while ( 
    $members && $members->next() ) {
                
    $options[$members->id] = sprintf('%s %s',$members->firstname$members->lastname);
            }
            return 
    $options;
        }
        
    }
    'header_callback', 'child_record_callback' und 'filter' werden nun unterschiedlich gesetzt, je nachdem ob der GET-Parameter 'type=member' gesetzt wurde. In diesem Fall gehört die übermittelte ID zum Mitglied und nicht zum Event.

    Leider weist die Headline dann noch auf den Event-Bereich hin, was sich aber per Hook relativ einfach lösen lässt.

    config.php
    PHP-Code:
    $GLOBALS['TL_HOOKS']['parseTemplate'][] = array('Tickettool''parseTemplate'); 
    Tickettool.php
    PHP-Code:
        private function TicketsByMember()
        {
            return (
    Input::get('table') == 'tl_calendar_tickets' && Input::get('type') == 'member' && !Input::get('act'));
        }

        public function 
    parseTemplate($objTemplate)
        {
            if (
    $objTemplate->getName() && $this->TicketsByMember()) {
                
    $member = \MemberModel::findById(Input::get('id'));
                
    $objTemplate->headline "Tickets » " $member->firstname " " $member->lastname;
            }
        } 
    Schwieriger wurde es da schon mit dem Zurücklink und mit dem Link zum Editieren, da ja nun im Header die Daten des Mitglieds stehen, sollte man beim Klick auf den Editierbutton nicht in den Editor für einen Event springen.

    Das konnte ich nur durch Suchen und Ersetzen lösen.

    config.php
    PHP-Code:
        $GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = array('Tickettool''replaceBacklink');
        
    $GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = array('Tickettool''replaceEditlink'); 
    Tickettool.php
    PHP-Code:
        public function replaceBacklink($strBuffer)
        {
            return 
    $this->TicketsByMember() ? preg_replace_callback('/<[^>]*class="header_back"[^>]*>/',array('Tickettool','replaceBacklinkHref'),$strBuffer) : $strBuffer;
        }
        
        private function 
    replaceBacklinkHref($match)
        {
            
    $url '/contao/main.php?do=member&rt='.REQUEST_TOKEN;
            return 
    preg_replace('/ href="[^"]*/',' href="'.$url,$match[0]);
        }
            
        public function 
    replaceEditlink($strBuffer)
        {
            return 
    $this->TicketsByMember() ? preg_replace_callback('/<[^>]*class="tl_header[^"]*"[^>]*>[^>]*<[^>]*class="tl_content_right"[^>]*>[^>]*<[^>]*class="edit"[^>]*>/',array('Tickettool','replaceEditlinkHref'),$strBuffer) : $strBuffer;
        }
        
        private function 
    replaceEditlinkHref($match)
        {
            
    $url '/contao/main.php?do=member&act=edit&id='.CURRENT_ID.'&rt='.REQUEST_TOKEN;
            return 
    preg_replace('/ href="[^"]*/',' href="'.$url,$match[0]);
        } 
    Leider habe ich es noch nicht geschafft, dass kein Event vorausgewählt ist, wenn man in der Mitgliederübersicht auf "Neue Tickets" klickt. Hier wäre es natürlich sinnvoll, wenn das entsprechende Mitglied vorausgewählt ist und kein Event. Hier müsste aber vermutlich noch einiges umgebaut werden, da unter Mode 4 ja immer eine entsprechende pid vorhanden sein muss und das fest verdrahtet ist. Man kann es über 'default' im DCA also nicht überschreiben.

    Ich denke, ich werde wieder zu Mode 1 wechseln und den Infoblock über der Liste irgendwie rein basteln.

    Viele Grüße,
    Dennis
    Geändert von chatjack (16.07.2017 um 15:42 Uhr)

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 2 (Registrierte Benutzer: 0, Gäste: 2)

Lesezeichen

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •