Опять пишу большой топик в ответ на чужой вопрос.
Топик раскрывает некоторые преимущества работы с 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>
И вот тебе чистый SQL:-)