Named scope for Zend Framework

Working with the database, you always have to write a variety of search methods. Here's a typical scenario:

Suppose we need to display a list of users on the website. In the beginning it can be $user_table->fetchAll(). But if you want to display only women? Write a method getFemaleUsers(). But only those who is not banned and has the avatar? And the output in the admin area only the girls, but without taking into account the status of the user?

In the end we will get the car methods, which partially overlap each other or doing the same thing, and differs only sort. But they still need to test...



In this approach, there is nothing wrong, but it's quickly tiring. If there are several project developers, it can sometimes appear methods that do the same thing, but called differently.

This problem has a solution and it is called named scope. It is implemented in rails and looks like this:

the
class User < ActiveRecord::Base
named_scope :active, :conditions = > {: active = > true}
named_scope :inactive, :conditions = > {: active = > false}
named_scope :male, :conditions = > {: sex = > male}
end


the
User.active # will Select all active users
User.inactive # will Select all inactive users
User.active.male # Choose all active men


A little explanation. Methods in ruby are generated very often, and calling them brackets is almost always omitted. Goes above call methods, not properties.

As the same to implement in Zend Framework? We will come Zend_Db_Table_Select. Sorry ZF does not allow regular tools to replace the select statement for tables, so we will act independently.

Parse the example gateway dbTable_User. First you need to override the select method, and instantiate in, for example, dbTable_User_Select (heir Zend_Db_Table_Select). Then open the class and write the methods we need.

the
class Zend_Db_Table_Select extends dbTable_User_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.

the
$user_table- > select ()- > hasAvatar ()- > sex('male');
$user_table- > select()->status('active')->sortById();


By combining techniques you can make almost any sample, and only enough to test these micro techniques.

In the end we got the objects of type Select, and in order to make a request to the database they will be inserted in the fetchRow or fetchAll gateway. Here again, we're gonna cheat and will do for all of our dbTable_... _Select a common parent in which we will define the following methods:

the
class Zend_Db_Table_Select extends Ext_Db_Table_Select
{
public function fetchRow()
{
return $this->getTable()->fetchRow($this);
}

public function fetchRowIfExists($message = 'page not on the site')
{
return $this->getTable()->fetchRowIfExists($this, $message);
}

public function fetchAll($limit = null, $offset = null) // Not the best name for the method)
{
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 are useful techniques also can 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 fact the select begins to proxy to the dbTable object that stores inside. As a bonus we get a number of convenient methods of count, sum, etc. Now to the select to get what you need, you can do so:

the
$select->fetchRow(); // Take string
$select- > getPaginator($page); // Paging
$select->fetchAll(5); // get 5 rows

// Often needed where an empty result should throw 404
$select->fetchRowIfExists();
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

When the basin is small, or it's time to choose VPS server

Performance comparison of hierarchical models, Django and PostgreSQL

From Tomsk to Silicon Valley and Back