Named scope for Zend Framework
Working with the database, you constantly have to write many search methods. Here is a typical scenario:
Suppose we need to list the users on a site. At first, it could be like this - $ user_table-> fetchAll (). And if you want to display only girls? Let's write the getFemaleUsers () method. But only those who are not banned and have an avatar? And the conclusion in the admin panel is only for girls, but without taking into account the status of the user?
In the end, we get a wagon of methods that partially overlap each other or even do the same thing, and only sorting is different. But they still need to be tested ...
There is nothing wrong with this approach, but it quickly tires. If there are several developers in a project, sometimes methods may appear that do the same thing, but are named differently.
This task has a solution and it is called named scope . This is implemented in rails and looks like this:
A little explanation. Methods in ruby are very often generated, and when they are called, brackets are almost always omitted. The above is a call to methods, not properties.
How to implement the same in Zend Framework? Zend_Db_Table_Select will come to our aid. Unfortunately, ZF does not make it possible to replace select with tables using regular means, so we will act independently.
We parse the dbTable_User gateway as an example. First you need to override the select method, and instantiate inside, for example, dbTable_User_Select (successor to Zend_Db_Table_Select). Then we open this class and write the methods we need.
All! You can use it.
By combining methods, you can make almost any sample, and it is enough to test only these micro methods.
As a result, we got objects of type Select, and in order to make a request to the database they will have to be inserted into the fetchRow or fetchAll of the gateway. Here we again cheat and make for all our dbTable_ ... _Select common parents in which we define the following methods:
In essence, select begins to proxy to the dbTable object, which it stores inside itself. As a bonus, we get a number of convenient methods like count, sum, etc. Now, in order to get from the resulting select what you need to do this:
Suppose we need to list the users on a site. At first, it could be like this - $ user_table-> fetchAll (). And if you want to display only girls? Let's write the getFemaleUsers () method. But only those who are not banned and have an avatar? And the conclusion in the admin panel is only for girls, but without taking into account the status of the user?
In the end, we get a wagon of methods that partially overlap each other or even do the same thing, and only sorting is different. But they still need to be tested ...
There is nothing wrong with this approach, but it quickly tires. If there are several developers in a project, sometimes methods may appear that do the same thing, but are named differently.
This task has a solution and it is called named scope . This is implemented in rails and looks like this:
class User <ActiveRecord :: Base named_scope: active,: conditions => {: active => true} named_scope: inactive,: conditions => {: active => false} named_scope: male,: conditions => {: sex => male} end
User.active # Selects all active users User.inactive # Selects all inactive users User.active.male # Selects all active men
A little explanation. Methods in ruby are very often generated, and when they are called, brackets are almost always omitted. The above is a call to methods, not properties.
How to implement the same in Zend Framework? Zend_Db_Table_Select will come to our aid. Unfortunately, ZF does not make it possible to replace select with tables using regular means, so we will act independently.
We parse the dbTable_User gateway as an example. First you need to override the select method, and instantiate inside, for example, dbTable_User_Select (successor to Zend_Db_Table_Select). Then we open this class and write the methods we need.
class dbTable_User_Select extends Zend_Db_Table_Select { public function status ($ status) { return $ this-> where ('status =?', $ status); } public function sex ($ sex) { return $ this-> where ('sex =?', $ sex); } public function hasAvatar () { return $ this-> where ('avatar is not null'); } public function sortById () { return $ this-> order ('id DESC); } }
All! You can use it.
$ user_table-> select () -> hasAvatar () -> sex ('male'); $ user_table-> select () -> status ('active') -> sortById ();
By combining methods, you can make almost any sample, and it is enough to test only these micro methods.
As a result, we got objects of type Select, and in order to make a request to the database they will have to be inserted into the fetchRow or fetchAll of the gateway. Here we again cheat and make for all our dbTable_ ... _Select common parents in which we define the following methods:
class Ext_Db_Table_Select extends Zend_Db_Table_Select { public function fetchRow () { return $ this-> getTable () -> fetchRow ($ this); } public function fetchRowIfExists ($ message = 'This page is not on the site') { return $ this-> getTable () -> fetchRowIfExists ($ this, $ message); } public function fetchAll ($ limit = null, $ offset = null) // Not the best method name) { if ($ limit) { $ this-> limit ($ limit, $ offset); } return $ this-> getTable () -> fetchAll ($ this); } public function getPaginator ($ page = 1, $ limit = 10, $ pageRange = 7) { $ adaptee = new Ext_Paginator_AdapterAggregate ($ this); $ paginator = Zend_Paginator :: factory ($ adaptee); $ paginator-> setItemCountPerPage ($ limit); $ paginator-> setCurrentPageNumber ($ page); $ paginator-> setPageRange ($ pageRange); return $ paginator; } // These useful methods can also be implemented. public function count () public function max ($ field) {}; public function min ($ field) {}; public function sum ($ field) {}; public function exists () {}; public function random ($ limit = 5) // Pseudo Random { $ count = $ this-> count (); $ offset = ($ count> $ limit)? $ count - $ limit: 0; $ this-> limit ($ limit, mt_rand (0, $ offset)); return $ this-> fetchAll (); } }
In essence, select begins to proxy to the dbTable object, which it stores inside itself. As a bonus, we get a number of convenient methods like count, sum, etc. Now, in order to get from the resulting select what you need to do this:
$ select-> fetchRow (); // Get the line $ select-> getPaginator ($ page); // Paging $ select-> fetchAll (5); // take 5 lines // Often needed where 404 should be thrown if empty $ select-> fetchRowIfExists ();