В PHP 5.3 появился ActiveRecord аналогичный Ruby on Rails

Поиски решения активной записи в php были изнурительны до того момента, как один из источников в google не предложил вариант ActiveRecord аналогичный Ruby on Rails. Читатель заметит, что вышеупомянутые результаты слишком устаревшие и большая часть из них мало общего с действенностью.

В конце концов, PHP получит более надежный способ активной записи аналогичный способу применяемому в RoR. И, к счастью, это время настало! Спасибо PHP 5. 3 и его новым полезным функциям: схлопыванию, позднему статистическому связыванию и пространству имен.

Я со своим другом Каеном, внесли улучшения в раннюю версию на базе ORM, которую он написал до появления PHP 5. 3. Мы создали ActiveRecord вдохновленные Ruby on Rails и попытались сохранить его возможности, насколько это было возможно. Нашей основной целью в этом проекте – дать возможность PHP-разработчикам создавать крупные проекты с большей гибкостью.

Мы также надеемся что использование данного продукта подтолкнет PHP сообщество к дальнейшему осознанию всех замечательных преимуществ Ruby on Rails. Ладно , хватит крутиться вокруг да около, давайте перейдем к самому интересному!
 

Обзор ActiveRecord


Позвольте мне согласиться с тем фактом, что мы пытались сохранить сходство между нашим детящем и ActiveRecord на базе Ruby on rails, чтобы избежать головной боли и повысить работоспособность программиста. Сохраняя это сходство, мы постарались воссоздать многие функции. Вот список этих функций:

  • Методы поиска
  • Методы динамического поиска
  • Методы записи
  • Отношения
  • Верификация
  • Обратные вызовы
  • Сериализация
  • Поддержка различных драйверов
  • Другие параметры


Также здесь есть и другие возможности, как пространства имен, дополнительные драйверы, транзакции (то чего мы хотели бы пораньше) и многое другое мы добавим в будущем, но для начала я думаю совсем неплохо. Мы надеемся, запустить сайт с документацией и разместить исходники на сервисе исходных кодов в течении 2-3х недель. Не забывайте следить за обновлениями, которые вскоре появятся.
 

Конфигурация


Установка проста и линейна. Здесь есть всего 2 типа конфигурации, которые вы можете выбрать:
 

  • Установка типовой auto_load директории
  • Настройка соединений с вашей базой данных


Примеры:

ActiveRecordConfig::initialize(function($cfg)
{
$cfg->set_model_directory('/path/to/your/model_directory');
$cfg->set_connections(array('development' =>
'mysql://username:password@localhost/database_name'));
});
#Альтернативно(w/o ограничение 5.3):
$cfg = ActiveRecordConfig::instance();
$cfg->set_model_directory('/path/to/your/model_directory');
$cfg->set_connections(array('development' => 'mysql://username:password@localhost/database_name'));


Как только вы настроите два этих параметра ваша работа окончена. ActiveRecord заботится о вас и берет остальную часть работы на себя. Она не требует проводить какую либо дополнительную работу со схемами ваших yaml/xml файлов. Также запросы к базу данных для получения информации и кэш-файлов будет проходить без лишних вызовов для одной схемы.

Методы поиска


ActiveRecord поддерживает несколько методов, с помощью которых, вы можете найти записи либо по первичному ключу, либо сконструировав свой собственный с набором опций, к примеру: сортировка, лимит, выбор, группировка.

