Thread: [Postfixadmin-devel] refactoring
Brought to you by:
christian_boltz,
gingerdog
From: David G. <da...@co...> - 2008-07-22 20:47:52
|
Hi, I'm wondering if we should refactor the codebase into having a distinct object layer which : a) Could be exposed via xmlrpc or soap (useful for 3rd party integration) b) Could be more easily tested (unit tests etc) c) Will move some logic from the controllers into a model layer. Pseudo example: Mailbox object: -> login($u, $p); -> addMailbox($name, $domain) -> deleteMailbox($name, [$domain]); -> updateMailbox($assoc_array_of_params); Vacation object: -> setAway($msg, $mailbox); -> setReturned($mailbox); Domain object: -> addNewDomain($name, $other, $parameters); -> listDomains(); -> addMailbox($name); Alias object: -> addNewAlias($source, $dest); -> listAliasesForDomain($domain_name, $paging, $parameters); -> removeAlias($source, $dest); So these objects would encapsulate all the required SQL logic, and should also have authentication checks (as appropriate). They could then be exposed via e.g. xmlrpc or soap - however this might require all methods having an additional two parameters (username, password) etc, or writing a simple proxy object. I've made a vaguely related blog post - http://codepoets.co.uk/using-soap-and-xmlrpc-php5-newbies-findings Feedback welcome :) I've also released postfixadmin 2.2.1. David. -- David Goodwin [ david at codepoets dot co dot uk ] [ http://www.codepoets.co.uk ] |
From: Christian B. <pos...@cb...> - 2008-07-22 23:55:11
Attachments:
missed-fixes.diff
|
Hello, Am Dienstag, 22. Juli 2008 schrieb David Goodwin: > I'm wondering if we should refactor the codebase into having a > distinct object layer which : > > a) Could be exposed via xmlrpc or soap (useful for 3rd party > integration) > > b) Could be more easily tested (unit tests etc) > > c) Will move some logic from the controllers into a model layer. Just a short note: I'm also thinking about refactoring since some time. My focus was more on making programming and changes easier, but having an automated interface would be a nice side effect. My idea in short: - create a basic class with the required functions/methods. Most important items: (intentionally skipping the parameter lists) * [non-public] table structure as array (like $fm_struct in fetchmail.php) * function get_list() (for list view) * function get_list_for_domain() (for list view) - both get_list* should have an optional $search parameter * function get_item() (current values, for edit form) * function edit() (called when submitting the edit form) parameters given as array with named keys edit() calls: - [non-public] function validate_by_type() (simple check against field type given in table structure) - [non-public] function validate_special() (other checks that are not covered by type check) * function add() (basically like edit()) * function delete() * [non-public] check_domain_permission() (check if the admin has permissions for this domain) * [non-public] check_other_permission() (check other permissions, for example if editing mailbox aliases is allowed) * other non-public functions as needed - target should be to have most code in the common class and as least as possible in the mailbox/alias/whatever class. - make each object type (admin, domain, mailbox, alias) a PHP class based on the basic class described above - create/use a class for rendering lists Maybe we can use the Table class from http://exorsus.net/software/, example on http://exorsus.net/software/table_class/test_complete.php (I'm using this class at other places already) - create a class for rendering edit forms (see fetchmail.php for ideas) or use the one from http://exorsus.net/software - create a small class rendering the domain dropdown we have at nearly every list page > Pseudo example: > > Mailbox object: > -> login($u, $p); > -> addMailbox($name, $domain) > -> deleteMailbox($name, [$domain]); > -> updateMailbox($assoc_array_of_params); Since you already propose separate objects for mailbox, domain etc, I'd prefer to have common names like "add", "edit", "delete". > Vacation object: > -> setAway($msg, $mailbox); > -> setReturned($mailbox); > > Domain object: > -> addNewDomain($name, $other, $parameters); > -> listDomains(); > -> addMailbox($name); > > Alias object: > -> addNewAlias($source, $dest); > -> listAliasesForDomain($domain_name, $paging, $parameters); > -> removeAlias($source, $dest); Admin object: -> list admins -> list domains for admin -> create admin -> add domain to admin > So these objects would encapsulate all the required SQL logic, and > should also have authentication checks (as appropriate). They could > then be exposed via e.g. xmlrpc or soap - however this might require > all methods having an additional two parameters (username, password) > etc, or writing a simple proxy object. A central proxy object is probably easier to maintain... (as always: if you can do it at a central place, don't spread the same code across 10 files ;-) The basic permission checks (is access to this domain allowed) could be handled in the basic class. If more details have to be checked, each class can do it additionally. > I've made a vaguely related blog post - > http://codepoets.co.uk/using-soap-and-xmlrpc-php5-newbies-findings Just had a quick look at it - sounds interesting, but I'll need some more time to read it. Right now, I like this the best: SOAP is really now just called "SOAP", I think they've dropped the "Simple..." bit from the name as it can be anything but simple. ;-) > I've also released postfixadmin 2.2.1. Good to hear. As always ;-) I found some small problems. You have missed some small fixes, see the attached patch. In case you wonder: I generated this patch with (the following 3 lines should be entered as a single one): svn diff https://postfixadmin.svn.sourceforge.net/svnroot/postfixadmin/branches/postfixadmin-2.2.1 https://postfixadmin.svn.sourceforge.net/svnroot/postfixadmin/trunk and then removed everything related to alias domains. Please read the patch and don't blindly apply it to the 2.2(.2) branch - at some places I have replaced big changes by short comments (upgrade.php, language files) As a side effect of not including alias domains, you have caused a small problem with database upgrade - upgrade.php is currently at Revison 392 (in trunk) and 397 (in 2.2.1 branch). This means the functions to create the alias_domain table won't run when merged back in because it has a lower number (upgrade_300 and upgrade_362 - I just wonder why we have it twice...) The problem isn't really big - we have to rename the functions to a higher number - and we need IF NOT EXISTS in the CREATE TABLE statement for those using the svn version ;-) Oh, and IMHO we should include all database changes from trunk in future releases even if it produces unused tables. Causes less trouble ;-) On the positive side, I have updated the RPM packages and also uploaded an openSUSE RPM to SF. I also updated the changelog and updated debian/changes in trunk. Regards, Christian Boltz -- Meine Katze hat zu der Maus auch gesagt: "Kannst ganz beruhigt sein, ich tu Dir nichts!" Und vom Fressen hat die Katze kein Ton gesagt. [Rolf-Hubert Pobloth in suse-linux] |
From: Christian B. <pos...@cb...> - 2008-07-28 17:14:34
Attachments:
baseclass.php
|
Hello, Am Mittwoch, 23. Juli 2008 schrieb Christian Boltz: > My idea in short: > - create a basic class with the required functions/methods. I have written a proof-of-concept class postfixadminBaseclass as described in my proposal. It is attached to this mail. Please note that the class does not contain real code yet, only the structure and sometimes some dummy code. It also still misses some (internal) functions like permission check. Functions and variable definitions are currently sorted by action - this needs to be changed to "variables first", but the current sorting is easier for the initial development. I did some small changes compared to the proposal in my mail - see the comments inside the file for details. Comments welcome: - do you think this could become the basis of all postfixadmin pages? - what should I/we do better? (We have 35 °C outside, so I'm sure the baseclass isn't perfect ;-) Regards, Christian Boltz -- > welche log willst sehen ??? Das ist die Postfixbuch-Users Liste, vielleicht das Log von, hmmm, Postfix? Nur so ne Idee. [> R. Wilhelm und Ralf Hildebrandt in postfixbuch-users] |
From: David G. <da...@co...> - 2008-07-28 20:28:01
|
Christian Boltz wrote : > Hello, > > Am Mittwoch, 23. Juli 2008 schrieb Christian Boltz: > > My idea in short: > > - create a basic class with the required functions/methods. > > I have written a proof-of-concept class postfixadminBaseclass as > described in my proposal. It is attached to this mail. > > Please note that the class does not contain real code yet, only the > structure and sometimes some dummy code. It also still misses some > (internal) functions like permission check. > > Functions and variable definitions are currently sorted by action - this > needs to be changed to "variables first", but the current sorting is > easier for the initial development. > > I did some small changes compared to the proposal in my mail - see the > comments inside the file for details. Right, I'll include the code inline, as I'm lazy (and using mutt, while my office computer is dead thanks to the thunder+lightening) <?php # template for all postfixadmin classes (admins, domains, mailboxes etc.) # # What it DOES: # * handling of listing (database -> array) # * handling of editing/adding items (database -> variables for item-to-edit and variables -> database) # * input validation for editing/adding items # * permission checks # * accepts / returns data as variables/arrays # # What it DOES NOT: # * rendering of lists -> table_class # * rendering of edit forms -> form_class # * output HTML etc. class postfixadminBaseclass { protected function __construct() { $this->initStruct; $this->initDefaults; } # name, also used for generating links public function name($listmode=0) { # usually: return "baseclass"; # for "virtual" list vs. "mailbox" editing # if ($listmode == 0) { # return "mailbox"; # } else { # return "virtual"; # } } ^^ What's name() trying to do? # * [read-only] table structure as array (like $fm_struct in # fetchmail.php) ^^ You love fetchmail.php don't you ? :) # * function get_list() (for list view) # * function get_list_for_domain() (for list view) # - both get_list* should have an optional $search parameter # -> I decided to merge this to one function # -> "list" is a reserved word, switched to "items" public function items ($domain="", $admin="", $search="") { # get list from database # return array (array(key -> value), array(key -> value), ...) } ^^ OK, this makes sense. # * function get_item() (current values, for edit form) public function item ($primarykey) { # get item from database # return array (key -> value) } ^^ Ditto; seems fine. # handles add and edit calls internally protected function addOrEdit($primarykey, Array $newvalues, $mode) { # mode: 0 = edit, 1 = new # calls: [TODO] # - [non-public] function validate_by_type() (simple check against # field type given in table structure) ^^ I think this is unnecessary; database introspection might be a better bet. # -> see fetchmail.php _inp_*() # -> also check that only allowed fields are set # - [non-public] function validate_special() (other checks that are # not covered by type check) ^^ OK; good plan. } # TODO # * [non-public] check_domain_permission() (check if the admin has # permissions for this domain) # * [non-public] check_other_permission() (check other permissions, for # example if editing mailbox aliases is allowed) # * other non-public functions as needed - target should be to have most # code in the common class and as least as possible in the # mailbox/alias/whatever class. # -> this also means that functions should be split into subparts where needed It would be nice for the permission definitions to be done in one place, where ever that may be. Could permissions be listed a bit like : e.g. /** * decorator for permission enforcement */ class PermissionProxy { public function __construct($real) { $this->real = $real; } $perms = array ( 'object.functionName' => array('role','role','role'), 'otherobject.somethingElse' => array('role', 'role'), // etc ) function __call($name, $values) { // see if $name is in permissions array, and role(s) // match. $key = get_class($this->real) . '.' $name; $permission = array_key_exists($key, $perms)) && .. etc .. if($permission) { return call_user_func_array(array($whatever,$name), $values); } else { throw new PermissionException("Access denied"); } } } So, exposed via xmlrpc etc... /** * phpdoc needs adding IRL * clients (whether 'local' or via xmlrpc/soap etc) connect to this. */ class AliasServer { protected $backend = null; public function __construct() { $this->backend = new PermissionProxy(new Alias()); } public function addAlias($p, $p, $p) { return $this->backend->addAlias($u, $p); } public function deleteAlias($u, $p) { return $this->backend->deleteAlias($admin); } public function getAliasList($domain, $offset, $limit) { return $this->backend->getAliasList($domain, $offset, $limit); } public function search($domain, $string) { // whatever } } /* The above isn't quite right yet, as $username/$password need * passing in to each method call... as xmlrpc isn't very stateful ... * perhaps my decorator idea can't/won't work */ Then for the actual Model object (e.g. Alias) : /* * see http://framework.zend.com/manual/en/zend.db.table.html * perhaps have a PostfixAdminAbstract class with additional * functionality over Zend_Db_Abstract in it for Alias to inherit from? */ class Alias extends Zend_Db_Abstract { protected $_name = 'alias'; protected $_primary = 'id'; // whatever the pkey field is protected $_sequence = false; // force use of pkey field value in insert . public function __construct() { $db = Zend_Db::factory('....whatever...'); //? parent::__construct($db); } // Zend_Db_Abstract provides: // insert(array(key=>value, key=>value ... )); // update($data, $where); // delete($where); // find($pkey); // fetchall($select_query); // perhaps we'd want to wrap e.g. update in a call like ... public function edit($pkey, $data) { // perform validation check(s); throw some sort of // exception if they fail. return $this->update($data, $this->getAdapter()->quoteInto('pkey = ?', $pkey)); } } > Comments welcome: (ditto) > - do you think this could become the basis of all postfixadmin pages? I'm keen to separate a page from the underlying logic used for it. We should provide e.g. xmlrpc or soap integration, and decouple the business logic from the controller scripts that generate html pages. Having some sort of base controller and/or model class will be a good thing. > - what should I/we do better? (We have 35 °C outside, so I'm sure the > baseclass isn't perfect ;-) Heh; it was warm here, but also humid (as is nearly always the case in the UK); thankfully we've just had a few thunderstorms and things seem better. The dog wasn't happy though. I think a good start is perhaps to list all classes, and the functions they need : e.g. Vacation: - isEnabled($email); - create($email, $subject, $body, $whatever); - delete($email, $subject, $body, $whatever); - retrieve($email); Domain: - list($offset, $limit = 20) - retrieve($name); - create($name, $backup_mx, etc); - delete($name); Mailbox: - list($offset, $limit = 20); - retrieve($name); - create($name, $fullname, $password, ... etc) - delete($name); etc There would need to be some sort of shared 'authentication'/'user' data/object so we can enforce permission checks (e.g that a user can only delete their own mailbox, and not someone elses; but a global admin can delete any... etc) </ramble> And so on, David. -- David Goodwin [ david at codepoets dot co dot uk ] [ http://www.codepoets.co.uk ] |
From: Christian B. <pos...@cb...> - 2008-07-28 23:03:15
|
Hello, this mail has two parts: a) summing up the IRC session (copy and paste from the IRC log) b) things we didn't talk about in IRC Gingerdog, you might want to skip to b) ;-) a) Am Montag, 28. Juli 2008 schrieb David Goodwin: > Christian Boltz wrote : > > Am Mittwoch, 23. Juli 2008 schrieb Christian Boltz: > > > My idea in short: > > > - create a basic class with the required functions/methods. > > > > I have written a proof-of-concept class postfixadminBaseclass as > > described in my proposal. It is attached to this mail. > Right, I'll include the code inline, as I'm lazy (and using mutt, > while my office computer is dead thanks to the thunder+lightening) > class postfixadminBaseclass { ... > # name, also used for generating links > public function name($listmode=0) { > # usually: > return "baseclass"; ... > } > > ^^ What's name() trying to do? The intention was to use it as basename for generating links (to the "add new", "edit" and "list" pages). However, I'm not sure if this should be really inside the class, since it has to do with HTML rendering. -> removal candidate, I'll comment it out in my draft (and already have an idea how to replace it ;-) ... > # handles add and edit calls internally > protected function addOrEdit($primarykey, Array $newvalues, > $mode) { # mode: 0 = edit, 1 = new > > # calls: [TODO] > # - [non-public] function validate_by_type() (simple check > against # field type given in table structure) > > ^^ I think this is unnecessary; database introspection might be a > better bet. [GingerDog] i think type checks etc would be better handled by asking the model class to validate() itself we can do most checks this way (nearly automatically - in the central class). And it even has the advantage that we can define our own types if needed - like "mail address" ... > # TODO > # * [non-public] check_domain_permission() (check if the admin > has # permissions for this domain) > # * [non-public] check_other_permission() (check other > permissions, for # example if editing mailbox aliases is allowed) ... > It would be nice for the permission definitions to be done in one > place, where ever that may be. > > Could permissions be listed a bit like : > > e.g. > > /** > * decorator for permission enforcement > */ > class PermissionProxy { ... I'm not planning to implement a login($user, $pass) inside the class. But I'm thinking about a check "has permissions for this domain?" or "is superadmin?" which is basically what we have in each script right now. The base class would handle this without modification in each module And the "special permission checks" I mentioned are things like checking $CONF['fetchmail'] ;-) [GingerDog] Permissions checks (or at least enforcements) shouldn't really be in the individual controller(s) if they are moved to the model classes then they take effect for any user, regardless of whether they're coming through the web interface, xmlrpc or whatever and there may be less repetition The checks would be in the base class - no need to redefine them each time. Just using the functions from the parent class doesn't look bad for me ;-) Part b) > So, exposed via xmlrpc etc... > > /** > * phpdoc needs adding IRL > * clients (whether 'local' or via xmlrpc/soap etc) connect to this. > */ > class AliasServer { ... > public function addAlias($p, $p, $p) { > return $this->backend->addAlias($u, $p); > } If possible, we should have common names ("add", "edit") instead of type-specific ones. If you simply add a $type-Parameter, you don't even need to implement a xmlrpc connector class for each type ;-) (the data arguments can/should be passed as array to be flexible) > public function getAliasList($domain, $offset, $limit) { > return $this->backend->getAliasList($domain, $offset, > $limit); } Ah, you just found two missing parameters in my items() function: $offset and $limit. I now have: public function items ($domain="", $admin="", $search="", $offset = -1, $limit = -1) Looks like I should switch to a named parameter array instead of lots of optional parameters... # $filter can contain several parameters to filter the list. # All parameters in $filter are optional. # $filter = array( # 'domain' -> "", # 'admin' -> "", # 'search -> "", # 'offset' -> 0, # 'limit' -> -1, # unlimited # ) public function items (array $filter) { Looks better ;-) > public function search($domain, $string) { > // whatever > } Already included in items(), see above ;-) > /* The above isn't quite right yet, as $username/$password need > * passing in to each method call... as xmlrpc isn't very stateful > ... * perhaps my decorator idea can't/won't work > */ This makes another two parameters to the generic xmlrpc calls: username and password. (I'll forget about this for now - first I need a working baseclass and then I'll think about xmlrpc again ;-) > Then for the actual Model object (e.g. Alias) : ... > class Alias extends Zend_Db_Abstract { > protected $_name = 'alias'; > protected $_primary = 'id'; // whatever the pkey field is > protected $_sequence = false; // force use of pkey field > value in insert . public function __construct() { > $db = Zend_Db::factory('....whatever...'); //? > parent::__construct($db); > } ... Or just use our db_insert (and db_update, db_delete etc.) function we already have. I'll probably do this when filling the baseclass with code. And again: Do _not_ make such things specific to a table or module unless really needed ;-) > > Comments welcome: (ditto) > > - do you think this could become the basis of all postfixadmin > > pages? > > I'm keen to separate a page from the underlying logic used for it. /me too ;-) > We should provide e.g. xmlrpc or soap integration, and decouple the > business logic from the controller scripts that generate html pages. ACK - even if my main target is to make maintenance and writing new modules easier. Adding xmlrpc or soap integration doesn't conflict with this target. > Having some sort of base controller and/or model class will be a good > thing. Yes. I'm sure we don't even foresee how many good things we will get by having a class-based implementation :-) Last IRC quote for this mail: If my class works as I expect, most modules will contain of "overwrite table name, overwrite database scheme/field list, overwrite default values" - and nothing else :-) > > - what should I/we do better? (We have 35 °C outside, so I'm sure > > the baseclass isn't perfect ;-) > > Heh; it was warm here, but also humid (as is nearly always the case > in the UK); thankfully we've just had a few thunderstorms and things > seem better. The dog wasn't happy though. ;-) > I think a good start is perhaps to list all classes, and the > functions they need : Yes - and we should also keep in mind how to map them on the standard method names in my baseclass. > Vacation: > - isEnabled($email); items() with a search parameter (empty result = no vacation) The easier way would be an itemExists() function, however I'm not sure if we need this. > - create($email, $subject, $body, $whatever); > - delete($email, $subject, $body, $whatever); > - retrieve($email); > > Domain: > - list($offset, $limit = 20) > - retrieve($name); > - create($name, $backup_mx, etc); > - delete($name); > > Mailbox: > - list($offset, $limit = 20); > - retrieve($name); > - create($name, $fullname, $password, ... etc) > - delete($name); All those will work with the functions I already have [retrieve -> item(), create -> add()]. > There would need to be some sort of shared 'authentication'/'user' > data/object so we can enforce permission checks (e.g that a user can > only delete their own mailbox, and not someone elses; but a global > admin can delete any... etc) Yes - as written above, the login details could just be additional parameters. The username has to be passed to the baseclass somehow (parameter to each function or as a global variable - what's better?) The password check should be done outside because it differs on the implementation (HTML output has a session, xmlrpc might need to pass it each time). My personal summary of the mail is that my baseclass isn't that bad. If nobody objects, I'll create a classes/ directory in SVN and check it in in the next days ;-) Regards, Christian Boltz -- Und dann war da noch der junge Mann, der unbedingt Schriftsteller werden wollte. Er wollte Emotionen wecken und die Leute zum Weinen bringen. Sein Traum wurde wahr, er verfaßt heute die Fehlermeldungen bei Microsoft. |
From: Christian B. <pos...@cb...> - 2008-08-14 22:06:41
Attachments:
baseclass.php
fetchmail-class.php
|
Hello, just to keep you up to date: I have updated the baseclass and filled it with some code (by splitting fetchmail.php). I also created a class for fetchmail as a first example. The two files are attached. Be warned that the code is completely untested and still is not as abstract as it should be at many places. However, you should get the point. Comments and patches welcome ;-) Regards, Christian Boltz -- > > My calendar shows May 12th to be a Friday, not a Thursday? > I meant 11th ;-(. With all the delays, perhaps mentioning the year would also be a good idea. ;-) [> Andreas Jaeger and houghi in opensuse] |
From: David G. <da...@co...> - 2008-07-29 20:59:27
|
21:36 < lenix> ok, i've made a first step and managed to dump the model of my current db-structure into some PHP/ZendFramework code 21:36 < lenix> see http://lenix.de/pfaModel.phps and http://lenix.de/pfaModel.sql 21:37 < lenix> see http://framework.zend.com/manual/en/zend.db.table.relationships.html#zend.db.table.relationships.cascading for onDelete/onUpdate 21:38 < GingerDog> looks good 21:38 < GingerDog> i'm not sure i like the pfa prefix though 21:38 < lenix> $_columns is for reference-purposes only, i don't know whether such a variable does exist in ZF 21:39 < lenix> i would use some kind of prefix, i don't care which one 21:39 < GingerDog> Most importantly, do not declare cascading operations both in the RDBMS and in your Zend_Db_Table class. 21:39 < lenix> but it proves to be good pratice if you want to include the code of/in some other software 21:39 < lenix> GingerDog: exactly 21:40 < lenix> i've got cascading-stuff inside my innodb already, that's why i commented it out 21:40 < GingerDog> can you mail the code, or a url of it, to the -devel mailing list 21:41 < lenix> GingerDog: i intended to add some validation-routines and an usage-example first.. 21:41 < lenix> but if you think publishing it in such an early state of course i can 21:42 < lenix> .. an early state make sense, of course .. 21:43 < lenix> anyway, i will call it a day now and go play some foosball :) 21:43 < lenix> ttyl 21:43 < GingerDog> k 21:44 < GingerDog> if you're going to imrpove on it then keep at it 21:44 < GingerDog> but it needs "publishing" sooner rather than later 21:50 < lenix> if you think it is enough for a first step already feel free to copy/paste our conversation to the list -- David Goodwin [ david at codepoets dot co dot uk ] [ http://www.codepoets.co.uk ] |
From: Christian B. <pos...@cb...> - 2008-08-14 21:36:11
|
Hello, Am Dienstag, 29. Juli 2008 schrieb David Goodwin: > 21:36 < lenix> ok, i've made a first step and managed to dump the > model of my current db-structure into some PHP/ZendFramework code > 21:36 < lenix> see http://lenix.de/pfaModel.phps and > http://lenix.de/pfaModel.sql Looks good, but I'm still not sure if we a) need a class for each table b) need a "big" abstraction layer for doing some SELECT, INSERT, UPDATE and DELETE operations The other option would be a small database class with a syntax like $db->begin # begin transaction - or simply ignore call if not supported $db->insert($table, $values_array) $db->update($table, $primarykey_field, $primarykey_value, $values_array) $array = $db->select($table, $cond, $limit, $orderby) and some helper functions like $db->cond($field, $operation, $value) # example: $db->cond("domain", "=", "example.com") $db->and($cond1, $cond2, $cond3, ...) # used to build WHERE clauses # example: $db->and($db->cond(...), $db->cond(...) ) $db->or($cond1, ...) # same with OR The helper functions might look superfluous, but they make the statements independent from the SQL language. The advantage I see with this solution: It would be really lightweight and only contain what we really need. When thinking further: what would be easier for someone who wants to add LDAP support? (I'm not a LDAP user/admin/fan, but it looks like some people would like to use it. So we should at least try to make it easy for them.) > 21:38 < lenix> $_columns is for reference-purposes only, i don't know > whether such a variable does exist in ZF OK, this would have been my first complaint otherwise. We (will) have the table structure in $struct already, duplicating it in the database class is pointless. We have the database structure in upgrade.php also, but I'm afraid we won't be able to avoid this - unless someone extracts the database scheme comparison from Typo3 ;-) > 21:41 < lenix> GingerDog: i intended to add some validation-routines > and an usage-example first.. I'll have validation code in my module class already, not sure if you need additional validation in the database class. Having some usage examples (for insert, update, delete and select) would be nice. Regards, Christian Boltz -- "Guten Tag, ich möchte gerne einen Tisch reservieren." "Gerne, auf welchen Namen denn?" "31337 /-/ /\ X0R!" [Jens Benecke in suse-linux zum Thema Realnames] |