Zend_Db_Table_Select Dynamic Finder
Hello, Habr! 
Wrote a class using Zend_Db_Table_Select and allowing the use of Dynamic Finder in models in projects on the Zend Framework. An article about what this class can do, as well as a link to the source code are offered to your attention.
Dynamic Finder is a method that allows you to get data from a database table by writing the names of the fields you are looking for as the name of a class method, and the values of these fields as an argument to the method. For example, it can be used in an instance of a model class associated with any database table.
Dynamic Finder avoids writing a number of methods of the form getById (...), getByLoginAndPassword (...), getAllByCountry (...) inside the model in the form of constructing full-fledged SQL queries and samples. Instead, in this implementation, it is enough to connect the Dynamic Finder to the model properly, and, further, the programmer can use these methods of the model directly in the controller or view. Moreover, in reality these methods do not exist in the model at all.
Thus, the programmer’s time is saved.
Dynamic Finder has already been implemented in one form or another in various libraries and frameworks, in particular in Ruby on Rails.
In this implementation, Dynamic Finder is an add-in that uses Zend_Db_Select / Zend_Db_Table_Select, and is designed to select from only one table.
Several types of syntax are used. The simplest:
getBy ... is identical to getAllBy ... - i.e. implies a query with many rows. To get only one line, you can use getOneBy ...
The syntax of the names of the requested fields used in the name of the method is to record the names of these fields in CamelCase mode. In this case, fields with the name of the form user_name should be written in the name of the method as UserName (each word starting with an underscore is replaced with a capital letter). Different fields in the name of the "virtual method" are separated by logical operators And or Or.
For instance,
The syntax of the argument of the “virtual method” supports two forms: short (as arguments, comma separated values of the fields used to construct the query, see examples above) and full. The full form requires an associative array as a method argument and looks like this in the most general form:
The order of writing the field values (the values array, or the simplest case) must correspond to the order of the field names in the name of the "virtual method". The options array and key-value pairs containing it are optional, but there are no default values for them. You can also use instances of the Zend_Db_Expr class as arguments:
In my opinion, the easiest way is to start the object of the Dymanic Finder class in the model as private - property:
Primary processing of the “virtual method”; getting data from the database after generating the desired Zend_Db_Table_Select:
$ this-> getTable () should return a Zend_Db_Table object associated with the model.
In principle, everything can be very different. For example, you can feed the DymanicFinder as select in some way to a pre-prepared instance of Zend_Db_Table_Select (Zend_Db_Select) that meets your specific task. Also, in another way, you can pass an array-list of fields available in the table. Similarly, the results of transforming the Zend_Db_Select () object can be processed differently (instead of the conditions for checking getOneBy). It is for the sake of possible improvements necessary for the final programmer, Dynamic Finder in this case is made in the form of such a "semi-finished product." For the sake of all kinds of customization.
There is also an option for external parsing of the method name (instead of the internal _camelCase2underscore ()). Those. your rules for naming columns in tables and in method names for the finder will be different. In this case, somewhere before calling the __call method, you need to define the $ this-> columnParseCallback property in the form of a callback (as for call_user_func ()), in which you define the external parser function of your method name.
Inside, we have php code that will not work if you don’t pass it to either the Zend_Db_Table_Select descendant (Zend_Db_Select is sufficient if you work, for example, with one table), or a list of valid fields. But is it not enough that subsequently the programmer will write when writing the virtual method? ;)
The source code of the class is available at the link .
UPD : The bug with line 337 is fixed, formatting is also slightly corrected. Thanks to user dmitry_dvp

