Наше тело получает жизнь из пустоты. Существование там, где ничего нет, составляет смысл слов: "Форма есть пустота". Слова же: "Пустота есть форма" свидетельствуют о том, что пустота содержит в себе вещи. Не следует полагать, что пустота и вещи суть различны.
Сегодня решил написать не про модули, а про сущности и хранилища; просили.
Вспомним договорённости.
Подумаем про хранилища. Напишем:
interface CRUD{public function & create();public function & read($criteria);public function update();public function delete($criteria);}
почему так? рассказываю дальше:
abstract class StorageEngine implements CRUD{protected $__entity;function __construct($what){ $this->__entity = $what; }function __destruct(){ $this->update(); }// здесь ещё раз список методов, т.к. конкретную реализацию оставим для неабстрактных классов}
ясно? или не полностью?
Возврат значений по ссылке обеспечивает обратную связь сущности (ещё не объявленной) с хранилищем, которое деструктором закрывает сущность, сохраняет её на физическом уровне.
Возврат значений по ссылке обеспечивает обратную связь сущности (ещё не объявленной) с хранилищем, которое деструктором закрывает сущность, сохраняет её на физическом уровне.
Методы обеспечивают элементарный доступ к сущностям, сложенным в хранилище.
create обеспечивает динамическое создание копии сущности (пока только в памяти времени исполнения)
read читает коллекции сущностей из физического хранилища
update сохраняет коллекцию обратно
delete удаляет быстро и беспощадно
$criteria - признак выборки, XPath
Понимаете ведь, что это только здесь всё так красиво :) Внутри там конкретный аксессор к конкретному хранилищу и много других радостей. К которому можно подключить доп. драйвер и простенький шаблонизатор SQL для совсем уж чудных запросов. Для наших задач вполне хватает $accessor->query('SELECT _read(:criteria)', $array('citeria'=>$criteria));
Как кому-то уже понятно, в качестве драйвера используется PDO::PG, а сами выборки переложены на могучие плечи субд, на пользовательские функции. (Конкретнно чтение, выборку по критерию правильнее было бы оформить через VIEW, но я пошёл по пути унификации. И ещё: в процессе написания функций я обнаружил, что постгрес поддерживает перегрузку функций - функции с одним именем, но разным набором параметров)
Про сущности же подумаем так:
interface XML{function asXML();function XPath();}
Это два метода, которые нам необходимы. Первый для преобразования объекта к читабельному виду, второй для удобной работы. Да-да, XPath гораздо удобней, чем in_array(). Освоение множеств XML и преобразований требует некоторого мозга, но особого труда не составляет, будем работать с нормальными технологиями.
Кто использовал XML с PHP, конечно же, уже узнал этот интерфейс :) Да, это SimpleXML. Не будем изобретать сущности, извините за тавтологию, воспользуемся имеющейся.
class Entity extends SimpleXMLElement implements XML{// здесь меня ожидало несколько весьма занятных ээ... особенностей реализации языка. например, нельзя переопределить конструктор. пришлось изобретать конструкцию загрузки сущностей из схем и других источников, типа такойstatic function load($source){if (isXML($source)) $xml = $source;if (is_file($source)) $xml = file_get_contents($source);return new self($xml);}}
Со статическими методами тоже получилось интересно, почти неделю парился, уже думал, что пхп не поддерживает их перегрузку. Оказалось ещё хитрее ;) До ветки 5.3 self указывает не на текущий класс, а на класс, в котором был написан. То есть наследовать от Entity можно только с переопределением загрузчика. Но в принципе, особой нужды в этом нет, SimpleXML дал нам Entity::getName(), который выдаст имя корневого элемента (здесь необходимо вспомнить правила оформления XML;)
Ещё в сущностях есть пара вспомогательных статических методов, которые не несут принципиальной смысловой нагрузки, их можно посмотреть в коде. На этом, вроде, всё про систему хранения.
Вопросы?
зы: ах да, пример
$sth = new EntityStorage( Entity::load('scheme.xml') );
$sth->create();
или
$data_collection = & $sth->read('user/profile[name="USERNAME"]');
foreach ($data_collection as $user)
{
print $user->id;
print $user->profile->name;
}
$user->profile->name = 'LASTUSER';
$sth->update();
и замечание напоследок: нет, это не ORM, здесь отсутствует преобразование из плоской формы в объектную. На Observer похоже, но отсутствует подписка на изменения. Как назвать, не особенно важно, оно работает =%)