Moritz Bunkus [Wed, 30 Jan 2013 11:55:41 +0000 (12:55 +0100)]
Stringifizierbare Klassen laden, bevor YAML::Load() aufgerufen wird
Hintergrund. Normalerweise dumpt YAML Klassen sinnvoll, sprich mit
Typus, Paketnamen und Innereien. Für eine Instanz von
SL::Locale::String könnte das z.B. so aussehen:
Lädt mal das wieder, so entsteht daraus auch ein Objekt. Allerdings
ist es zwingend erforderlich, dass Perl die Klassendefinition zum
Zeitpunkt von YAML::Load() bereits gesehen hat. Ansonsten geht die
Stringifizierung verloren, weil sie zum Zeitpunkt des "bless()"ens
nicht bekannt war.
Das passierte mit normalen CGI, weil der Controller selber erst nach
dem Auslesen der Session via "require..." geladen wird, der Controller
lädt Rose-DB-Model, das lädt SL::Locale::String.
Moritz Bunkus [Tue, 22 Jan 2013 15:26:38 +0000 (16:26 +0100)]
Rose: Fremdschlüsselbenennung fixen
Die von Rose erzeugten Fremdschlüsselaccessoren heißen wie die
Spaltennamen, also z.B. in Perl 'trans' zu Spalte 'trans_id'. Das ist
unintuitiv und muss an vielen Stellen (z.B. bei den manager_args,
with_objects etc.) auch als 'trans' angegeben werden.
Also im Generatorscript gewisse Namen auf sinnvollere Namen mappen.
Moritz Bunkus [Wed, 16 Jan 2013 10:59:42 +0000 (11:59 +0100)]
CSV-Import Lieferadressen: Funktion gefixt
Shipto hat keine custom variables. Die Base-Klasse hat sich aber
darauf verlassen, indem es 'all_cvar_configs' aufruft. Der Test mit
'$self->can("all_cvar_configs")' ist hier sinnfrei, weil
Rose::Object::MethodMaker nun mal genau diese Methoden anlegt.
Sven Schöling [Tue, 8 Jan 2013 15:37:27 +0000 (16:37 +0100)]
Stillen Fehler bei cascade-save von one-to-many relations behoben.
Folgendes Phänomen:
table X table X_items
id X_id references X(id)
wird in Rose zu
SL::DB::X und SL::DB::XItems, wobei SL::DB::XItems::X eine automatische
relationship zu X bildet, und in den meisten Fällen SL::DB::X::items eine
manuelle Relationship in die Gegnrichtung.
Was nun passiert ist, war, dass ein save(cascade => 1) auf X die items nicht
mitegspeichert hat.
Das Problem war, dass unser Hooksystem nicht sichergestellt hat, dass die
überladene save Methode von SL::DB::Object immer das Ergebnis der eigentlichen
Speicherung zurückgeliefert.
Rose::DB::Object selber braucht diesen Rückgabewert nicht, und dokumentiert das
Verhalten auch nur informal. Die von den relations angelegten post-save Hooks
prüfen den aber, und schmeissen bei nichterfolg eine Exception.
Das nächste Problem ist jetzt, dass Rose::DB::Object intern die Fehler nicht
direkt wirft, sondern den letzten Fehler in $self->error speichert, und den
dann einfach wirft. Unser undef der überladenen save Methode wird als Fehler
erkannt, aber weil nie ein Fehler gesetzt wurde, wird effektiv "die undef"
aufgerufen.
Das landet dann als "Died at .../Rose/DB/Object/MakeMethods/Generic.pm line
3741." im eval error von Rose::DB::Object::save. Das gibt das Ganze weiter an
den Rose::DB::Object::Metadata::handle_error, der das wiederum an Carp::croak
weitergibt.
Carp packt das gnaze in eine weitere Lage "Died at" ein, und bubblet das ganze
weiter an unser Hooksystem, wo die Rose::DB::do_transaction den Fehler fängt,
und folgerictig ein rollback triggert.
Jetzt der Trick: Bei Rose ist Rose::DB::Object für die Eskalation zuständig.
Rose::DB::do_transaction beendet nur die Transaktion und sieht zu dass nichts
kaputtgeht, und gibt dann undef zurück. Die Exception ist damit im
Errorattribut der DB Connection versenkt.
Rose::DB::Object umgeht das gleiche Problem indem im Fehlerfall die Exception
gefangen wird, die Transaktion sauber beendet wird, und danach erst der
Metadata::handle_error den Fehler zur weiteren Eskalation bekommt.
Dieser Patch erweitert unser Hooksystem so, dass immer der Rückgabewert des
RDBO::save zurückgegeben wird, was dann den Fehler nicht mehr triggert.
Zusätzlich müssen später noch Exceptions im Hooksystem gefangen werden, und
auch da sauber die Transaktion beendet werden, bevor die gehandhabt werden.