ilyautkin 12 июля 2013 0 11
На сайте есть страница пользователя. На ней выводится его профиль, созданные им объявления, его последние заявки и пр. Это все отдельные объекты. Кроме того есть страницы со списками этих объектов «Мои объявления», «Мои заявки». Хотелось бы на любой из страниц делать поменьше запросов. Соответственно, нужны 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;


И отсюда вопрос, где эти методы лучше хранить? Создать отдельный класс с ними? Или в код класса того или иного объекта вставлять как метод — но тогда их из процессора просто так не вызовешь… А можно прямо в этом процессоре и хранить. Какой вариант предпочтительнее? Или, может это все совсем не так делается?
11 комментариев
Fi1osof1
Fi1osof 12 июля 2013г в 13:47 #
Илья, привет!
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.
ilyautkin1
ilyautkin 12 июля 2013г в 14:11 #
А, все, понял, спасибо)))
Fi1osof1
Fi1osof 12 июля 2013г в 14:23 #
Пожалуйста.
Можешь скачать магазин и посмотреть как там сделано.
ilyautkin1
ilyautkin 12 июля 2013г в 14:33 #
Я туда и смотрю) Просто в этом процессоре мне количество и не нужно — пользователь один, а уже присоединенных объектов много. Еще надо будет посмотреть, можно ли после Join'ов ограничивать количество и сортировать присоединенные записи…
Fi1osof1
Fi1osof 12 июля 2013г в 15:05 #
Просто в этом процессоре мне количество и не нужно — пользователь один
Так а что же ты тогда используешь modObjectGetListProcessor? Используй modObjectGetProcessor он делает выборку только одного процессора.
Еще надо будет посмотреть, можно ли после Join'ов ограничивать количество и сортировать присоединенные записи…
Все эти вещи выполняются в list-процессорах пакета shopModx. Посмотри как это там выполняется. Лично я исползую их практически везде, и еще не было задачи, на которую мне не хватало бы getdata-процессора.

P.S. если у тебя суперузкопрофильная задача, тогда вообще используй просто modPropcessor, и основную логику пиши в методе process.
Н
Наталия Ковалёва 28 января 2016г в 18:56 #
Добрый вечер! Подскажите по поводу 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,
            ));
        }


как бы все работает, Но при вызове выводит Новинки + Скидки все в одном массиве.
Подскажите что нужно сделать, чтобы остались только Скидки?? спасибо
Fi1osof1
Fi1osof 28 января 2016г в 19:21 #
Так а скидки у вас где реализованы? Да и расширять скорее всего вам надо было web/catalog/products/getdata, у вас и кода в процессоре меньше бы тогда было.

P.S. Лучше это было отдельным топиком писать, а то оффтоп получается.
Н
Наталия Ковалёва 28 января 2016г в 19:34 #
я пробывала его расширять
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'");
        }

но получается тоже самое
Fi1osof1
Fi1osof 28 января 2016г в 19:38 #
Здесь вы только фильтруете по по полю. Но здесь нет непосредственно выборки select().
У вас написано:
По аналогии с новинками хочу вывести на главную еще и скидки.
Вы имеете ввиду «получить товары, на которые скидки имеются» или именно вывести сами скидки?
Н
Наталия Ковалёва 28 января 2016г в 19:42 #
товары, на которые есть скидки
Подскажите, где нужно дописать выборку?
Fi1osof1
Fi1osof 28 января 2016г в 19:55 #
Вот чтобы вам не переписывать выборку, вам надо было просто расширять процессор 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, у вас будет выборка только соответствующих товаров.

Если у вас вопросы еще останутся — пишите отдельный топик, мы уже Илью совсем заспамили.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.