Опять пишу большой топик в ответ на чужой вопрос.
Топик раскрывает некоторые преимущества работы с xPDO и написал одну хитрость для не посвященных. Но в целом топик оформлен ужасно и не является исчерпывающей мануалой, потому заходите на свой страх и риск, и не пишите сообщений типа «фуууу...».
Так что же дает xPDO лично мне?
1) Сравним эти 2 запроса:
$sql = array(
select => "a.*,
ah.description,
ah.conditions,
ah.features,
ah.action_end,
ah.full_price,
ah.discount,
ah.sale_price,
ah.cost_discount,
adrs.name as firmname,
(select act.cat_cat_id from ".self::$tables['actions_categories']." as act
where act.action_action_id = a.action_id
limit 1) as cat_id,
(select cat.name from ".self::$tables['actions_categories']." as act
join ".self::$tables['categories']." as cat on cat.cat_id = act.cat_cat_id
where act.action_action_id = a.action_id
limit 1) as category,
c.pagetitle,
c.longtitle,
c.id,
c.uri,
cp.id as partnerDocID,
cp.uri as partnerDocUri,
cp.published as parentIsPublished,
cp.deleted as parentIsDeleted,
cp.hidemenu as parentIsHideMenu,
ai.value as action_image,
pi.value as partner_logo,
(select count(*) from ".self::$tables['user_cupon']." as uc where uc.action_action_id = a.action_id) as bought,
metro.station as metro",
from => self::$tables['actions']." as a
join ".self::$tables['actions_history']." ah ON ah.action_action_id = a.action_id and
ah.actstat_actstat_id = 5
and now() between ah.start_date and ah.end_date AND NOW() < ah.action_end
join ".self::$tables['actions_status']." as `as` on `as`.actstat_id = ah.actstat_actstat_id
join ".self::$tables['partners']." as p on p.partner_id = a.partner_partner_id
join ".self::$tables['partners_history']." as ph on ph.partner_partner_id = p.partner_id
and now() between ph.start_date and ph.end_date
join ".self::$tables['partners_statuses']." as ps on ps.partstatus_id = ph.partstatus_partstatus_id".
" join ".self::$tables['catalog_content']." as cc on cc.action_action_id = a.action_id
join ".self::$tables['catalog_content']." as ccp on ccp.partner_partner_id = p.partner_id
join ".self::$tables['site_content']." as c on cc.cont_cont_id = c.id
and c.published = 1 and c.hidemenu = 0 and c.deleted = 0
join ".self::$tables['tv_values']." as ai on ai.contentid = c.id
and ai.tmplvarid = ".self::$TVs['actionImg']."
left join (select aa.action_action_id, adh.name from ".self::$tables['addresses']." as ca
join ".self::$tables['addresses_history']."
as adh on adh.adrs_adrs_id = ca.adrs_id and adh.adrstat_adrstat_id = 1
and now() between adh.start_date and adh.end_date
join ".self::$tables['actions_addresses']." as aa on ca.adrs_id = aa.adrs_adrs_id and aa.status = 1
and now() between aa.start_date and aa.end_date
where adh.city in (". implode(",", $cities). ")
{$adrs_where}
group by aa.action_action_id
) as adrs on adrs.action_action_id = a.action_id
left join ".self::$tables['site_content']." as cp on ccp.cont_cont_id = cp.id
left join ".self::$tables['tv_values']." as pi on pi.contentid = cp.id
and pi.tmplvarid = ".self::$TVs['partnerLogo']."
left join (
SELECT caa.action_action_id, if(cm.complex_name is not null && cm.complex_name != '',
cm.complex_name, cm.station) as station
FROM modx_catalog_actions_addresses as caa
join modx_catalog_metro_relations as cmr on cmr.adrs_adrs_id = caa.adrs_adrs_id
join modx_catalog_metro as cm on cm.metro_id = cmr.metro_metro_id
where now() between caa.start_date and caa.end_date
group by 1
) as metro on metro.action_action_id = a.action_id
". ($not_sended == true ? " left join modx_catalog_actions_sended as `asn` on
`asn`.action_action_id = a.action_id ": "")."
where `as`.status = 'Активна'
and ps.status = 'Активный'
and (adrs.action_action_id is not null OR ah.all_cities = '1')
{$where}
order by c.publishedon desc",
limit => self::$limit,
offset => self::$offset
);
// Получаем города, которые используются для этого хоста
$cities = self::get_host_cities();
$where = array(
'now() between ah.start_date and ah.end_date',
'ah.actstat_actstat_id' => 5,
'NOW() < ah.action_end',
'now() between ph.start_date and ph.end_date',
'ph.partstatus_partstatus_id' => 2,
'c.published' => 1,
'c.hidemenu' => 0,
'c.deleted' => 0,
'ai.tmplvarid' => self::$TVs['actionImg'],
'now() between aa.start_date and aa.end_date',
'aa.status' => 1,
'now() between adh.start_date and adh.end_date',
);
$q = self::$modx->newQuery('Actions');
$q->select(array(
'Actions.*',
'ah.description',
'ah.conditions',
'ah.features',
'ah.action_end',
'ah.full_price',
'ah.discount',
'ah.sale_price',
'ah.cost_discount',
'adh.name as firmname',
'c.pagetitle',
'c.longtitle',
'c.id',
'c.uri',
'cp.id as partnerDocID',
'cp.uri as partnerDocUri',
'cp.published as parentIsPublished',
'cp.deleted as parentIsDeleted',
'cp.hidemenu as parentIsHideMenu',
'ai.value as action_image',
'pi.value as partner_logo',
"if(cm.complex_name is not null && cm.complex_name != '', cm.complex_name, cm.station) as metro"
));
$q->innerJoin('ActionsHistory', 'ah', 'ah.action_action_id = Actions.action_id');
$q->innerJoin('Partners', 'p', 'p.partner_id = Actions.partner_partner_id');
$q->innerJoin('PartnersHistory', 'ph', 'ph.partner_partner_id = p.partner_id');
$q->innerJoin('Content', 'cc', 'cc.action_action_id = Actions.action_id');
$q->innerJoin('Content', 'ccp', 'ccp.partner_partner_id = p.partner_id');
$q->innerJoin('modResource', 'c', 'cc.cont_cont_id = c.id');
$q->innerJoin('modResource', 'cp', 'ccp.cont_cont_id = cp.id');
$q->innerJoin('modTemplateVarResource', 'ai', 'ai.contentid = c.id');
$q->innerJoin('ActionsAddresses', 'aa', 'aa.action_action_id = Actions.action_id');
$q->innerJoin('AddressesHistory', 'adh', 'adh.adrs_adrs_id = aa.adrs_adrs_id');
$q->leftJoin('MetroRelations', 'cmr', 'cmr.adrs_adrs_id = aa.adrs_adrs_id');
$q->leftJoin('Metro', 'cm', 'cm.metro_id = cmr.metro_metro_id');
$q->leftJoin('modTemplateVarResource', 'pi', 'pi.contentid = cp.id AND pi.tmplvarid = '.self::$TVs['partnerLogo']);
if($not_sended == true){
$q->leftJoin('ActionsSended', 'asn', 'asn.action_action_id = Actions.action_id');
$where['asn.actsnd_id'] = NULL;
}
$q->where($where);
$q->andCondition( "(adh.city IN (".implode(",", $cities).") OR ah.all_cities = '1')" );
if($not_sended == false){
self::$rows = self::$modx->getCount('Actions', $q);
$q->limit(self::$limit, self::$offset);
}
// Подсчитываем кол-во строк
$q->groupby('Actions.action_id');
$q->sortby('c.publishedon', 'DESC');
if(!$q->prepare()){
return false;
}
if(!$q->stmt->execute()){
return false;
}
$result__ = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
Да, каждый пример — это один запрос и да, иногда нужны и такие большие запросы. Так вот, как считаешь, какой легче будет сопровождать и дорабатывать? Лично я отвечу: второй запрос (который на xPDO) сопровождать в разы легче.
2. Если у тебя таблица изменилась, тебе не надо лазить по всему проекту и искать, во всех ли у тебя запросах прописаны все необходимые колонки…
3. Простейшая для xPDO операция:
$object = $modx->getObject('object', $where);
$object->fromArray($data);
$object->save();
На чистой связке PHP+Mysql это как бе гемор, так как надо проверить какие данные есть в массиве $data, какие колонки могут этому соответствовать, а какие нет, какие типы данных и какие преобразования могут понадобиться… Дофига гемора.
Это маленькая часть из преимуществ.
SELECT * FROM atable WHERE id=$parent AND id>(MIN+((MAX-MIN)/COUNT)*offset LIMIT numrows
Это вообще не проблема. Подробней читаем здесь.
А конкретно по поводу WHERE id=$parent AND id>(MIN+((MAX-MIN)/COUNT)*offset: надо правильно массив условий собирать. $where = array(
'id' => $parent,
'id > (MIN+((MAX-MIN)/COUNT)*offset'
)
Не 'id:>' =>, а именно так, как я написал, потому что иначе xPDO запрос соберет так, как будто '(MIN+((MAX-MIN)/COUNT)*offset' — это название колонки.
Но все же одно ограничение действительно есть, которое я встречал. На xPDO нельзя собрать запроса типа UNION ALL. Но это так редко используется…
И под конец компенсация за мой наезд: твоя проблема в том, что ты не видишь SQL?
$q = $modx->newQuery($class);
$q->select($select);
$q->where($where);
$q->prepere();
<strong>print $q->toSQL();</strong>