#поиск по первичному ключу
Author::find(3);
#поиск нескольких записей по первичному ключу
Author::find(1, 2, 3);
#поиск первой записи по лимиту
Author::first();
#поиск последней записи по сортировке и лимиту
Author::last();
Author::all();
#это возможно будет для вас адом, но вы должны выполнить свой sql-запрос для поиска
Author::find_by_sql();
## еще вы можете добавить много дополнительных опций к методам поиска
#sql => ORDER BY name
Author::find(3, array('order' => 'name'));
#sql => WHERE author_id IN (1, 2, 3)
# поиск с условиями как массив
Author::find('all', array('conditions' => array('author_id IN(?)', array(1, 2, 3))));
#sql => WHERE author_id = 3
#поиск с условиями как строка
Author::find('first', array('conditions' => 'author_id=3'));
#sql => GROUP BY name
Author::find(3, array('group' => 'name'));
#sql => LIMIT 0, 3
Author::find('all', array('limit' => 3));
#sql => select * from `author` INNER JOIN etc. . .
Author::find('all', array('joins' =>
'INNER JOIN book on (book. author_id = author. id)'));
#sql => SELECT name FROM table
Author::first(array('select' => 'name'));
#этод метод не возвращает запись
#возвращает да/нет
Author::exists(1);
#возвращает число
Author::count(array('conditions' => array('name = ?', 'John')));

#доступ очень простой
$book = Book::first();
echo
$book->title;
echo
$book->author_id;
# возвращает массив
$books = Book::all();
echo
$books[0]->title;


Методы динамического поиска


ActiveRecord на основе RoR расширяет функции использования поиска, позволяя динамически создавать методы основанные на атрибутивных именах. Это значит, вы с легкостью можете сделать запрос"find_by_attribute_name" без явного классового определения. Мы сделали это возможным с помощью использования волшебного метода в PHP 5.3: __callStatic().

Author::find_by_name('George Bush');
#вы можете это сделать используя и/или
Author::find_by_name_or_author_id('George Bush', 2);
Person::find_by_first_name_and_last_name('Obama', 'Mama');
#также имеется find_all_by(найти всё по какому-либо параметру)
Author::find_all_by_name('Tito');
Author::find_all_by_name(array('Tito', 'Bill Clinton'));


Методы записи


Какой смысл иметь объект, который инкапсулирует запись из БД, если вы не можете ничего сделать с этим?

#выполняет SQL insert, такой же какой вы делаете при добавлении записи
$book = new Artist(array('name' => 'Tito'));
$book->save();

## обновление
# обновление возможно, только после нахождения обновляемой строки
$book = Book::find(1);
$book->title = 'new title!';
$book->save();

#это автоматически выполняет сохранение
$book = Book::find(1);
$book->update_attributes(array('title' => 'new title!',
'price' => 5. 00));
#еще автоматическое сохранение
$book = Book::find(1);
$book->update_attribute('title', 'some new title');
$book = new Book;
$book->title = 'new title!';
$book->author_id = 5;
$book->save();
$book->created_at # мы также поддерживаем временные отметки created_at/updated_at где это нужно
echo $book->id; #id также получает авто инкрементированное значение

#удаление
$author = Author::find(4);
$author->delete();

#вы получаете запись в режими только чтение без возможности изменить её
$book = Book::first(array('readonly' => true));
$book->title = 'new'; # или вы можете установить этот режим с помощью метода $book->readonly(true);
#это запустит процессы ActiveRecordReadonlyException
$book->save();


Отношения


Объединения - сложная часть ActiveRecord. Они используют те же самые опции, что в RoR.

#отношения декларируются в статическом свойстве
class Book extends ActiveRecordModel {
static
$belongs_to = array(
array(
'publisher'),
array(
'author', 'readonly' => true, 'select' => 'name', 'conditions' => "name != 'jax'"),
array(
'another', 'class_name' => 'SomeModel')
);
#has_many допускает select/conditions/limit/readonly/group/primary_key
#has_many также применима через опцию которую вы можете использовать с источником(source)
#для уточнения класса
static $has_many = array(
array(
'revisions'),
array(
'editors', 'through' => 'revisions')
);
static
$has_one = array(
array(
'something')
);
}
#индекс декларируемый для каждой ассоциации является "attribute_name"
#которую вы можете использовать для работы с моделью как, например:
$book = Book::first();
echo
$book->publisher->name;
echo
$book->author->name; # у нас есть только имя как атрибут выборки
#ниже будет запускаться опция readonlyException — смотрите методы записи

#методы выбора
$book->author->save();
#has_many
echo $book->revisions[0]->id;
#has_many
echo $book->editors[0]->name;


Верификация


