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
Druckbare Version
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
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
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:
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?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';
Wie gesagt, bin noch nicht zum nächsten Tagebucheintrag gekommen, habe momentan leider zuviel um die Ohren.
Stefan
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
Vielen Dank für die zahlreichen Hilfsangebote!
@dl1ely: wahrscheinlich habe ich genau den von Dir beschriebenen Fehler gemacht!
/config/config.php:
/languages/de/modules.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'
);
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.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', '');
Vielen Dank!
Wenn ich die /languages/de/modules wie folgt ändere:
verschwinden zwar die zwei Fehler der Startseite und das Modul wird in der Mittelspalte angezeigt: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', '');
Der Ursprungsfehler bleibt aber:Zitat:
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}
??? Ratlosigkeit - Bin schon gespannt, wie's weitergeht...:rolleyes:Zitat:
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}
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!:D
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.:confused: 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
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
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
Ü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
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.
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
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:
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.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;
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:
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.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'
)
)
)
);
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):
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!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';
Wie sieht das nun aus?
https://community.contao.org/de/atta...1&d=1272743117
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):
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".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');
?>
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):
Hier so weit nichts Spannendes: Weiterhin wird eine Tabelle bearbeitet, und ich aktiviere Versionierung.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,
),
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.PHP-Code:
// List
'list' => array
(
'sorting' => array
(
'mode' => 2,
'fields' => array('datum DESC', 'turnierort', 'pid'),
'panelLayout' => 'filter;sort,search,limit'
),
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.
So, hier beginnt etwas die Magie...ich bastele mir das Format der Ausgabezeilen für die Backendansicht.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')
),
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.
Zu den globalen Operationen gibt es eigentlich nichts zu sagen. Die bleiben so, wie der Extensioncreator sie angelegt hat...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'
)
)
),
Die Palettendefinition hat sich nicht geändert, und Subpaletten gibt es weiterhin nicht.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
(
'' => ''
),
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:
// 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)
),
"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:
'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')
),
Hier gibt es keine großen Besonderheiten mehr. Gegenüber Schritt 11 habe ich die durchsuchbaren und sortierbaren Felder etwas erweitert bzw. geändert.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)
),
)
);
Nun kommt die Backendklasse, in der ich die Callbacks unterbringe:
Auftaktgeplänkel...PHP-Code:
class tl_gw_meldungen extends Backend
{
/**
* Import the back end user object
*/
public function __construct()
{
parent::__construct();
$this->import('BackendUser', 'User');
}
Zunächst der options_callback, der mir die Liste der aktiven Turnierpaare für die Auswahl in der Dropdown-Box liefert:
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".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;
}
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#.
Mit der pid aus dem aktuellen Datensatz holen wir den Datensatz des Turnierpaares...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);
...und bauen aus den Namensbestandteilen den Paarnamen zusammen, wobei die Nachnamen fett erscheinen sollen.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;
}
};
In Abhängigkeit vom Inhalt des lat_std-Feldes wird eine Farbe zugewiesen. Falls der Inhalt unbekannt ist, bleibt die Schrift schwarz.PHP-Code:
$colour = 'black';
switch($row['lat_std'])
{
case 'Std':
$colour = 'orange';
break;
case 'Lat':
$colour = 'red';
break;
}
Wir ersetzen die Platzhalter #name# und #section_colour# im Label-String durch die neu berechneten Werte, und geben den Label zurück.PHP-Code:
$label = str_replace('#section_colour#', $colour, $label);
$label = str_replace('#name#', $name, $label);
return $label;
}
};
?>
Was haben wir damit nun erreicht:
https://community.contao.org/de/atta...1&d=1272746013
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.
https://community.contao.org/de/atta...1&d=1272746078
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?
https://community.contao.org/de/atta...1&d=1272746218
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...
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.
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
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 ;)
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:
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.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')
),
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
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
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
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 ;)
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 :
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:PHP-Code:
// Front end module
array_insert($GLOBALS['FE_MOD']['turnierpaare'], 0, array
(
'gw_turnierpaarliste' => 'gwTurnierpaarliste',
'gw_meldeliste' => 'gwMeldeliste'
));
gw_ml_pagesize ist also ein int mit maximal 4 Stellen, gw_ml_coupledetails ein string.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;
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:
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.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')
);
Nun brauchen wir noch hübsche Labels für die neuen Felder im Backend. /system/modules/gw_turnierpaare/languages/de/modules.php:
Entsprechend die englische Variante natürlich genauso.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/');
Damit sind wir im Backend hier angekommen:
https://community.contao.org/de/atta...1&d=1275065020
Nun das Frontendmodul /system/modules/gw_turnierpaare/gwMeldeliste.php :
Zwei Templatenamen: Einer für die Ausgabe der Liste, der andere wenn etwas schiefgegangen ist...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';
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:
public static $strPageKey = 'page';
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:
/**
* 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;
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:
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;
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.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;
}
Ich weiss, dass man diesen Check, ob eine weitere Seite existiert auch anders lösen kann, wahrscheinlich sogar eleganter. Aber erstmal funktioniert es :-).
Hier kommen die ganzen Datensätze des Ergebnis rein...PHP-Code:
$arrMeldungen = array();
Ergebnisdatensätze aus der DB holen - wenn keine gefunden wurden, dann Error-Template ausgeben.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;
}
Jede Row in ein assoziatives Array umwandeln...PHP-Code:
while($newArr = $objMeldungen->fetchAssoc())
{
Und für jede Row aus der pid den Namen und den Alias des Turnierpaares bestimmen und mit ins assoziative Array aufnehmen.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;
Schließlich wird jeder Datensatz an das große Ergebnisarray angehangen und dann ins Template geschrieben.PHP-Code:
$arrMeldungen[] = $newArr;
}
$this->Template->meldungen = $arrMeldungen;
}
}
?>
Womit wir zu den Templates kommen. Zunächst /system/modules/gw_turnierpaare/templates/gw_meldeliste_error.tpl :
Erstmal easy as this, hier könnte man sich natürlich beliebig weiter austoben als nur mit diesem lapidaren Satz.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>
Spannender ist /system/modules/gw_turnierpaare/templates/gw_meldeliste.tpl :
Standardauftakt...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; ?>
Header der Tabelle...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>
Wir gehen durch alle rows im Array durch.PHP-Code:
<tbody>
<?php foreach ($this->meldungen as $meldung): ?>
Datum "richtig" formatieren...PHP-Code:
<tr>
<td class="centered">
<?php echo date('d.m.Y', $meldung['datum']); ?>
</td>
Hier wird der Paarname und als hinterlegter Link die Detail-URL mit dem Paaralias ausgegeben.PHP-Code:
<td><a href="<?php echo $this->coupledetails; ?><?php echo $meldung['paaralias']; ?>.html"><?php echo $meldung['name']; ?></a>
</td>
In Abhängigkeit von der Tanzart wird dem TD eine CSS-Klasse zugewiesen (zur farblichen Absetzung).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>
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:
<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>
Das liefert uns im Frontend (ohne weitere CSS-Modifikationen) bei 6 Meldungen (nur zur Demo) pro Seite: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; ?>
Seite <?php echo ($this->page+1); ?>
<?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>
https://community.contao.org/de/atta...1&d=1275066520
und beim Weiterschalten auf die zweite Seite (.../page/1.html):
https://community.contao.org/de/atta...1&d=1275066520
Ein Klick auf den Turnierpaarnamen springt zur Detail-URL, bei mir /turnierpaarliste/info/<alias>.html:
https://community.contao.org/de/atta...1&d=1275066520
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...
Hi Stefan,
vielen, vielen Dank für Deine super Arbeit!
Zum Schritt 13 habe ich noch 2 Anmerkungen:
- 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").
- 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
Hallo!
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 ;-).
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
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:
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!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;
}
}
Stefan
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
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
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
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.
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]
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)
Lösung 2: HookPHP-Code:
public function run()
{
global $objPage;
// Get page ID
$pageId = $this->getPageIdFromUrl();
// filter alias
if (stripos($pageId, '/info') >0 )
{
$pageId = substr($pageId,0,stripos($pageId, '/info'));
}
}
2.1 Ergänzung des TL-Hook array.
config.php - /system/modules/gw_turnierpaare/config/
2.2 Hook Klassendatei erstellen.PHP-Code:
$GLOBALS['TL_HOOKS']['getPageIdFromUrl'][] = array('gwHook', 'gwGetPageIdFromUrl');
gwHook.php - /system/modules/gw_turnierpaare/
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.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);
}
}
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
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"
in der .htaccess .Code:RewriteRule .*\.html$ index.php [L]
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
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 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
Das Prooblem kommt daher, dass die Forensoftware in den langen Codeteilen jedes Leerzeichen mit einem 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.
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 :D
Von mir aus kannst du das gerne tun.
Hallo Stefan,
Ich habe mir unter der stillschweigenden Voraussetzung, dass du damit einverstanden sein wirst, mal erlaubt,
- die Forumsbeiträge bis #104 mit minimalen Kürzungen in eine PDF-Datei zu packen
- ein Inhaltsverzeichnis in das PDF einzuarbeiten
- 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
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
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 :D
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 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
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" :D
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. :p
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
Schau dir mal System::addToUrl() an.
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
Ich setze das zur Zeit so ein (jedoch grade aus dem Kopf hingeschrieben):
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.PHP-Code:
$strParams = '&item=itemIdOrAlias';
$strDetailUrl = $this->addToUrl($strParams);
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!
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.
http://www.embeeart.de/stuff/contao-...tao-screen.jpg
Ich freue mich sehr wenn jemand mir helfen kann, ich komm einfach nicht weiter.
Vielen Dank und Liebe Grüße
Qualtext
Du musst deine content-Elemente noch registrieren. In der Datei /modules/<modulname>/config/config.php musst du dein Modul bekannt machen:
Code:$GLOBALS['TL_CTE']['league-manager']['lm_teamspercontest'] = 'lm_teamspercontest';
Komische Frage: Aber in der List weiter unten findest du auch kein passendes Element?
Danke für deine Hilfe.
Aber ich benutze doch direkt das zip-file von dl1ely (http://dl.dropbox.com/u/804662/gw_tu...e_20100529.zip)...
Ok... du meinst ich solle es so ins List-Menu einbauen?
Habe ich gemacht, ich frage mich nur, was "lm_teamspercontest" sein soll?
Siehe Bild:
http://www.embeeart.de/stuff/contao-...ao-problem.jpg
benutzt von euch niemand Contao 2.9.1 und hat das gleiche Problem?
Hallo,
funktioniert bei irgend jemanden von euch dieses Modul in Contao 2.9.1?
Sagt doch mal was.
Danke
Qualtext
Um die Module über die Liste zu erhalten müssen sie in Ihrer Config zu den Frontend-Modulen hinzugefügt werden.
Auf der Linken Seite siehst du nur die Backendmodule
Hallo!
Ja, ich bin noch da...nachdem ich meine Doktorarbeit eingereicht habe, habe ich sogar wieder Zeit zum Foren-Lesen. Habe leider keine neue Benachrichtigungsmail über die Diskussion hier erhalten, darum habe ich es nur per Zufall entdeckt.
Also:
Meine Erweiterung definiert keine Content-Elemente, sondern nur Module. Um also z.B. die Turnierpaarliste in eine Seite einzubauen, muss ein Frontend-Modul für das verwendete Theme definiert werden, was eins der Module meiner Erweiterung referenziert. Wenn man dies getan hat, kann man bei den Content-Elementen unter "Include-Elemente" den Wert "Modul" auswählen, und sieht in der dann erscheinenden Dropdown-Box die definierten Frontend-Module. Dort das oben erwähnte Frontend-Modul auswählen, und man hat den Output des Moduls als Content-Element.
Screenshot: http://screencast.com/t/Yzg3NzVj
Ich hoffe das hilft...
Stefan
Hallo!
Auch ich gehöre zu den "Im-Bett-auf-dem-Sofa-und-sonst-wo"-Lesern und weil dieses "Tutorial" wirklich sehr interessant ist (voll mit den Überlegungen die man sich selbst ständig macht, an dieser Stelle besten Dank an Stefan für den Sack voll Arbeit) hatte ich gehofft, es irgendwo als PDF zu finden. Ist wahrscheinlich auch irgendwo - ich hab's nur nicht gefunden.
Also: Selbst ist der Mann. Ich hab also alle Beiträge in ein OO-Dokument kopiert und ein PDF draus gemacht.
Einige Sachen habe ich geändert:
- Ich hab alle "Fremd-Diskussionen" entfernt. Sie sind zwar interessant aber durch enthaltene Links für Papier deutlich ungeeigneter - und lenken beim Lesen auch ab.
- Ich habe nach bestem Wissen und Gewissen alle PHP-Teile neu formatiert, weil ich keine Möglichkeit gefunden habe, ein PDF mit Scrollbars zu drucken...
- Zusätzlich hab ich hier und Seitenumbrüche eingebaut um Code möglichst auf einer Seite zu lassen.
Das ist eigentlich alles - der Ruhm der Arbeit bleibt beim Autor.
Bedauerlicherweise kann ich die Datei hier nicht anhängen -mit 1 MB leider schon zu groß- aber wer möchte kann sie hier runterladen.
Ich hoffe, es hilft dem einen oder anderen...
Naja, seit Mitte Juli gibt es bereits ein PDF-File im Wiki unter
http://de.contaowiki.org/TEE-14_Downloads
Ich bin aufgrund vieler Angelegenheiten leider nicht dazu gekommen, mich weiter um die Pflege des Wikis zu kümmern.
mfg,
Schnippsel
ganz blöde Frage: funktioniert das Tutorial mit der aktuellen Contao Version auch noch oder habt ihr einen anderen Vorschlag für ein Tutorial/Tagebuch zur Erstellung einer Extension für die aktuelle Version?
herzlichen dank
lg Vrael