arrilot / bitrix-models

MIT License
121 stars 37 forks source link

Когда много полей в базе свойств элемента инфоблока #8

Closed ProklUng closed 6 years ago

ProklUng commented 6 years ago

Отличная штука, спасибо. Пара моментов:

Когда много полей в базе свойств элемента инфоблока и ставишь опцию PROPS ожидаемо вываливается с ошибкой Too many tables; MySQL can only use 61 tables in a join. Причем, количество property не впечатляющее - штук 20 или 30 на элемент.

Хорошо бы сделать по аналогии с activate/deactivate функцию установки цен.

arrilot commented 6 years ago

Скорее всего у тебя в настройках инфоблока указана первая версия (общая таблица). Крайне рекомендуется использовать вторую версию (даже сам Битрикс в доке пишет об этом).

"Во второй версии инфоблоков при выборке элементов можно сразу получать значения свойств, т.к. количество присоединяемых таблиц в запросе не увеличивается с каждым свойством, а всегда равно единице"

Добавил в документацию ремарку насчёт этого. Скорее всего это no-fix

Насчёт цен - можешь добавить уже непосредственно в свою модель. Если получится что-то стоящее и универсальное - присылай PR.

vkryukov76 commented 6 years ago

В интернтет-магазинах в инфоблоке может быть под сотню свойств (иногда больше, особенно если есть интеграция с 1С).

Поэтому там невозможно использование второй версии.

Есть идеи - как быть в таком случае?

arrilot commented 6 years ago

1) мириться с ограничениями вроде невозможности использовать PROPS когда много свойств и использовать апи битрикса напрямую там где модель не работает 2) не использовать модель вообще для этого инфоблока

Все это не очень здорово конечно. Оставлю открытым всё-таки

vkryukov76 commented 6 years ago

http://bxapi.ru/src/?module_id=iblock&name=CIBlockElement::GetPropertyValuesArray

Как вариант можно для ИБ первой версии либо начиная с определенного количества свойств получать значения для каждого элемента отдельно.

Это несколько медленней, зато сработает.

Либо как в news.list:

$rsElement = CIBlockElement::GetList($arSort, array_merge($arFilter, $arrFilter), false, $arNavParams, $arSelect);
$rsElement->SetUrlTemplates($arParams["DETAIL_URL"], "", $arParams["IBLOCK_URL"]);
while($obElement = $rsElement->GetNextElement())
{
    $arItem = $obElement->GetFields();
    $arItem = $obElement->GetProperties();
}

Либо как в catalog.section:

if (!empty($arResult["ELEMENTS"]) && ($bGetProperties || ($bCatalog && $boolNeedCatalogCache)))
    {
        $arPropFilter = array(
            'ID' => $arResult["ELEMENTS"],
            'IBLOCK_ID' => $arParams['IBLOCK_ID']
        );
        CIBlockElement::GetPropertyValuesArray($arElementLink, $arParams["IBLOCK_ID"], $arPropFilter);

        foreach ($arResult["ITEMS"] as &$arItem)
        {
            if ($bCatalog && $boolNeedCatalogCache)
                CCatalogDiscount::SetProductPropertiesCache($arItem['ID'], $arItem["PROPERTIES"]);

            if (!empty($bGetProperties))
            {
                if (!empty($propertyList))
                {
                    foreach ($propertyList as &$pid)
                    {
                        if (!isset($arItem["PROPERTIES"][$pid]))
                            continue;
                        $prop = &$arItem["PROPERTIES"][$pid];
                        $boolArr = is_array($prop["VALUE"]);
                        if (
                                ($boolArr && !empty($prop["VALUE"]))
                                || (!$boolArr && strlen($prop["VALUE"]) > 0)
                        )
                        {
                            $arItem["DISPLAY_PROPERTIES"][$pid] = CIBlockFormatProperties::GetDisplayValue($arItem, $prop, "catalog_out");
                        }
                        unset($prop);
                    }
                    unset($pid);
                }

                if ($bGetProductProperties)
                {
                    $arItem["PRODUCT_PROPERTIES"] = CIBlockPriceTools::GetProductProperties(
                        $arParams["IBLOCK_ID"],
                        $arItem["ID"],
                        $arParams["PRODUCT_PROPERTIES"],
                        $arItem["PROPERTIES"]
                    );
                    if (!empty($arItem["PRODUCT_PROPERTIES"]))
                        $arItem['PRODUCT_PROPERTIES_FILL'] = CIBlockPriceTools::getFillProductProperties($arItem['PRODUCT_PROPERTIES']);
                }
            }
        }
        unset($arItem);
    }
ProklUng commented 6 years ago

О ценах. Подскажите, пожалуйста, как сделать так (унаследовать чего и как), чтобы можно было бы выполнять операцию таким образом:

$products = oboi::query()->select('ID')->setBasePrice (27.5, 'EUR');

И во всей выборке устанавливается базовая цена 27.5.

Или хотя бы в варианте для одной позиции.

$products = new oboi (27768); $products->price (27.5);

ProklUng commented 6 years ago

Еще момент. При выборке свойств не выдает XML_ID для свойства типа список.

$products = paints::ExcludeColorotecs()->select('ID')

            ->sort(['SORT' =>'DESC'])
            ->select ('NAME', 'FIELDS',
                'PROPERTY_COLLECTIONV2', 'PROPERTY_COLLECTION',
                'PROPERTY_ARTICUL', 'PROPERTY_GRADIENT',
                'PROPERTY_COLLECTIONV2'
            )
            ->getList()
            ->toArray()

;

            printr ($products);

[50494] => Array ( [ID] => 50494 [TIMESTAMP_X] => 21.07.2017 10:50:55

       [...] 

        [PROPERTY_GRADIENT_VALUE] => 0%
        [PROPERTY_GRADIENT_ENUM_ID] => 24545
        [PROPERTY_GRADIENT_VALUE_ID] => 50494:335

    )
arrilot commented 6 years ago

Он их не выдает потому что их не возвращает Битрикс из CiblockElement::GetList() + Fetch()/GetNext()

Битрикс возвращает только следующие поля для свойства типа список

  "PROPERTY_COUNTRY_VALUE" => "Россия"
  "PROPERTY_COUNTRY_ENUM_ID" => "1"
  "PROPERTY_COUNTRY_VALUE_ID" => "28:17"
arrilot commented 6 years ago

Проблема из темы issue решена в v0.6