Название говорит само за себя. До того как сохранить/обновить/извлечь к каждому определению, которое вы создали, будет применена верификация и только после её удачного прохождения модель будет возвращена. В противном случае, вы увидите сообщение об ошибке и сможете вернуться обратно для ее исправления.

class Book extends ActiveRecordModel
{
static
$validates_format_of = array(
array(
'title', 'with' => '/^[a-zW]*$/', 'allow_blank' => true)
);
static
$validates_exclusion_of = array(
array(
'title', 'in' => array('blah', 'alpha', 'bravo'))
);
static
$validates_inclusion_of = array(
array(
'title', 'within' => array('tragedy of dubya', 'sharks wit laserz'))
);
static
$validates_length_of = array(
array(
'title', 'within' => array(1, 5)),
array(
'attribute2', 'in' => array(1, 2)),
array(
'attribute3', 'is' => 4, 'allow_null' => true)
);
# same as above since it is just an alias
static $validates_size_of = array();
static
$validates_numericality_of = array( array('title') );
static
$validates_presence_of = array( array('title') );
};
$book = new Book;
$book->title = 'this is not part of the inclusion';
if (!
$book->save())
print_r($book->errors->on('title'));


Обратные вызовы


Обратные вызовы дают вам возможность управлять вашей моделью до/после какого-то события на протяжении ее существования. Вы можете выбрать методы, которые будут вызваны как callback до или после других методов примененных в модели. К сожалению, даже PHP 5.3 имеет ограничения - вы не можете иcпользовать callback в виде статических методов, они должны быть динамическими.

#Ниже приведены команды, которые вы можете использовать
#Если ваш обратный вызов является недействительным для before_*, он отменит
#действие и остальные вызовы
class Book extends ActiveRecordModel{
static
$after_construct;
static
$before_save = array('do_something_before_save');
static
$after_save;
static
$before_create;
static
$after_create;
static
$before_update;
static
$after_update;
static
$before_validation;
static
$after_validation;
static
$before_validation_on_create;
static
$after_validation_on_create;
static
$before_validation_on_update;
static
$after_validation_on_update;
static
$before_destroy;
static
$after_destroy;
#это будет вызвано перед обновлением
public function do_something_before_save() {}
}


Сериализация


class Book extends ActiveRecordModel{
public function
upper_title(){
return
strtoupper($this->title);
}
}
#produces: {title: 'sharks wit lazers', author_id: 2}
$book = Book::find(1);
$book->to_json();
#produces: {title: 'sharks wit lazers'}
$book->to_json(array('except' => 'author_id'));
#produces: {upper_title: 'SHARKS WIT LAZERS'}
#создает массив методов, которые затем будут вызваны
$book->to_json(array('methods' => 'upper_title', 'only' => 'upper_title'));
#produces {title: 'sharks wit lazers', author_id: 2}
$book->to_json(array('include' => array('author')));
#также поддерживает xml, который имеет теже опиции, но нужны больше для тестирования =)
$book->to_xml();


Поддержка различных драйверов


В настоящее время существует поддержка только для MySQL (через mysqli) и sqlite3. Однако мы надеемся ввести большее число драйверов в проект, что должно помочь в работе с такими БД как PostgresSQL и Oracle. Соедиение/адаптер - сделан так, что не возникнет никаких затруднений при создании большего числа драйверов, когда будет нужно.
 

Другие параметры


При декларировании модели вы также можете указать primary_key и table_name.
Защищенные/доступные определения уже доступны, так что вы можете справится со многими распространенными проблемами. Атрибуты могут быть псевдонимами, чтобы вам было легче получить доступ к ним через разные имена.

class Book extends ActiveRecordModel{
static
$primary_key = 'book_id';
static
$table_name = 'book_table';
static
$attr_accessible = array('author_id');
static
$attr_protected = array('book_id');
static
$alias_attribute = array(
'new_alias' => 'actual_attribute',
'new_alias_two' => 'other_actual_attribute'
);
}


Будущее




Рекомендуем почитать

 

Добавить комментарий


Ваше имя:


Комментарий:


Введите: Картинка