Named scope w CakePHP
Sunday, August 31st, 2008Kilka dni temu napisałem jak ulepszyć system callbacków w kontrolerach CakePHP wzorując się na rozwiązaniu zastosowanym w Ruby on Rails. Dziś przeniesiemy kolejny fajny feature z Railsów do Cake’a – named scope.
Named scope czyli po polsku “nazwany zakres/dziedzina”. Chodzi o definicję podzbiorów rekordów danego modelu w celu późniejszego łatwiejszego ich wyszukiwania.
Zaczniemy znowu od przykładu. Definicja modelu User w RoR:
class User < ActiveRecord::Base # podzbiór użytkowników, którzy aktywowali konto named_scope :activated, :conditions => "activated_at is not null" # podzbiór użytkoników, którzy są on-line named_scope :online, :conditions => "date_add(last_activity, interval 5 minute) > now()" end
To bardzo prosty przykład, w rzeczywistości named scope nadaje się też do dużo bardziej ciekawych rzeczy. Jednak “wersja Cake’owa”, którą zaprezentuje poniżej jest właśnie ograniczona do definicji warunków.
Zdefiniowane wyżej zakresy możemy później użyć podczas wyszukiwania:
# wszyscy aktywowani użytkownicy users = User.activated.find(:all) # wszyscy aktywowani i on-line użytkownicy z liczbą punktów większą od 10 users = User.activated.online.find(:all, :conditions => "points > 10")
Zalety zapisu widać właściwie od razu. Named scope upraszcza zapis. Często powtarzające się warunki wyszukiwania (dostęp tylko do aktywowanych użytkowników potrzebujemy w wielu miejscach aplikacji) umieszczamy w named scope, a inne umieszczamy “po staremu” w :conditions. Zapis wygodny i bardzo czytelny.
Podobną funkcjonalność w Cake’u zapewni nam NamedScopeBehavior, który przetłumaczy (w callbacku modelu beforeFind) zdefiniowane zakresy na warunki przekazane później do zapytania SQL.
Plik named_scope.php pobrany repozytorium należy umieścić w folderze app/models/behaviors. Później w modelu możemy już definiować zakresy.
class User extends AppModel {
var $actsAs = array(
'NamedScope' => array(
'activated' => array('User.activated in not null'),
'online' => array('date_add(User.last_activity, interval 5 minute) > now()')
)
);
}
Teraz już możemy zacząć korzystać.
$this->User->find('all', array('scope' => 'activated'));
$this->User->find('all',
array('conditions' => 'points > 10', 'scope' => array('activated', 'online')));
Paginacja działa równie dobrze:
$paginate = array(
'User' => array(
'order' => 'created ASC',
'limit' => 20,
'scope' => array('online', 'activated')
)
);
Mam nadzieję, że NamedScopeBehavior ułatwi i uprzyjemni Wam trochę development w CakePHP :)