Florian Lagg wrote:
Of course they are writable for the plugin but it's just a local copy and not the original data. The plugin has to RETURN the altered data. That's simple data-in and data-out. Altering arguments that are passed by reference makes it hard to understand where data is changed when reading/debugging the code.
I agree that it might not be clear to the plugin if the modified data it returns will really be used by the app but I don't like to build a
complex
data structure before calling a hook. As an application developer I'd
like
to compose hook arguments inline like
$plugin->trigger_hook('a-hook', array('foo' => $bar, ...));
You can even use a class inline (using a constructor in the class), I'm describing it below. I think we should use a class because it's more secure.
because I think this is the common case. Let's move the specification which modified data will finally be used to the documentation of the plugin-hooks.
Ok, than any hook should send them array(foo), where foo is a data
class.
I suggest to always use a name => value map. Since PHP does not support named parameters this is the best way to achieve maximum extendability.
agree.
With the above code (classes rather than arrays) we can delegate some data checking logic to the plugin-architecture.
Sorry, I don't understand what you mean. Example? Maybe we should continue this conversation in German :-)
TO DEVELOPRES ONLY SPEAKING ENGLISH: I just wanted to discuss some more complex detail with Thomas in german - excuse me for that. I will translate a summary after the discussion ends in english.
OK. In einer eigenen Datenklasse könnten wir Variablen beim editieren überprüfen:
Also zum Beispiel: //--------------------------------------------------------------------- // die Datenklasse "foo": class foo { private $bar_ro; //read-only argument private $bar_rw; //read-write argument
//konstruktur public foo($bar_ro, $$bar_rw) { $this->bar_ro = $bar_ro; $this->bar_rw = $bar_rw; }
//read-only argument $bar_ro hat nur einen getter: public function getBar_ro() { return $bar_ro; }
//read-write: getter und setter: public function getBar_rw() { return $bar_rw; } public function setBar_rw($value) { //im setter einer variable können wir daten vom plugin überprüfen, //hier zB muß der Wert bar_rw positiv bleiben: if($value < 0) throw new Exception('setBar_rw bust be equal or more than 0');
//alles klar, der Wert ist OK: return true;
} }
//Aufruf des hooks im code von RC:
//Beispiel RC Daten: $bar_ro = 3; $bar_rw = 4;
//hook aufrufen $returnData = rcube_plugins::get_instance()->trigger_hook( 'a-hook', new foo(bar_ro => $bar_ro, bar_rw => $bar_rw));
//das plugin kann nur die werte verändern wie wir das in der datenklasse foo erlauben
//dann returnData zurückschreiben $bar_ro = $returnData->getBar_ro(); $bar_rw = $returnData->getBar_rw();
Ist eigentlich nicht komplizierter, aber viel sicherer.
But a loooot more code to write, to understand and to maintain. Named parameters (=array) are easier to use and simpler to understand. Security? The rule is to not modify the parameters or to clone the array before calling the hook. Simple, easy, flexible.
Außerdem kann man in der plugin-architektur diese klasse nacheinander an mehrere plugins geben ohne dass diese sich direkt ausknocken können.
QA should assure that.
Mit arrays könnte zB das erste Plugin die ID des angemeldeten Benutzers ändern und das 2. Plugin hat ein problem. Mit Datenklassen können wir das von vorne herein verbieten.
Ich würds gern so machen. Was dagegen?
I vote against this approach as it seems to be too complicated.
Wenn nicht, wo sollen wir die ganzen Datenklassen hinlegen (im Filesystem)? Ich schlage mal vor program/include/rcube_plugins_dataclasses/* oder wenn diese außerhalb von Plugins auch verwendet werden program/include/rcube_dataclasses/*
Danke inzwischen,
Mike