📜 ⬆️ ⬇️

Zend_Db_Table_Select Dynamic Finder

Hi, Habr! Dynamic finder

Wrote a class that uses Zend_Db_Table_Select and allows you to use Dynamic Finder in models in projects on the Zend Framework. The article that this class can, as well as a link to the source code are offered to your attention.

What is it, why?


')
Dynamic Finder is a method that allows you to retrieve 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 class of a model associated with a database table.

Dynamic Finder avoids writing a number of methods like getById (...), getByLoginAndPassword (...), getAllByCountry (...) inside the model in the form of building full-fledged SQL queries and selections. Instead, in this implementation, it is sufficient to connect Dynamic Finder to the model properly, and, further, the programmer can use these model methods directly in the controller or view. At the same time, these methods in the model do not exist at all.

Thus, the time saved by the programmer 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-on that uses Zend_Db_Select / Zend_Db_Table_Select and is intended for samples 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 multiple lines. You can use getOneBy to get only one line ...

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 a name of the form user_name must be written in the name of the method as UserName (each word starting with an underscore is replaced with a word with a capital letter). Different fields in the name of the “virtual method” are separated by the logical operators And or Or.

For example,
$ user -> getOneByLoginAndPassword ( $ login , $ password ) ;


The syntax of the “virtual method” argument supports two forms: short (as arguments, comma-separated, write the values ​​of the fields by which the query is based, see examples above) and full. The full form requires an associative array as a method argument and, in its most general form, looks like this:

$ data = $ files -> getAllByPaperId (
array ( 'values' => array ( $ paperId , ... ) ,
'options' => array (
'order' => array ( 'orig_filename ASC' ) ,
'offset' => $ offset ,
'limit' => 10
) ) ) ;


The order of writing field values ​​(values ​​array, or the simplest case) must correspond to the order of field names in the name of the “virtual method”. The options array and the key-value pairs that contain it are optional, but there are no default values ​​for them either. You can also use instances of the class Zend_Db_Expr as arguments:
$ data = $ tagObj -> getAllByTag ( new Zend_Db_Expr ( sprintf ( "LIKE ' % s %% '" , $ beginStr ) ) ) ;


Connect to the model.



In my opinion, the easiest way is to get the object of the Dymanic Finder class itself as a private property in the model:
/ **
* 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”; retrieving 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 () must return a Zend_Db_Table object associated with the model.

In principle, everything can be completely different. For example, you can feed DymanicFinder as a select in some way a previously prepared instance of Zend_Db_Table_Select (Zend_Db_Select) that is specifically for your specific task. Also, in another way, you can transfer an array-list of available fields in the table. Similarly, the transformation results of the Zend_Db_Select () object can be processed differently (instead of the conditions for the getOneBy check). It is for the sake of possible improvements needed by the final programmer that Dynamic Finder in this case is made in the form of such a “semi-finished product”. For all sorts of customization.

There is also a variant of the external parsing of the method name (instead of the internal _camelCase2underscore ()). Those. Your column naming rules in the tables and method names for the file will differ. 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 specify the external parser function of your method name.

Implementation.



And inside we have a php-code that will not work if you don’t pass either a Zend_Db_Table_Select successor to it (Zend_Db_Select is enough if you work with one table, for example) or a list of valid fields. And then you never know what the programmer will use when writing a virtual method? ;)

The source code of the class is available by reference .

UPD : The bug with line 337 is fixed, the formatting is also slightly fixed. Thanks to dmitry_dvp

Source: https://habr.com/ru/post/86353/


All Articles