Wrote a class using Zend_Db_Table_Select and allowing the use of Dynamic Finder in models in projects on the Zend Framework. An article about what this class can do, as well as a link to the source code are offered to your attention.
What is this, why?
Dynamic Finder is a method that allows you to get data from a database table by writing the names of the fields you are looking for as the name of a class method, and the values of these fields as an argument to the method. For example, it can be used in an instance of a model class associated with any database table.
Dynamic Finder avoids writing a number of methods of the form getById (...), getByLoginAndPassword (...), getAllByCountry (...) inside the model in the form of constructing full-fledged SQL queries and samples. Instead, in this implementation, it is enough to connect the Dynamic Finder to the model properly, and, further, the programmer can use these methods of the model directly in the controller or view. Moreover, in reality these methods do not exist in the model at all.
Thus, the programmer’s time is saved.
Dynamic Finder has already been implemented in one form or another in various libraries and frameworks, in particular in Ruby on Rails.
In this implementation, Dynamic Finder is an add-in that uses Zend_Db_Select / Zend_Db_Table_Select, and is designed to select from only one table.
How to use it?
Several types of syntax are used. The simplest:
$ modelObj-> getByTag ($ tag);
getBy ... is identical to getAllBy ... - i.e. implies a query with many rows. To get only one line, you can use getOneBy ...
The syntax of the names of the requested fields used in the name of the method is to record the names of these fields in CamelCase mode. In this case, fields with the name of the form user_name should be written in the name of the method as UserName (each word starting with an underscore is replaced with a capital letter). Different fields in the name of the "virtual method" are separated by logical operators And or Or.
For instance,
$ user-> getOneByLoginAndPassword ($ login, $ password);
The syntax of the argument of the “virtual method” supports two forms: short (as arguments, comma separated values of the fields used to construct the query, see examples above) and full. The full form requires an associative array as a method argument and looks like this in the most general form:
$ data = $ files-> getAllByPaperId (
array ('values' => array ($ paperId, ...),
'options' => array (
'order' => array ('orig_filename ASC'),
'offset' = > $ offset,
'limit' => 10
)));
The order of writing the field values (the values array, or the simplest case) must correspond to the order of the field names in the name of the "virtual method". The options array and key-value pairs containing it are optional, but there are no default values for them. You can also use instances of the Zend_Db_Expr class as arguments:
$ data = $ tagObj-> getAllByTag (new Zend_Db_Expr (sprintf ("LIKE '% s %%'", $ beginStr)));
Connection to the model.
In my opinion, the easiest way is to start the object of the Dymanic Finder class in the model as private - property:
/ **
* Dynamic Finder object
* @var DynamicFinder
* /
private $ _dynFinder;
public function __construct () {
if (! class_exists ('DynamicFinder', false)) {
require_once 'path_to'. '/DynamicFinder.php';
}
$ this -> _ dynFinder = new DynamicFinder ();
}
Primary processing of the “virtual method”; getting data from the database after generating the desired Zend_Db_Table_Select:
public function __call ($ name, $ arguments)
{
$ this -> _ dynFinder-> select = $ this-> getTable () -> select ();
$ this -> _ dynFinder-> allowedFields = $ this-> getTable () -> info (Zend_Db_Table_Abstract :: COLS);
$ select = call_user_func_array (array ($ this -> _ dynFinder, $ name), $ arguments);
if (strpos ($ name, 'getOneBy') === 0) {
return $ this-> getTable () -> fetchRow ($ select);
} else {
return $ this-> getTable () -> fetchAll ($ select);
}
}
$ this-> getTable () should return a Zend_Db_Table object associated with the model.
In principle, everything can be very different. For example, you can feed the DymanicFinder as select in some way to a pre-prepared instance of Zend_Db_Table_Select (Zend_Db_Select) that meets your specific task. Also, in another way, you can pass an array-list of fields available in the table. Similarly, the results of transforming the Zend_Db_Select () object can be processed differently (instead of the conditions for checking getOneBy). It is for the sake of possible improvements necessary for the final programmer, Dynamic Finder in this case is made in the form of such a "semi-finished product." For the sake of all kinds of customization.
There is also an option for external parsing of the method name (instead of the internal _camelCase2underscore ()). Those. your rules for naming columns in tables and in method names for the finder will be different. In this case, somewhere before calling the __call method, you need to define the $ this-> columnParseCallback property in the form of a callback (as for call_user_func ()), in which you define the external parser function of your method name.
Implementation.
Inside, we have php code that will not work if you don’t pass it to either the Zend_Db_Table_Select descendant (Zend_Db_Select is sufficient if you work, for example, with one table), or a list of valid fields. But is it not enough that subsequently the programmer will write when writing the virtual method? ;)
The source code of the class is available at the link .
UPD : The bug with line 337 is fixed, formatting is also slightly corrected. Thanks to user dmitry_dvp