From 772f08d07f41febb13a52e066036d23faa0490fc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sven=20Sch=C3=B6ling?= Date: Fri, 14 Oct 2011 12:40:04 +0200 Subject: [PATCH] =?utf8?q?$::request=20als=20globale=20Variable=20eingef?= =?utf8?q?=C3=BChrt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- SL/Dispatcher.pm | 3 + doc/20111013_globale_variablen.txt | 216 +++++++++++++++++++++++++++++ scripts/console | 1 + scripts/rose_auto_create_model.pl | 1 + scripts/task_server.pl | 1 + t/structure/globals.t | 2 +- 6 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 doc/20111013_globale_variablen.txt diff --git a/SL/Dispatcher.pm b/SL/Dispatcher.pm index 291953b77..cfb4fb834 100644 --- a/SL/Dispatcher.pm +++ b/SL/Dispatcher.pm @@ -95,6 +95,7 @@ sub pre_startup_setup { $::auth = SL::Auth->new; $::form = undef; %::myconfig = (); + $::request = undef; } $SIG{__WARN__} = sub { @@ -171,6 +172,7 @@ sub handle_request { $::locale = Locale->new($::lx_office_conf{system}->{language}); $::form = Form->new; $::instance_conf = SL::InstanceConfiguration->new; + $::request = { }; my $session_result = $::auth->restore_session; $::auth->create_or_refresh_session; @@ -251,6 +253,7 @@ sub handle_request { $::locale = undef; $::form = undef; $::myconfig = (); + $::request = undef; Form::disconnect_standard_dbh; $::lxdebug->end_request; diff --git a/doc/20111013_globale_variablen.txt b/doc/20111013_globale_variablen.txt new file mode 100644 index 000000000..37af08733 --- /dev/null +++ b/doc/20111013_globale_variablen.txt @@ -0,0 +1,216 @@ +nachdem Holger heute den Bug eingestellt hat den ich schon lange befürchtet +habe, bin ich heute mal die globalen Variablen angegangen. Das ganze ist über +die Jahre leider recht komfus geworden, deshalb hier ne Erklärung, die +hoffentlich sowas in Zukunft vermeidet. + + +Wie sehen globale Variablen in Perl aus? +---------------------------------------- + +Globale Variablen liegen in einem speziellen namespace namens "main", der von +überall erreichbar ist. Darüber hinaus sind bareword globs global und die +meisten speziellen Variablen sind... speziell. + +Daraus ergeben sich folgende Formen: + + $main::form - expliziter namespace main + $::form - impliziter namespace main + open FILE, "file.txt" - FILE ist global + $_ - speziell. + +(Ja, da fehlen noch ein paar Sachen, ich weiß) + +Im Gegensatz zu PHP gibt es kein Schlüsselwort wir "global" mit dem man +importieren kann, my, our und local machen was anderes. + + my $form - lexikalische Variable, gültig bis zum Ende des scopes + our $form - $form referenziert ab hier $PACKAGE::form. + local $form - Alle Änderungen an $form werden am Ende des scopes zurückgesetzt + +Warum ist das ein Problem? +-------------------------- + +Das erste Problem ist FCGI. + +sql-ledger hat fast alles im globalen namespace abgelegt, und erwartet, dass es +da auch wiederzufinden ist. Unter FCGI müssen diese Sachen auch wieder +aufgeräumt werden, damit sie nicht in den nächsten Request kommen. Einige +Sachen wiederum sollen nicht gelöscht werden, wie zum Beispiel +Datenbankverbindungen, weil die ne Ewigkeit zum initialisieren brauchen. + +Das zweite Problem ist strict. + +Unter strict werden alle Variablen die nicht explizit mit Package, my oder our +angegeben werden als Tippfehler angemarkert, was einen vor so mancher Stunde +suchen nach einem Bug erspart. Da globale Variablen aber implizit mit Package +angegeben werden, werden die nicht geprüft, und ein Tippfehler da fällt +niemandem auf. + +Kanonische globale Variablen +---------------------------- + +Um dieses Problem im Griff zu halten gibt es einige wenige globale Variablen, +die kanonisch sind, und alles andere sollte anderweitig umhergereicht werden. + +Diese Variablen sind im Moment die folgenden neun: + + $::form + %::myconfig + $::locale + $::lxdebug + $::auth + $::lx_office_conf + $::instance_conf + $::dispatcher + $::request + +Damit diese nicht als Müllhalde misbrauch werden, im Folgenden eine kurze +Erläuterung was man von denn erwarten kann. + + +$::form + +- Ist ein Objekt der Klasse "Form" +- Wird nach jedem Request gelöscht +- Muss auch in Tests und Konsolenscripts vorhanden sein. +- Enthält am Anfang eines Requests die Requestparameter vom User +- Kann zwar intern über Requestgrenzen ein Datenbankhandle cachen, das wird + aber momentan absichtlich zerstört + +$::form wurde unter sql ledger als Gottobjekt für alles misbraucht. Sämtliche alten +Funktionen unter SL/ mutieren $::form, das heißt, alles was einem lieb ist, +sollte man vor einem Aufruf von zum Beispiel IS->retrieve_customer in Sicherheit bringen. + +Das Objekt der Klasse Form hat leider im Moment noch viele zentrale Funktionen +Gdie vom internen Zustand abhängen, deshalb bitte nie einfach zerstören oder +überschreiben. Es geht ziemlich sicher etwas kaputt. + +$::form ist gleichzeitig der Standard Scope in den Template::Toolkit Templates +ausserhalb der Controller, der Ausdruck [% var %] greift auf $::form->{var} zu. +Unter Controllern ist der Standard Scope anders, da lautet der Zugriff [% +FORM.var %]. In Druckvorlagen sind normale Variablen ebenfall im $::form Scope, +d.h. <%var%> zeigt auf $::form->{var}. Innerhalb von Schleifen +wird $::form->{TEMPLATE_ARRAYS}{var}[$index] bevorzugt wenn vorhanden. + + +%::myconfig + +- Das einzige Hash unter den globalen Variablen +- Wird spätestens benötigt wenn auf die Datenbank zugegriffen wird +- Wird bei jedem Request neu erstellt. +- Enthält die Userdaten des aktuellen Logins +- Sollte nicht ohne Filterung irgendwo gedumpt werden oder extern serialisiert + werden, weil da auch der Datenbankzugriff für diesen user drinsteht. +- Enthält unter anderem Listenbegrenzung vclimit, Datumsformat dateformat und + Nummernformat numberformat +- Enthält Datenbankzugriffinformationen + +%::myconfig ist im Moment der Ersatz für ein Userobjekt. Die meisten Funktionen, +die etwas anhand des aktuellen Users entscheiden müssen befragen %::myconfig. + + +$::locale + +- Objekt der Klasse "Locale" +- Wird pro Request erstellt +- Muss auch für Tests und Scripte immer verfügbar sein. +- Cached intern über Requestgrenzen hinweg benutzte Locales + +Lokalisierung für den aktuellen User. Alle Übersetzungen, Zahlen- und +Datumsformatierungen laufen über dieses Objekt. + + +$::lxdebug + +- Objekt der Klasse "LXDebug" +- Wird global gecached +- Muss immer verfügbar sein, in nahezu allen Funktionen + +$::lxdebug stellt Debuggingfunktionen bereit, wie "enter_sub" und "leave_sub", +mit denen in den alten Modulen ein brauchbares Tracing gebaut ist, "log_time", +mit der man die Wallclockzeit seit Requeststart loggen kann, und "message" und +"dump" mit denen man flott Informationen ins Log packen kann. + + +$::auth + +- Objekt der Klasse "SL::Auth" +- Wird global gecached +- Hat eine permanente DB Verbindung zur Authdatenbank +- Wird nach jedem Request resettet. + +$::auth stellt Funktionen bereit um die Rechte des aktuellen Users abzufragen. +Obwohl diese Informationen vom aktuellen User abhängen wird das Objekt aus +Geschwindigkeitsgründen nur einmal angelegt und dann nach jedem Request kurz +resettet. + + +$::lx_office_conf + +- Objekt der Klasse "SL::LxOfficeConf" +- Global gecached +- Repräsentation der config/lx_office.conf[.default] Dateien + +Globale Konfiguration. + +Configdateien werden zum Start gelesen, und nicht mehr angefasst. Es ist +derzeit nicht geplant, dass das Programm die Konfiguration ändern kann oder +sollte. + +Der Konfigurationskey + + [Debug] + + file = /tmp/lxoffice_debug_log.txt + +ist im Programm als $::lx_office_conf->{Debug}{file} erreichbar. + +Warnung: Zugriff auf die Konfiguration erfolgt im Moment über Hashkeys, sind +also nicht gegen Tippfehler abgesichert. + + +$::instance_conf + +- Objekt der Klasse "SL::InstanceConfiguration" +- wird pro Request neu erstellt. + +Funktioniert wie $::lx_office_conf, speichert aber Daten die von der Instanz +abhängig sind. Eine Instanz ist hier eine Mandantendatenbank. Prominentestes +Datum ist "eur", die Information ob Bilanz oder Einnahmenüberschussrechnung +gemacht wird. + + + +$::dispatcher + +- Objekt der Klasse "SL::Dispatcher" +- wird pro Serverprozess erstellt. +- enthält Informationen über die technische Verbindung zum Server + +Der dritte Punkt ist auch der einzige Grund warum das Objekt global gespeichert +wird. Wird vermutlich irgendwann in einem anderen Objekt untergebracht. + + + +$::request + +- Hashref +- Wird pro Request neu initialisiert. +- Keine Unterstruktur garantiert. + +$::request ist ein generischer Platz um Daten "für den aktuellen Request" +abzulegen. Sollte nicht für action at a distance benutzt werden, sondern um +lokales memoizing zu ermöglichen, das garantiert am Ende des Requests zerstört +wird. + +Vieles von dem was im moment in $::form liegt sollte eigentlich hier liegen. +Die groben Differentialkriterien sind: + +- Kommt es vom User, und soll unverändert wieder an den User? + => $::form, steht da eh schon + +- Sind es Daten aus der Datenbank, die nur bis zum Ende des Requests gebraucht werden? + => $::request + +- Muss ich von anderen Teilen des Programms lesend drauf zugreifen? + => $::request, aber Zugriff über Wrappermethode diff --git a/scripts/console b/scripts/console index d567c5640..df9f6bf9d 100755 --- a/scripts/console +++ b/scripts/console @@ -66,6 +66,7 @@ sub lxinit { $::form = Form->new; $::auth = SL::Auth->new; $::instance_conf = SL::InstanceConfiguration->new; + $::request = { }; die 'cannot reach auth db' unless $::auth->session_tables_present; diff --git a/scripts/rose_auto_create_model.pl b/scripts/rose_auto_create_model.pl index fb6ef7ef9..5a7a12262 100755 --- a/scripts/rose_auto_create_model.pl +++ b/scripts/rose_auto_create_model.pl @@ -63,6 +63,7 @@ sub setup { $::auth = SL::Auth->new(); $::user = User->new($login); %::myconfig = $auth->read_user($login); + $::request = { }; $form->{script} = 'rose_meta_data.pl'; $form->{login} = $login; diff --git a/scripts/task_server.pl b/scripts/task_server.pl index 1931b6a86..66e81e7c8 100755 --- a/scripts/task_server.pl +++ b/scripts/task_server.pl @@ -43,6 +43,7 @@ sub lxinit { $::cgi = CGI->new qw(); $::form = Form->new; $::auth = SL::Auth->new; + $::request = { }; die 'cannot reach auth db' unless $::auth->session_tables_present; diff --git a/t/structure/globals.t b/t/structure/globals.t index 232dca685..14e0445d2 100644 --- a/t/structure/globals.t +++ b/t/structure/globals.t @@ -7,7 +7,7 @@ use Support::Files; my (@globals, $testcount); BEGIN { - @globals = qw(lxdebug auth myconfig form cgi lx_office_conf locale dispatcher instance_conf); + @globals = qw(lxdebug auth myconfig form cgi lx_office_conf locale dispatcher instance_conf request); $testcount = scalar(@Support::Files::testitems); } -- 2.20.1