Не зарегистрирован
Вход
Забыли пароль?
Регистрация
Подписаться
Сэкономьте время — перед вопросом на форуме узнайте, как найти ответ быстрее
По техническим проблемам необходимо обращаться в Консультационный центр

Поиск по форуму: 

Приглашаем в блог Amiro.CMS. Регулярные обзоры, опыт, решения, практикумы.

Форум  ->   Разработка плагинов, вопросы по API  ->  Связь товара и его свойств (точнее их названий)

Раздел для разработчиков. Обсуждение создания плагинов, вопросы и пожелания по API Amiro.CMS

Добавлено: 28.08.14 22:51:22 #1




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Пытаюсь сделать выгрузку на Яндекс.Маркет со свойствами товаров (чего, как ни странно, в стандартной реализации нет).
Вытряс из ТП вот такой ответ:

Здравствуйте,

Если не перечислять вручную, то можно организовать через php-функицю, например, так -

function getCustomFieldsXML ($id) {
$ret = '';
$oItem = AMI::getResourceModel('eshop_item/table'->find($id);
foreach($oItem->getData() as $key => $value) {
if(strpos($key, 'custom_field_' === 0 && isset($value) && mb_strlen($value) > 0) {
$ret .= '<'.$key.'>'.$value.'</'.$key.">\n";
}
}
return $ret;
}

Вызывать в нужном сете, результат выводить.
Если нужно получать названия свойств, то можно взять их из dataset_data категории, в которой лежит товар.


Долго бился над тем, как же имея готовую и, в принципе, рабочую функцию, получить dataset_data. Оказалось что ни как.
В итоге написал вот такой код:
function getCustomFieldsXML($id) {
    $ret = '';
    $oRes = AMI::getResourceModel('eshop_item/table');
    $oRes->setActiveDependence('cat');
    $oItem = $oRes->getList();
    $oItem->addColumn('*');
    $oItem->addColumn('dataset_data', 'cat');
    $oItem->setWhereDef("AND i.id=".$id);
    $oItem->load();
    if ($oItem->count() > 0) {
        $data = $oItem->current()->getData();
        $ret .= print_r($data,TRUE);
        $dataSet = unserialize($data['cat_dataset_data']);
        $ret .= print_r($dataSet,TRUE);
        /*foreach ($data as $key => $value) {
            if (strpos($key, 'custom_field_') === 0 && isset($value) && mb_strlen($value) > 0) {
                $cfId = str_replace('custom_field_', "", $key);
                $ret .= '<prop name="' . $dataSet['fields_captions'][$cfId] . '">' . $value . "</prop>\n";
            }
        }*/
    }
    return $ret;
}


В целом оно все работает, значение custom_field товара получаем. dataset_data тоже получаем (в данном случае поле называется cat_dataset_data).
Но есть одно большое и противное НО, с которым я не понимаю как бороться: в результате запроса я получаю значения custom_field_N товара, где N[6,35], и названия свойств в массиве cat_dataset_data[fields_captions][M], где M[71,87].

А теперь вопрос: как связать название свойства и его значение, если идентификаторы названий идут от 71 до 87, а идентификаторы значений от 6 до 35?
Где логика?

Кто ни чего не понял, результаты выполнения функции можно посмотреть тут: http://business.rame0.biz/

Для примера, ситуация с доп.изображениями:
Значения у товара хранятся как:
Array
(
.......
    [custom_field_26] => _mod_files/ce_images/eshop/eshop-noim-s.jpg
    [custom_field_27] => _mod_files/ce_images/eshop/eshop-noim.jpg
    [custom_field_28] => _mod_files/ce_images/eshop/eshop-noim-s.jpg
    [custom_field_29] => _mod_files/ce_images/eshop/eshop-noim.jpg
    [custom_field_30] => _mod_files/ce_images/eshop/eshop-noim-s.jpg
    [custom_field_31] => _mod_files/ce_images/eshop/eshop-noim.jpg
    [custom_field_32] => _mod_files/ce_images/eshop/eshop-noim-s.jpg
    [custom_field_33] => _mod_files/ce_images/eshop/eshop-noim.jpg
    [custom_field_34] => _mod_files/ce_images/eshop/eshop-noim-s.jpg
    [custom_field_35] => _mod_files/ce_images/eshop/eshop-noim.jpg
......
)


А вот названия свойств хранятся как:
[fields_captions] => Array
        (
....
            [90] => Доп. изображение 1 мал.
            [91] => Доп. изображение 1 бол.
            [92] => Доп. изображение 2 мал.
            [93] => Доп. изображение 2 бол.
            [94] => Доп. изображение 3 мал.
            [95] => Доп. изображение 3 бол.
            [96] => Доп. изображение 4 мал.
            [97] => Доп. изображение 4 бол.
            [98] => Доп. изображение 5 мал.
            [99] => Доп. изображение 5 бол.
....
)



Добавлено: 29.08.14 09:26:02 #2

Партнер


Регистрация: 22.02.09
Сообщений: 472


Обратиться по имени

Рамиль Алиякберов:
А теперь вопрос: как связать название свойства и его значение, если идентификаторы названий идут от 71 до 87, а идентификаторы значений от 6 до 35?
Через таблицу cms_es_custom_types
M - это cms_es_custom_types.id
N - cms_es_custom_types.fnum



Добавлено: 29.08.14 15:44:14 #3




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Evgeney S., спасибо, попробую.



Добавлено: 29.08.14 17:39:58 #4




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Evgeney S., спасибо еще раз!
Пришел вот к такому решению, надеюсь кому то еще будет полезно.
function getCustomFieldsXML($id) {
    $ret = '';
    $oDB = AMI::getSingleton('db');
    $custtypesDB = $oDB->select("SELECT * FROM `cms_es_custom_types`");
    $custtypes = array();
    foreach ($custtypesDB as $ct) {
        if ($ct['isnot_all'] == 0 && $ct['is_prop'] == 0 && $ct['type_owner'] == 'item' && $ct['ftype'] !== 'picture') {
            $custtypes["custom_field_{$ct['fnum']}"] = $ct;
            $custtypes["custom_field_{$ct['fnum']}"]['name'] = unserialize($ct['default_caption']);
        }
    }
    $oItem = AMI::getResourceModel('eshop_item/table')->find($id);
    $data = $oItem->getData();
    foreach ($data as $key => $value) {
        if (!empty($custtypes[$key]) && isset($value) && mb_strlen($value) > 0) {
            $ret .= '<prop name="' . $custtypes[$key]['name'][$data['lang']] . '">' . $value . "</prop>\n";
        }
    }
    return $ret;
}



Не сильно жестко я ограничил данные справочников? А может наоборот слабо?



Добавлено: 29.08.14 21:51:34 #5

Партнер


Регистрация: 22.02.09
Сообщений: 472


Обратиться по имени

А зачем делается эта проверка:
$ct['isnot_all'] == 0
?
Если я не ошибаюсь, это флаг "Но показывать в общем списке". Эта проверка действительно нужна?
unserialize($ct['default_caption'])
Это будет название (заголовок) свойства по-умолчанию. В наборе свойств это название может быть переопределено, поэтому правильнее брать его из cms_es_datasets.fields_captions или из таблицы категорий (как в первом посте).
Ну и не забывать, что значения могут хранится не только "по значению", но и ссылками на значения справочников, и еще есть тип "набор флагов"



Добавлено: 29.08.14 22:44:00 #6




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Evgeney S.:
А зачем делается эта проверка:
$ct['isnot_all'] == 0
?
Если я не ошибаюсь, это флаг "Но показывать в общем списке". Эта проверка действительно нужна?
unserialize($ct['default_caption'])
Это будет название (заголовок) свойства по-умолчанию. В наборе свойств это название может быть переопределено, поэтому правильнее брать его из cms_es_datasets.fields_captions или из таблицы категорий (как в первом посте).
Ну и не забывать, что значения могут хранится не только "по значению", но и ссылками на значения справочников, и еще есть тип "набор флагов"


isnot_all - это уже по вкусу. По мне (и по текущему сайту, на котором 170+ свойств на 5 наборов), так если свойство не отображается в стандартной (опять же для этого сайта) таблице характеристик, то оно и в маркете не нужно.

Что касается второй части вопроса, то соглашусь. Сам как раз пришел к этому. Но не по тем причинам, что вы указали, а из за банальной находки, что fnum - не уникальный параметр. В частности на демо сайте, fnum=15 у свойств "С этим товаром рекомендуем" и "Размер".

Как именно хранится свойство, мне разбираться не хочется (ведь в результатах выборки я получаю уже значение, даже если что то хранится как ссылка на значение справочника. нет?), поэтому функция фильтрует то что мне не надо вот так:
$ct['ftype'] !== 'picture'

Хотя, этот кусок лучше было бы переписать вот так:
!in_array($ct['ftype'], array('picture',...))


А вот за указание на тип набор флагов - спасибо. Надо будет еще и с ним разобраться

В общем, надо еще копнуть. Это была версия 0.0.3 alpha



Добавлено: 30.08.14 01:40:20 #7




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Заметил в предыдущих своих постах опечатку:
Вместо
 $ret .= '<prop name="' . ... . '">' . ... . "</prop>\n";

Должно быть
 $ret .= '<param name="' . ... . '">' . ... . "</param>\n";


Собственно, вот что у меня получилось в итоге:

// Составление параметров для выгрузки на маркет
function getCustomFieldsXML($id) {
    $ret = '\n';
    $oDB = AMI::getSingleton('db');
    $custtypesDB = $oDB->select("SELECT * FROM `cms_es_custom_types`");
    $custtypes = array();
    foreach ($custtypesDB as $ct) {
        if ($ct['isnot_all'] == 0 && $ct['is_prop'] == 0 && $ct['type_owner'] == 'item' && !in_array($ct['ftype'], array('picture'))) {
            $ct['default_params'] = unserialize($ct['default_params']);
            $custtypes[$ct['id']] = $ct;
        }
    }
    //$ret.=print_r($custtypes, true);
    $oRes = AMI::getResourceModel('eshop_item/table');
    $oRes->setActiveDependence('cat');
    $oItem = $oRes->getList();
    $oItem->addColumn('*');
    $oItem->addColumn('dataset_data', 'cat');
    $oItem->setWhereDef("AND i.id=" . $id);
    $oItem->load();
    if ($oItem->count() > 0) {
        $data = $oItem->current()->getData();
        $data['cat_dataset_data'] = unserialize($data['cat_dataset_data']);
        //$ret .= print_r($data, TRUE);
        foreach ($data['cat_dataset_data']['fields_captions'] as $key => $value) {
            if (
            // Проверяем, существует ли параметр в описании набора свойств
                    !empty($custtypes[$key]) &&
                    // Проверяем, заполнено ли значение параметра
                    ((isset($data["custom_field_" . $custtypes[$key]['fnum']]) && mb_strlen($data["custom_field_" . $custtypes[$key]['fnum']]) > 0)
                    // Могут быть ситуации, когда значение параметра записано в custom_field_N_1
                    || (isset($data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]) && mb_strlen($data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]) > 0))
            ) {
                switch ($custtypes[$key]['value_type']) {
                    // Если свойство - набор флагов
                    case 'scalar':
                        if ($custtypes[$key]['ftype'] == 'flagmap') {
                            $ret .= flagmapToText($value, $custtypes[$key]['default_params']['flag'][$data['lang']], $data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]);
                        }
                        break;
                    //если свойство - ссылка на знач. справочника или ссылка на много значений справочника
                    case 'ref_reference':
                    case 'ref_set':
                        $rIds = str_replace(";", ",", trim($data["custom_field_" . $custtypes[$key]['fnum']], ";"));
                        $refName = $oDB->select("SELECT `name` FROM `cms_es_reference_" . sprintf("%04d", $custtypes[$key]['ref_table_num']) . "` where id in(" . $rIds . ")");
                        foreach ($refName as $item) {
                            $ret .= '<param name="' . $value . '">' . $item['name'] . "</param>\n";
                        }
                        break;
                    // Все остальные типы свойств
                    default :
                        $ret .= '<param name="' . $value . '">' . $data["custom_field_" . $custtypes[$key]['fnum']] . "</param>\n";
                        break;
                }
            }
        }
    }
    return $ret;
}

