© Сделано на LiveStreet
Дизайн - ©2009 MODx RED Group
После написания первой вводной статьи по xPDO, где я разобрал только базовые понятия и простейшие запросы/операции, обещался я вам (и себе), что обязательно копну глубже. Потребовало это достаточное кол-во времени, ибо «почва через чур каменистая», и похоже кроме самого Jason`а Coward`а никто не знает точно как сделать с xPDO все «правильно и красиво». Надеюсь недостаток документации восполнится после выхода Революшн (а на данный момент добрая половина функционала xPDO не задокументированна вобще :( ).// Простой пример newQuery
<?php
$query= $xpdo->newQuery('Actor', array('actor_id:>' => 2));
$query->limit(10);
$actors = $xpdo->getCollection('Actor',$query);
foreach ($actors as $actor)
{
echo $actor->first_name."
";
}
?><?php
$query= $xpdo->newQuery('Actor');
$query->where(array(
'actor_id:>' => 2)
);
?>Не томя вам душу выкладываю, что у xPDO::newQuery есть следующие функции конструкторы запроса:<?php
// сложный пример
$query= $xpdo->newQuery('Actor');
$query->select('Actor.actor_id, Actor.last_name');
$query->where(array('actor_id:<=' => 20));
$query->andCondition(array('actor_id:!=' => 8));
$query->orCondition(array('actor_id:!=' => 7));
$query->sortby('actor_id','DESC');
$query->groupby('first_name');
$query->limit(10);
$actors = $xpdo->getCollection('Actor',$query);
foreach ($actors as $actor) {
print_r($actor);
}
?>!NB Здесь хочу отметить тот, неразрешенный мною до сих пор глюк, у меня почему то отказывается работать getCollection при использовании $query->select, при $query->innerJoin (left и right тоже), и попытке засунуть в него сырой запрос с xPDOCriteria. Почему-то обрывается соединение с сервером по нехватке памяти. Консультации по вопросу мне не помогли, пробовал на двух локальных серверах. Есть подозрения, что это какой-то глюк моей тестовой Sakila DB. На форуме меня заверили, что это должно работать, я склонен этому верить :) на днях дойдёт дело до сложных запросов в одном проекте, который я начал делать на xPDO — попробую на нём и отпишусь ещё по этой теме.
... WHERE ( `Actor`.`actor_id` <= ? AND `Actor`.`actor_id` != ? OR `Actor`.`actor_id` != ? )<?php
$query= $xpdo->newQuery('Actor');
$query->where(array(
array(
'actor_id:<=' => '20',
array(
'OR:last_name:LIKE' => '%a%',
'AND:actor_id:>' => '5'
)
),
'actor_id:<=' => '30',
'OR:actor_id:>=' => '6',
));
$query->limit(10);
?>тоесть все Condition`ы можно запихнуть прямо в where() и получаем такой запрос на выходе... WHERE ( ( `Actor`.`actor_id` <= ? OR ( `Actor`.`last_name` LIKE ? AND `Actor`.`actor_id` > ? ) ) AND `Actor`.`actor_id` <= ? OR `Actor`.`actor_id` >= ? )$query->prepare();
echo "RAW SQL : ".$query->toSQL();И получаем чистый SQL запрос, без кучи лишней информации.$actorTable = $xpdo->getTableName('Actor');
$query= new xPDOCriteria($xpdo,'
SELECT first_name, last_name FROM '.$actorTable.'
WHERE actor_id = :index
LIMIT 1
',array(
':index' => 2,
));
$actors = $xpdo->getObject('Actor',$query);
print_r($actors);
Замечу сразу, что SELECT * не проходит. Нужно указывать поля явно! Здесь полный полёт фантазии запрос может быть абсолютно любой и соответсвенно вместо getObject может стоять getCollection. <?xml version="1.0" encoding="UTF-8"?>
<model package="MyDBModel" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM">
<object class="Actor" table="actor" extends="xPDOObject"><param name="wmode" value="opaque"></param>
<field key="actor_id" dbtype="smallint" precision="5" attributes="unsigned" phptype="integer" null="false" index="pk" generated="native" />
<field key="first_name" dbtype="varchar" precision="45" phptype="string" null="false" />
<field key="last_name" dbtype="varchar" precision="45" phptype="string" null="false" index="index" />
<field key="last_update" dbtype="timestamp" phptype="timestamp" null="false" default="CURRENT_TIMESTAMP" extra="on update current_timestamp" />
<composite alias="FilmActor" class="FilmActor" local="actor_id" foreign="actor_id" cardinality="many" owner="local" />
</object>
<object class="Film" table="film" extends="xPDOObject"><param name="wmode" value="opaque"></param>
<field key="film_id" dbtype="smallint" precision="5" attributes="unsigned" phptype="integer" null="false" index="pk" generated="native" />
<field key="title" dbtype="varchar" precision="255" phptype="string" null="false" index="index" />
<field key="description" dbtype="text" phptype="string" null="true" />
<field key="release_year" dbtype="year" precision="4" phptype="string" null="true" />
<field key="language_id" dbtype="tinyint" precision="3" attributes="unsigned" phptype="integer" null="false" index="index" />
<field key="original_language_id" dbtype="tinyint" precision="3" attributes="unsigned" phptype="integer" null="true" index="index" />
<field key="rental_duration" dbtype="tinyint" precision="3" attributes="unsigned" phptype="integer" null="false" default="3" />
<field key="rental_rate" dbtype="decimal" precision="4,2" phptype="float" null="false" default="4.99" />
<field key="length" dbtype="smallint" precision="5" attributes="unsigned" phptype="integer" null="true" />
<field key="replacement_cost" dbtype="decimal" precision="5,2" phptype="float" null="false" default="19.99" />
<field key="rating" dbtype="enum" precision="'G','PG','PG-13','R','NC-17'" phptype="string" null="true" default="G" />
<field key="special_features" dbtype="set" precision="'Trailers','Commentaries','Deleted Scenes','Behind the Scenes'" phptype="string" null="true" />
<field key="last_update" dbtype="timestamp" phptype="timestamp" null="false" default="CURRENT_TIMESTAMP" extra="on update current_timestamp" />
<composite alias="FilmActor" class="FilmActor" local="film_id" foreign="film_id" cardinality="many" owner="local" />
</object>
<object class="FilmActor" table="film_actor" extends="xPDOObject"><param name="wmode" value="opaque"></param>
<field key="actor_id" dbtype="smallint" precision="5" attributes="unsigned" phptype="integer" null="false" index="pk" />
<field key="film_id" dbtype="smallint" precision="5" attributes="unsigned" phptype="integer" null="false" index="pk" />
<field key="last_update" dbtype="timestamp" phptype="timestamp" null="false" default="CURRENT_TIMESTAMP" extra="on update current_timestamp" />
<aggregate alias="Actor" class="Actor" local="actor_id" foreign="actor_id" cardinality="one" owner="foreign" />
<aggregate alias="Film" class="Film" local="film_id" foreign="film_id" cardinality="one" owner="foreign" />
</object>
</model>Теперь нужно запустить парсер схемы в модель. Если делать по моей прошлой стате, то это файл dbParser.php$actor = $xpdo->getObject('Actor',1);
echo "Actor - ".$actor->first_name." ".$actor->last_name."
";
$actors = $actor->getMany('FilmActor');
foreach ($actors as $actor) {
echo "Film ".$actor->film_id;
echo " / ".$actor->getOne('Film')->title."
";
} $items = $xpdo->getCollectionGraph('FilmActor', '{"Film":{},"Actor":{}}', array('FilmActor.actor_id' => 1,));
//print_r($items);
foreach($items as $item)
{
echo "FilmActor Actro_ID = ".$item->actor_id."
";
echo "Film Title = ".$item->Film->title."
";<?php
$c = $xpdo->newQuery('FilmActor');
$c->bindGraph('{"Film":{},"Actor":{}}');
$c->where(array(
'FilmActor.actor_id' => 1,
));
$items = $xpdo->getCollectionGraph('FilmActor', '{"Film":{},"Actor":{}}', $c);
?>Новое здесь только bindGraph('{«Film»:{},«Actor»:{}}');$c = $xpdo->newQuery('FilmActor');
$c->innerJoin('Film','Film','Film.film_id = FilmActor.film_id');
$c->innerJoin('Actor','Actor','Actor.actor_id = FilmActor.actor_id');
$с->select('Film.film_id, Film.title, FilmActor.film_id, FilmActor.actor_id');
$c->where(array(
'FilmActor.actor_id' => 1,
));
$items = $xpdo->getCollection('FilmActor',$c);$total = $xpdo->getCount('Box',array(
'width' => 20,
));
}$actor->toArray()это антипод функции fromArray() (которая используется при создании объектов).<?php
$actorTable = $xpdo->getTableName('Actor');
$query= new xPDOCriteria($xpdo, "SELECT * FROM {$actorTable} WHERE `actor_id` < :index LIMIT 10", array(
':index' => 2,
));
if ($query->prepare() && $query->stmt->execute()) {
while ($actor = $query->stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($actor);
}
}
?>
Комментарии (14)
RSS свернуть / развернутьКак самочувствие после использования?
Ну и хотелось бы пару слов услышать про применение в жизни. Как оно?
pitbull
Про применение в жизни. Вобще довольно неплохо — разнобразные варианты критерии, способ указания логических операторов — к этому очень быстро привыкаешь. Использовать их удобно. Сегодня буду как раз воплощать «сложные» запросы в одном «реальном» проекте — надеюсь getCollection() все же заработает :)
Одно неудобство — во время разработки меняется структура БД и часто приходится перегенерировать схему+модель. От чего слетают указанные связи «agregate/composite» — тут уже появилась задумка сделать GUI`шный интерфейс для генерации с возможностью сохранения связей.
Кстати еще есть возможность указать способы валидации записей перед сохранением (по простым логическим признакам типа мин-длина, макс-длина, не пустое и по вызову кастомной функции).
И вызывается просто $item->validate(); но об этому наверно будет 3-я статья :))) + еще может чего узрею к тому времени.
P/S Вобще ORM — это не мелочь по карманам тырить, с той же Doctrine разве что документации по более будет, а мороки подготовительной, наверно, не меньше. Зато xPDO — по размерам легка и реализует только необходимый минимум, что зачастую и требуется.
iJack
bullder
xPDO меня буквально наполняет благоговейным трепетом. С одной стороны он кажется монстрообразным, а с другой его гибкость поражает.
Это уже на Revo или отдельно?
Carw
А тот проект что я говорю, это совершенно отдельно от MODx, просто надоело писать ручками запросы и решил использовать ОРМ фрэймворк, вот и влез на свою голову, решил типа убить одним выстрелом двух зайцев (параллельно глубже поняв как работает MODx Revo) :)
iJack
Carw
atma
З.Ы. Кстати про баги с getCollection что я писал в посте — их похоже реально нет, это были проблемы какие-то с конкретной тестовой БД. С другой БД все работает хорошо.
iJack
Другими словами AND, OR, LIKE, etc PDO понимает как экспрешн, а тут надо raw, но все же array
atma
kzawner
Никакого публичного класса для возврата объекта PDO я не увидел, значит как я понимаю нужно самому дописать в класс xPDO что-то типа может будет работать :)
А кстати основная сложность и непонимание в xPDO у меня была как раз в том, как сгенерировать и распарсить модели классов, что-то документация абсолютно невнятно освещала эти вопросы. Да и кстати использовал его в разработке двух не маленьких проектов — всё классно, экономит время и нервы (когда знаешь все его приколы :) ), но всё же понял, что без полноценного фрэймворка с АР не обойтись, так что дальше использовать xPDO врядли буду.
iJack
kzawner
dmitry_modx_customize
С уважением. Елена.
defele
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.