Seite 3 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 81 bis 120 von 129

Thema: Tagebuch einer Extension-Entwicklung

  1. #81
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Zitat Zitat von Jürgen Beitrag anzeigen
    @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
    Wie gesagt, der einzige Tip, den ich erstmal habe, wäre per echo o.ä. sich den String der Palettendefinition im DCA nach der Modifikation anzugucken. Ich vermute einfach, da läuft beim str_replace oder wie auch immer der bestehende String modifziert wird was schief. Ohne den String zu sehen ist das aber schwer zu sagen...

    Stefan

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

    Standard

    Zitat Zitat von TLight Beitrag anzeigen
    Was zum T. ist BOM?
    http://de.wikipedia.org/wiki/Byte_Order_Mark
    So long,
    FloB since Nov. 2007 +706P +115P and counting

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

    Standard

    Übrigens, aus meiner persönlichen Sicht ist die mangelnde Kenntnis dieser Abkürzung keine Schande - ich kannte sie bis vor Kurzem auch noch nicht und habe sie erst in der Wikipedia kennengelernt. Und das obwohl ich mir eigentlich einbilde, in der Informatik-Welt schon umfangreiche Kenntnisse zu besitzen. Bei UTF habe ich aber wohl noch Lücken ;-)

    Stefan

  4. #84
    Contao-Nutzer
    Registriert seit
    12.01.2010.
    Beiträge
    42

    Standard

    Hallo dl1ely,

    ausgezeichnetes Tutorial! Das motiviert wirklich, sich ein bisschen umfassender mit Tl zu beschäftigen. So was ähnliches wollte ich mal mit der Anpassung von Templates machen, muss aber zu meiner Schande gestehen, dass ich nicht die Ausdauer (und Kenntnisse) hatte das durchzuziehen.
    Aber grundsätzlich finde ich diese Methode - ein "Anfänger" -> oder besser "Nicht-Experte" - schildert wie er ein Projekt durchführt, mit allen Unsicherheiten und Fehlern die dabei entstehen und die Community begleitet mit Kommentaren und Hinweisen, die beste Form sich Wissen anzueignen.
    Am Schluss sollte dabei allerdings ein HowTo herauskommen, das die Entwicklung Schritt für Schritt abbildet und auf die möglichen Fehler an entsprechender Stelle hinweist.
    Das muss nicht notwendigerweise von Dir kommen, Du machst Dir schon genug Arbeit, sondern vielleicht von einem Team das Deine Vorlage redaktionell bearbeitet und zusammen mit Dir vielleicht eine Extension bastelt die vom speziellen Fall auf eine universelle Variante zielt.
    Ich bin gerne dabei.
    Grüße, Klaus

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

    Standard

    Naja gut, schauen wir mal...Vielleicht kann man das in der Tat "am Ende" in ein "normales", leichter lesbares Tutorial umwandeln. Leider geht es momentan nicht voran, weil ich meine Prioritäten außerhalb von TL leider höher setzen muss. Der Tag hat nur 24 Stunden, und ich brauche momentan auch ohne das Tagebuch gefühlt mindestens 48h.

    Ich weiß, dass das blöd ist für die Leute, die es auf einen Rutsch hier nachlesen, und nun etwas mitten in der Luft hängen. Ich werde das Modul (und das Tagebuch) auf JEDEN FALL zuende machen, ganz einfach deshalb weil ich das Modul wirklich aktiv brauchen werde. Nur momentan weiß ich nicht, wann und mit welcher Geschwindigkeit es weitergehen wird.

    Sterben wird es nicht, auch wenn es hier etwas ruhiger wurde/wird. VERSPROCHEN!

    Stefan

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

    Standard

    Schritt 12: Callback-Magie

    Ja, nach langer Pause geht es wirklich weiter. Diesmal wird die Backendpflege der "Meldungen"-Tabelle komplettiert. Gegenüber dem letzten Schritt haben sich nach fruchtbarer Diskussion einige Änderungen ergeben.

    Zunächst die Datenbankdefinition der Tabelle tl_gw_meldungen in system/modules/tl_gw_turnierpaare/config/database.sql:
    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` varchar(10) NOT NULL default '',
      `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;
    Das Feld datum war vorher vom Typ "date", aber das funktioniert so nicht, wenn man es als Datumsfeld im Backend verwenden will. Darum jetzt ein varchar(10). Der Rest blieb unverändert.

    Auch das Einfügen der Backendmodule in die Auswahlleiste auf der linken Seite des Backends ändere ich in /system/modules/tl_gw_turnierpaare/config/config.php ab:
    PHP-Code:
    // Back end module
    array_insert($GLOBALS['BE_MOD'], 0, array(
        
    'gw_paarverwaltung' => array(
          
    'gw_turnierpaare' => array
          (
            
    'tables' => array('tl_gw_turnierpaare'),
            
    'icon'   => 'system/modules/gw_turnierpaare/icons/turnierpaare.png'
          
    ),

          
    'gw_meldungen' => array
          (
            
    'tables' => array('tl_gw_meldungen'),
            
    'icon'   => 'system/modules/gw_turnierpaare/icons/meldeliste.png'
          
    )
        )
      )
    ); 
    Durch das array_insert kann ich mit zweiten Parameter steuern, an welcher Stelle das als letzter Parameter angegebene Array eingefügt werden soll. Bei einer "0" wie hier wandern meine Arrayeinträge ganz nach oben, bei einer "1" an zweite Stelle, usw. Da in der Praxis auf der Webseite häufiger neue Turnierpaarmeldungen eingegeben werden als neue Artikel, mächte ich die Turnierpaarverwaltung gerne ganz oben haben.

    Und dadurch, dass ich in dem Array was ich einfüge eine zusätzliche Ebene "gw_paarverwaltung" habe, gruppiere ich die beiden Einträge gw_turnierpaare und gw_meldungen in eine Untergruppe innerhalb des Menüs. Das schafft mehr Übersicht.

    Um die Language-Datei für diese Einträge muss ich mich jetzt auch einmal kümmern (/system/modules/tl_gw_turnierpaare/languages/modules.php):
    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'
    ACHTUNG: Während die Language-Einträge für die Module selbst ein Array bestehend aus dem Label des Menüeintrags und dem Beschreibungstext des Moduls sein müssen, ist der Label für die Überschrift der Gruppe im Menü (gw_paarverwaltung) nur ein einfacher String!

    Wie sieht das nun aus?


    Wo wir schonmal bei den Language-Dateien sind, machen wir auch noch die Label für die Felder des Backendmoduls (/system/modules/tl_gw_turnierpaare/languages/de/tl_gw_meldungen.php):
    PHP-Code:
    <?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
    /**
     * Fields
     */
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'] = array('Paar''Turnierpaar auswählen');

    $GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'] = array('Turnierdatum''Turnierdatum eingeben');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'] = array('Turnierort''Turnierort eingeben');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'] = array('Turnierform''Turnierform auswählen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'] = array('Startgruppe''Startgruppe auswählen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'] = array('Startklasse''Startklasse auswählen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'] = array('Latein/Standard''Tanzart auswählen');

    $GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'] = array('Anzahl gestarteter Paare''Die Paaranzahl des Turniers eingeben');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'] = array('Platz''Erzielter Platz');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'] = array('Platz bis''Geteilter Platz: Platz bis... - sonst leer lassen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'] = array('Bemerkung''Bemerkung eingeben');

    /**
     * Reference
     */
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['couple_legend'] = 'Paar';
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['tournament_legend'] = 'Turnier';
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['result_legend'] = 'Ergebnis';

    /**
     * Buttons
     */
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['new']    = array('Neue Meldung''Eine neue Turniermeldung anlegen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['edit']   = array('Editieren''Die Turniermeldung editieren');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['copy']   = array('Meldung kopieren''Die Turniermeldung in die Zwischenablage kopieren');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'] = array('Meldung löschen''Die Turniermeldung aus der Liste entfernen');
    $GLOBALS['TL_LANG']['tl_gw_meldungen']['show']   = array('Details''Die Detailansicht der Turniermeldung anzeigen');
    ?>
    Da muss ich wohl nicht mehr viel zu schreiben: Der erste Block sind Label und Beschreibungen für die Eingabefelder, der zweite Block sind die Label für die Palettenüberschriften, und die dritte Gruppe schließlich die Label und Beschreibungen für die "Aktionsbuttons".

    Kommen wir zum spannenden Teil, mir dem ich im Schritt 11 ja noch einen Kampf zu fechten hatte: der DCA-Record (/system/modules/tl_gw_turnierpaare/dca/tl_gw_meldungen.php):
    PHP-Code:
    <?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
    /**
     * Table tl_gw_meldungen 
     */
    $GLOBALS['TL_DCA']['tl_gw_meldungen'] = array
    (

        
    // Config
        
    'config' => array
        (
            
    'dataContainer'               => 'Table',
            
    'enableVersioning'            => true,
        ),
    Hier so weit nichts Spannendes: Weiterhin wird eine Tabelle bearbeitet, und ich aktiviere Versionierung.

    PHP-Code:
        // List
        
    'list' => array
        (
            
    'sorting' => array
            (
                
    'mode'                    => 2,
                
    'fields'                  => array('datum DESC''turnierort''pid'),
                
    'panelLayout'             => 'filter;sort,search,limit'
            
    ), 
    mode = 2 bedeutet, dass das Sortierfeld im Header der Tabelle wählbar ist, defaultmäßig sortiere ich nach Turnierdatum (Jüngste ganz oben), dann dem Ort, und schließlich der Paar-ID.

    Mit panelLayout aktiviere ich die Paletten oben am Kopf der Tabelle, um das Sortierfeld wählbar zu machen, das Suchfeld zu aktivieren und die Anzahl der Treffer limitieren zu können.

    PHP-Code:
            'label' => array
            (
                
    'fields'                  => array('datum','turnierort''turnierart''startgruppe','startklasse','lat_std'),
                
    'format'                  => '%s - #name# - <span style="font-weight: bold;">%s</span> - <span style="color: #section_colour#;">%s %s %s %s</span>',
                
    'label_callback'          => array('tl_gw_meldungen''lookup_pid')
            ), 
    So, hier beginnt etwas die Magie...ich bastele mir das Format der Ausgabezeilen für die Backendansicht.

    Leider habe ich hier nur die Felder der aktuellen Tabelle (tl_gw_meldungen) zur Verfügung, ich möchte aber gerne den Namen des Paares anzeigen, was zur "pid" gehört, die im Datensatz steht (pid ist der Foreign Key in die tl_gw_turnierpaare-Tabelle. Im klassischen SQL würde ich hier also einen JOIN machen).

    So direkt geht das leider nicht, darum definiere ich einen "label_callback", der weiter unten in dieser Datei als Funktion "lookup_pid()" in der Klasse "tl_gw_meldungen" definiert wird. Die Felder, die ich jetzt schon habe, definiere ich auch direkt im String. Für den Namen des Paares setze ich zunächst einen Platzhalter "#name#" in den String.

    Außerdem gibt es noch einen Platzhalter "#section_colour#". Ich möchte Turnierstarts in der Tanzform Standardtänze in orange darstellen, und solche in der Tanzform Lateinamerikanische Tänze in rot. Das kann ich an dieser Stelle im DCA-Record nicht entscheiden, weil es vom Inhalt des Felds "lat_std" abhängt. Auch das wird im label_callback geregelt.

    Die Platzhalter werden im label_callback durch ein str_replace mit den gewünschten Werten ersetzt. Schön ist das nicht, aber funktioniert.

    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'
                
    )
            )
        ), 
    Zu den globalen Operationen gibt es eigentlich nichts zu sagen. Die bleiben so, wie der Extensioncreator sie angelegt hat...

    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
        (
            
    ''                            => ''
        
    ), 
    Die Palettendefinition hat sich nicht geändert, und Subpaletten gibt es weiterhin nicht.

    PHP-Code:
        // Fields
        
    'fields' => array
        (
            
    'pid' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'],
                
    'inputType'               => 'select',
                
    'options_callback'        => array('tl_gw_meldungen''getActiveCouples'),
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'eval'                    => array('mandatory'=>true)
            ), 
    Das Feld "pid" war bisher ein foreignKey-Feld, aber damit konnte ich z.B. nur mit dem Partner-Nachnamen verknüpfen, nicht mit dem Paarnamen. Außerdem wurden hier immer ALLE Paare angezeigt, hier sollen aber nur AKTIVE Paare auswählbar sein. Um das besser machen zu können, definiere ich die Möglichkeiten in der Dropdown-Box selbst durch den options_callback "getActiveCouples()" in der Klasse tl_gw_meldungen, die gleich noch folgt.

    PHP-Code:
            'datum' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'],
                
    'inputType'               => 'text',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 6,
                
    'eval'                    => array('mandatory'=>true'datepicker'=>$this->getDatePickerString(), 'tl_class'=>'w50 wizard''minlength' => 1'maxlength'=>10'rgxp' => 'date')
            ), 
    "flag" = 6 ist hier der große Trick, damit das Timestamp-Format von "datum" richtig als Datum im Format TT.MM.JJJJ angezeigt wird. Abgeguckt habe ich das übrigens im Backend in /system/modules/backend/dca/tl_log.php .

    PHP-Code:
            'turnierort' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'],
                
    'inputType'               => 'text',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 11,
                
    'eval'                    => array('mandatory'=>true'minlength' => 1'maxlength'=>128'tl_class' => 'w50')
            ),
            
    'turnierart' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'],
                
    'inputType'               => 'select',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 11,
                
    'options'                 => gwTurnierpaarliste::$TurnierArten,
                
    'eval'                    => array('mandatory'=>false'tl_class' => 'w50')
            ),
            
    'startgruppe' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'],
                
    'inputType'               => 'select',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 11,
                
    'options'                 => gwTurnierpaarliste::$StartGruppen,
                
    'eval'                    => array('mandatory'=>false'includeBlankOption' => true'tl_class' => 'w50')
            ),
            
    'startklasse' => array
            (
                
    'label'                   => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'],
                
    'inputType'               => 'select',
                
    'search'                  => true,
                
    'sorting'                 => true,
                
    'flag'                    => 11,
                
    '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')
            ),
            
    '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)
            ),
        )
    ); 
    Hier gibt es keine großen Besonderheiten mehr. Gegenüber Schritt 11 habe ich die durchsuchbaren und sortierbaren Felder etwas erweitert bzw. geändert.

    Nun kommt die Backendklasse, in der ich die Callbacks unterbringe:
    PHP-Code:
    class tl_gw_meldungen extends Backend
    {

        
    /**
         * Import the back end user object
         */
        
    public function __construct()
        {
            
    parent::__construct();
            
    $this->import('BackendUser''User');
        } 
    Auftaktgeplänkel...

    Zunächst der options_callback, der mir die Liste der aktiven Turnierpaare für die Auswahl in der Dropdown-Box liefert:
    PHP-Code:
      public function getActiveCouples()
      {
          
    $couples = array();

            
    // Get all the active couples
            
    $objCouples $this->Database->prepare("SELECT id,partnernachname,partnervorname,partnerinnachname,partnerinvorname FROM tl_gw_turnierpaare WHERE aktiv='1' ORDER by partnernachname, partnervorname, partnerinnachname, partnerinvorname")
                                ->
    execute();

            while (
    $objCouples->next())
            {
                
    $k $objCouples->id;
                
    $v $objCouples->partnernachname;
                if(
    $objCouples->partnervorname)
                {
                   
    $v .= ', '.$objCouples->partnervorname;
          }
          if(
    $objCouples->partnerinnachname)
          {
            
    $v .= ' und '.$objCouples->partnerinnachname;
            if(
    $objCouples->partnerinvorname)
                  {
                     
    $v .= ', '.$objCouples->partnerinvorname;
            }
          }

                
    $couples[$k] =$v;
            }

            return 
    $couples;
      } 
    Der größte Teil der Funktion ist eigentlich das "Zusammenbasteln" des Paarnamens aus den Einzelbestandteilen der Namen von Partner und Partnerin. Zunächst werden aus der tl_gw_turnierpaare-Tabelle die Namen der aktiven Paare selektiert und der Ergebnisstring daraus zusammengesetzt. Das Ergebnis wird dann einem Array zugewiesen, wobei die ID des Paares der Array-Key ist, und der Paarname der Value - also z.B. $couples[47] = "Wupp, Willi und Wupp, Sieglinde".

    In der Dropdownbox steht der String, und wenn ich den dort auswähle, landet die ID 47 als "pid" in der Datenbanktabelle tl_gw_meldungen. Und, was noch vieeeeel cooler ist: Wenn ich nach dem pid-Feld sortiere, dann werden auch die Sortierheader durch die entsprechenden Strings ersetzt, statt dass dort der numerische pid-Wert steht. Leider erfolgt die Sortierung natürlich nach dem Key, nicht nach dem Value...aber das wäre ja fast zuviel verlangt :-).

    Weiter geht es mit label_callback. Als erstes Argument bekommt der die aktuelle Zeile aus der Datenbank, als zweites Argument den Label, wie er weiter oben im DCA-Record definiert wurde, hier also mit dem Platzhaltern #name# und #section_colour#.

    PHP-Code:
        public function lookup_pid($row$label)
        {
            
    $pid $row['pid'];
            
            
    // Datensatz mit ID pid aus Tabelle tl_gw_turnierpaare holen
        
    $prow $this->Database->prepare("SELECT * FROM tl_gw_turnierpaare WHERE id=?")
                                  ->
    execute($pid); 
    Mit der pid aus dem aktuellen Datensatz holen wir den Datensatz des Turnierpaares...

    PHP-Code:
        $name '<span style="font-weight: bold;">'.$prow->partnernachname.'</span>';
        if(
    $prow->partnervorname)
        {
          
    $name .= ', '.$prow->partnervorname;
        };
        if(
    $prow->partnerinnachname)
        {
          
    $name .= ' und <span style="font-weight: bold;">'.$prow->partnerinnachname.'</span>';
          if(
    $prow->partnerinvorname)
          {
            
    $name .= ', '.$prow->partnerinvorname;
          }
        }; 
    ...und bauen aus den Namensbestandteilen den Paarnamen zusammen, wobei die Nachnamen fett erscheinen sollen.

    PHP-Code:
        $colour 'black';
        switch(
    $row['lat_std'])
        {
          case 
    'Std':
            
    $colour 'orange';
            break;
          case 
    'Lat':
            
    $colour 'red';
            break;
        } 
    In Abhängigkeit vom Inhalt des lat_std-Feldes wird eine Farbe zugewiesen. Falls der Inhalt unbekannt ist, bleibt die Schrift schwarz.

    PHP-Code:
        $label str_replace('#section_colour#'$colour$label);
        
        
    $label str_replace('#name#'$name$label);
        
        return 
    $label;
      }

    };  
    ?> 
    Wir ersetzen die Platzhalter #name# und #section_colour# im Label-String durch die neu berechneten Werte, und geben den Label zurück.

    Was haben wir damit nun erreicht:


    Unsere Startmeldungen sind nach dem Datum sortiert, die Nachnamen im Paarnamen sind fett, die Stadt auch, und die "Kategorisierung" des Turniers ist orange oder rot, je nachdem ob es um Standardtänze oder lateinamerikanische Tänze geht.



    Sortieren wir nach den Paaren, dann wird die numerische pid in den Sortierheader durch unseren options_callback in die entsprechenden Strings umgesetzt - sehr nett. Leider erfolgt die Sortierung weiterhin numerisch nach der pid, und nicht alphabetisch nach den Strings. Vielleicht hat jemand noch eine Idee, wie man das lösen könnte?



    Und bei Neuanlage einer Turniermeldung werden in der Dropdown-Liste nurnoch die aktiven Paare aufgeführt, nicht mehr ALLE.

    Im nächsten Schritt geht es ans Frontendmodul für die Meldeliste...
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (01.05.2010 um 21:45 Uhr)

  7. #87
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Ich bin gerade in der DCA-Referenz über das Feld "findInSet" unter "eval" gestolpert:
    "Sort by the actual option values instead of their labels (available from version 2.7.RC1)."

    Das klingt wie das, was ich gerne für mein "pid"-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus der pid ergeben anstatt numerisch nach dem pid-Wert. Leider wirft das einen Fehler in DC_Table.php (Zeile 3468 bei TL 2.8.3), wo $keys nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit hardcodierten "options" im DCA-Record (Zeile 3461), ein options_callback wird dort nicht ausgewertet.

    Kann das einer der "Profis" bestätigen? Wäre das dann nicht evtl. ein kleiner lohnenswerter Punkt für einen Feature-Request? Sieht für mich nach einem Zweizeiler der Marke "Falls options nicht gesetzt ist options_callback ausführen, dann weitermachen" aus.

    Stefan

    EDIT: Ich habe mal ein Ticket dafür gemacht: http://https://contao.org/issues/1914
    Habe meine DC_Table.php entsprechend angepasst, und damit funktioniert es bei mir wie gewünscht.
    Geändert von dl1ely (02.05.2010 um 14:46 Uhr)

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

    Standard

    Oh, ich hatte gestern Abend vergessen, den Code für den nun aktuellen Stand hochzuladen. Ich werde den Link im ersten Post sofort aktualisieren, Sorry!

    Stefan

  9. #89
    Gesperrt
    Registriert seit
    16.02.2010.
    Ort
    München
    Beiträge
    9

    Standard

    Hi Stefan,

    ersteinmal vielen vieln Dank für dein tagebuch. Habe heute die peinliche Entdeckung gemacht, das du ja die ganze zeit noch dabei bist zu Entwickeln(habe endlich mal aufs Datum geschaut ) und dies garkein uralter beitrag war, wie ich es die ganze Zeit gedacht habe.

    Ich Entwickel seit zwei Monaten an einem Webseiten Katalog und wusste echt nicht was da auf mich zu kommt. Leider sind solche Art von "Katalogen" eher weniger vertreten und auch die catalouge extension für meine Dienste doch etwas zu überladen ist(da ich nix verkaufe) musste ich mich mit den gleichen Sachen asueinandersetzen und dein Tagebuch war eine große hilfe.

    auch wenn ich oft geflucht ahbe, denn bei dir funktionierten Sachen, die ich etwas umständlciher machen musste. Was aber auch an meiner Datenbank struktur liegt. Hällt man sich nicht an die gedachten Strukturen, muss man einiges nachimplementieren. Um genauer zu sein ist es für mein vorhaben nicht so simpel nur 1:n beziheungen zu finden.

    Zum Verständniss: eine Webseite hat einen ersteller/empfehler und einen Webmaster/Kontaktperson. Diese können gleich aber auch unterschiedlcih sein, sind aber beide in der tl_member gespeichert. Klar könnte ich miene Tabelle noch etwas "zerlegen" und schauen das ich den webmaster in eine kleine Tabelle auslagere. Bloß die Frage ist wie sinnvoll es für mich ist. Ich fahre nebenbei kleine Geschwindigkeitstests, da ich die komplette Seite dynamisch lassen muss...naja egal man könnte darauf eingehen, wenn es gewollt ist.

    ich wollte darauf hinaus, je spezieller der wunsch ist, desto mehr eigenarbeit ist dabei.
    Als Beispiel nehme man das save_callback für ein field. Funktioniert einwandfrei, außer ich definiere vorher ein input_field_callback, dann wird dieses Callback nicht mehr angerührt und ich muss einen Globalen callback ausführen. Und das nur, weil es eigentlich nur ein "anzeigefeld" sein sollte, was automatisch befüllt wird und auch nicht änderbar ist. (Vielleicht ist aber auch genau das der Knackpunkt warum es nicht geht)

    so aber lange rede kurzer sinn

    Zitat Zitat von dl1ely Beitrag anzeigen
    Das klingt wie das, was ich gerne für mein "pid"-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus der pid ergeben anstatt numerisch nach dem pid-Wert. Leider wirft das einen Fehler in DC_Table.php (Zeile 3468 bei TL 2.8.3), wo $keys nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit hardcodierten "options" im DCA-Record (Zeile 3461), ein options_callback wird dort nicht ausgewertet.
    mir ist auch aufgefallen und ich hoffe ich lehne mich nicht zu weit aus dem fenster, aber dieser Treiber scheint älter zu sein. Denn ich finde man merkt bei Typolight die struktur und die üerlegungen dahinter. Es gibt zwei möglichkeiten die DC_table zu erweitern. du kannst(solange es keine sortierung oder filter sein soll) kannst du dort wo du das label definierts und die Felder dafür, Tabellenübergreifend arbeiten.

    Denn im Code wird der String nochmal zerlegt. du kannst sozusagen <feldname>:<table_name>.<table_field> sagen, dann macht er nochmal einen DB aufruf und holt diese Information für dich.
    Willst du es beim Sortieren haben, gibt es auch dort ein hook, welcher aber leider erst aufgerufen wurde nachdem die DB abgefragt wurde(und auch leider schon sortiert). Nun bekomme ich schon das Ergebniss und kann dieses abändern. An sich ja auch nicht schlecht immerhin noch besser als ids dort stehen zu haben, aber dadurch ist es nur eine "gruppierung" und keine Sortierung mehr. Aber bei genauem überlegen(da ich mir dachte ok...dann halt mein eigener Treiber) glaube ich, das es leider dann nicht mehr trivial und performant sortiert werden kann...ist aber noch nicht ins detail durchdacht.

    also bei mir sieht es nun so aus:

    PHP-Code:
    'label' => array (
                
    'fields'            => array ('id''title''url''ersteller_id:tl_member.username'),
                
    'format'            => '<span style="font-weight: bold;">#%s</span> WCard von <span style="font-weight: bold;">%s</span>'
                                        
    ' (%s) Empfohlen von: <span style="font-weight: bold;">%s</span>',
                
    'group_callback'    => array('WCards''listViewGroupCallback')
            ), 
    dass Callback ist für die Nachbearbeitung wenn Sortiert wird. Obwohl ich deine Lösung auch sehr interessant finde und auch heute gleich mal testen werde, ob ich es auch nicht so lösen kann.

    Nochmal Danke für deine mühe...auch wenn es schade ist, dass nun "erst"(ist nicht abwertend gemeint) dort bist, da ich gerade nachlesen wollte, was du bezüglich des frontend Inputs tust, da ich mir dort gerade den Kopf zerbreche.

    Grüße Nick
    Geändert von Setsunaa (03.05.2010 um 13:07 Uhr)

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

    Standard

    Hi Nick!

    Leider kann ich dir mit deinen Ausführungen in der zweiten Hälfte eines Posts nicht so ganz folgen.
    Die Notation "feld_A:Tabelle_B.feld_B" im DCA-Record für Tabelle A ist mir gestern erst versehentlich unter die Augen gekommen (Ticket-ID #88). In meinem Fall würde es mir nicht soviel helfen, da ich einen String brauche, der sich aus mehreren Feldern aus Tabelle B zusammensetzt, und das auch noch abhängig von den Inhalten. Ohne eigenen PHP-Code geht es da nicht, darum muss der Label-Callback bleiben.

    Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.

    Mit meiner Entwicklung wirds noch weitergehen, auch der User-Input im Frontend kommt noch. Leider ist die Freizeit begrenzt, und es ist auch nur ein Freizeitprojekt. Von daher kann ich es leider nicht "runterrattern". Außerdem dauert das Erstellen jedes Schrittes ca. 1h, mit Tippen, Pasten vom Code in den Post und dem Anfertigen der Screenshots. Aber egal, da muss ich jetzt durch. Das Ende ist in Sicht :-).

    Und es motiviert mich natürlich auch, dass wohl schon Einige etwas aus diesem Thread hier mitnehmen konnten, ich hatte mit so positivem Feedback gar nicht unbedingt gerechnet.

    Stefan

  11. #91
    Gesperrt
    Registriert seit
    16.02.2010.
    Ort
    München
    Beiträge
    9

    Standard

    Hi Stefan,

    sorry das ich mich unverständlich ausgedrückt habe. Dies ist ein Problem, was häufiger auftritt, da ich ein, wie sagt man, "ein in ein schwarzes Loch hineindenker" bin . Aber ich versuche mein bestes, also bitte nicht übel nehmen...

    Stimmt du setzt deinen String zusammen, dies dachte ich mir auch, als ich dir den Vorschlag geschrieben hatt, aber wollte diesen nicht rausnehmen, da es ja vielleicht anderen helfen kann.

    Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form, die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.

    Also in "meiner" Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member. Wenn ich danach sortieren möchte, wird nur die Zahl aus "meiner" tabelle sortiert und ich habe keine möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen. Leider nur danach, dadurch ist es halt nur eine Gruppierung.

    Die Stelle in der DC_Table wo du gerne die Änderung hättest hatte ich schon gesehen, aber als für mich unbrauchbar abgestempelt, da dies mir nicht weiterhilft. Aber vielleicht habe ich auch nur etwas übersehen...

    Naja ich muss eh viel selber schreiben, dank (an manchen stellen wirklich unnötige) Abhängigkeiten und Wünsche.
    Na dann freue ich mich auf deine Weiterführung und wünsche dir viel Erfolg.

    Grüße
    Geändert von Setsunaa (03.05.2010 um 14:36 Uhr)

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

    Standard

    Zitat Zitat von Setsunaa Beitrag anzeigen
    Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form, die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.

    Also in "meiner" Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member. Wenn ich danach sortieren möchte, wird nur die Zahl aus "meiner" tabelle sortiert und ich habe keine möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen. Leider nur danach, dadurch ist es halt nur eine Gruppierung.
    Und das findInSet zusammen mit einem Options-Callback hilft dir nicht? Kann deinen konkreten Fall da gerade nicht überschauen. Wie gesagt, bei mir löst es mein Problem...

    Zitat Zitat von Setsunaa Beitrag anzeigen
    Die Stelle in der DC_Table wo du gerne die Änderung hättest hatte ich schon gesehen, aber als für mich unbrauchbar abgestempelt, da dies mir nicht weiterhilft. Aber vielleicht habe ich auch nur etwas übersehen...

    Naja ich muss eh viel selber schreiben, dank (an manchen stellen wirklich unnötige) Abhängigkeiten und Wünsche.
    Na dann freue ich mich auf deine Weiterführung und wünsche dir viel Erfolg.

    Grüße
    Danke,
    Stefan

  13. #93
    Gesperrt
    Registriert seit
    16.02.2010.
    Ort
    München
    Beiträge
    9

    Standard

    hmm...wäre möglich, aber ich empfinde es als unschön und mein erster Gedanke dabei war, wie performant ist es, ab einer gewissen User Zahl. Denn dieses Callback würde wenn dann bei jedem einzelnen ausgeführt werden müssen. Aber es könnte auch ganz einfach sein, ich schau mir deine Lösung noch an. Danke für den Hinweiß.

    Naja ist ersteinmal nicht so wichtig, das kann ich noch später ändern...und wenn es soll eh mehr über das Frontend gemacht werden, dafür muss ich eh noch einen "Admin" Bereich bauen...
    Welches mir heute wirklich Kopfschmerzen bereitet....vorallem durch den Spruch "keep it simpel" und dann hat man kleinigkeiten, die echt nicht leicht zu lösen sind...naja einfach nur speziell

    aber mit Herausforderungen wächst man ja bekanntlich

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

    Standard

    Zitat Zitat von dl1ely Beitrag anzeigen
    Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.
    Juchu:
    * Status wurde geändert von New zu Accepted.
    * Zielversion wurde gesetzt auf 2.9.0.

    :-)

    Stefan

  15. #95
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Schritt 13: Frontendmodul Meldeliste

    So, weiter geht es mit dem vorerst letzten Schritt: Das Frontendmodul für die Meldeliste.
    Besondere Herausforderungen sind hier die Möglichkeit der Verknüpfung einzelner Einträge mit dem Frontendmodul für die Turnierpaardetails, und eine konfigurierbare seitenweise Anzeige der Einträge der Meldeliste (Da diese im Lauf der Zeit sehr umfangreich werden kann).

    Die Klasse des Frontendmoduls heisst "gwMeldeliste", und da ich sie schon bei der Erstellung im Extension Creator angegeben hatte, ist diese schon als Frontendmodul registriert. Trotzdem checken wir das nochmal in /system/modules/gw_turnierpaare/config.php :
    PHP-Code:
    // Front end module
    array_insert($GLOBALS['FE_MOD']['turnierpaare'], 0, array
    (
        
    'gw_turnierpaarliste' => 'gwTurnierpaarliste',
        
    'gw_meldeliste' => 'gwMeldeliste'
    )); 
    Für die Konfiguration des Frontend-Moduls für die Darstellung benötige ich zwei Parameter: Die Anzahl der Datensätze pro Seite und die URL, auf die weitergeleitet werden soll, wenn man auf einen Tanzpaarnamen klickt (Das sollte eine URL sein, auf der das Frontendmodul der Turnierpaarliste eingebunden ist). Darum muss /system/modules/gw_turnierpaare/config/database.sql erweitert werden:
    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',
      `gw_ml_pagesize` int(4) NOT NULL default '50',
      `gw_ml_coupledetails` varchar(255) NULL default NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    gw_ml_pagesize ist also ein int mit maximal 4 Stellen, gw_ml_coupledetails ein string.

    Damit die beim Anlegen des Moduls auch angezeigt und editiert werden können, müssen wir an das DCA von tl_module ran, also in /system/modules/gw_turnierpaare/dca/tl_module.php einfügen:
    PHP-Code:
    $GLOBALS['TL_DCA']['tl_module']['palettes']['gw_meldeliste'] = '{title_legend},name,headline,type;{size_legend},gw_ml_pagesize, gw_ml_coupledetails;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space';

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

        
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_ml_pagesize'],
        
    'default'                 => '50',
        
    'exclude'                 => true,
        
    'inputType'               => 'text',
      
    'eval'                    => array('mandatory'=>true'minlength' => 1'maxlength'=>4'rgxp' => 'digit''tl_class' => 'w50')
    );

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

        
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_ml_coupledetails'],
        
    'exclude'                 => true,
        
    'inputType'               => 'text',
      
    'eval'                    => array('mandatory'=>false'tl_class' => 'w50')
    ); 
    Zunächst legen wir die neue Palette an, in der neben einigen Standardfeldern unsere beiden neuen Datenbankfelder stehen, und anschließend definieren wir diese Felder im DCA. Für die pagesize nehme ich einen Default von 50, ansonsten sind die Optionen inzwischen wohlbekannt.

    Nun brauchen wir noch hübsche Labels für die neuen Felder im Backend. /system/modules/gw_turnierpaare/languages/de/modules.php:
    PHP-Code:
    $GLOBALS['TL_LANG']['tl_module']['size_legend']     = 'Seitenlänge und Detail-URL';

    $GLOBALS['TL_LANG']['tl_module']['gw_ml_pagesize'] = array('Meldungen pro Seite''Bitte geben Sie an, wieviele Meldungen pro Seite ausgegeben werden sollen');
    $GLOBALS['TL_LANG']['tl_module']['gw_ml_coupledetails'] = array('URL der Paar-Detailseite' 'URL, auf der die Paardetails ausgegeben werden, z.B. /turnierpaarliste/info/'); 
    Entsprechend die englische Variante natürlich genauso.

    Damit sind wir im Backend hier angekommen:


    Nun das Frontendmodul /system/modules/gw_turnierpaare/gwMeldeliste.php :
    PHP-Code:
    <?php if (!defined('TL_ROOT')) die('You can not access this file directly!');

    /**
     * Class gwMeldeliste 
     *
     * @copyright  (C) 2010 
     * @author     Stefan Pfeiffer 
     * @package    Controller
     */
    class gwMeldeliste extends Module
    {

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

        protected 
    $strErrorTemplate 'gw_meldeliste_error';
    Zwei Templatenamen: Einer für die Ausgabe der Liste, der andere wenn etwas schiefgegangen ist...

    PHP-Code:
      public static $strPageKey 'page'
    Der URL-Bestandteil, der beim Blättern in der Liste unsere aktuelle Seite mitzählt. Mit 'page' also z.B. .../meldeliste/page/3.html um die dritte Seite anzeigen zu lassen.

    PHP-Code:
        /**
         * Generate module
         */
        
    protected function compile()
        {
            
    $moduleParams $this->Database->prepare("SELECT gw_ml_pagesize, gw_ml_coupledetails FROM tl_module WHERE id=?")
                    ->
    limit(1)
                    ->
    execute($this->id);

        
    $pagesize $moduleParams->gw_ml_pagesize;
        
        
    $this->Template->coupledetails $moduleParams->gw_ml_coupledetails
    Zunächst holen wir uns unsere beiden Modulparameter aus der Datenbank. die Detail-URL schreiben wir gleich ins Template, die pagesize merken wir uns erstmal.

    PHP-Code:
        if ( strlen($this->Input->get(gwMeldeliste::$strPageKey)) )
            {
          if(
    is_numeric($this->Input->get(gwMeldeliste::$strPageKey)))
          {
            
    $page $this->Input->get(gwMeldeliste::$strPageKey);
          }
          else
          {
            
    // Error
            
    $this->Template = new FrontendTemplate($this->strErrorTemplate);
            return;
          }
            }
            else
            {
          
    $page 0;
        }

        
    $this->Template->page $page
    Falls eine Seitenzahl in der URL angegeben, wird diese in $page gespeichert. Falls die Angabe nicht-numerisch ist, wird das Fehlertemplate ausgegeben. Und wenn keine Seitenzahl angegeben wird, tragen wir 0 ins Template ein.

    PHP-Code:
        $limit " LIMIT ".($pagesize*$page).",".$pagesize;
            
        
    $testNextPage $this->Database->execute("SELECT * from tl_gw_meldungen ORDER BY datum DESC LIMIT ".($pagesize*($page+1)).",1");
        if(
    $testNextPage->numRows 1)
        {
          
    $this->Template->nextpage = -1;
        }
        else
        {
          
    $this->Template->nextpage $page+1;
        } 
    Hier basteln wir uns das passende "LIMIT"-Statement für die aktuell ausgewählte Seite zusammen. Ausserdem machen wir einen Testselect auf die erste row der darauffolgenden Seite. Falls diese existiert, wird die Nummer der nächsten Seite ins Template geschrieben, ansonsten eine -1 als Hinweis fürs Template.

    Ich weiss, dass man diesen Check, ob eine weitere Seite existiert auch anders lösen kann, wahrscheinlich sogar eleganter. Aber erstmal funktioniert es :-).

    PHP-Code:
        $arrMeldungen = array(); 
    Hier kommen die ganzen Datensätze des Ergebnis rein...

    PHP-Code:
        $objMeldungen $this->Database->execute("SELECT * FROM tl_gw_meldungen ORDER BY datum DESC".$limit);
        
        if(
    $objMeldungen->numRows == 0)
        {
          
    // Error
          
    $this->Template = new FrontendTemplate($this->strErrorTemplate);
          return;
        } 
    Ergebnisdatensätze aus der DB holen - wenn keine gefunden wurden, dann Error-Template ausgeben.

    PHP-Code:
        while($newArr $objMeldungen->fetchAssoc())
        { 
    Jede Row in ein assoziatives Array umwandeln...

    PHP-Code:
          $objPaar $this->Database->execute("SELECT * FROM tl_gw_turnierpaare WHERE id=".$newArr['pid']);
        
          
    $name =   $objPaar->partnernachname;
          if(
    $objPaar->partnervorname)
          {
            
    $name .= ', '.$objPaar->partnervorname;
          }
          if(
    $objPaar->partnerinnachname)
          {
            
    $name .= ' und '.$objPaar->partnerinnachname;
          }
          if(
    $objPaar->partnerinvorname)
          {
            
    $name .= ', '.$objPaar->partnerinvorname;
          }
          
    $newArr['name'] = $name;
          
    $newArr['paaralias'] = $objPaar->alias
    Und für jede Row aus der pid den Namen und den Alias des Turnierpaares bestimmen und mit ins assoziative Array aufnehmen.

    PHP-Code:
          $arrMeldungen[] = $newArr;
        }
        
        
    $this->Template->meldungen $arrMeldungen;
        }
    }
    ?> 
    Schließlich wird jeder Datensatz an das große Ergebnisarray angehangen und dann ins Template geschrieben.

    Womit wir zu den Templates kommen. Zunächst /system/modules/gw_turnierpaare/templates/gw_meldeliste_error.tpl :
    PHP-Code:
    <div class="<?php echo $this->class?> block meldeliste"<?php echo $this->cssID?>

    <?php if ($this->style): ?> style="<?php echo $this->style?>"<?php endif; ?>>



    <h3>Es trat ein Fehler auf!</h3>
    Erstmal easy as this, hier könnte man sich natürlich beliebig weiter austoben als nur mit diesem lapidaren Satz.

    Spannender ist /system/modules/gw_turnierpaare/templates/gw_meldeliste.tpl :
    PHP-Code:
    <div class="<?php echo $this->class?>"<?php echo $this->cssID?><?php if ($this->style): ?> style="<?php echo $this->style?>"<?php endif; ?>>
    <?php if ($this->headline): ?>
    <<?php echo $this->hl?>><?php echo $this->headline?></<?php echo $this->hl?>>
    <?php endif; ?>
    Standardauftakt...

    PHP-Code:
    <table cellpadding="4" cellspacing="0" summary="Meldeliste">
      <
    thead>
        <
    tr>
          <
    th class="centered">Datum</th>
          <
    th class="centered">Name</th>
          <
    th class="centered">Ort</th>
          <
    th class="centered">Turnier</th>
          <
    th class="centered">Turnierart</th>
          <
    th class="centered">Platz</th>
          <
    th class="centered">Paare</th>
          <
    th class="centered">Bemerkung</th>
        </
    tr>
      </
    thead
    Header der Tabelle...

    PHP-Code:
      <tbody>
    <?php foreach ($this->meldungen as $meldung): ?>
    Wir gehen durch alle rows im Array durch.

    PHP-Code:
      <tr>
      <td class="centered">
      <?php echo date('d.m.Y'$meldung['datum']); ?>
      </td>
    Datum "richtig" formatieren...

    PHP-Code:
      <td><a href="<?php echo $this->coupledetails?><?php echo $meldung['paaralias']; ?>.html"><?php echo $meldung['name']; ?></a>
      </td>
    Hier wird der Paarname und als hinterlegter Link die Detail-URL mit dem Paaralias ausgegeben.

    PHP-Code:
      <td class="centered"><strong><?php echo $meldung['turnierort']; ?></strong>
      </td>
      <td class="centered<?php if ($meldung['lat_std'] == 'Std'){echo ' std';} else { if ($meldung['lat_std'] == 'Lat'){echo ' lat';}}?>"><?php echo $meldung['startgruppe']; ?> <?php echo $meldung['startklasse']; ?> <?php echo $meldung['lat_std']; ?>
      </td>
    In Abhängigkeit von der Tanzart wird dem TD eine CSS-Klasse zugewiesen (zur farblichen Absetzung).

    PHP-Code:
      <td class="centered"><?php echo $meldung['turnierart']; ?>
      </td>
      <td class="centered"><?php echo $meldung['platz_von']; ?>
      <?php if (strlen($meldung['platz_bis']) > 0): ?>
      <?php if ($meldung['platz_von'] != $meldung['platz_bis']): ?>
      <?php echo " - ".$meldung['platz_bis']; ?>
      <?php endif; ?>
      <?php endif; ?>

      </td>
      <td class="centered"><?php echo $meldung['anzahlpaare']; ?>
      </td>
      <td><?php echo $meldung['bemerkung']; ?>
      </td>
      </tr><?php endforeach; ?>
      </tbody>
    </table>
    So weit unsere Tabelle...Es fehlen noch die Links, um eine Seite vor oder zurück zu springen...wenn es dann davor oder dahinter noch Seiten gibt.

    PHP-Code:
    <?php if ($this->page 1): ?>
    <a id="prev" href="/{{env::page_alias}}/<?php echo gwMeldeliste::$strPageKey?>/<?php echo ($this->page-1); ?>.html"<<<</a>
    <?php elseif ($this->page == 1): ?>
    <a href="/{{env::page_alias}}.html"<<<</a>
    <?php endif; ?>

    &nbsp;Seite <?php echo ($this->page+1); ?>&nbsp;

    <?php if ($this->nextpage >= 0): ?>
    <a id="next" href="/{{env::page_alias}}/<?php echo gwMeldeliste::$strPageKey?>/<?php echo $this->nextpage?>.html">>>></a>
    <?php endif; ?>

    </div>
    Das liefert uns im Frontend (ohne weitere CSS-Modifikationen) bei 6 Meldungen (nur zur Demo) pro Seite:


    und beim Weiterschalten auf die zweite Seite (.../page/1.html):


    Ein Klick auf den Turnierpaarnamen springt zur Detail-URL, bei mir /turnierpaarliste/info/<alias>.html:


    So, das soll es erstmal gewesen sein. Ich habe eine Menge gelernt, und würde den Code JETZT ganz anders aufziehen. Und das werde ich auch tun (haha). Allerdings ist der Zeithorizont unklar, und ich werde es auch nicht mehr schaffen "nebenbei" das Tagebuch zu führen. Pro Folge war es doch ca. eine Stunde Arbeit - mehr als gedacht! Mir fehlen für meinen Einsatz des Moduls auch noch einige kleine Features, aber das ist wirklich sehr speziell. Zunächst werde ich gemeinsam genutzte Funktionen der Back- und Frontendmodule wohl in eine gemeinsame Klasse packen, um die Module und auch die Templates etwas zu entschlacken.

    Vielleicht werde ich zu gegebener Zeit zum Thema "AJAX" in Frontendmodulen nochmal etwas schreiben, aber dann nur speziell auf diesen Teilbereich bezogen.

    Es tut mir leid, dass es hier die letzten Wochen etwas zäh und "langweilig" wurde, aber unerwarteter Weise war meine Freizeit (in der ich das hier tue) knapper als gedacht. Ich hoffe, Einige konnten teilweise Kleinigkeiten aus meinem Lernprozess mitnehmen , egal wie chaotisch er war, und für sich sinnvoll nutzen.

    Stefan

    EDIT: Den Downloadlink zum Archiv des Quelltextes im ersten Beitrag des Threads ist jetzt auch aktualisiert...
    Angehängte Grafiken Angehängte Grafiken
    Geändert von dl1ely (28.05.2010 um 19:33 Uhr)

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

    Standard

    Hi Stefan,

    vielen, vielen Dank für Deine super Arbeit!

    Zum Schritt 13 habe ich noch 2 Anmerkungen:

    1. Statt Deinem Test für eine nächste Seite würde ich ein "SELECT COUNT(*) AS count FROM tl_gw_meldungen" machen, das kann MySQL sehr schnell, ohne wirklich auf die Datensätze zugreifen zu müssen. Basierend auf der Anzahl aller Datensätze und unter Berücksichtigung der Sätze pro Seite kann man dann eine beliebige Paginierung erzeugen (etwa auch "Erste/Letzte Seite" oder "5 Seiten weiter/zurück").
    2. Statt die Meldungen erst zu selektieren und dann in der WHILE Schleife die Paar-Infos (für die Namen) einzeln nachzuselektieren solltest Du vor der Schelife einen JOIN zwischen 'tl_gw_meldungen' und 'tl_gw_turnierpaare' machen und in der Schleife dann nur noch die Namen zusammensetzen. Das ist erheblich performanter, es wird nur 1 statt 51 Statements abgesetzt und JOIN ist ja nun gerade eine der Stärken von relationalen Datenbanken.

    Jedenfalls wünsche ich Dir sehr viel Erfolg bei Deiner geplanten Überarbeitung und ich würde mich SEHR freuen, wenn Du auch noch etwas zu AJAX schreibst.

    LG, Georg

  17. #97
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Hallo!

    Zitat Zitat von deerwood Beitrag anzeigen
    Hi Stefan,

    vielen, vielen Dank für Deine super Arbeit!

    Zum Schritt 13 habe ich noch 2 Anmerkungen:

    1. Statt Deinem Test für eine nächste Seite würde ich ein "SELECT COUNT(*) AS count FROM tl_gw_meldungen" machen, das kann MySQL sehr schnell, ohne wirklich auf die Datensätze zugreifen zu müssen. Basierend auf der Anzahl aller Datensätze und unter Berücksichtigung der Sätze pro Seite kann man dann eine beliebige Paginierung erzeugen (etwa auch "Erste/Letzte Seite" oder "5 Seiten weiter/zurück").
    Ja, das geht sicherlich auch, und mit der Gesamtzahl der Datensätze kann man die von dir beschriebenen Dinge umsetzen. Ob das bezüglich der Performance wirklich so viel Unterschied macht? Ich glaube nicht, dass das wirklich messbar ist, wenn es einmal Seitenabruf aufgerufen wird. Ich überlasse das mal als Übung dem interessierten Leser ;-).

    Zitat Zitat von deerwood Beitrag anzeigen
    1. Statt die Meldungen erst zu selektieren und dann in der WHILE Schleife die Paar-Infos (für die Namen) einzeln nachzuselektieren solltest Du vor der Schelife einen JOIN zwischen 'tl_gw_meldungen' und 'tl_gw_turnierpaare' machen und in der Schleife dann nur noch die Namen zusammensetzen. Das ist erheblich performanter, es wird nur 1 statt 51 Statements abgesetzt und JOIN ist ja nun gerade eine der Stärken von relationalen Datenbanken.

    Jedenfalls wünsche ich Dir sehr viel Erfolg bei Deiner geplanten Überarbeitung und ich würde mich SEHR freuen, wenn Du auch noch etwas zu AJAX schreibst.

    LG, Georg
    Ja, da hast Du natürlich völlig recht. Ein Join ist deutlich besser. So wie ich das gemacht habe, war das quick'n'dirty, und sollte nicht als Vorbild dienen. Mir war erstmal unklar, welche Keys im assoziativen Array genutzt werden, wenn ich zwei Tabellen joine. Muss ich ein Feld wie "tabelle2.partnernachname" dann immer mit "AS" umbenennen? Ich muss mir mal anschauen, wie das in anderen Modulen gemacht wird, und dann schiebe ich nochmal eine Version nach, die es besser macht, und die Anzahl der Queries in der Tat drastisch reduziert :-).

    Vielen Dank für deine Kommentare.

    Stefan
    Geändert von dl1ely (29.05.2010 um 12:58 Uhr)

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

    Standard

    Schritt 13b: JOIN-Power

    Wie oben besprochen habe ich die Schleife über die Meldungen durch einen Join ersetzt. Im assoziativen Array werden einfach die Feldnamen aus jeder Tabelle benutzt, bei Konflikten gewinnt vermutlich die letztgenannte Tabelle(?).

    /system/modules/gw_turnierpaare/gwMeldeliste.php sieht jetzt im unteren Teil so aus:
    PHP-Code:
        $objMeldungen $this->Database->execute("SELECT * FROM tl_gw_meldungen m, tl_gw_turnierpaare p WHERE m.pid = p.id ORDER BY datum DESC".$limit);
        
        if(
    $objMeldungen->numRows == 0)
        {
          
    // Error
          
    $this->Template = new FrontendTemplate($this->strErrorTemplate);
          return;
        }
          
        
    $arrMeldungen $objMeldungen->fetchAllAssoc();
        
    $templateResult = array();

        foreach(
    $arrMeldungen as $meldung)
        {
          
    $name $meldung['partnernachname'];
          if(
    $meldung['partnervorname'])
          {
            
    $name .= ', '.$meldung['partnervorname'];
          }
          if(
    $meldung['partnerinnachname'])
          {
            
    $name .= ' und '.$meldung['partnerinnachname'];
          }
          if(
    $meldung['partnerinvorname'])
          {
            
    $name .= ', '.$meldung['partnerinvorname'];
          }
          
    $meldung['name'] = $name;
          
    $templateResult[] = $meldung;
        }
        
    $this->Template->meldungen $templateResult;
        }

    Also statt einer Schleife über alle Rows mit neuem SELECT für den Paarnamen nurnoch eine Schleife über alle Result-Rows, um aus den Namensbestandteilen den Anzeigenamen zu basteln...Wesentlich performanter!

    Stefan

  19. #99
    Contao-Nutzer Avatar von MBM
    Registriert seit
    12.02.2010.
    Ort
    Berlin
    Beiträge
    39

    Daumen hoch Danke!

    Hallo Stefan,

    ein wirklich ausgesprochen lehrreiches, gutes und informatives Tutorial.

    Mir gefällt in besonderer Weise wie ausführlich Du Deine Lösungsgedanken zu den verschiedenen Anforderungen beschreibst. Sehr spannend.

    Ich werde jetzt auch mein erstes Modul mal umsetzen und sicherlich öfter auf dieses Tutorial zurückgreifen.

    Gruß Adrian

  20. #100
    Contao-Nutzer Avatar von MBM
    Registriert seit
    12.02.2010.
    Ort
    Berlin
    Beiträge
    39

    Standard Detailseiten

    Hallo Stefan,

    ich habe mir Dein Modul mal runtergeladen und es mal installiert und getestet. Es funktioniert auch soweit bis auf die Ansicht der Detailseite. Bekomme immer ein Page not found...

    Ich frage mich wie Du das gelöst hast. Hat es vielleicht mit meiner Konfiguration des Apache Webserver zu tun?

    Ich benutze in der Apache Konfiguration mod_rewrite und das Contao CMS 2.8.3 liegt in einem ALIAS Ordner. Auch ist inder CMS Konfiguration die index.php Anzeige ausgeschaltet (eben mod_rewrite).

    URL: http://webserver/contao/

    Code:
    <alias "/<pfad>/contao_tuts">
    RewriteBase /contao

  21. #101
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Hallo!

    Da wird bestimmt der Hund im Thema "Wie baue ich die Detail-URL zusammen" begraben sein. Wie sieht denn die "normale" URL der Meldeliste aus, und welche URL wird versucht aufzurufen, wenn Du den "Detail"-Link anklickst? Kannst den Domainnamen ja gerne weglassen.

    Es kann gut sein, dass mein Ansatz für die Detail-URL nur bei bestimmten Randbedingungen funktioniert, dann müsste ich das nochmal nachbessern.

    Danke für die Info.

    Stefan

  22. #102
    Contao-Nutzer Avatar von MBM
    Registriert seit
    12.02.2010.
    Ort
    Berlin
    Beiträge
    39

    Standard Hooks

    Zitat Zitat von dl1ely Beitrag anzeigen
    Hallo!
    Da wird bestimmt der Hund im Thema "Wie baue ich die Detail-URL zusammen" begraben sein.
    Hunde begraben ? Mich würde ja interessieren unter welcher Konfiguration das bei Dir läuft.
    Nun ja, ich habe jetzt auch eine Lösung entwickelt. Ich weiß zwar auch nicht ob das Best Practise ist und ob es nicht einen einfacheren Weg gibt, aber es funktioniert.

    Zitat Zitat von dl1ely Beitrag anzeigen
    Wie sieht denn die "normale" URL der Meldeliste aus, und welche URL wird versucht aufzurufen, wenn Du den "Detail"-Link anklickst? Kannst den Domainnamen ja gerne weglassen.
    Meine Konfigurationsparameter

    Im Backend ist URL's umschreiben auf aktiv gestellt.

    Code:
    Hauptlink: http://cms/contao/turnierpaareliste.html
    Detaillink: http://cms/contao/turnierpaareliste/info/test_testin.htm
    
    # htaccess
    RewriteBase /contao
    RewriteRule ^(.*)/info/(.*)$ $1.html?info=$2
    RewriteRule .*\.html$ index.php [L]

    Zitat Zitat von dl1ely Beitrag anzeigen
    Es kann gut sein, dass mein Ansatz für die Detail-URL nur bei bestimmten Randbedingungen funktioniert, dann müsste ich das nochmal nachbessern.
    Ich habe nun ein wenig experimentiert und zwei Lösungen gefunden.
    Die erste war Quick & Dirty und ist nicht update sicher und die zweite könnte gehen.

    Lösung 1: index.php ergänzen (Nicht zu empfehlen)
    PHP-Code:
        public function run()
        {
            global 
    $objPage;
            
    // Get page ID
            
    $pageId $this->getPageIdFromUrl();
                    
    // filter  alias
            
    if (stripos($pageId'/info') >)
            {
                
    $pageId substr($pageId,0,stripos($pageId'/info'));
            }

    Lösung 2: Hook

    2.1 Ergänzung des TL-Hook array.

    config.php - /system/modules/gw_turnierpaare/config/
    PHP-Code:
    $GLOBALS['TL_HOOKS']['getPageIdFromUrl'][] = array('gwHook''gwGetPageIdFromUrl'); 
    2.2 Hook Klassendatei erstellen.

    gwHook.php - /system/modules/gw_turnierpaare/
    PHP-Code:
    class gwHook extends Controller
    {
     public function  
    gwGetPageIdFromUrl($arrFragments)
     {
        
    // get alias (-url)    
         
    $url explode('/'$arrFragments[0]) ;
        
    // filter or cut, seo parameter and set only alias
         
    $arrFragments[0] = $url[0] ;
           return 
    array_unique($arrFragments); 
    }      

    Nochmal Danke für Dein Tutorial hier an dieser Stelle, hat mir persönlich bei der Einarbeitung in die TL-Modulentwicklung die schnellsten Erfolge gebracht.

  23. #103
    Contao-Nutzer Avatar von althoffc
    Registriert seit
    24.06.2009.
    Beiträge
    125

    Standard

    Hallo Stefan,

    tausend viel Dank für Dein Tagebuch. Das ist echt klasse.

    Ich habe Dein Tagebuch erst heute entdeckt. Habe meine ersten Gehversuche zur eigenen Modulentwicklung vor wenigen Wochen gemacht und bin gleich zu Beginn auf die gleichen, von Dir ausführlich beschriebenen Fragen (und Antworten dazu) gestossen.

    Ich kann Deine Fragen/Situation/Zeitdruck sehr gut nachvollziehen. Ich arbeite selbst ebenfalls in meiner Freizeit für eine Vereinsseite und komme immer nur Stück für Stück weiter.
    Dein Tagebuch klärt viele Fragen und Probleme und macht Mut weiterzumachen.

    Ich könnte mir vorstellen, so weit es meine Zeit zulässt, am Ende ebenfalls an einer redaktionellen Überarbeitung/Erstellung eines Tutorials, wie zuvor schon einmal vorgeschlagen, beizutragen.

    Nochmals vielen Dank für Dein Tagebuch.

    Gruß, Carsten
    Albert Einstein: Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.

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

    Standard

    Hallo MBM,

    sorry für die verspätete Antwort, aber ich war leider ziemlich beschäftigt. Ich kann dir auf Anhieb nicht sagen, warum das nicht so funktioniert wie bei mir.

    In meiner .htaccess ist "RewriteBase /", da die Contao-Installation nicht in einem Unterverzeichnis liegt. Sonst habe ich auch "nur"

    Code:
    RewriteRule .*\.html$ index.php [L]
    in der .htaccess .

    Bei der Detail-URL schreibst du nur was von ".htm" am Ende der URL. Das ist aber sicherlich auch ".html", genau wie bei der Übersichts-URL, oder?

    Bis auf die Rewritebase sehe ich erstmal keinen zwingenden Unterschied. Aber es wundert mich, dass es daran haken soll.

    Dass du schon eine Menge gelernt hast zeigt ja dein Lösungsansatz mit dem Hook, das zeugt vom Lernerfolg ;-).

    schöne Grüße,
    Stefan

  25. #105
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Frage Dieses Tutorial ausdrucken

    Hat jemand eine Möglichkeit gefunden, dieses Tutorial vollständig und lesbar auszudrucken? Es soll ja noch Leute geben, die ganz altmodisch Papier und Textmarker verwenden.

    Wenn ich die Normalansicht verwende, sind zwar die Abbildungen dabei, aber die Codeteile sind fast alle abgeschnitten.

    Verwende ich die Themenoption Druckbare Version anzeigen fehlen nicht nur die Abbildungen, sondern bei einigen Codeteilen ist ebenfalls ein Teil abgeschnitten.

  26. #106
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Das ist keine Antwort auf deine Frage, aber wahrscheinlich wird es das Tagebuch "bald" auch auf http://www.contao-wiki.de zu sehen geben, also fürs Wiki aufbereitet. Dann lässt es sich vielleicht auch besser ausdrucken.

    Wann "bald" sein wird? Keine Ahnung...

    Stefan

  27. #107
    Administrator Avatar von Nina
    Registriert seit
    04.06.2009.
    Ort
    Hamburg
    Beiträge
    4.755
    Contao-Projekt unterstützen

    Support Contao

    Standard

    Zitat Zitat von Schnippsel Beitrag anzeigen
    Hat jemand eine Möglichkeit gefunden, dieses Tutorial vollständig und lesbar auszudrucken? Es soll ja noch Leute geben, die ganz altmodisch Papier und Textmarker verwenden.

    Wenn ich die Normalansicht verwende, sind zwar die Abbildungen dabei, aber die Codeteile sind fast alle abgeschnitten.

    Verwende ich die Themenoption Druckbare Version anzeigen fehlen nicht nur die Abbildungen, sondern bei einigen Codeteilen ist ebenfalls ein Teil abgeschnitten.
    Das Prooblem kommt daher, dass die Forensoftware in den langen Codeteilen jedes Leerzeichen mit einem &nbsp; auffüllt. Dadurch kann es an diesen Stellen zu keinem Zeilenumbruch kommen, selbst wenn ich die no-wrap-Einstellung im CSS ändere.

    Auf die Schnelle weiß ich daher dafür keine Lösung. Ich behalte es aber im Auge.

  28. #108
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Information Dieses Tutorial ausdrucken

    Also ich hab' mir da in einer irren Foddelarbeit ein 127-seitiges (!) PDF-Dokument erstellt, das ich natürlich gerne der Community zur Verfügung stellen würde.

    Allerdings sind dabei nicht nur die Lobhudel-Beiträge entfernt, sondern auch manche Anrede und Grußformel. Ich wollt's so kurz wie möglich haben. Auch die Fotos der Poster und den ganzen Forumskram habe ich entfernt.

    Also müssten Stefan und Nina wohl ihr Plazet geben, dass diese PDF-Datei hier eingestellt wird. Soll ich Euch beiden das Ding erstmal per PM zur Ansicht zuschicken?

    Leider habe ich keine Sorgfalt darauf verwendet, dass
    • die Seitenumbrüche ordentlich sind
    • die Zeilenumbrüche im Code korrekt sind

    da mir das
    • nicht so wichtig und vor allem
    • zuviel Arbeit

    war. Für meine Zwecke langt es so wie es ist.

    Auf Wunsch (Kermit wirbelt wild mit den Händen!) würde ich mich vielleicht an die Überarbeitung setzen - oder irgendjemand, der sowas gerne macht, die DOC-Datei mailen

  29. #109
    Administrator Avatar von Nina
    Registriert seit
    04.06.2009.
    Ort
    Hamburg
    Beiträge
    4.755
    Contao-Projekt unterstützen

    Support Contao

    Standard

    Von mir aus kannst du das gerne tun.

  30. #110
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Information

    Zitat Zitat von dl1ely Beitrag anzeigen
    Das ist keine Antwort auf deine Frage, aber wahrscheinlich wird es das Tagebuch "bald" auch auf http://www.contao-wiki.de zu sehen geben, also fürs Wiki aufbereitet. Dann lässt es sich vielleicht auch besser ausdrucken.

    Wann "bald" sein wird? Keine Ahnung...

    Stefan
    Hallo Stefan,

    Ich habe mir unter der stillschweigenden Voraussetzung, dass du damit einverstanden sein wirst, mal erlaubt,
    1. die Forumsbeiträge bis #104 mit minimalen Kürzungen in eine PDF-Datei zu packen
    2. ein Inhaltsverzeichnis in das PDF einzuarbeiten
    3. im contao-wiki bei den Dev HOWTOS einen Beitrag einzustellen, der das Gerüst für dein Tutorial abgibt.

    Link zum Wiki-Artikel

    Da sich ja hier einige Leute gemeldet haben, die sich zur Mitarbeit bereit erklärt haben: vielleicht können wir dir die Arbeit insoweit erleichtern, indem wir zunächst einmal die Forumsbeiträge ins Wiki stellen. Das allein ist ja schon eine ziemlich Friggelei. Und du kannst dann anschließend die Überarbeitung machen.

    Solltest du mit meinem Vorgehen nicht einverstanden sein, dann bleibt es dir selbstverständlich unbenommen, mich zur Löschung des Wiki-Artikels aufzufordern oder ihn gleich selbst zu löschen.

    LG,
    Schnippsel
    Geändert von Schnippsel (07.07.2010 um 12:37 Uhr)

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

    Standard

    Hi!

    Leider habe ich die neuen Posts in diesem Thread nicht per Email mitgeteilt bekommen, darum bin ich nur per Zufall über den Wiki-Artikel und die letzten Posts hier gestolpert.

    Ich habe NICHTS gegen die Weiterverarbeitung des "Tagebuchs" in ein PDF oder einen Wiki-Artikel. Im Gegenteil, ich freue mich, wenn sich jemand die unglaubliche Arbeit macht und die Postings ins Wiki hievt - ich komme nämlich momentan gar nicht dazu...

    Also, vielen Dank für deine Arbeit, und "hau rein" :-).

    Stefan

  32. #112
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Daumen hoch On the road to the wiki!

    Zitat Zitat von dl1ely Beitrag anzeigen

    Ich habe NICHTS gegen die Weiterverarbeitung des "Tagebuchs" in ein PDF oder einen Wiki-Artikel. Im Gegenteil, ich freue mich, wenn sich jemand die unglaubliche Arbeit macht und die Postings ins Wiki hievt - ich komme nämlich momentan gar nicht dazu...

    Also, vielen Dank für deine Arbeit, und "hau rein" :-).
    Gut, Stefan, dann werde ich daran weiterarbeiten. Es war mir schon wichtig, Deine Zustimmung zu haben. Ich hoffe, dass Du mit meinen behutsamen Überarbeitungen, Ergänzungen, Erweiterungen (dazu ist ein Wiki ja da) einverstanden sein wirst.

    Wahrscheinlich wird es auch bei mir so seine Zeit brauchen, bis ich das Grundgerüst zusammengetragen habe. Alle Interessenten bitte ich also um Geduld.

    Das Wichtigste: der Download des PDFs und der Link auf Dein ZIP sind ja schon eingestellt. Leider kann man ins Wiki kein ZIP-File hochladen, sonst wäre alles an einer Stelle.

    Wie Du beim Blick ins Wiki unter Diskussion vielleicht gesehen hast, ist das Einstellen nicht ganz so trivial, wie ich es mir ursprünglich vorgestellt hatte.

    Xtra hat auf das grundlegendste Problem hingewiesen: Artikel sollten nicht über 32 K haben, damit sie ausreichend bearbeitbar bleiben. Manitougs hat sehr hilfreiche Hinweise zur Seitenbenamsung und zum Einstellen Deines "TEE"s in die Wiki-Struktur gegeben.

    Ich werde zum Abschluss der Arbeit an Deinem Tutorial dann ein eigenes Tutorial zum Thema "Meine ersten Schritte im Wiki (MSW)" hinterherschieben

  33. #113
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Beitrag Namenskonvention

    Hallo Stefan,

    Irritiert bin ich über eine Inkonsistenz in Deiner Namenskonvention.

    Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich).

    Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.

    mfg,
    Schnippsel

  34. #114
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Beitrag Copyright und Lizenz

    Hallo Stefan,

    Etwas sehr rasant bist Du für mein Empfinden über die Thematik "Autor, Copyright und Lizenz" hinweggehuscht, indem Du sie als "Selbsterklärend" deklariert hast.

    Gut: wer der Autor ist, ist tatsächlich meist selbsterklärend, Allerdings würde eine kleine Änderung die Sache noch deutlicher machen, indem man nämlich einfach "Autor(en)" - bei tl_extension.php in den Language Files - schriebe. Da ich selber in vielen Projekten (mit)arbeite, an denen verschiedene Leute am Quellcode arbeiten, ist mir der Hinweis wichtig.

    Schwieriger sieht es beim Copyright aus, selbst bei Einzelkämpfern. Wurde der Code z.B. in Rahmen eines normalen Arbeitsverhältnisses erstellt, liegt das Copyright vermutlich nicht beim Autor, sondern bei der Firma (oder dem Verein?), für die er programmiert. Bei Freelancern ist die Frage des Copyrights ggf. abhängig von der Art des Vertrages (Werkvertrag/Dienstvertrag) und/oder entsprechenden vertraglichen Regelungen.

    Auch die Frage der Lizenz ist nicht unbedingt trivial, obwohl ich natürlich bei einem "echten" Entwickler (also jemand, der sich beruflich und bezahlt mit derlei Dingen beschäftigt) davon ausgehe, dass er sich über Lizenzfragen im Klaren ist.

    Es sei darauf hingewiesen, dass der ''Extension-Creator'' im Kopf der generierten Dateien generell den Text für die GNU/LGPL einträgt, egal was man selbst unter "Lizenz" reinschreibt. Das beruht auf den Templates, die sich unter /system/modules/development/templates finden.

    Für diejenigen, die sich über die GNU/LGPL informieren möchten, hier ein paar Links:

    GNU Lesser General Public License Version 3.0

    Siehe dazu auch:

    Freie Software
    Freie Software/Open Source

    Mir ist auch der Zusammenhang zwischen Copyright und Lizenz nicht wirklich klar. Ist Copyright nicht eigentlich auch eine Art Lizenz? Da wäre es schön, wenn ein juristischer Fachmann Licht ins Dunkel bringen könnte - ein Link auf eine verständliche Seite würde mir genügen.

    Zu guter Letzt: gibt es nicht auch eine Art Vererbung der Lizenz? So weit ich es verstanden habe, darf ich in ein Open Source Projekt (Parent) auch nur Open Source Erweiterungen (Child) einbringen.

    mfg,
    Schnippsel
    Geändert von Schnippsel (07.07.2010 um 13:10 Uhr)

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

    Standard

    Zitat Zitat von Schnippsel Beitrag anzeigen
    Hallo Stefan,

    Irritiert bin ich über eine Inkonsistenz in Deiner Namenskonvention.

    Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich).

    Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.

    mfg,
    Schnippsel
    Hallo!

    Dann kann ich mich nur für diese Inkonsistenz entschuldigen, sie war nicht beabsichtigt ;-).

    Sorry,
    Stefan

  36. #116
    Contao-Nutzer
    Registriert seit
    10.07.2009.
    Ort
    Frankfurt am Main
    Beiträge
    14

    Beitrag Namenskonvention

    Naja, Stefan, meine Intention war natürlich nicht, Dich dazu zu bringen, dass Du Dir nun Asche aufs Haupt streust! Ich war einfach nur Deiner Bitte gefolgt, die Du am Ende von Schritt 2 formuliert hattest: "Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben"

    Der Hinweis ging auch mehr an die geneigten Leser, unter denen sicherlich auch solche sind, die ihr Brot nicht als berufsmäßige Entwickler bzw. Programmierer verdienen. Wie man an Deinem Beispiel halt schön sehen kann, bleiben gute Ansätze manchmal auf halber Strecke stecken.

    Was ich aus den unterschiedlichsten Projekten gelernt habe: es ist im Grunde egal, welche Namenskonvention man verwendet. Hauptsache, man verwendet eine und hält sie konsequent ein! Als externer Projektmitarbeiter ist das so ungefähr das Erste, was man eingebläut kriegt.

    Sofern es in einer bestimmten Programmiersprache Standards oder auch nur Quasi-Standards gibt, orientiert man sich zweckmäßigerweise natürlich an diesen. Da ich nicht aus der PHP-Welt komme, kann ich dazu aber nichts Genaueres sagen - ich schaff' mich da gerade erst rein.

    In meinem bisherigen Arbeitsumfeld waren das z.B. die

    Die klassischen Ansätze sind, einzeln oder kombiniert, die Verwendung von


    mfg,
    Schnippsel

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

    Standard

    Zitat Zitat von dl1ely Beitrag anzeigen
    PHP-Code:
    ...
      <td><?php echo '<a href="/{{env::page_alias}}/'.gwTurnierpaarliste::$strDetailKey.'/'.$paar['alias'].'.html">Detail</a>'?>
    ...
    Schau dir mal System::addToUrl() an.
    So long,
    FloB since Nov. 2007 +706P +115P and counting

  38. #118
    Contao-Nutzer
    Registriert seit
    04.12.2009.
    Beiträge
    194

    Standard

    Danke für den Tipp...aber macht das dasselbe, was ich da manuell mache? Müsste ich mal ausprobieren, leider gibt es ja keinen Beispiel-Output in der Doku...
    Hängt es mir einen beliebigen String einfach platt hinten an die URL? Dann könnte ich es in der Tat benutzen...

    Stefan

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

    Standard

    Ich setze das zur Zeit so ein (jedoch grade aus dem Kopf hingeschrieben):
    PHP-Code:
    $strParams '&item=itemIdOrAlias';
    $strDetailUrl $this->addToUrl($strParams); 
    Als Basis wird die aktuelle Seite genommen, somit fällt der Teil mit dem InsertTag komplett weg. Wenn sprechende URLs im Backend deaktiviert sind (z. B. für IIS), werden die Daten von Contao automatisch als Query an die URL angehängt.

    Code kann füchterlich falsch sein, womöglich aber auch genau richtig .

    Kam im Übrigen jetzt erst dazu, alles zu lesen, deswegen jetzt erst der Tipp. Gutes Tutorial, vielen Dank für deine Arbeit!
    So long,
    FloB since Nov. 2007 +706P +115P and counting

  40. #120
    Contao-Nutzer
    Registriert seit
    21.09.2010.
    Beiträge
    3

    Standard Irgendwas ist da komisch...

    Hallo,

    ich habe mich mit diesem Tutorial beschäftigt, weil ich auf Fehlersuche bin. Ich habe vorher bereits ein Tutorial durchgearbeitet (http://blog.qzminski.com/2010/04/cre...dule-part-one/) und stoße (wie auch bei diesem Tutorial) auf folgendes Problem:

    Ich sehe in der Liste keine selbst-erstellten Module zur Auswahl, wenn ich einen neuen Artikel erstellen will. Weder die CD-Collection, noch die Paar-Tanz-Sachen.

    Ich nutze Contao 2.9.1, hab auch mal nen Screenshot angehängt.



    Ich freue mich sehr wenn jemand mir helfen kann, ich komm einfach nicht weiter.

    Vielen Dank und Liebe Grüße
    Qualtext

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
  •