// Получаем текст из flagmap (набора флагов)
function flagmapToText($pname, $map, $value) {
    $result = '' . $value;
    foreach ($map as $key => $val) {
        if ((pow(2, $key - 1) & $value) > 0) {
            $result.= '<param name="' . $pname . '">' . $val['c'] . "</param>\n";
        }
    }
    return $result;
}



Добавлено: 06.09.14 19:16:32 #8




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

Последняя, рабочая версия
Добавлять надо в файл common_functions.php


// Составление параметров для выгрузки на маркет
function getCustomFieldsXML($id) {
    $ret = "\n";
    $oDB = AMI::getSingleton('db');
    $custtypesDB = $oDB->select("SELECT * FROM `cms_es_custom_types`");
    $custtypes = array();
    foreach ($custtypesDB as $ct) {
        if ($ct['isnot_all'] == 0 && $ct['is_prop'] == 0 && $ct['type_owner'] == 'item' && !in_array($ct['ftype'], array('picture'))) {
            $ct['default_params'] = unserialize($ct['default_params']);
            $custtypes[$ct['id']] = $ct;
        }
    }
    //$ret.=print_r($custtypes, true);
    $oRes = AMI::getResourceModel('eshop_item/table');
    $oRes->setActiveDependence('cat');
    $oItem = $oRes->getList();
    $oItem->addColumn('*');
    $oItem->addColumn('dataset_data', 'cat');
    $oItem->setWhereDef("AND i.id=" . $id);
    $oItem->load();
    if ($oItem->count() > 0) {
        $data = $oItem->current()->getData();
        $data['cat_dataset_data'] = unserialize($data['cat_dataset_data']);
        //$ret .= print_r($data, TRUE);
        foreach ($data['cat_dataset_data']['fields_captions'] as $key => $value) {
            if (
            // Проверяем, существует ли параметр в описании набора свойств
                    !empty($custtypes[$key]) &&
                    // Проверяем, заполнено ли значение параметра
                    ((isset($data["custom_field_" . $custtypes[$key]['fnum']]) && mb_strlen($data["custom_field_" . $custtypes[$key]['fnum']]) > 0)
                    // Могут быть ситуации, когда значение параметра записано в custom_field_N_1
                    || (isset($data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]) && mb_strlen($data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]) > 0))
            ) {
                switch ($custtypes[$key]['value_type']) {
                    // Если свойство - набор флагов
                    case 'scalar':
                        if ($custtypes[$key]['ftype'] == 'flagmap') {
                            $ret .= flagmapToText($value, $custtypes[$key]['default_params']['flag'][$data['lang']], $data["custom_field_" . $custtypes[$key]['fnum'] . "_1"]);
                        }
                        break;
                    //если свойство - ссылка на знач. справочника или ссылка на много значений справочника
                    case 'ref_reference':
                    case 'ref_set':
                        $rIds = str_replace(";", ",", trim($data["custom_field_" . $custtypes[$key]['fnum']], ";"));
                        if(mb_strlen($rIds) > 0) {
                            $refName = $oDB->select("SELECT `name` FROM `cms_es_reference_" . sprintf("%04d", $custtypes[$key]['ref_table_num']) . "` where id in(" . $rIds . ")");
                            foreach ($refName as $item) {
								if(mb_strlen($item['name'])>0)
									$ret .= '<param name="' . $value . '">' . $item['name'] . "</param>\n";
                            }
                        }
                        break;
                    // Все остальные типы свойств
                    default :
						if(mb_strlen($data["custom_field_" . $custtypes[$key]['fnum']])>0)
							$ret .= '<param name="' . $value . '">' . $data["custom_field_" . $custtypes[$key]['fnum']] . "</param>\n";
                        break;
                }
            }
        }
    }
    return $ret;
}

