Илья
12 июля 2013 г., 9:29

Реализация "модульности" процессоров

На сайте есть страница пользователя. На ней выводится его профиль, созданные им объявления, его последние заявки и пр. Это все отдельные объекты. Кроме того есть страницы со списками этих объектов «Мои объявления», «Мои заявки». Хотелось бы на любой из страниц делать поменьше запросов. Соответственно, нужны JOIN.
Как я представляю реализацию таких выборок.
Для страницы пользователя есть процессор xpectaProfileGetProcessor, в который передается id пользователя и он выбирает все его данные:
<?php class xpectaProfileGetProcessor extends modObjectGetListProcessor{ public $classKey = 'modUser'; public function getData() { $c = $this->modx->newQuery($this->classKey); $c->where(array('id' => $this->getProperty('id'))); $c->select(array( "{$this->classKey}.*", )); $data = array(); if($c->prepare() && $c->stmt->execute()){ $data = $c->stmt->fetchAll(PDO::FETCH_ASSOC); } return $data; } } return 'xpectaProfileGetProcessor';
В него я хочу передавать список «модулей», которые нужно запустить. Каждый из них будет выглядеть как-то так:
$c->leftJoin('xpectaAd', 'xpectaAd'); $c->select(array( "xpectaAd.id as ad_id", 'xpectaAd.title as ad_title', //... )); return $c;
И отсюда вопрос, где эти методы лучше хранить? Создать отдельный класс с ними? Или в код класса того или иного объекта вставлять как метод — но тогда их из процессора просто так не вызовешь… А можно прямо в этом процессоре и хранить. Какой вариант предпочтительнее? Или, может это все совсем не так делается?
Илья, привет! 1. Ты используешь базовый процессор modObjectGetListProcessor. Переопределять в нем метод getData надо очень осторожно. Вот ты не очень удачно это сделал, так как ты из метода вынес очень полезные методы, такие как prepareQueryBeforeCount и prepareQueryAfterCount. Вот сравни:
public function getData() { $data = array(); $limit = intval($this->getProperty('limit')); $start = intval($this->getProperty('start')); /* query for chunks */ $c = $this->modx->newQuery($this->classKey); $c = $this->prepareQueryBeforeCount($c); $data['total'] = $this->modx->getCount($this->classKey,$c); $c = $this->prepareQueryAfterCount($c); $sortClassKey = $this->getSortClassKey(); $sortKey = $this->modx->getSelectColumns($sortClassKey, $this->getProperty('sortAlias',$sortClassKey),'',array($this->getProperty('sort'))); if (empty($sortKey)) $sortKey = $this->getProperty('sort'); $c->sortby($sortKey,$this->getProperty('dir')); if ($limit > 0) { $c->limit($limit,$start); } $data['results'] = $this->modx->getCollection($this->classKey,$c); return $data; }
Так вот как раз на уровне этих методов и происходит вклинивание в формирование запроса. То есть в расширяющем процессоре ты пишешь примерно следующее:
public function prepareQueryBeforeCount(xPDOQuery $c) { $c = parent::prepareQueryBeforeCount($c); // Добавляешь условия к запросу return $c; }
Это тебе позволит не лезть в общую логику.
2. По поводу самой логики: я сам чаще всего использую только два метода: а) Расширение классов (переопределяя методы типа prepareQueryBeforeCount) б) Передачей параметров. К примеру вот часть кода процессора:
class ....{ public function initialize(){ $this->setDefaultProperties(array( 'hot' => false, // Флаг, что делать только выборку новинок )); return parent::initialize(); } public function prepareQueryBeforeCount(xPDOQuery $c) { $c = parent::prepareQueryBeforeCount($c); // Если указано, что нужны только новинки if($this->getProperty('hot')){ // Добавляем условие только новинок } return $c; } }
И вот уже при вызове этого процессора ты просто передаешь параметр 'hot' => true и все. По умолчаниюу тебя стоит 'hot' => false.
А, все, понял, спасибо)))
Пожалуйста. Можешь скачать магазин и посмотреть как там сделано.
Я туда и смотрю) Просто в этом процессоре мне количество и не нужно — пользователь один, а уже присоединенных объектов много. Еще надо будет посмотреть, можно ли после Join'ов ограничивать количество и сортировать присоединенные записи…
Просто в этом процессоре мне количество и не нужно — пользователь один
Так а что же ты тогда используешь modObjectGetListProcessor? Используй modObjectGetProcessor он делает выборку только одного процессора.
Еще надо будет посмотреть, можно ли после Join'ов ограничивать количество и сортировать присоединенные записи…
Все эти вещи выполняются в list-процессорах пакета shopModx. Посмотри как это там выполняется. Лично я исползую их практически везде, и еще не было задачи, на которую мне не хватало бы getdata-процессора.
P.S. если у тебя суперузкопрофильная задача, тогда вообще используй просто modPropcessor, и основную логику пиши в методе process.
Добрый вечер! Подскажите по поводу getdata-процессора. По аналогии с новинками хочу вывести на главную еще и скидки. Создала еще поле hot1 и директорию в которую положила свой getdata.class.php
require_once dirname(dirname(__FILE__)).'/getdatanew.class.php'; class modWebCatalogProductsHot1GetdataProcessor2 extends modWebCatalogProductsGetdataProcessor1{ public function initialize(){ $this->setDefaultProperties(array( 'hot1' => true, // Получать скидки "sort" => "{$this->classKey}.publishedon", "dir" => "ASC", )); return parent::initialize(); } } return 'modWebCatalogProductsHot1GetdataProcessor2';
в файле getdatanew.class.php задала процессор modWebCatalogProductsGetdataProcessor1 так, чтобы выводил скидки
require_once dirname(dirname(dirname(__FILE__))).'/resources/getdata.class.php'; class modWebCatalogProductsGetdataProcessor1 extends modWebResourcesGetdataProcessor{ public function initialize(){ $this->setDefaultProperties(array( 'hot1' => false, // Получать скидки )); $this->setProperties(array( "base_currency_id" => (int)$this->modx->getOption("shopmodx.default_currency"), // ID базовой валюты магазина )); return parent::initialize(); } public function prepareQueryBeforeCount(xPDOQuery $z) { $z = parent::prepareQueryBeforeCount($z); $alias = $z->getAlias(); $z->innerJoin('ShopmodxProduct', 'Product'); if($this->getProperty('hot1')){ $z->innerJoin('modTemplateVarResource', 'hot1', "hot1.contentid = {$alias}.id AND hot1.tmplvarid = 15 AND hot1.value='1'"); } // Поиск товаров в категории и подкатегориях if($category_id = $this->getProperty('category_id')){ $categories = array(); $this->getCategories($category_id, $categories); $Z->where(array( "parent:IN" => $categories, )); }
как бы все работает, Но при вызове выводит Новинки + Скидки все в одном массиве. Подскажите что нужно сделать, чтобы остались только Скидки?? спасибо
Так а скидки у вас где реализованы? Да и расширять скорее всего вам надо было web/catalog/products/getdata, у вас и кода в процессоре меньше бы тогда было.
P.S. Лучше это было отдельным топиком писать, а то оффтоп получается.
я пробывала его расширять
if($this->getProperty('hot')){ $c->innerJoin('modTemplateVarResource', 'hot', "hot.contentid = {$alias}.id AND hot.tmplvarid = 8 AND hot.value='1'"); } elseif($this->getProperty('hot1')){ $c->innerJoin('modTemplateVarResource', 'hot1', "hot1.contentid = {$alias}.id AND hot1.tmplvarid = 15 AND hot1.value='1'"); }
но получается тоже самое
Здесь вы только фильтруете по по полю. Но здесь нет непосредственно выборки select(). У вас написано:
По аналогии с новинками хочу вывести на главную еще и скидки.
Вы имеете ввиду «получить товары, на которые скидки имеются» или именно вывести сами скидки?
товары, на которые есть скидки Подскажите, где нужно дописать выборку?
Вот чтобы вам не переписывать выборку, вам надо было просто расширять процессор web/catalog/products/getdata, потому что там уже прописано все необходимое. Вам же в вашем процессоре надо прописать только это:
if($this->getProperty('hot1')){ $z->innerJoin('modTemplateVarResource', 'hot1', "hot1.contentid = {$alias}.id AND hot1.tmplvarid = 15 AND hot1.value='1'"); }
То есть если у вас передается переменная hot1, у вас будет выборка только соответствующих товаров.
Если у вас вопросы еще останутся — пишите отдельный топик, мы уже Илью совсем заспамили.

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