Добавлено: Связь товара и его свойств (точнее их названий) 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
Обратиться по имени
@Дмитрий: Я это к тому, что есть еще связанные товары через кастомные поля, но при выгрузке в Маркет там используется свой тег и для них выгружаются идентификаторы, но стандартный амировский разделитель в виде точки запятой не подходит, нужна запятая.
Ну, если будет надо, можно и это добавить. Пока такой задачи не было, поэтому не заморачивался.