Seite 2 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 41 bis 80 von 129

Thema: Tagebuch einer Extension-Entwicklung

  1. #41
    Contao-Fan Avatar von deerwood
    Registriert seit
    24.11.2009.
    Ort
    Hamburg
    Beiträge
    344

    Standard

    Moin Stefan,

    Zitat Zitat von dl1ely Beitrag anzeigen
    Habe gerade zufällig entdeckt, dass die angehängten Bilder nicht inline angezeigt werden, wenn man nicht im Forum angemeldet ist. Das könnte den davon betroffenen Lesern vielleicht etwas den roten Faden kosten. Hat jemand eine Idee, wie ich die Bilder besser einbinden kann?
    Leider nein ... aber vergiss das einfach: wer hier mitliest, will ja lernen / entwickeln und dann kannst Du davon ausgehen, dass derjenige sich auch anmelden kann / bereits angemeldet ist!

    Ich lese immer noch mit und lerne aus Deinen Erfahrungen. Danke für Deine immense Mühe, uns all Deine Schritte bis ins Detail zu dokumentieren/erklären! Das kostet Dich wahrscheinlich VIEL mehr Zeit, als die Entwicklung selbst. Faszinierend.

    Ein ganz kleiner Tipp noch: verwende doch in Zukunft besser die PHP statt der CODE Formatierung, ...

    LG, Georg
    Geändert von deerwood (11.03.2010 um 19:52 Uhr) Grund: Ablenkende Formatierungsbeispiele entfernt

  2. #42
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Hallo Georg,

    Danke für den Tip, ich habe das soeben in allen Posts geändert. Es ist mir ein Rätsel, wie ich den "PHP"-Button oben neben dem "CODE"-Button so konsequent übersehen konnte. Wahrscheinlich, weil ich ihn nur einmal benutzt habe, und danach "CODE" immer von Hand eingegeben habe :-).

    In der Tat ist es viel mehr Arbeit als erwartet, aber jetzt ziehe ich das durch ;-)

    Stefan

  3. #43
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 7b: Ein wenig Finetuning

    Zunächst mal habe ich mir die Palettendefinitionen in system/modules/backend/dca/tl_module.php angeschaut und festgestellt, dass der von mir benutzte Code aus einem Tutorial wohl etwas veraltet ist. Ich orientiere mich an den anderen Einträgen und ändere meine Palettendefinition für die Modul-Verwaltung in system/modules/gw_turnierpaare/dca/tl_module.php auf:
    PHP-Code:
    <?php
    // Add a palette to tl_module

    $GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space';
    ?>
    Damit haben wir schöne Palettenüberschriften und den "Standardsatz" an Eigenschaften für Module.

    Dann hatte ich das hier entdeckt: https://contao.org/blog-leser/items/...zugreifen.html, und erinnerte mich an den save_callback für das Passwort-Feld der Paare, der genau sowas (Datensatz mit aktueller ID aus Datenbank einlesen) macht. Da ich sowieso nur 2.8 einsetze, wo das Feature des "activeRecord" verfügbar ist, klang das gut, und ich wollte es so umsetzen.

    Aber: Der activeRecord enthält im save_callback wirklich die aktuellen Werte der Felder in der Eingabemaske. Im Falle des Passwortfelds also den leeren String, wenn nichts eingegeben wurde, bzw. das neue Klartextpasswort. Im save_callback brauche ich aber das alte, in der DB vorliegende Passwort (um den salt dort herauszuholen). Das geht mit dem activeRecord nicht, und ich muss mit der alten Methode, das Feld aus der Datenbank zu holen leben. Wenn man aber wirklich die aktuell in der Maske vorliegenden Felder benötigt, ist der activeRecord bestimmt ein super Feature.

    Nur ein kurzer Eintrag heute. Nächste Woche wird es urlaubsbedingt auch nichts geben, ich entschuldige mich also schon mal für die längere Pause.

    Stefan
    Geändert von dl1ely (23.03.2010 um 20:32 Uhr)

  4. #44
    Contao-Urgestein Avatar von Toflar
    Registriert seit
    15.06.2009.
    Beiträge
    4.467
    Partner-ID
    8667
    User beschenken
    Wunschliste

    Standard

    Als kleine Ergänzung. Ich finde das passt gerade schön hier rein:

    Oftmals muss man für ältere TL Versionen mit dem Code ein bisschen anders umgehen. Aber man möchte die Erweiterung trotzdem für mehrere Versionen freigeben.

    Dann muss man halt an diversen Orten die TL-Version prüfen:
    PHP-Code:
    if(version_compare(VERSION '.' BUILD'2.8.0''<'))
    {
       
    // mach für Versionen unter 2.8.0 das
    }
    else
    {
       
    // ab Version 2.8.0 mach das

    Viel Spass
    Contao Core-Entwickler @terminal42 gmbh
    Wir sind Contao Premium-Partner!
    Für Individuallösungen kannst du uns gerne kontaktieren.
    PS: Heute schon getrakked?

  5. #45
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Super, vielen Dank!

    Stefan

  6. #46
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 8: Parameter fürs Modul

    Die Ausgabe im Frontendmodul möchte ich gerne in der Modulverwaltung parametrisieren können. Einerseits soll man auswählen können, ob das Modul nur aktive oder nur inaktive, oder alle Paare auflisten soll. Andererseits soll der Sortiermodus zwischen "Nachnamen alphabetisch" und "Nach Altersgruppe aufsteigend" wählbar sein.

    Dafür ist der etablierte Weg eine Erweiterung der Tabelle tl_module um die benötigten Felder. Man soll bestehende Fehler wenn möglich recyclen, aber man recycelt dann auch die Beschreibungstexte usw mit, das war für mich nicht passend.

    Also habe ich neue Felder angelegt. In der config/database.php meiner Extension:
    Code:
    --
    -- Extend table 'tl_module'
    --
    
    CREATE TABLE `tl_module` (
      `gw_tp_showonlyactive` char(1) NOT NULL default 'B',
      `gw_tp_couplesorting` char(1) NOT NULL default 'A',
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    Hier füge ich also zwei "CHAR"-Felder hinzu, die Buchstabencodes enthalten (Beim Filter: B = Alle Paare [Both], A = Nur aktive Paare, I = Nur inaktive Paare; Beim Sortieren: A = Alphabetisch, C = Nach Altersklasse [Class]), die ich dann später im Frontend-Ausgabemodul auslesen und interpretieren muss. WICHTIG: Obwohl ich nur eine schon bestehende Tabelle ERWEITERN will, muss ich hier "CREATE TABLE" verwenden. Das Installtool macht das Richtige daraus...

    Danach muss ich das Installtool aufrufen, um die neuen Felder anlegen zu lassen.

    Dann muss der DCA-Record für tl_module so erweitert werden, dass meine Felder angezeigt werden, wenn in der Dropdown-Liste der zur Verfügung stehenden Module die Turnierpaarliste ausgewählt wird.

    Dafür nehmen wir uns system/modules/gw_turnierpaare/dca/tl_module.php vor:
    PHP-Code:
    $GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{sort_legend},gw_tp_showonlyactive,gw_tp_couplesorting;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space'
    In der Subpalette für mein Modul füge ich einen neuen Abschnitt mit Überschrift "sort_legend" ein. Darin werden meine beiden neuen Datenbankfelder angezeigt.

    Die müssen noch im DCA definiert werden:
    PHP-Code:
    $GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_showonlyactive'] = array
    (
        
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_showonlyactive'],
        
    'default'                 => 'B',
        
    'exclude'                 => true,
        
    'inputType'               => 'select',
        
    'options'                 => array('B','A','I'),
        
    'reference'               => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'],
        
    'eval'                    => array('mandatory'=>true'tl_class' => 'w50')
    );

    $GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_couplesorting'] = array
    (

        
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'],
        
    'default'                 => 'A',
        
    'exclude'                 => true,
        
    'inputType'               => 'select',
        
    'options'                 => array('A','C'),
        
    'reference'               => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'],
        
    'eval'                    => array('mandatory'=>true)
    ); 
    Der Typ ist "select", also eine Dropdownbox. Die "options" sind die Werte, die in die Datenbank geschrieben werden sollen. Die "reference" sind im Gegensatz dazu die Werte, die in der Dropdown-Box angezeigt werden sollen. Hier war mir anfangs unklar, wie genau die Übersetzungen definiert werden müssen. Dazu gleich mehr. Hier setze ich erstmal die Referenz auf ein Array, was in den Sprachfiles definiert wird. Da die Werte in der Modulverwaltung angezeigt werden, habe ich mich dazu entschlossen, sie unter ['tl_module'] einzusortieren, aber mit meinem Präfix "gw_tp", um Namenskollisionen unwahrscheinlich zu machen.

    Nun noch die Definition der Strings in der deutschen Sprachdatei (englisch geht genauso). Da die String zur Modulverwaltung gehören, habe ich mich dazu entschlossen, sie in die Datei system/modules/gw_turnierpaare/languages/de/modules.php zu schreiben. Man hätte auch eine neue Datei tl_module.php anlegen können. Ich weiss nicht, was da "best practice" ist.

    Wir ergänzen also die modules.php um:
    PHP-Code:
    /**
     * Back end fields for tl_module
     */
    $GLOBALS['TL_LANG']['tl_module']['sort_legend']     = 'Filter und Sortierung';
     
    $GLOBALS['TL_LANG']['tl_module']['gw_tp_showonlyactive'] = array('Aktive/Inaktive Paare auflisten?''Bitte wählen Sie aus, ob nur aktive, inaktive oder alle Paare gelistet werden sollen');
    $GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'] = array('B' => 'Alle Paare''A' => 'Nur aktive Paare''I' => 'Nur inaktive Paare');

    $GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'] = array('Sortiermodus''Bitte wählen Sie aus, wie die Liste der Turnierpaare sortiert sein soll');
    $GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'] = array('A' => 'Alphabetisch''C' => 'Nach Altersklasse aufsteigend'); 
    Hier kommt nun der Knackpunkt der "reference"-Arrays, der mir nicht klar war, und erst durch Abgucken bei anderen Extensions geklärt wurde:
    Das reference-Array darf nicht einfach ein aufsteigendes Array der Texte zu den Optionen sein wie das "options"-Array (also "array('text1','text2','text3');"), sondern es muss ein assoziatives Array mit der Beziehung 'option1' => 'Text1' sein, sonst funktioniert es nicht. Die DCA-Referenz bleibt da leider sehr schwammig.

    Auch die Abschnittsüberschrift "sort_legend" definieren wir hier.

    Damit haben wir dieses Ergebnis:


    Leider schaffe ich es in diesem Schritt nicht mehr, die neuen Felder in der Frontendausgabe auch noch auszuwerten (Der Kampf mit dem reference-Array hat doch etwas Zeit gekostet), das muss bis zum nächsten Mal (übernächste Woche) warten, sorry.
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (23.03.2010 um 20:32 Uhr)

  7. #47
    Contao-Nutzer
    Registriert seit
    25.09.2009.
    Ort
    Österreich; Wien & Salzburg
    Beiträge
    66

    Standard Wow

    Wow, Danke für die Mühe, hier trifft der lern & Spaßfaktor mal perfekt aufeinander.
    werde versuchen das ganze in naher Zukunft auch mal praktisch nachzuvollziehen
    Beste Grüße aus Österreich
    XING: https://www.xing.com/profile/Johannes_Ferner2

  8. #48
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 8b: Parameter für das Modul, die zweite

    Nun geht es daran, die Modulparameter aus Schritt 7 im Frontendmodul auch wirklich zu nutzen.
    Dafür muss ich sie mir zuerst beschaffen. Das geschieht zu Beginn der compile()-Funktion in /system/modules/gw_turnierpaare/gwTurnierpaarliste.php:
    PHP-Code:
            $moduleParams $this->Database->prepare("SELECT * FROM tl_module WHERE id=?")
                            ->
    limit(1)
                            ->
    execute($this->id); 
    $this->id enthält die Modul-ID, und über einen Blick in die Datenbank bekommen wir alle Felder der entsprechenden Zeile und damit auch unsere Parameter.

    Die muss ich nun auswerten uns entsprechend reagieren. Zunächst das Flag, das mir nur die aktiven Paare, nur die inaktiven oder beide liefert:
    PHP-Code:
        $whereClause '';
        if(
    $moduleParams->gw_tp_showonlyactive == 'A')
        {
          
    $whereClause "WHERE aktiv='1'";
        }
        else
        {
          if(
    $moduleParams->gw_tp_showonlyactive == 'I')
          {
            
    $whereClause "WHERE aktiv=''";
          }
        } 
    Die Variable $whereClause baue ich später in meinen SELECT der Turnierpaare ein.

    Für die Sortierung muss ich die alphabetische Sortierung nach Nachname Herr und Nachname Dame einerseits und die Sortierung nach Startgruppe (und dann Startklasse und erst dann Nachnamen) unterscheiden.

    Der erste Fall ist einfach ("ORDER BY partnernachname, partnerinnachname"), der andere aber komplizierter, da die Sortierrreihenfolge nicht alphabetisch ist, sondern sich nach den Altersklassen richten soll, die Jüngsten zuerst. Aber ein wenig Googeln hilft, das Problem mit einem SQL-Query zu lösen. Die FIELD()-Funktion liefert mir den Index des Inhalts eines Datenbankfeldes innerhalb einer Liste von Werten. Das kann ich benutzen, um in beliebiger Reihenfolge zu sortieren. Will ich das Feld "field" in der Reihenfolge "BCA" sortieren, leistet das "ORDER BY FIELD(field,'B','C','A')".

    PHP-Code:
        $orderClause 'partnernachname, partnerinnachname';
        if(
    $moduleParams->gw_tp_couplesorting == 'C')
        {
          
    // Nach Altersgruppen sortieren
          
    $fieldstartgruppe="''";
           foreach(array(
    'KIN I','KIN II''JUN I''JUN II''JUG''HGR''HGR II''SEN I''SEN II''SEN III''SEN IV') as $gruppe)
          {
            
    $fieldstartgruppe .= ",'".$gruppe."'";
          }

          
    $fieldstartklasse="''";
          foreach(array(
    '-''E','D''C''B''A''S''PRO''LL''OL''RL''2. BL''1. BL') as $klasse)
          {
            
    $fieldstartklasse .= ",'".$klasse."'";
          }
          
          
    $orderClause "FIELD(startgruppe,".$fieldstartgruppe."), FIELD(startklassestandard,".$fieldstartklasse."), FIELD(startklasselatein,".$fieldstartklasse."), partnernachname, partnerinnachname";
        } 
    Defaultmäßig wird nach den Nachnamen alphabetisch sortiert. Wenn aber das gw_tp_couplesorting-Feld 'C' ist, dann wird aus den möglichen Werten der Altersgruppe und der Startklasse jeweils ein String zusammengebaut, der dann in $orderClause zum "ORDER BY"-Teil zusammengebaut wird.

    So wird zuerst nach der Altersgruppe (in vorgegebener Reihenfolge), dann nach den Startklassen Standard und Latein (in vorgegebener Reihenfolge) und schließlich nach den Nachnamen sortiert. Natürlich hätte ich die Liste der Gruppen und Klassen direkt als String definieren können, statt ein Array anzulegen, mit einer Variable drüberzulaufen, um daraus wieder einen String zu machen. Aber der Gedanke war, das 'options"-Feld der DCA-Definition der entsprechenden Felder im DCA-Record zu nutzen. Eine Änderung der möglichen Optionen dort würde dann auch gleich an dieser Stelle genutzt werden. Leider scheint die DCA-Definition des Backend-Moduls an dieser Stelle (Frontend-Modul!) leider nicht geladen zu sein, $GLOBALS['TL_DCA'] ist zumindest nicht vorhanden. Schade! Aber vielleicht lagere ich die Arrays noch in eine gemeinsame, geteilte Include-Datei aus, die ich in DCA-Definition und im Frontendmodul nutzen kann. Darum bleibt es erstmal bei der Schleife über den Arrayelementen.

    Schließlich muss das ursprüngliche SELECT-Statement noch um die neuen Variablen $whereClause und $orderClause erweitert werden:
    PHP-Code:
        $objPaare $this->Database->execute("SELECT * FROM tl_gw_turnierpaare " $whereClause "ORDER BY " $orderClause); 
    Ich definiere nun zwei Module, einmal die Liste der aktiven Turnierpaare, die eben nur die aktiven Paare anzeigt, sortiert nach Startgruppen und Klassen, und eine Liste der inaktiven Paare, alphabetisch sortiert. Beide Module füge in in eine Seite als Inhaltselemente ein.

    Das Ergebnis:


    Oben das Modul, das die aktiven Turnierpaare sortiert nach Altersgruppe anzeigt, unten das Modul, das die inaktiven Paare alphabetisch sortiert anzeigt. Die graue Farbe bei den Inaktiven wird auch noch geändert, und im nächsten Schritt wird es an den "Detail"-Link gehen.
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (23.03.2010 um 20:33 Uhr)

  9. #49
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 9: Details, Details, Details!

    In der Listenübersicht der Turnierpaare ist als Link bereits vorgesehen, dass man beim Klick auf den "Detail"-Link eines Paares zu einer Detail-Seite kommen kann. Ich möchte das mit demselben Modul regeln, also ohne Weiterleitungsseite auf eine (versteckte) Seite mit einem "DetailViewer"-Modul.

    Ich habe mir das schamlos beim EFG abgeguckt. Meine Turnierpaarliste liegt unter turnierpaarliste.html. Wenn man als URL z.B. turnierpaarliste/info/8.html verwendet, wird trotzdem die Seite "turnierpaarliste" aufgerufen, aber jetzt hat der GET-Parameter "info" den Wert 8. Sehr praktisch.

    Prüft man im Modulcode auf diesen Parameter, kann man dann gegebenenfalls auf das Detail-Template wechseln und anderen Code ausführen.

    Nochmal der entsprechende Abschnitt aus dem Template der /system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl:
    PHP-Code:
      </td>
      <td><?php echo '<a href="/turnierpaarliste/info/'.$paar['id'].'.html">Detail</a>'?>
      </td>
    Hier wird aus der Paar-ID der Detail-Link gebaut. Mich stört noch, dass mein Seitenname "turnierpaarliste" hardkodiert ist. Das werde ich noch ändern müssen, habe gerade aber keine Idee, wie ich an diese Information komme. Außerdem wäre es schöner, statt mit der numerischen ID mit einem alphanumerischen Alias zu arbeiten, so wie bei Seiten oder Artikeln. Das werde ich noch in einem zukünftigen Schritt implementieren.

    Das Template für die Detailseite /system/modules/gw_turnierpaare/templates/gw_turnierpaarliste_detail.tpl sieht so aus:
    PHP-Code:
    <div class="<?php echo $this->class?> block paarvisitenkarte"<?php echo $this->cssID?>
    <?php 
    if ($this->style): ?> style="<?php echo $this->style?>"<?php endif; ?>>

    <h3><?php echo $this->paar['partnernachname']; ?>
    <?php 
    if($this->paar['partnervorname']) { echo ", ".$this->paar['partnervorname']; }; ?>
    <?php 
    if($this->paar['partnerinnachname']) { echo " und ".$this->paar['partnerinnachname']; }; ?>
    <?php 
    if($this->paar['partnerinvorname']) { echo ", ".$this->paar['partnerinvorname']; }; ?>
    </h3>

    <?php if ($this->paar['bild']): ?>
    <div class="left">
    <?php if($this->paar['bildfullsize']): ?>
    <a href="<?php echo $this->paar['bildfullsize']; ?>" rel="lightbox[bild]">
    <?php endif; ?>
    <img src="<?php echo $this->paar['bild']; ?>">
    <?php if($this->paar['bildfullsize']): ?>
    </a>
    <?php endif; ?>

    </div>
    <?php endif; ?>

    <div class="right">
    <ul>
    <?php if ($this->paar['startklassestandard'] != '-'): ?>
    <li>
      <?php echo $this->paar['startgruppe']." ".$this->paar['startklassestandard']." Standard"?>
    </li>
    <?php endif; ?>

    <?php if ($this->paar['startklasselatein'] != '-'): ?>
    <li>
      <?php echo $this->paar['startgruppe']." ".$this->paar['startklasselatein']." Latein"?>
    </li>
    <?php endif; ?>

    <li>
       Aktiv: <?php echo $this->paar['aktivseit']; ?> - <?php if($this->paar['aktivbis']) { echo $this->paar['aktivbis']; } else { echo "heute"; }; ?>
    </li>

    <?php if ($this->paar['anschrift']): ?>
    <li>
       <?php echo nl2br($this->paar['anschrift']); ?>
    </li>
    <?php endif; ?>

    <?php if ($this->paar['telefon']): ?>
    <li>
       Tel.: <?php echo $this->paar['telefon']; ?>
    </li>
    <?php endif; ?>


    <?php if ($this->paar['fax']): ?>
    <li>
       Fax: <?php echo $this->paar['fax']; ?>
    </li>
    <?php endif; ?>


    <?php if ($this->paar['mobil']): ?>
    <li>
       Mob.: <?php echo $this->paar['mobil']; ?>
    </li>
    <?php endif; ?>


    <?php if ($this->paar['email']): ?>
    <li>
       EMail: {{email::<?php echo $this->paar['email']; ?>}}
    </li>
    <?php endif; ?>

    <?php if ($this->paar['homepage']): ?>
    <li>
       Homepage: <a href="<?php echo $this->paar['homepage']; ?>"><?php echo $this->paar['homepage']; ?></a>
    </li>
    <?php endif; ?>

    </ul>
    </div>

    <div class="twocol">
    <?php echo nl2br($this->paar['beschreibung']); ?>
    </div>

    </div>
    Im Prinzip nichts besonderes, ich bastele aus den Namen eine schöne Überschrift, Bild und die anderen Texte werden in DIVs verpackt, die ich per CSS dann "hübsch" anordne. Beim Bild wird unser Modulcode in $paar['bild'] eine verkleinerte Version (180px breit max.) zurückliefern, in $paar['bildfullsize'] befindet sich das Originalbild, das hier im Template dann über eine Lightbox großklickbar ist. Das Array $paar im Template entspricht ansonsten den Datenbankfeldern in tl_gw_turnierpaare.

    Die Hauptarbeit passiert nun in der Frontend-Modul-Klasse /system/modules/gw_turnierpaare/gwTurnierpaarliste.php:
    PHP-Code:
    class gwTurnierpaarliste extends Module
    {

        
    /**
         * Template
         * @var string
         */
        
    protected $strTemplate 'gw_turnierpaarliste';

      protected 
    $strDetailKey 'info'
    Zunächst definiere ich wie üblich den "Default"-Templatenamen, das ist der für die gesamte Liste. Zusätzlich definiere ich hier das URL-Fragment, was meinen "Detail-Link" ausmachen soll.

    PHP-Code:
      function obj2Arr($objPaar)
      {
        
    $newArr = array
          (
            
    'partnernachname' => trim($objPaar->partnernachname),
            
    'partnervorname' => trim($objPaar->partnervorname),
            
    'partnerinnachname' => trim($objPaar->partnerinnachname),
            
    'partnerinvorname' => trim($objPaar->partnerinvorname),
            
    'startgruppe' => $objPaar->startgruppe,
            
    'startklasselatein' => $objPaar->startklasselatein,
            
    'startklassestandard' => $objPaar->startklassestandard,
            
    'aktiv' => $objPaar->aktiv,
            
    'aktivseit' => $objPaar->aktivseit,
            
    'aktivbis' => $objPaar->aktivbis,
            
    'id' => $objPaar->id,
            
    'beschreibung' => $objPaar->beschreibung,
          );

          if(
    $objPaar->zeigeanschrift == '1')
          {
            
    $newArr['anschrift'] = $objPaar->anschrift;
          }

          if(
    $objPaar->zeigetelefon == '1')
          {
            
    $newArr['telefon'] = $objPaar->telefon;
          }

          if(
    $objPaar->zeigefax == '1')
          {
            
    $newArr['fax'] = $objPaar->fax;
          }

          if(
    $objPaar->zeigemobil == '1')
          {
            
    $newArr['mobil'] = $objPaar->mobil;
          }

          if(
    $objPaar->zeigeemail == '1')
          {
            
    $newArr['email'] = $objPaar->email;
          }

          if(
    $objPaar->zeigehomepage == '1')
          {
            
    $newArr['homepage'] = $objPaar->homepage;
          }

        return 
    $newArr;
      } 
    Diese Utility-Funktion füllt mir eine Zeile des Resultsets der Datenbank in ein Array. Ich brauche das an zwei Stellen, darum habe ich das hierhin ausgelagert. Hier werden auch schon die "zeige"-Flags berücksichtigt: Sind die nicht angehakt, landet auch nichts im Array. Damit spare ich mir die Abfragen im Template.

    PHP-Code:
        protected function compile()
        {
            if ( 
    strlen($this->Input->get($this->strDetailKey)) )
            {
          
    // A "detail"-URL is given -> Output turnierpaarliste_detail template
          
    $this->compileDetailTemplate();

        }
        else
        {
          
    // Output the turnierpaarliste template
          
    $this->compileListTemplate();
          }

    Die alte "Compile"-Funktion wurde angenehm kurz. Falls der GET-Parameter mit dem Namen "info" gesetzt ist (über unsere URL turnierpaarliste/info/8.html), dann wird eine Funktion zur Ausgabe des Detail-Templates aufgerufen, ansonsten eine für das Listentemplate.

    PHP-Code:
      // Compiles the turnierpaarliste template
      
    protected function compileListTemplate()
      {
            
    $moduleParams $this->Database->prepare("SELECT * FROM tl_module WHERE id=?")
                    ->
    limit(1)
                    ->
    execute($this->id);

        
    $whereClause '';
        if(
    $moduleParams->gw_tp_showonlyactive == 'A')
        {
          
    $whereClause "WHERE aktiv='1'";
        }
        else
        {
          if(
    $moduleParams->gw_tp_showonlyactive == 'I')
          {
            
    $whereClause "WHERE aktiv=''";
          }
        }

        
    $orderClause 'partnernachname, partnerinnachname';
        if(
    $moduleParams->gw_tp_couplesorting == 'C')
        {
          
    // Nach Altersgruppen sortieren
          
    $fieldstartgruppe="''";
           foreach(array(
    'KIN I','KIN II''JUN I''JUN II''JUG''HGR''HGR II''SEN I''SEN II''SEN III''SEN IV') as $gruppe)
          {
            
    $fieldstartgruppe .= ",'".$gruppe."'";
          }

          
    $fieldstartklasse="''";
          foreach(array(
    '-''E','D''C''B''A''S''PRO''LL''OL''RL''2. BL''1. BL') as $klasse)
          {
            
    $fieldstartklasse .= ",'".$klasse."'";
          }

          
    $orderClause "FIELD(startgruppe,".$fieldstartgruppe."), FIELD(startklassestandard,".$fieldstartklasse."), FIELD(startklasselatein,".$fieldstartklasse."), partnernachname, partnerinnachname";
        }

        
    $arrPaare = array();

        
    $objPaare $this->Database->execute("SELECT * FROM tl_gw_turnierpaare " $whereClause "ORDER BY " $orderClause);

        while (
    $objPaare->next())
        {
          
    $newArr $this->obj2Arr($objPaare);

          if(
    strlen($objPaare->bild) == 0)
          {
            
    $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png';
          }
          else
          {
            
    $newArr['bild'] = $this->getImage($objPaare->bild'''48');
          }

          
    $arrPaare[] = $newArr;
        }

        
    $this->Template->paare $arrPaare;
      } 
    Bei der Ausgabe des Listentemplates hat sich nicht viel gegenüber dem letzten Schritt getan, nur die Utility-Funktion obj2Arr wird jetzt benutzt, um den Großteil der Felder aus der Datenbank ins Array zu packen. Als Paarbild wird ein Thumbnail von max. 48 Pixeln Höhe ausgegeben.

    PHP-Code:
      // Compiles the data for the turnierparliste_detail template
      
    protected function compileDetailTemplate()
      {
        
    $coupleRow $this->Database->prepare("SELECT * FROM tl_gw_turnierpaare WHERE id=?")
                ->
    limit(1)
                ->
    execute($this->Input->get($this->strDetailKey));

        
    $this->strTemplate 'gw_turnierpaarliste_detail';
        
    $this->Template = new FrontendTemplate($this->strTemplate);

        
    $newArr $this->obj2Arr($coupleRow);

        if(
    strlen($coupleRow->bild) == 0)
        {
          
    $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png';
        }
        else
        {
          
    $newArr['bild'] = $this->getImage($coupleRow->bild'180''');
          
    $newArr['bildfullsize'] = $coupleRow->bild;
        }

        
    $this->Template->paar $newArr;
      } 
    Hier die Ausgabe des Detail-Templates: Zunächst holen wir uns das Paar aus der Datenbank, dessen Detailseite ausgegeben werden soll. Hier wäre wohl zukünftig noch eine Fehlerabfrage ("ID existiert nicht") notwendig. *Hüstel*

    Dann müssen wir das andere Template wählen. Dafür ersetze ich den Namen durch den Neuen. Das alleine reichte aber nicht: Es erschien immer noch das alte Template, weil es schon initialisiert war, als compile() aufgerufen wurde.

    Eine Änderung von $strTemplate bleibt dann unbemerkt. Darum muss jetzt in der nächsten Zeile ein neues Frontendtemplate instanziert werden. Ich hätte den Namen auch direkt als Parameter bei der Instanzierung angeben können. Dann fülle ich mit obj2Arr() mein Paar-Array, und gebe (falls vorhanden) das Paarbild-Thumbnail mit maximal 180 Pixel Breite aus, und zusätzlich das Originalbild.

    Das Ergebnis ist das Folgende - Turnierpaarliste:


    Ich habe das Default-Bild noch ausgetauscht, das angezeigt wird, wenn kein Paarbild hinterlegt ist (Ich hänge es auch hier nochmal an). Das "richtige" Paarbild ist übrigens ein freies aus Wikimedia Commons.

    Nach Klick auf einen Detaillink:
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (13.04.2010 um 14:04 Uhr)

  10. #50
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 10: Etwas Feinschliff

    Einige Details will ich noch verbessern, bevor es endlich an die noch fehlenden Turniermeldungen geht.

    Insgesamt ist es ein Mischmasch von vielen Kleinigkeiten, die aber teilweise in mehreren Dateien Auswirkungen haben. Es könnte also chaotisch werden :-).

    Beginnen wir wir mit /system/modules/gw_turnierpaare/geTurnierpaarliste.php , der Klasse in der die Frontendtemplates gefüllt werden.
    PHP-Code:
    class gwTurnierpaarliste extends Module
    {

        
    /**
         * Template
         * @var string
         */
        
    protected $strTemplate 'gw_turnierpaarliste';

        protected 
    $strDetailTemplate 'gw_turnierpaarliste_detail';

        protected 
    $strDetailErrorTemplate 'gw_turnierpaarliste_error';


      public static 
    $strDetailKey 'info';
      
      public static 
    $StartGruppen = array('KIN I','KIN II''JUN I''JUN II''JUG''HGR''HGR II''SEN I''SEN II''SEN III''SEN IV');
      
      public static 
    $StartKlassen = array('-''E','D''C''B''A''S''PRO''LL''OL''RL''2. BL''1. BL'); 
    Zunächst definiere ich mir neben meinem "Defaulttemplate" noch einen Templatenamen für die Detailansicht, und ein "Error-Template", das angezigt wird, wenn das für die Detailansicht gewünschte Tanzpaar nicht gefunden wird.

    Dann folgen 3 statische Variablendeklarationen, dies sind also Klassenvariablen. Die werde ich Klassenübergreifend nutzen, weil die entsprechenden Einträge in mehreren Files genutzt werden, und ich sie nur an einer Stelle editieren möchte. $strDetailKey benötigen wir im Listentemplate, die beiden anderen Variablen im DCA-Record für die Tabelle tl_gw_turnierpaare und für die sortierte Ausgabe nach Startgruppe und -klasse.

    Hier verwenden wir sie dann auch (Funktion compileListTemplate()):
    PHP-Code:
    ...
          
    // Nach Altersgruppen sortieren
          
    $fieldstartgruppe="''";
           foreach(
    gwTurnierpaarliste::$StartGruppen as $gruppe)
          {
            
    $fieldstartgruppe .= ",'".$gruppe."'";
          }

          
    $fieldstartklasse="''";
          foreach(
    gwTurnierpaarliste::$StartKlassen as $klasse)
          {
            
    $fieldstartklasse .= ",'".$klasse."'";
          }
    ... 
    Und auch die Verwendung von §strDetailKey wird angepasst:
    PHP-Code:
    ...
            if ( 
    strlen($this->Input->get(gwTurnierpaarliste::$strDetailKey)) )
    ... 
    Im DCA-Record für die Felder startgruppe, startklasselatein und startklassestandard sinngemäß (Datei /system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php):
    PHP-Code:
    ...
            
    'startgruppe' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe'],
                
    'inputType'               => 'select',
                
    'sorting'                 => true,
                
    'options'                 => gwTurnierpaarliste::$StartGruppen,
                
    'eval'                    => array('mandatory'=>false'includeBlankOption' => true)
            ),
            
    'startklasselatein' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein'],
                
    'inputType'               => 'select',
                
    'sorting'                 => true,
                
    'options'                 => gwTurnierpaarliste::$StartKlassen,
                
    'eval'                    => array('mandatory'=>true'tl_class' => 'w50')
            ),
            
    'startklassestandard' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklassestandard'],
                
    'inputType'               => 'select',
                
    'sorting'                 => true,
                
    'options'                 => gwTurnierpaarliste::$StartKlassen,
                
    'eval'                    => array('mandatory'=>true)
            ),
    ... 
    und schließlich noch im Template für die Übersichtsliste /system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl:
    PHP-Code:
    ...
      <td><?php echo '<a href="/{{env::page_alias}}/'.gwTurnierpaarliste::$strDetailKey.'/'.$paar['alias'].'.html">Detail</a>'?>
    ...
    Hier benutzen wir auch das Insert-Tag {{env:age_alias}}, um den Seitenalias nicht wie bisher hart im Template kodiert zu haben. Das funktioniert jetzt, egal wie die Seite heißt, auf der das Frondendmodul eingebunden wird.

    Hier sieht man auch noch eine andere Änderung: $paar['alias']. Ich möchte die Detailseite nicht nur über die numerische ID des Paares aufrufen können, sondern eleganter über einen Seitenalias, z.b. /turnierpaarliste/info/mueller.html .

    Dafür definiere ich ein neues varchar(128)-Feld in der tl_gw_turnierpaare-Tabelle (/system/modules/gw_turnierpaare/config/database.sql):
    Code:
    ...
      `partnerinvorname` varchar(64) NULL default NULL,
      `alias` varchar(128) NOT NULL default '',
      `startgruppe` varchar(32) NOT NULL default '',
    ...
    Die Definitionen für den DCA-Record klaue ich mir bei tl_article.php aus dem Backend (/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php):
    PHP-Code:
    ...
            
    'alias' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['alias'],
                
    'exclude'                 => true,
                
    'inputType'               => 'text',
                
    'eval'                    => array('rgxp'=>'alnum''doNotCopy'=>true'spaceToUnderscore'=>true'maxlength'=>128'tl_class'=>'w50'),
                
    'save_callback' => array
                (
                    array(
    'tl_gw_turnierpaare''generateAlias')
                )
        ),
    ... 
    In die Palette tragen wir das Feld auch noch ein, damit es manuell editierbar bleibt:
    PHP-Code:
        // Palettes
        
    'palettes' => array
        (
            
    '__selector__'                => array('resetpassword'),
            
    'default'                     => '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname,alias;'
                                          
    .'{classes_legend},startgruppe,startklasselatein,startklassestandard;'
    ... 
    Und wir müssen den Callback schreiben
    PHP-Code:
      /**
       * Generate alias from couples names
       */
        
    public function generateAlias($varValueDataContainer $dc)
        {
            
    $autoAlias false;

            
    // Generate alias if there is none
            
    if (!strlen($varValue))
            {
                
    $autoAlias true;
                
    $key $dc->activeRecord->partnernachname;
                if(
    strlen($dc->activeRecord->partnerinnachname) > && strcmp($dc->activeRecord->partnernachname,$dc->activeRecord->partnerinnachname))
                {
            
    $key $key.'_'.$dc->activeRecord->partnerinnachname;
          }
                
    $varValue standardize($key);
            }

            
    $objAlias $this->Database->prepare("SELECT id FROM tl_gw_turnierpaare WHERE id=? OR alias=?")
                                       ->
    execute($dc->id$varValue);

            
    // Check whether the page alias exists
            
    if ($objAlias->numRows 1)
            {
                if (!
    $autoAlias)
                {
                    throw new 
    Exception(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $varValue));
                }

                
    $varValue .= '-' $dc->id;
            }

            return 
    $varValue;
        } 
    Der Seitenalias ist nachnameherr_nachnamedame, wenn die Nachnamen verschieden sind, falls sie gleich sind nur nachname. Ein Paar Müller/Schulze wäre also mueller_schulze, ein Ehepaar Maier nur maier. Das ganze wird mit einer eingebauten TL-Funktion standardisiert. Sollte der Alias schon existieren (eher unwahrscheinlich), dann wird die ID hintenan gehängt. Das ist 1:1 so wie bei Seitenaliasen in TL auch.

    Im Frontendmodul /system/modules/gw_turnierpaare/gwTurnierpaarliste.php erfolgen dafür nun auch noch Anpassungen. Zunächst in der Funktion obj2Arr, damit das neue Feld auch im Template zur Verfügung steht:
    PHP-Code:
    ...
            
    'id' => $objPaar->id,
            
    'alias' => $objPaar->alias,
            
    'beschreibung' => $objPaar->beschreibung,
    ... 
    und schließlich in compileDetailTemplate:
    PHP-Code:
      // Compiles the data for the turnierparliste_detail template
      
    protected function compileDetailTemplate()
      {
        
    $coupleRow $this->Database->prepare("SELECT * FROM tl_gw_turnierpaare WHERE id=? OR alias=?")
                ->
    limit(1)
                ->
    execute($this->Input->get(self::$strDetailKey),$this->Input->get(self::$strDetailKey));

        if(
    $coupleRow->numRows == 0)
        {
              
    $this->Template = new FrontendTemplate($this->strDetailErrorTemplate);
        }
        else
        {
          
    $this->Template = new FrontendTemplate($this->strDetailTemplate);

          
    $newArr $this->obj2Arr($coupleRow);

          if(
    strlen($coupleRow->bild) == 0)
          {
            
    $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png';
          }
          else
          {
            
    $newArr['bild'] = $this->getImage($coupleRow->bild'180''');
            
    $newArr['bildfullsize'] = $coupleRow->bild;
          }

          
    $this->Template->paar $newArr;
        }
      } 
    Hier wird entweder nach ID oder nach Alias gesucht. Aufruf der Detailseite würde also sowohl über /info/12.html als auch info/mueller.html funktionieren. Wird kein Datensatz mit dieser ID gefunden, wird das Error-Template ausgegeben, ansonsten wie üblich der Detail-Datensatz.

    Schließlich noch das sehr simple neue Template system/modules/gw_turnierpaare/templates/gw_turnierpaarliste_error.tpl:
    PHP-Code:
    <div class="<?php echo $this->class?> block paarvisitenkarte"<?php echo $this->cssID?>
    <?php 
    if ($this->style): ?> style="<?php echo $this->style?>"<?php endif; ?>>

    <h3>Dieses Paar existiert leider nicht!</h3>

    Da sich rein optisch außer einem Extra Feld im Backend für den Alias nichts getan hat, verzichte ich in diesem Schritt auf Screenshots. Leider ging es auch etwas kreuz und quer mit kleinen Änderungen in mehreren Dateien. Ich hoffe trotzdem man konnte noch folgen...

  11. #51
    Contao-Nutzer Avatar von Jürgen
    Registriert seit
    24.06.2009.
    Ort
    Mühlheim
    Beiträge
    40

    Daumen hoch Vielen Dank

    Super Tutorial, vielen Dank für die ganze Arbeit.

    Eine Frage zu der Demoanwendung am Anfang. Diese habe ich installiert und das Backend funktioniert auch gut. Nur das erstellen eines Moduls macht mir Schwierigkeiten. Da scheint Typolight sich aufzuhängen. Der Bildschirm bleibt einfach weiß.

    Mach ich da irgendeinen Fehler?

    LG
    Jürgen

  12. #52
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Hmmm....komisch. Klingt nach einem PHP-Fehler o.ä.

    Ich teste das hochgeladene Archiv mal, vielleicht ist da beim Packen was schiefgegangen.

    Stefan

  13. #53
    Contao-Fan Avatar von Wichteldesign
    Registriert seit
    23.06.2009.
    Ort
    Nürtingen
    Beiträge
    353

    Standard

    Hi,

    ich fange gerade endlich mal an mich weitergehend mit der Modulentwicklung zu beschäftigen. Dein Tagebuch macht wirklich Mut auf mehr. Habs gerade von Anfang bis zum Ende durchgelesen und bin begeistert. Einfach mal Danke!

    Gruß Felix
    Besten Gruß, Felix Peters
    Wichteldesign // Github // @wichteldesign // @el_wichtel

  14. #54
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von Jürgen Beitrag anzeigen
    Super Tutorial, vielen Dank für die ganze Arbeit.

    Eine Frage zu der Demoanwendung am Anfang. Diese habe ich installiert und das Backend funktioniert auch gut. Nur das erstellen eines Moduls macht mir Schwierigkeiten. Da scheint Typolight sich aufzuhängen. Der Bildschirm bleibt einfach weiß.

    Mach ich da irgendeinen Fehler?

    LG
    Jürgen
    Hallo Jürgen,

    ich habs nochmal getestet, und bei mir funktioniert Alles. Hast du eine Möglichkeit, irgendwie an einen möglichen PHP-Fehler ranzukommen? Zugriff auf error.log o.ä.? Fehlermeldungen in der TL-Config zugelassen?

    Stefan

  15. #55
    Contao-Nutzer Avatar von Jürgen
    Registriert seit
    24.06.2009.
    Ort
    Mühlheim
    Beiträge
    40

    Standard Merci

    Zitat Zitat von dl1ely Beitrag anzeigen
    Hallo Jürgen,

    ich habs nochmal getestet, und bei mir funktioniert Alles. Hast du eine Möglichkeit, irgendwie an einen möglichen PHP-Fehler ranzukommen? Zugriff auf error.log o.ä.? Fehlermeldungen in der TL-Config zugelassen?

    Stefan
    Hallo Stefan,
    schon mal vielen Dank und sorry das ich dir jetzt noch Arbeit mache. Ich hab es local unter winxp pro oder win7 pro unter xampp laufen.
    Ich hab mal displayErrors aktiviert und als erstes kommt die Fehlermeldung

    Warning: Cannot modify header information - headers already sent by (output started at G:\xampplite\htdocs\test\system\modules\gw_turnier paare\dca\tl_module.php:32) in G:\xampplite\htdocs\test\system\libraries\Template .php on line 174
    Hilft das dir weiter?

    Grüße
    Jürgen

  16. #56
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Jürgen,

    bitte öffne /system/modules/gw_turnierpaare/dca/tl_module.php in einem Editor. Zeilen 31 und 32 sind Leerzeilen, bitte entferne die. Die letzte Zeile muss Zeile 30 mit "?>" sein.

    Ich denke, daran wird es liegen. Ich vermute, das hängt mit den unterschiedlichen Zeilenumbrüchen bei Linux/Windows zusammen, bei mir tritt das Problem zumindest nicht auf. Dadurch werden wohl zwei Leerzeilen ausgegeben, bevor dann in Zeile 174 von system/libraries/Template.php der Header für die Seite gesetzt wird. Das schlägt dann natürlich fehl. In Zukunft werde ich mehr auf die Leerzeilen-Problematik achten. In der nächsten "Version" des Quelltexts wird das behoben sein.

    Danke an lindesbs für den Tipp.


    Stefan

  17. #57
    Contao-Nutzer Avatar von Jürgen
    Registriert seit
    24.06.2009.
    Ort
    Mühlheim
    Beiträge
    40

    Daumen hoch Das wars

    Merci jetzt funktionierts. Was so ein paar Leerzeichen bewirken können. Wieder was gelernt.

    Viele Grüße
    Jürgen

  18. #58
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Hi!

    Ja, ich habe auch was dabei gelernt...So habe ich auch was von dem Tutorial :-)

    Stefan

  19. #59
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 11: Die zweite Tabelle

    Ich habe mich lange davor gedrückt, aber jetzt muss es an meine zweite Tabelle gehen: tl_gw_meldungen.

    Meldungen sind Teilnahmen von Turnierpaaren an Turnieren. Sie bestehen aus dem Datum der Turnierteilnahme, dem Ort, der Startgruppe (Altersklasse) und der Startklasse (aus Regeltechnischen Gründen müssen die NICHT zwingend mit den entsprechenden Werten, die beim Turnierpaar eingetragen sind übereinstimmen), der Tanzart (Standard/Lateinamerikanisch), der Turnierart (Hier unterscheidet man "offene Turniere", "Einladungsturniere", "Landesmeisterschaften", "Deutsche Meisterschaften" usw), der Anzahl der gestarteten Paare, dem Platz (Da es geteilte Plätze wie 5.-7. geben kann gibt es "platz_von" und "platz_bis"), und einem Freitext als Bemerkung.

    Soviel zur Domain specific knowledge.

    Schauen wir uns nochmal die SQL-Definition in config/database.sql an:
    Code:
    -- 
    -- Table `tl_gw_meldungen`
    -- 
    
    CREATE TABLE `tl_gw_meldungen` (
      `id` int(10) unsigned NOT NULL auto_increment,
      `pid` int(10) unsigned NOT NULL default '0',
      `sorting` int(10) unsigned NOT NULL default '0',
      `tstamp` int(10) unsigned NOT NULL default '0',
      `datum` date NOT NULL default '2000-01-01',
      `startgruppe` varchar(32) NOT NULL default '',
      `startklasse` varchar(12) NOT NULL default '',
      `lat_std` char(32) NOT NULL default '',
      `turnierort` varchar(128) NOT NULL default '',
      `turnierart` varchar(64) NULL default NULL,
      `anzahlpaare` int(4) NULL default NULL,
      `platz_von` int(4) NULL default NULL,
      `platz_bis` int(4) NULL default NULL,
      `bemerkung` text NULL,
      PRIMARY KEY  (`id`),
      KEY `pid` (`pid`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    Die ersten 4 Felder sind ja so "default". Hier macht pid (Parent-ID) aber auch Sinn. Die Meldungen sind "Childs" der Turnierpaare. Im Backend wollte ich auch so vorgehen, also bei den Turnierpaaren auf einen Tree-View umstellen. Im DCA-Record für tl_gw_turnierpaare habe ich also unter "sort" den "mode" auf 5 gestellt, und im DCA-Record für tl_gw_meldungen auf 6.

    Dann straft mich TYPOlight aber mit der SQL-Fehlermeldung, dass es in der Tabelle tl_gw_turnierpaare kein Feld "pid" gäbe. Richtig, gibt es auch nicht. Da das die Parent-Tabelle ist, braucht die auch kein "pid". Nun gut, offensichtlich erfordert die Logik das so, also erfülle ich den Wunsch und spendiere auch tl_gw_turnierpaare ein Feld "pid".

    Beim Betrachten im Backend fällt mir aber auf, dass das unpraktisch ist: Der Sportwart, der das im Backend pflegt, den interessiert nur die nach dem Turnierdatum sortierte Liste, neueste ganz oben. Der will gar nicht erst das Turnierpaar suchen, um dort eine Meldung einzugeben.

    Ich entscheide mich, Turnierpaare und Meldungen im Backend getrennt zu verwalten, aber bei den Meldungen dann eine foreign-key-Beziehung über die pid zur Turnierpaartabelle zu haben. Wenn der Sportwart eine neue Meldung anlegt, soll er über ein Dropdown das Turnierpaar auswählen, zu dem diese Meldung gehört, die Liste selbst soll aber nach dem Datum absteigend sortiert sein.

    Ich brauche also eine weitere Seite im Backend, und modifiziere /system/modules/gw_turnierpaare/config/config.php auf:
    PHP-Code:
    // Back end module
    $GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array
    (
        
    'tables' => array('tl_gw_turnierpaare'),
        
    'icon'   => 'system/modules/gw_turnierpaare/icons/turnierpaare.png'
    );

    $GLOBALS['BE_MOD']['content']['gw_meldungen'] = array
    (
        
    'tables' => array('tl_gw_meldungen'),
        
    'icon'   => 'system/modules/gw_turnierpaare/icons/meldeliste.png'
    ); 
    Also zwei hier formal getrennte Tabellen mit getrennten Backendseiten und verschiedenen Icons (meldeliste.png hänge ich hier an, das soll ein Siegerpodest darstellen).

    Dann gehts an DCA für die Meldungstabelle, in /system/modules/gw_turnierpaare/dca/tl_gw_meldungen.php:
    PHP-Code:
    /**
     * Table tl_gw_meldungen 
     */
    $GLOBALS['TL_DCA']['tl_gw_meldungen'] = array
    (

        
    // Config
        
    'config' => array
        (
            
    'dataContainer'               => 'Table',
            
    'enableVersioning'            => true,
        ), 
    Hier keine Besonderheiten, es ist eine Tabelle mit Versionierung...

    PHP-Code:
        // List
        
    'list' => array
        (
            
    'sorting' => array
            (
                
    'mode'                    => 1,
                
    'fields'                  => array('datum DESC''turnierort'),
                
    'panelLayout'             => '',
                
    'flag'                    => 8,
            ), 
    Sortierung nach festem Feld, nämlich dem absteigenden Datum, und dann nach dem Turnierort alphabetisch. Das Panel für Sortieren, Filtern usw lasse ich erstmal weg (Das sorgte nämlich für eine kryptische Fehlermeldung - ich kümmere mich später darum). flag 8 ist das absteigende Sortieren nach dem Monat. Zu meinem Problem damit komme ich später.

    PHP-Code:
            'label' => array
            (
                
    'fields'                  => array('datum''turnierort''turnierart''startgruppe','startklasse','lat_std','pid'),
                
    'format'                  => '<span style="font-weight: bold;">%s</span>, %s (%s), %s %s %s - %s'
            
    ), 
    Hier bastele ich mir die Ausgabezeile, mit dem Datum in fett, dann dem Ort, der Turnierart, Startgruppe und Klasse und der Info, ob Standard oder Lateinamerikanisch. Dann müsste dort eigentlich noch der Name des Tanzpaares hin, aber der steht ja nicht (direkt) in der Tabelle, sondern nur die pid. Darum nehme ich erstmal die - besser als Nix. Ich vermute, ich muss/kann da mit einem Label-Callback arbeiten und die pid selbst in die Namen auflösen.

    PHP-Code:
            'global_operations' => array
            (
                
    'all' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['MSC']['all'],
                    
    'href'                => 'act=select',
                    
    'class'               => 'header_edit_all',
                    
    'attributes'          => 'onclick="Backend.getScrollOffset();"'
                
    )
            ),
            
    'operations' => array
            (
                
    'edit' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit'],
                    
    'href'                => 'act=edit',
                    
    'icon'                => 'edit.gif'
                
    ),
                
    'copy' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy'],
                    
    'href'                => 'act=copy',
                    
    'icon'                => 'copy.gif'
                
    ),
                
    'delete' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'],
                    
    'href'                => 'act=delete',
                    
    'icon'                => 'delete.gif',
                    
    'attributes'          => 'onclick="if (!confirm(\'' $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();"'
                
    ),
                
    'show' => array
                (
                    
    'label'               => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['show'],
                    
    'href'                => 'act=show',
                    
    'icon'                => 'show.gif'
                
    )
            )
        ), 
    Hier bleibt erstmal alles so, wie vom Extension Creator vorgegeben.

    PHP-Code:
        // Palettes
        
    'palettes' => array
        (
            
    '__selector__'                => array(''),
            
    'default'                     => '{couple_legend},pid;{tournament_legend},datum,turnierort,turnierart,startgruppe,startklasse,lat_std;'
                                        
    .'{result_legend},anzahlpaare,platz_von,platz_bis,bemerkung;'
        
    ),

        
    // Subpalettes
        
    'subpalettes' => array
        (
            
    ''                            => ''
        
    ), 
    Auch hier nichts spannendes: Eine normale Palette für alle Felder.

    PHP-Code:
        // Fields
        
    'fields' => array
        (
            
    'pid' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'],
                
    'inputType'               => 'select',
                
    'foreignKey'              => 'tl_gw_turnierpaare.partnernachname',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'eval'                    => array('mandatory'=>true)
            ), 
    pid soll ein Foreign Key in die Turnierpaare-Tabelle sein. mir der foreignKey-Option wird das Dropdown-Feld mit den Partnernachnamen aus der Turnierpaar-Tabelle gefüllt. Zum ersten Testen ist das ganz OK, aber eigentlich stelle ich mir das anders vor: Es sollen dort nur AKTIVE Paare auswählbar sein, und ich hätte dort gerne die kompletten Namen des Turnierpaares stehen, nicht nur den Nachnamen des Herrn. Auch da wird wohl ein Callback hermüssen - später.

    PHP-Code:
            'datum' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'],
                
    'inputType'               => 'text',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 11,
                
    'eval'                    => array('mandatory'=>true'datepicker'=>$this->getDatePickerString(), 'tl_class'=>'w50 wizard''minlength' => 1'maxlength'=>64'rgxp' => 'date')
            ), 
    Abgeguckt beim DCA-Record für Artikel: Das Datumsfeld. Insbesondere den getDatePickerString() verstehe ich nicht - muss ich aber auch erstmal nicht. Kommt Zeit, kommt Erleuchtung.

    PHP-Code:
            'turnierort' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'],
                
    'inputType'               => 'text',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 1,
                
    'eval'                    => array('mandatory'=>true'minlength' => 1'maxlength'=>128'tl_class' => 'w50')
            ), 
    Nichts Besonderes hier...

    PHP-Code:
            'turnierart' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'],
                
    'inputType'               => 'select',
                
    'sorting'                 => false,
                
    'options'                 => gwTurnierpaarliste::$TurnierArten,
                
    'eval'                    => array('mandatory'=>false'includeBlankOption' => true'tl_class' => 'w50')
            ), 
    Ähnlich wie bei den Startgruppen und Klassen lagere ich die Optionen für "Turnierart" in meine Frontendklasse aus. Gefällt mir besser so, und ich kann es "Re-usen".

    PHP-Code:
            'startgruppe' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'],
                
    'inputType'               => 'select',
                
    'sorting'                 => true,
                
    'flag'                    => 1,
                
    'options'                 => gwTurnierpaarliste::$StartGruppen,
                
    'eval'                    => array('mandatory'=>false'includeBlankOption' => true'tl_class' => 'w50')
            ),
            
    'startklasse' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'],
                
    'inputType'               => 'select',
                
    'sorting'                 => false,
                
    'options'                 => gwTurnierpaarliste::$StartKlassen,
                
    'eval'                    => array('mandatory'=>true'tl_class' => 'w50')
            ),
            
    'lat_std' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'],
                
    'inputType'               => 'select',
                
    'sorting'                 => false,
                
    'options'                 => gwTurnierpaarliste::$TanzArten,
                
    'eval'                    => array('mandatory'=>true'tl_class' => 'w50')
            ), 
    Wie zuvor, normale Dropdownfelder, deren Optionen ich in der Frontendklasse gwTurnierpaarliste ablege, um sie von verschiedenen Bereichen aus nutzen zu können.

    PHP-Code:
            'anzahlpaare' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'],
                
    'inputType'               => 'text',
                
    'eval'                    => array('mandatory'=>false'minlength' => 1'maxlength'=>4'rgxp' => 'digit')
            ),
            
    'platz_von' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'],
                
    'inputType'               => 'text',
                
    'eval'                    => array('mandatory'=>false'minlength' => 1'maxlength'=>4'rgxp' => 'digit''tl_class' => 'w50')
            ),
            
    'platz_bis' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'],
                
    'inputType'               => 'text',
                
    'eval'                    => array('mandatory'=>false'minlength' => 1'maxlength'=>4'rgxp' => 'digit''tl_class' => 'w50')
            ),
            
    'bemerkung' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'],
                
    'inputType'               => 'textarea',
                
    'eval'                    => array('mandatory'=>false'cols' => 80'rows' => 20'allowHtml' => false)
            ),
        )
    ); 
    Auch hier eigentlich "Hausmannskost": 3 Felder für Zahlen und ein Textfeld für die Bemerkung.

    /system/modules/gw_turnierpaare/gwTurnierpaarliste.php (das Frontend-Modul) erweitere ich noch um die Optionenlisten für Tanzart und Turnierart:
    PHP-Code:
      public static $TurnierArten = array('-''OT','ET''LM''DM''EM''WM');
      
      public static 
    $TanzArten = array('-''Std','Lat'); 
    Zum ersten Testen füge ich zwei Testdatensätze in die Meldungstabelle ein. Ergebnis:


    Gut, die Tabellenheader sehen noch nicht so aus wie gewünscht, aber das ist Feinschliff. Die gewünschten Informationen (mit pid 7) werden angezeigt.

    Wenn ich einen neuen Eintrag hinzufüge, sieht das so aus:


    Durch das Fehlen der Language-Einträge natürlich noch sehr unschön, aber alle Felder sind da. Die Foreign-Key-Beziehung in die Turnierpaar-Tabelle klappt (rudimentär) auch.
    Mich wundert der "20.12.2000" als Default im Datumsfeld, aber ich habe auch keinen Default vorgegeben. Es wäre wohl praktisch, durch einen Load-Callback das aktuelle Datum dort als Default vorzugeben.

    Ich gebe also mal Daten ein:


    Und drücke auf Speichern- was sehe ich beim Datum:


    30.11.1999? Das habe ich im Datepicker aber nicht ausgewählt....auch eine manuelle Eingabe sorgt für das selbe 1999er-Ergebnis.

    Und in der Übersichtstabelle dann das:


    0000-00-00...hm.

    Das ist alles nicht so ermutigend. Ich habe die Konfiguration für das Datumsfeld bei tl_article.php abgeschaut, da funktioniert ja auch alles.

    Erstmal Pause, demnächst geht es weiter.

    Stefan
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (13.04.2010 um 14:02 Uhr)

  20. #60
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Bevor noch mehr Leute da Zeit reinstecken: Das Problem bei meinem Datumsfeld ist einfach, dass ich instinktiv in MYSQL ein "date"-Feld angelegt habe. Es muss aber ein varchar(10) sein. Logisch ist das nicht. Also bitte keine weiteren Hinweise zur Fehlerbehebung, lindesbs war der Schnellste, danke :-).

    Hätte ich mehr Zeit gehabt, hätte ich mir selbst mal die DB-Struktur von tl_article angeschaut, um den Unterschied zu finden, Aber Zeit ist gerade knapp, und ich wollte endlich die nächste "Folge" rausschicken. Im nächsten Schritt wird das Datumsfeld also voraussichtlich hervorragend funktionieren, indem wir es in ein "varchar(10)" verwandeln :-).

    Stefan

  21. #61
    Contao-Fan Avatar von deerwood
    Registriert seit
    24.11.2009.
    Ort
    Hamburg
    Beiträge
    344

    Standard

    Hi Stefan,

    Abgeguckt beim DCA-Record für Artikel: Das Datumsfeld.
    Ich habe gerade mal schnell gecheckt: DB Datentyp DATE() wird in TL offenbar nirgendwo verwendet, alle Felder, die im DCA den DatePicker verwenden, haben in der DB den Datentyp VARCHAR(10) (bis auf tl_news.date, das ist merkwürdigerweise INT(10) ). Vielleicht ist das das Problem?

    Edit: Sorry, habe nicht schnell genug gecheckt/getippt.

    LG, Georg

  22. #62
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Ja, ich vermute sehr stark, dass das das Problem ist. Habe es einfach intuitiv (falsch) gemacht. Leider fehlte mir die Zeit, vorher "im Core" abzugucken. Eins habe ich sowieso schon gelernt: Das Einzige, auf was man sich in Sachen "TL-Entwickler-Doku" verlassen kann, ist der Core-Source ;-).

    EDIT: habe es schnell geändert und das Feld "datum" auf varchar(10) umgestellt. Jetzt klappt der Datepicker. Aber jetzt wird das Feld mit einem Unix-Timestamp gefüllt. Gebe ich das Feld also in meinen Tabellenzeilen aus oder als Sortierheader, steht dort nur Zahlenwust statt eines Datums. Ich wusste schon, warum ich lieber "date" haben wollte ;-). Ich kriege graue Haare. Da muss ich mir also definitiv noch was einfallen lassen...



    Stefan
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (13.04.2010 um 14:03 Uhr)

  23. #63
    Wandelndes Contao-Lexikon Avatar von BugBuster
    Registriert seit
    15.06.2009.
    Ort
    Berlin
    Beiträge
    10.513
    User beschenken
    Wunschliste

    Standard

    der Timestamp hat aber den Vorteil, das du diesen einfach wandeln kannst, genauer in die Form die der Nutzer im Backend (Einstellungen / Startseite) definiert hat.
    Mein Modul hat z.B. solch eine Zeile:

    PHP-Code:
    $VisitorsStartDate date($GLOBALS['TL_CONFIG']['dateFormat'],$objVisitors->visitors_startdate); 
    $objVisitors->visitors_startdate ist hier der Timestamp aus der DB.
    Grüße, BugBuster
    "view source" is your guide.
    Danke an alle Amazon Wunschlisten Erfüller

  24. #64
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Sicherlich richtig, aber wenn ich per DCA-Record im Backend damit arbeiten will, z.b. als Sortier-, bzw. Gruppierfeld, dann habe ich nicht die Möglichkeit, dort ein "date()" zu injecten. Aber ich schaue mal weiter, was mit Callbacks geht und wie ich meiner Anforderung näherkomme. :-)

    Stefan

  25. #65
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard Herzlichen Dank und Hilfe

    Zuerst einmal herzichen Dank für dieses hervorragende Tutorial!!! So etwas habe ich mir schon sehr lange gewünscht.

    Ich versuche nun, nach Deiner Vorlage eine Verwaltung für unseren Vereinsbekleidungs-Verleih zu programmieren. Ich habe den Extension-Creator, die Datenbank-Einrichtung und die DCA-Programmierung fürs Erste recht gut hinbekommen und alle kleinen Fehler ziemlich schnell lokalisieren und beheben können. Ich arbeite auf einer lokalen Installation und habe die Fehlermeldung eingeschaltet.

    Wenn ich mich richtig erinnere, so kommt seitdem ich das language file "modules.php" angefasst habe, folgende Fehlermeldung:
    Warning: Cannot modify header information - headers already sent by (output started at mein_pfad\system\modules\to_bekleidungsverleih\languages\de \modules.php:1) in mein_pfad\system\libraries\Template.php on line 174

    #0 [internal function]: __error(2, 'Cannot modify h...', 'mein_pfad...', 174, Array)
    #1 mein_pfad\system\libraries\Template.php(174): header('Content-Type: t...')
    #2 mein_pfad\system\modules\backend\BackendTemplate.php(135): Template->output()
    #3 mein_pfad\typolight\main.php(286): BackendTemplate->output()
    #4 mein_pfad\typolight\main.php(102): Main->output()
    #5 mein_pfad\typolight\main.php(295): Main->run()
    #6 {main}
    Leider bin ich nun mit meinem Latein am Ende... Weiß jemand Rat?

  26. #66
    Contao-Urgestein Avatar von Toflar
    Registriert seit
    15.06.2009.
    Beiträge
    4.467
    Partner-ID
    8667
    User beschenken
    Wunschliste

    Standard

    Bei Dir ist irgend ein Zeichen vor der ersten php Anweisung Also wahrscheinlich " <?php" statt "<?php" oder sowas
    Contao Core-Entwickler @terminal42 gmbh
    Wir sind Contao Premium-Partner!
    Für Individuallösungen kannst du uns gerne kontaktieren.
    PS: Heute schon getrakked?

  27. #67
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard

    Wow! Das ging ja schnell...

    Ich habe in modules.php nachgesehen - leider ist dort kein Freizeichen. Auch in keiner anderen der von mir angefassten Dateien (soweit ich mich erinnern kann).

    Zu allem Überfluss bemerke ich gerade, dass beim Laden der Startseite des Backends folgender Fehler 2x vor dem o. g. Fehler gelistet wird:

    Warning: Illegal offset type in mein_pfad\typolight\main.php on line 183

    #0 mein_pfad\typolight\main.php(183): __error(2, 'Illegal offset ...', 'mein_pfad...', 183, Array)
    #1 mein_pfad\typolight\main.php(93): Main->welcomeScreen()
    #2 mein_pfad\typolight\main.php(295): Main->run()
    #3 {main}
    Wenn jemand noch was weiß...
    ...wär's toll!

  28. #68
    Administrator Avatar von xchs
    Registriert seit
    19.06.2009.
    Beiträge
    14.557
    User beschenken
    Wunschliste
    Contao-Projekt unterstützen

    Support Contao

    Standard

    Zitat Zitat von TLight Beitrag anzeigen
    ...leider ist dort kein Freizeichen. Auch in keiner anderen der von mir angefassten Dateien (soweit ich mich erinnern kann).
    Das kann aber unter Umständen auch ein verstecktes Zeichen sein, je nachdem welchen Editor Du verwendest (UTF-8 vs. UTF-8 BOM usw.)
    Contao Community Administrator

    [Unterstützungsmöglichkeiten]

  29. #69
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard

    Nein, leider nichts zu finden. Auch im stinknormalen Editor ist da kein Zeichen. Ich verwende UTF-8-Codierung, aber auch da konnte ich nichts finden...

  30. #70
    Contao-Urgestein Avatar von FloB
    Registriert seit
    19.06.2009.
    Ort
    Sonnensystem
    Beiträge
    1.618

    Standard

    Schau alle Dateien durch. Mit welchem Editor bearbeitest du die Dateien? Schau mal da nach eine Option bezüglich des BOM.

    Einen BOM "siehst" du eigentlich auch nur in einem Hex-Editor.
    So long,
    FloB since Nov. 2007 +706P +115P and counting

  31. #71
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von TLight Beitrag anzeigen
    Nein, leider nichts zu finden. Auch im stinknormalen Editor ist da kein Zeichen. Ich verwende UTF-8-Codierung, aber auch da konnte ich nichts finden...
    Hmm, es muss aber definitiv was mit modules.php, Zeile 1 zu tun haben.

    Wenn du magst, kannst du mir dein File schicken (zip, damit beim Versenden nix passiert), an stefan@fam-pfeiffer.de

    Stefan

  32. #72
    Contao-Nutzer Avatar von Jürgen
    Registriert seit
    24.06.2009.
    Ort
    Mühlheim
    Beiträge
    40

    Standard

    Ich hatte heute auch das Problem mit diesem Fehler. Wollte zwei Ankreuzfelder ergänzen. Hab dann die Codierung von UTF-8 auf UTF-8 ohne BOM umgestellt und siehe, da seit dem klappt es. Benutze das Notepad++ unter Windows.

    Wenn ich noch eine Frage stellen darf. Wenn ich calender_events um zwei Checkboxen erweitern möchte und das der Titel_legende zuweise wird ein Checkboxfeld verdoppelt und die Legende verschwindet. Erweitere ich aber z.B. die Publish_legende werden wie gewünscht nur zwei Felder angezeigt und auch die Legende bleibt erhalten.

    Mach ich da was falsch oder hat da TL ein Problem.

    Grüße
    Jürgen

  33. #73
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von TLight Beitrag anzeigen
    Wow! Das ging ja schnell...

    Ich habe in modules.php nachgesehen - leider ist dort kein Freizeichen. Auch in keiner anderen der von mir angefassten Dateien (soweit ich mich erinnern kann).

    Zu allem Überfluss bemerke ich gerade, dass beim Laden der Startseite des Backends folgender Fehler 2x vor dem o. g. Fehler gelistet wird:



    Wenn jemand noch was weiß...
    ...wär's toll!
    Hi!

    Schick mir mal bitte deine /lang/de/modules.php Sprachdatei (Oder zeige sie uns hier, die ist ja nicht so lang). Ich weiß ja nicht, ob du es genauso wie ich gemacht hast, aber ich bin über diesen Fehler auch gestolpert, aber das gehört zum nächsten Teil des Tagesbuchs. Und bevor wir hier in die falsche Richtung rennen, würde ich gerne sehen, wie diese Datei aussieht. Falls es "mein" Fehler ist, kann ich dir dann sagen woran es liegt ;-).

    Oder um es doch hier vorweg zu nehmen: Wenn du wie ich in der aktuellen Version dein(e) Backendmodul(e) unter eine eigene Obergruppe gesetzt hast (bei mir gw_paarverwaltung), dann darf der entsprechende Übersetzungseintrag $GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] NICHT ein Array sein (erster Eintrag Text fürs Menü, zweiter Eintrag der Erklärungstext), sondern einfach nur ein String, der den Menüeintrag darstellt. Das ist anders als bei den Einträgen für die Module selbst. Bei meinem Modul ist das jetzt so:

    PHP-Code:
    /**
     * Back end modules
     */
    $GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare''Verwaltung der Turnierpaare.');

    $GLOBALS['TL_LANG']['MOD']['gw_meldungen'] = array('Meldungen''Verwaltung der Turniermeldungen (Meldeliste).');

    $GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] = 'Paarverwaltung'
    Die letzte Zeil ist der Menüeintrag für die "Gruppe" im Backendmenü, die ersten beiden Einträge die Werte für meine beiden Backendmodule. Hatte auch für die "Gruppe" ein Array aus Menütext und Erklärungstext, und das brachte mir den von dir beschriebenen Fehler. Ist das dein Problem?

    Wie gesagt, bin noch nicht zum nächsten Tagebucheintrag gekommen, habe momentan leider zuviel um die Ohren.

    Stefan

  34. #74
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von Jürgen Beitrag anzeigen
    Wenn ich noch eine Frage stellen darf. Wenn ich calender_events um zwei Checkboxen erweitern möchte und das der Titel_legende zuweise wird ein Checkboxfeld verdoppelt und die Legende verschwindet. Erweitere ich aber z.B. die Publish_legende werden wie gewünscht nur zwei Felder angezeigt und auch die Legende bleibt erhalten.

    Mach ich da was falsch oder hat da TL ein Problem.

    Grüße
    Jürgen
    Mal ein Schuss ins Blaue: Macht dein str_replace für den Paletteneintrag wirklich das richtige? Check das lieber mal durch ein Debugging-Echo oder ähnlich. Beim richtigen str_replace() zur Modifikation der bestehenden Palette kann man sich böse vertun.

    Stefan

  35. #75
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    OK, hier Kommando zurück. Der von mir beschriebene Fehler kann erst zuschlagen, wenn man eine Modifikation der /config/config.php macht, die ich bisher hier noch gar nicht beschrieben habe, sondern die erst in der nächsten Tagebuchfolge erscheint. Wenn du also bisher alles so gemacht hast wie ich, kann es nicht dein Problem sein. Trotzdem hat das Problem definitiv mit falschen Einträgen in den Language-Dateien (und zwar modules.php) zu suchen. Entweder hast du irgendwo ein Array, wo ein String erwartet wird, oder umgekehrt.

    Falls du es selbst nicht findest, bitte deine config/config.php und language/de/modules.php zu mir, dann schaue ich mir das an.

    Sorry für die Verwirrung, das ist das Problem, wenn der eigentliche Code schon einen Schritt weiter ist als die aktuelle Tagebuchberichterstattung...

    Stefan


    Zitat Zitat von dl1ely Beitrag anzeigen
    Hi!

    Schick mir mal bitte deine /lang/de/modules.php Sprachdatei (Oder zeige sie uns hier, die ist ja nicht so lang). Ich weiß ja nicht, ob du es genauso wie ich gemacht hast, aber ich bin über diesen Fehler auch gestolpert, aber das gehört zum nächsten Teil des Tagesbuchs. Und bevor wir hier in die falsche Richtung rennen, würde ich gerne sehen, wie diese Datei aussieht. Falls es "mein" Fehler ist, kann ich dir dann sagen woran es liegt ;-).

    Oder um es doch hier vorweg zu nehmen: Wenn du wie ich in der aktuellen Version dein(e) Backendmodul(e) unter eine eigene Obergruppe gesetzt hast (bei mir gw_paarverwaltung), dann darf der entsprechende Übersetzungseintrag $GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] NICHT ein Array sein (erster Eintrag Text fürs Menü, zweiter Eintrag der Erklärungstext), sondern einfach nur ein String, der den Menüeintrag darstellt. Das ist anders als bei den Einträgen für die Module selbst. Bei meinem Modul ist das jetzt so:

    PHP-Code:
    /**
     * Back end modules
     */
    $GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare''Verwaltung der Turnierpaare.');

    $GLOBALS['TL_LANG']['MOD']['gw_meldungen'] = array('Meldungen''Verwaltung der Turniermeldungen (Meldeliste).');

    $GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] = 'Paarverwaltung'
    Die letzte Zeil ist der Menüeintrag für die "Gruppe" im Backendmenü, die ersten beiden Einträge die Werte für meine beiden Backendmodule. Hatte auch für die "Gruppe" ein Array aus Menütext und Erklärungstext, und das brachte mir den von dir beschriebenen Fehler. Ist das dein Problem?

    Wie gesagt, bin noch nicht zum nächsten Tagebucheintrag gekommen, habe momentan leider zuviel um die Ohren.

    Stefan

  36. #76
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard

    Vielen Dank für die zahlreichen Hilfsangebote!

    @dl1ely: wahrscheinlich habe ich genau den von Dir beschriebenen Fehler gemacht!

    /config/config.php:
    PHP-Code:
    $GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_magazin'] = array
    (
        
    'tables' => array('tl_to_bkvs_magazin'),
        
    'icon'   => 'system/modules/to_bekleidungsverleih/icons/trikot.png'
    ); 
    $GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_verleih'] = array
    (
        
    'tables' => array('tl_to_bkvs_verleih'),
        
    'icon'   => 'system/modules/to_bekleidungsverleih/icons/trikot.png'
    ); 
    /languages/de/modules.php:
    PHP-Code:
    /**
     * Back end modules
     */
    $GLOBALS['TL_LANG']['MOD']['to_bekleidungsverleih'] = array('Bekleidungsverleih''');
    $GLOBALS['TL_LANG']['MOD']['to_magazin']            = array('Magazin''');
    $GLOBALS['TL_LANG']['MOD']['to_verleih']            = array('Verleih'''); 
    Leider habe ich Deine Lösung nicht ganz verstanden. Aber ich warte einfach auf Deinen neuen Tagebucheintrag. Will Dir nicht noch mehr Arbeit machen als Du eh schon hast.

    Vielen Dank!

  37. #77
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard

    Wenn ich die /languages/de/modules wie folgt ändere:
    PHP-Code:
    /**
     * Back end modules
     */
    $GLOBALS['TL_LANG']['MOD']['to_bekleidungsverleih'] ='Bekleidungsverleih';
    $GLOBALS['TL_LANG']['MOD']['to_magazin']            = array('Magazin''');
    $GLOBALS['TL_LANG']['MOD']['to_verleih']            = array('Verleih'''); 
    verschwinden zwar die zwei Fehler der Startseite und das Modul wird in der Mittelspalte angezeigt:
    Warning: Illegal offset type in mein_pfad\typolight\main.php on line 183

    #0 mein_pfad\typolight\main.php(183): __error(2, 'Illegal offset ...', 'mein_pfad...', 183, Array)
    #1 mein_pfad\typolight\main.php(93): Main->welcomeScreen()
    #2 mein_pfad\typolight\main.php(295): Main->run()
    #3 {main}
    Der Ursprungsfehler bleibt aber:
    Warning: Cannot modify header information - headers already sent by (output started at mein_pfad\system\modules\to_bekleidungsverleih\lan guages\de \modules.php:1) in mein_pfad\system\libraries\Template.php on line 174

    #0 [internal function]: __error(2, 'Cannot modify h...', 'mein_pfad...', 174, Array)
    #1 mein_pfad\system\libraries\Template.php(174): header('Content-Type: t...')
    #2 mein_pfad\system\modules\backend\BackendTemplate.p hp(135): Template->output()
    #3 mein_pfad\typolight\main.php(286): BackendTemplate->output()
    #4 mein_pfad\typolight\main.php(102): Main->output()
    #5 mein_pfad\typolight\main.php(295): Main->run()
    #6 {main}
    ??? Ratlosigkeit - Bin schon gespannt, wie's weitergeht...
    Angehängte Dateien Angehängte Dateien

  38. #78
    Contao-Nutzer Avatar von TLight
    Registriert seit
    30.06.2009.
    Ort
    bei München
    Beiträge
    168

    Standard --> gelöst!!!

    Bevor sich nun zu viele mit meinem Problem beschäftigen, hier die Lösung:

    Habe meine Dateien in Notepad++ in UTF-8 ohne BOM konvertiert - und das Problem hat sich erledigt. Was zum T. ist BOM? Nun ja, vielen Dank für all Eure Hilfe. Toll, wie schnell das geklappt hat!

    Gruß, Torsten

  39. #79
    Contao-Nutzer Avatar von Jürgen
    Registriert seit
    24.06.2009.
    Ort
    Mühlheim
    Beiträge
    40

    Standard

    Zitat Zitat von dl1ely Beitrag anzeigen
    Mal ein Schuss ins Blaue: Macht dein str_replace für den Paletteneintrag wirklich das richtige? Check das lieber mal durch ein Debugging-Echo oder ähnlich. Beim richtigen str_replace() zur Modifikation der bestehenden Palette kann man sich böse vertun.

    Stefan
    Zitat Zitat von TLight Beitrag anzeigen
    Bevor sich nun zu viele mit meinem Problem beschäftigen, hier die Lösung:

    Habe meine Dateien in Notepad++ in UTF-8 ohne BOM konvertiert - und das Problem hat sich erledigt. Was zum T. ist BOM? Nun ja, vielen Dank für all Eure Hilfe. Toll, wie schnell das geklappt hat!

    Gruß, Torsten
    @Torsten: Gerne. Ich war auch schon kurz vor dem verzweifeln mit dem BOM.

    @Stefan: Ich hab das Beispiel "CalenderFreeEntry" aus dem Wiki benutzt. Auch dort tritt das Problem auf. Genauer gesagt wird beim Hinzufügen von einer Checkbox die Legende nicht mehr angezeigt (nur bei Titel_legende). Wenn ich nun eine zweite Checkbox hinzufüge erscheint eine von diesen doppelt. Sobald ich es auf eine andere Legende lege funktioniert alles wie erwartet.
    Das versteh ich nicht. Wenn es bei allen Legenden funktioniert und bei der Titel_legende nicht. Vielleicht liegt es daran das Titel_legende die erste beim Calendar_event ist?

    Grüße
    Jürgen

  40. #80
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von TLight Beitrag anzeigen
    Vielen Dank für die zahlreichen Hilfsangebote!

    @dl1ely: wahrscheinlich habe ich genau den von Dir beschriebenen Fehler gemacht!

    /config/config.php:
    PHP-Code:
    $GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_magazin'] = array
    (
        
    'tables' => array('tl_to_bkvs_magazin'),
        
    'icon'   => 'system/modules/to_bekleidungsverleih/icons/trikot.png'
    ); 
    $GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_verleih'] = array
    (
        
    'tables' => array('tl_to_bkvs_verleih'),
        
    'icon'   => 'system/modules/to_bekleidungsverleih/icons/trikot.png'
    ); 
    /languages/de/modules.php:
    PHP-Code:
    /**
     * Back end modules
     */
    $GLOBALS['TL_LANG']['MOD']['to_bekleidungsverleih'] = array('Bekleidungsverleih''');
    $GLOBALS['TL_LANG']['MOD']['to_magazin']            = array('Magazin''');
    $GLOBALS['TL_LANG']['MOD']['to_verleih']            = array('Verleih'''); 
    Leider habe ich Deine Lösung nicht ganz verstanden. Aber ich warte einfach auf Deinen neuen Tagebucheintrag. Will Dir nicht noch mehr Arbeit machen als Du eh schon hast.

    Vielen Dank!
    Hallo!

    Naja, "Lösung nicht verstanden". Eine Lösung ist es eigentlich nicht, eher eine Erklärung.
    to_bekleidungsverleih ist die "Obergruppe" im Backend-Modul-Menü für deine beiden Backend-Module to_magazin und to_verleih. Und bei TL ist es nunmal so, dass dann in der Language-Datei bei der Obergruppe nur ein einzelner Übersetzungsstring stehen darf, während bei den Backendmodulen selbst ein Array bestehend aus Übersetzung des Menüeintrags und des Erklärungstextes stehen muss.

    Witzigerweise bist du in genau dasselbe Problem wie ich gelaufen, aber ich hätte erst in der nächsten Tagebuchausgabe davon berichtet. Jetzt ist ja alles geklärt.

    Stefan

Aktive Benutzer

Aktive Benutzer

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

Ähnliche Themen

  1. [tl_gallery] Skizzierung einer neuen Galerie Extension
    Von cbeier im Forum Entwickler-Fragen
    Antworten: 6
    Letzter Beitrag: 23.03.2012, 22:01
  2. Update einer Extension
    Von Lengen1971 im Forum Installation / Update
    Antworten: 0
    Letzter Beitrag: 16.02.2011, 15:27
  3. Allgeimene Frage bezüglich Extension Entwicklung
    Von endlezZ im Forum Entwickler-Fragen
    Antworten: 37
    Letzter Beitrag: 02.11.2010, 10:11
  4. SQL einer individuellen Extension aktualisiert sich nicht
    Von andreasisaak im Forum Entwickler-Fragen
    Antworten: 3
    Letzter Beitrag: 16.03.2010, 11:04
  5. Verwendung einer externen PHP Klasse in einer Extension klappt nicht
    Von Schlauchbeutelmaschine im Forum Entwickler-Fragen
    Antworten: 2
    Letzter Beitrag: 03.12.2009, 11:03

Lesezeichen

Lesezeichen

Berechtigungen

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