// Получаем текст из flagmap (набора флагов)
function flagmapToText($pname, $map, $value) {
    $result = '' . $value;
    foreach ($map as $key => $val) {
        if ((pow(2, $key - 1) & $value) > 0) {
            $result.= '<param name="' . $pname . '">' . $val['c'] . "</param>\n";
        }
    }
    return $result;
}




Добавлено: 06.09.14 19:23:48 #9




Регистрация: 14.07.08
Сообщений: 1126


Обратиться по имени

А вы просто сливаете эти данные общим списком в описание товара для маркета?



Разработка мобильной версии сайта с сохранением дизайна и позиций в поиске
Добавлено: 06.09.14 19:35:09 #10




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

@Дмитрий:
А вы просто сливаете эти данные общим списком в описание товара для маркета?


Если я правильно понял, то не совсем так.
Сливаются только данные, которые отображаются в общем списке. Ну и + проверка, что это не картинка.

if ($ct['isnot_all'] == 0 && $ct['is_prop'] == 0 && $ct['type_owner'] == 'item' && !in_array($ct['ftype'], array('picture'))) {



Добавлено: 06.09.14 19:44:53 #11




Регистрация: 14.07.08
Сообщений: 1126


Обратиться по имени

Я это к тому, что есть еще связанные товары через кастомные поля, но при выгрузке в Маркет там используется свой тег <rec><rec> и для них выгружаются идентификаторы, но стандартный амировский разделитель в виде точки запятой не подходит, нужна запятая.



Разработка мобильной версии сайта с сохранением дизайна и позиций в поиске
Добавлено: 06.09.14 19:56:52 #12




Регистрация: 24.09.10
Сообщений: 63


Обратиться по имени

@Дмитрий:
Я это к тому, что есть еще связанные товары через кастомные поля, но при выгрузке в Маркет там используется свой тег и для них выгружаются идентификаторы, но стандартный амировский разделитель в виде точки запятой не подходит, нужна запятая.


Ну, если будет надо, можно и это добавить. Пока такой задачи не было, поэтому не заморачивался.





Создать новую тему

Всего тем: 6661
Всего сообщений: 27851
Всего зарегистрированных пользователей: 26741
Последний зарегистрированный пользователь: user6353089940