Runonce: Unterschied zwischen den Versionen

Aus Contao Community Documentation

K (Problemfall)
K
 
(7 dazwischenliegende Versionen von einem Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
===Hinweis===
 
{{Achtung|Artikel wird grad überarbeitet, bitte nichts dran ändern solange dieser Hinweis noch besteht. Dringende Hinweise über IRC an mich. (BugBuster)}}
 
 
[[Category:Dev HOWTOS]]
 
[[Category:Dev Snippets]]
 
 
{{AppliesTo|TLVersion=ab 2.7|Version=ab 2.9}}
 
{{AppliesTo|TLVersion=ab 2.7|Version=ab 2.9}}
 
Live Update nutzt diese, die Extensions nutzen diese auch: eine Datei <code>runonce.php</code>
 
Live Update nutzt diese, die Extensions nutzen diese auch: eine Datei <code>runonce.php</code>
Zeile 9: Zeile 4:
 
Diese Datei tut genau das, was der Name schon vermuten lässt. Sie wird nur einmal ausgeführt und anschließend gelöscht.
 
Diese Datei tut genau das, was der Name schon vermuten lässt. Sie wird nur einmal ausgeführt und anschließend gelöscht.
  
Von der Contao 2.9 zu 2.10 gab es eine Änderung diesbezüglich was Ort und Zeitpunkt des Aufrufes betrifft. Es ist möglich, für beide Arten gleichzeitg kompatibel zu sein und wird deshalb hier auch mit beschrieben.
+
Von Contao 2.9 zu 2.10 gab es eine Änderung diesbezüglich was Ort und Zeitpunkt des Aufrufes betrifft. Es ist möglich, für beide Arten gleichzeitg kompatibel zu sein und wird deshalb hier auch mit beschrieben.
 
+
[[Category:Dev HOWTOS]]
 +
[[Category:Dev Snippets]]
 
== Verwendung ab Contao 2.10 ==
 
== Verwendung ab Contao 2.10 ==
 
Ab Contao 2.10 ist die runonce Nutzung modulbasiert. Das heißt, jedes Modul bringt seine eigene runonce.php in der Verzeichnistruktur des Moduls mit. Nicht mehr wie in 2.9 im System Verzeichis.
 
Ab Contao 2.10 ist die runonce Nutzung modulbasiert. Das heißt, jedes Modul bringt seine eigene runonce.php in der Verzeichnistruktur des Moduls mit. Nicht mehr wie in 2.9 im System Verzeichis.
Zeile 22: Zeile 18:
 
=== Aufruf durch Contao ===
 
=== Aufruf durch Contao ===
 
Contao ruft die runonce.php Dateien aller aktiven Module auf (sofern vorhanden) direkt vor einem Datenbank Update bzw. dem Test ob dieser notwendig ist. Das passiert somit bei zwei Ereignissen:
 
Contao ruft die runonce.php Dateien aller aktiven Module auf (sofern vorhanden) direkt vor einem Datenbank Update bzw. dem Test ob dieser notwendig ist. Das passiert somit bei zwei Ereignissen:
* Installation oder Update oder Deinstalltion einer Erweiterung über den Erweiterungskatalog bzw. Erweiterungsverwaltung.
+
* Installation oder Update oder Deinstallation einer Erweiterung über den Erweiterungskatalog bzw. die Erweiterungsverwaltung.
 
* Liveupdate von Contao
 
* Liveupdate von Contao
 
Installiert man eine Erweiterung manuell oder macht ein manuelles Update von Contao, muss wie üblich die install.php aufgerufen werden, bzw. im Backend über Erweiterungsverwaltung - Datenbank aktualisieren, um den Vorgang auszulösen.
 
Installiert man eine Erweiterung manuell oder macht ein manuelles Update von Contao, muss wie üblich die install.php aufgerufen werden, bzw. im Backend über Erweiterungsverwaltung - Datenbank aktualisieren, um den Vorgang auszulösen.
Zeile 45: Zeile 41:
  
 
== Spezialfall: runonce.php für 2.9 und 2.10 ==
 
== Spezialfall: runonce.php für 2.9 und 2.10 ==
Wenn ein Modul definiert ist für 2.9 und 2.10 zu funktionieren und bringt eine runonce.php mit, muss diese beide Aufruforte unterstützen.
+
Wenn ein Modul definiert ist für 2.9 und 2.10 zu funktionieren und bringt es eine runonce.php mit, muss diese beide Aufruforte unterstützen.
 
Hier ist von der Idee, diese einfach an beiden Orten abzulegen und somit zweimal mitzubringen, dringend abzuraten. Grund ist der [[Runonce#Problemfall|Problemfall]] wie bei Contao 2.9 schon beschrieben.
 
Hier ist von der Idee, diese einfach an beiden Orten abzulegen und somit zweimal mitzubringen, dringend abzuraten. Grund ist der [[Runonce#Problemfall|Problemfall]] wie bei Contao 2.9 schon beschrieben.
Eine Lösung dafür ist auf dieser Seite zu finden: [[Runonce_Code_Beispiele|Runonce Code Beispiele]]
+
Eine Lösung dafür ist auf dieser Seite zu finden: [[Runonce_Code_Beispiele#Code_Beispiel_Spezialfall|Runonce Code Beispiele]]
 +
 
 
Dabei wird eine Universal-Runonce im /system Verzeichnis abgelegt, welche dann die runonce.php in den config Verzeichnissen der aktiven Module sucht und aufruft.
 
Dabei wird eine Universal-Runonce im /system Verzeichnis abgelegt, welche dann die runonce.php in den config Verzeichnissen der aktiven Module sucht und aufruft.
 
Im Prinzip wird hier die Contao 2.10 Variante nachgeahmt.
 
Im Prinzip wird hier die Contao 2.10 Variante nachgeahmt.
 
 
----
 
 
=Backup=
 
'''wird am Ende gelöscht'''
 
==Anwendungsbeispiele==
 
===Löschen einer Datei===
 
 
<source lang="php">
 
<?php @error_reporting(0); @ini_set("display_errors", 0);
 
try {
 
    // Datei relativ zu TL_ROOT
 
    $file = 'system/modules/demo/delete_me.gif';
 
    $objFiles = Files::getInstance();
 
    $objFiles->delete($file);
 
} catch (Exception $e) { $errors[] = $e->getMessage(); }
 
?>
 
</source>
 
 
Die Fehlerausgaben, sollte es welche geben, werden in diesem Beispiel unterdrückt.
 
 
===Datenbank Insert / Update===
 
<source lang="php">
 
<?php @error_reporting(0); @ini_set("display_errors", 0);
 
$objDatabase = Database::getInstance();
 
//
 
// Update database
 
try {
 
    $objDatabase->execute("UPDATE `tl_demo_table` SET `demo_counter`=0 WHERE demo_browser`='Unknown'");
 
} catch (Exception $e) { $errors[] = $e->getMessage(); }
 
//
 
// Insert database
 
try {
 
    $objDatabase->execute("INSERT INTO `tl_demo_table` (`id`, `demo_counter`) VALUES (0, '10')");
 
} catch (Exception $e) { $errors[] = $e->getMessage(); }
 
?>
 
</source>
 
 
===Datenbank Insert===
 
Der Class Name muss eineindeutig im System sein!
 
<source lang="php">
 
<?php
 
class BannerRunonceJob extends Controller
 
{
 
  public function __construct()
 
  {
 
      parent::__construct();
 
      $this->import('Database');
 
  }
 
  public function run()
 
  {
 
      $arrInsert=array(
 
          'action'    => 'runonce',
 
          'text'      => 'runonce'
 
      );
 
      $this->Database->prepare("INSERT INTO tl_log %s")->set($arrInsert)->execute();
 
  }
 
}
 
$objBannerRunonceJob = new BannerRunonceJob();
 
$objBannerRunonceJob->run();
 
?>
 
</source>
 
 
===Hinweis===
 
{{Achtung|Vorsicht damit bei Extensions mit Abhängigkeiten zu weiteren Extensions.<br />
 
Bringen 2 Extensions jeweils eine runonce.php mit, wird nur eine ausgeführt!}}
 
''Hier ist der Author nicht sicher, ob die erste oder die letzte davon.''
 
 
==Modulbasierte runonce.php==
 
 
Um den obigen Nachteil aus dem Weg zu gehen, wurde über eine modulbasierte ''runonce.php'' nachgedacht.<br />
 
Den nachfolgenden Code in die ''config.php'' des eigenen Modules einfügen. Den Pfad anpassen, "MODULNAME" durch den Verzeichnisnamen des eigenen Moduls ersetzen und eine runonce.php im config Verzeichnis erstellen.<br />
 
Diese ''runonce.php'' wird beim nächsten Seitenaufruf einmalig ausgeführt und danach gelöscht.
 
 
<source lang="php">
 
$runonceFile = '/system/modules/MODULNAME/config/runonce.php';
 
if (file_exists(TL_ROOT . $runonceFile))
 
{
 
include(TL_ROOT . $runonceFile);
 
$objFiles = Files::getInstance();
 
$objFiles->delete($runonceFile);
 
}
 
</source>
 
 
Nachteil dieser Variante: Die ER Verwaltung meckert, dass das Modul unvollständig sei, da nun eine Datei fehlt.<br />
 
Eine Idee wäre, die Datei nicht zu löschen, sondern zu überschreiben:
 
 
<source lang="php">
 
$runonceFile = 'system/modules/MODULNAME/config/runonce.php'; // relativ zu TL_ROOT
 
if (file_exists(TL_ROOT . '/' . $runonceFile))
 
{
 
  $GLOBALS['runonce']['MODULNAME'] = false;
 
  include(TL_ROOT . '/' . $runonceFile);
 
  if ($GLOBALS['runonce']['MODULNAME'] === false)
 
  {
 
      $objFiles = Files::getInstance();
 
      $objFiles->delete($runonceFile); // hier wird intern ein "TL_ROOT/" vorgesetzt
 
      //nun wieder neu anlegen mit neuem Inhalt
 
      $objFile = new File($runonceFile); // hier wird intern ein "TL_ROOT/" vorgesetzt
 
      $objFile->write("<?php \$GLOBALS['runonce']['MODULNAME'] = true; ?>");
 
      $objFile->close();
 
  }
 
}
 
</source>
 
 
Wobei man nun die file_exists Prüfung weglassen könnte.<br />
 
Andererseits könnte man diesen Abschnitt immer im Modul lassen und nur durch Setzen der Variablen ''$runonceFile'' bestimmen, ob es was zu tun gibt oder nicht.
 
 
===Probleme===
 
Einen kleinen Nebeneffekt hat die ganze Sache. Es kommt zu einer Fehlermeldung, sobald man die Datenbank Instanz nutzt; egal ob die funktions- oder objektorientierte Variante verwendet wird.<br />
 
Am Ende der Seite erscheint die Meldung:<br />
 
Fatal error: Exception thrown without a stack frame in Unknown  on line 0
 
Das Script selbst wird dabei ohne Probleme abgearbeitet, auch das Backend selbst wird dadurch nicht gestört.<br />
 
<br />
 
 
==Modulbasierte runonce.php als System runonce.php==
 
Durch Analyse einer runonce.php bei einem Liveupdate wurde klar, wenn diese aus dem System heraus aufgerufen wird und nicht aus einer config Datei, gibt es keine Fehlermeldung.<br />
 
Durch langes Experimentieren ist der Author auf eine Lösung gekommen, die zumindest bei ihm funktioniert.<br />
 
Prinzip:<br />
 
*in der config.php wird geprüft ob eine Datei /system/runonce.php existiert
 
*Ja: Abbruch, beim nächsten Seitenaufruf wird erneut geprüft.
 
*Nein: die mitgebrachte RunonceJob.php wird nach /system/runonce.php kopiert und dadurch beim nächsten Seitenaufruf abgearbeitet.
 
**die mitgebrachte wird überschrieben, um später zu erkennen, dass diese bereits ausgeführt wurde.
 
Damit die Fehlermeldung nicht auftritt, muss auch die eigentliche RunonceJob.php einen speziellen Syntax haben.<br />
 
Aus diesem Grund hier beide Dateien für ein einfaches Beispiel.<br />
 
Hier nun der geänderte Code - config.php:<br>
 
 
<source lang="php">
 
$runonceJob  = 'system/modules/MODULNAME/config/RunonceJob.php'; // eigene runonce
 
$runonceFile = 'system/runonce.php'; // system runonce
 
 
if ( (file_exists(TL_ROOT . '/' . $runonceJob)) && (!file_exists(TL_ROOT . '/' . $runonceFile)) )
 
{
 
//keine /system/runonce.php, let's go
 
$objFile = new File($runonceJob); // hier wird intern ein "TL_ROOT/" vorgesetzt
 
if ($objFile->filesize > 100)
 
{
 
$objFiles = Files::getInstance();
 
$objFiles->copy($runonceJob,$runonceFile);
 
//
 
$objFile->write("<?php // Module Migration Complete ?>");  // Datei muss kleiner 100 Zeichen werden
 
}
 
$objFile->close();
 
}
 
</source>
 
 
Hier wird über die Dateigröße geprüft, ob die Datei noch kopiert werden muss oder nicht.<br /><br />
 
Hier nun der Aufbau der passenden eigenen runonce.php, im obigem Beispiel die RunonceJob.php:
 
 
<source lang="php">
 
<?php @error_reporting(0); @ini_set("display_errors", 0); 
 
 
if (version_compare(VERSION . '.' . BUILD, '2.8.9', '>'))  // die soll nur ab Contao 2.9 ausgeführt werden
 
{
 
    $objDatabase = Database::getInstance();
 
    $objDatabase->listTables();
 
 
    // Nur wenn tl_meinmodul.feld_01 existiert aber tl_module.feld_02 nicht, gibt es was zu tun
 
    if ($objDatabase->fieldExists('feld_01', 'tl_meinmodul')
 
    && !$objDatabase->fieldExists('feld_02', 'tl_module'))
 
    {
 
        //Migration mit Neufeldanlegung
 
        //Feld anlegen
 
        try { $objDatabase->execute("ALTER TABLE `tl_module` ADD `feld_02` varchar(32) NOT NULL default ''"); }
 
        catch (Exception $e) { $errors[] = $e->getMessage(); }
 
      // Nun würden hier weiter Anweisungen folgen, z.B. das neue Feld gleich zu füllen.
 
    }
 
}
 
?>
 
</source>
 
 
Wichtig ist also, '''jede''' SQL Anweisung in ''<code>try { .... } catch (Exception $e) { $errors[] = $e->getMessage(); }</code>'' zu kapseln.
 
 
==Die Zukunft / Contao 2.10==
 
Die letzte Lösung funktioniert. Aber es wäre besser, wenn es die Möglichkeit gäbe, dass alle Module ihre eigene ''runonce.php'' mitbringen im Verzeichnis ''/system'', ohne das diese gegenseitig überschrieben werden.<br />
 
In '''Contao 2.10''' wurde im Core eine neue Variante implementiert, welche hier bald erläutert wird. Geplant habe ich das während des Contao-Camps zu tun.
 
  
 
----
 
----
--[[Benutzer:BugBuster|BugBuster]] 21:19, 6. Nov. 2011 (CET)
+
--[[Benutzer:BugBuster|BugBuster]] 22:19, 13. Nov. 2011 (CET)

Aktuelle Version vom 15. November 2011, 10:35 Uhr

betrifft
TYPOlight Version ab 2.7
Contao Version ab 2.9

Live Update nutzt diese, die Extensions nutzen diese auch: eine Datei runonce.php

Diese Datei tut genau das, was der Name schon vermuten lässt. Sie wird nur einmal ausgeführt und anschließend gelöscht.

Von Contao 2.9 zu 2.10 gab es eine Änderung diesbezüglich was Ort und Zeitpunkt des Aufrufes betrifft. Es ist möglich, für beide Arten gleichzeitg kompatibel zu sein und wird deshalb hier auch mit beschrieben.

Verwendung ab Contao 2.10

Ab Contao 2.10 ist die runonce Nutzung modulbasiert. Das heißt, jedes Modul bringt seine eigene runonce.php in der Verzeichnistruktur des Moduls mit. Nicht mehr wie in 2.9 im System Verzeichis.

Ablageort

Die runonce.php muss im config Verzeichnis des Moduls liegen. Beispiel:

/system/modules/banner/config/runonce.php

Der Ablageort /system/runonce.php funktioniert zwar auch noch, sollte aber nicht mehr verwendet werden, da es zu gegenseitigem Überschreiben kommen kann. (siehe dazu Problemfall in 2.9)

Aufruf durch Contao

Contao ruft die runonce.php Dateien aller aktiven Module auf (sofern vorhanden) direkt vor einem Datenbank Update bzw. dem Test ob dieser notwendig ist. Das passiert somit bei zwei Ereignissen:

  • Installation oder Update oder Deinstallation einer Erweiterung über den Erweiterungskatalog bzw. die Erweiterungsverwaltung.
  • Liveupdate von Contao

Installiert man eine Erweiterung manuell oder macht ein manuelles Update von Contao, muss wie üblich die install.php aufgerufen werden, bzw. im Backend über Erweiterungsverwaltung - Datenbank aktualisieren, um den Vorgang auszulösen.

Code Beispiele

Beispiele sind auf einer extra Seite zu finden: Runonce Code Beispiele

Verwendung in Contao 2.9 und älter

In Contao 2.9 und älter gibt es für alle Module und das Liveupdate einen gemeinsamen Ort für das Ablegen der runonce.php. Dies führte in der Vergangenheit zu Problemen. (siehe dazu Problemfall in 2.9)

Ablageort

Die runonce.php muss im /system Verzeichnis von Contao liegen. Beispiel:

/system/runonce.php

Aufruf durch Contao

Contao ruft die runonce.php auf, wenn vorhanden, bei jedem Seitenaufruf. Dabei spielt es keine Rolle ob es ein Frontend oder Backend Aufruf ist.

Problemfall

Wie schon erwähnt, kann das zu Probleme führen, wenn gleichzeigt mehrere Module installiert werden, die jeweils eine runonce.php mitbringen.

Eine Lösung für dieses Problem ist auf der Seite Runonce Code Beispiel Spezialfall zu finden. Diese Lösung funktioniert aber nur, wenn alle Entwickler sich dran halten.

Spezialfall: runonce.php für 2.9 und 2.10

Wenn ein Modul definiert ist für 2.9 und 2.10 zu funktionieren und bringt es eine runonce.php mit, muss diese beide Aufruforte unterstützen. Hier ist von der Idee, diese einfach an beiden Orten abzulegen und somit zweimal mitzubringen, dringend abzuraten. Grund ist der Problemfall wie bei Contao 2.9 schon beschrieben. Eine Lösung dafür ist auf dieser Seite zu finden: Runonce Code Beispiele

Dabei wird eine Universal-Runonce im /system Verzeichnis abgelegt, welche dann die runonce.php in den config Verzeichnissen der aktiven Module sucht und aufruft. Im Prinzip wird hier die Contao 2.10 Variante nachgeahmt.


--BugBuster 22:19, 13. Nov. 2011 (CET)

Ansichten
Meine Werkzeuge

Contao Community Documentation

irgendwie ist das Leben nicht fair...ich mache eine Webseite über Toilettenreinigung und Martin stellt Fotos für eine Schönheitswebseite frei...

Leo Unglaub
Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge