Інтеграція 1С-Бітрікс із PIM-системою Pimcore

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Інтеграція 1С-Бітрікс із PIM-системою Pimcore
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Інтеграція 1С-Бітрікс із PIM-системою Pimcore

Pimcore — платформа з відкритим кодом, що поєднує PIM (управління продуктами), DAM (цифрові активи) та CMS. На відміну від Akeneo, Pimcore можна розгорнути на власному сервері без хмарної підписки, що важливо для проектів із закритою інфраструктурою. Інтеграція з Бітріксом будується через REST API Pimcore або прямої взаємодії з базою даних, якщо обидві системи знаходяться в одній мережі.

Pimcore Data Objects та REST API

У Pimcore продукти зберігаються як Data Objects — структуровані об'єкти з полями (Field Definitions). Для кожного класу об'єктів (Product, Variant, Category) Pimcore автоматично генерує REST API:

GET  /api/objects?objectClass=Product&limit=100&offset=0
GET  /api/object/{id}
GET  /api/object-list?objectClass=Product&q={"active":true}
GET  /api/asset/{id}             — медіафайли
GET  /api/asset-list?q={"type":"image"}

Аутентифікація — Basic Auth або API Key в заголовку:

class PimcoreClient
{
    private string $baseUrl;
    private array  $authHeaders;

    public function __construct(string $baseUrl, string $apiKey)
    {
        $this->baseUrl     = rtrim($baseUrl, '/');
        $this->authHeaders = ['X-API-Key' => $apiKey];
    }

    public function getObjects(
        string $class,
        int $offset = 0,
        int $limit = 100,
        ?string $filter = null
    ): array {
        $http = new \Bitrix\Main\Web\HttpClient();
        foreach ($this->authHeaders as $k => $v) {
            $http->setHeader($k, $v);
        }

        $url = $this->baseUrl . '/api/objects'
             . '?objectClass=' . urlencode($class)
             . '&offset=' . $offset
             . '&limit=' . $limit;

        if ($filter) {
            $url .= '&q=' . urlencode($filter);
        }

        $response = $http->get($url);
        $data     = json_decode($response, true);

        return $data['data'] ?? [];
    }

    public function getAsset(int $assetId): ?string
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        foreach ($this->authHeaders as $k => $v) {
            $http->setHeader($k, $v);
        }
        return $http->get($this->baseUrl . '/api/asset/' . $assetId . '/download') ?: null;
    }
}

Структура даних у Pimcore

Data Object класу Product містить поля, визначені в адміністративному інтерфейсі Pimcore. Типова структура для електронної комерції:

{
  "id": 1234,
  "className": "Product",
  "elements": [
    {"name": "sku",          "type": "input",    "value": "PROD-001"},
    {"name": "name",         "type": "localized", "value": {"ru": "Назва", "en": "Name"}},
    {"name": "description",  "type": "wysiwyg",  "value": "<p>Опис...</p>"},
    {"name": "price",        "type": "numeric",  "value": 1500.00},
    {"name": "weight",       "type": "numeric",  "value": 0.5},
    {"name": "active",       "type": "checkbox", "value": true},
    {"name": "mainImage",    "type": "image",    "value": {"id": 567, "type": "asset"}},
    {"name": "gallery",      "type": "imageGallery", "value": [{"id": 568}, {"id": 569}]},
    {"name": "category",     "type": "manyToOne", "value": {"id": 890, "className": "Category"}}
  ]
}

Маппінг та синхронізація в Бітріксі

Агент читає об'єкти з Pimcore постранично та оновлює/створює елементи інфоблоку:

function syncPimcoreProductsAgent(): string
{
    $client   = new PimcoreClient(PIMCORE_URL, PIMCORE_API_KEY);
    $offset   = (int)\Bitrix\Main\Config\Option::get('pimcore_sync', 'offset', 0);
    $limit    = 50;
    $products = $client->getObjects('Product', $offset, $limit, '{"active":true}');

    if (empty($products)) {
        // Скидання для наступного повного циклу
        \Bitrix\Main\Config\Option::set('pimcore_sync', 'offset', 0);
        return __FUNCTION__ . '();';
    }

    foreach ($products as $pimProduct) {
        importPimcoreProduct($pimProduct, $client);
    }

    \Bitrix\Main\Config\Option::set('pimcore_sync', 'offset', $offset + $limit);
    return __FUNCTION__ . '();';
}

function importPimcoreProduct(array $product, PimcoreClient $client): void
{
    // Вилучаємо значення поля зі структури Data Object
    $getField = static function (array $elements, string $name) {
        foreach ($elements as $el) {
            if ($el['name'] === $name) {
                return $el['value'];
            }
        }
        return null;
    };

    $elements = $product['elements'];
    $sku      = $getField($elements, 'sku');
    $nameRu   = $getField($elements, 'name')['ru'] ?? '';
    $descRu   = $getField($elements, 'description') ?? '';
    $active   = $getField($elements, 'active') ? 'Y' : 'N';

    // Шукаємо за артикулом
    $existing = CIBlockElement::GetList(
        [],
        ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'PROPERTY_CML2_ARTICLE' => $sku]
    )->Fetch();

    $fields = [
        'IBLOCK_ID'   => CATALOG_IBLOCK_ID,
        'ACTIVE'      => $active,
        'NAME'        => $nameRu,
        'DETAIL_TEXT' => $descRu,
        'DETAIL_TEXT_TYPE' => 'html',
    ];

    $props = ['CML2_ARTICLE' => $sku];

    // Ціна
    $price = $getField($elements, 'price');

    $iblockEl = new CIBlockElement();

    if ($existing) {
        $productId = $existing['ID'];
        $iblockEl->Update($productId, $fields);
        CIBlockElement::SetPropertyValuesEx($productId, CATALOG_IBLOCK_ID, $props);
    } else {
        $productId = $iblockEl->Add($fields);
        if ($productId) {
            CIBlockElement::SetPropertyValuesEx($productId, CATALOG_IBLOCK_ID, $props);
        }
    }

    if ($productId && $price !== null) {
        updateCatalogPrice($productId, (float)$price);
    }

    // Основне зображення
    $mainImage = $getField($elements, 'mainImage');
    if ($productId && isset($mainImage['id'])) {
        importPimcoreAsset($productId, (int)$mainImage['id'], $client, 'DETAIL_PICTURE');
    }
}

function importPimcoreAsset(
    int $productId,
    int $assetId,
    PimcoreClient $client,
    string $field
): void {
    $cacheKey = "pimcore_asset_{$assetId}";
    $cache    = \Bitrix\Main\Data\Cache::createInstance();
    if ($cache->initCache(86400 * 30, $cacheKey, '/pimcore/assets')) {
        $bitrixFileId = $cache->getVars()['file_id'];
    } else {
        $content    = $client->getAsset($assetId);
        $tmpPath    = sys_get_temp_dir() . "/pim_{$assetId}.jpg";
        file_put_contents($tmpPath, $content);

        $bitrixFile   = \CFile::MakeFileArray($tmpPath);
        $bitrixFileId = \CFile::SaveFile($bitrixFile, 'iblock');
        unlink($tmpPath);

        $cache->startDataCache(86400 * 30, $cacheKey, '/pimcore/assets');
        $cache->endDataCache(['file_id' => $bitrixFileId]);
    }

    if ($field === 'DETAIL_PICTURE') {
        \CIBlockElement::Update($productId, ['DETAIL_PICTURE' => $bitrixFileId]);
    } else {
        \CIBlockElement::SetPropertyValues($productId, CATALOG_IBLOCK_ID,
            $bitrixFileId, 'MORE_PHOTO');
    }
}

Вебхуки Pimcore для операційного оновлення

Pimcore підтримує вебхуки при зміні Data Object. Налаштовується в Pimcore → Settings → Webhooks:

  • Event: pimcore.dataobject.postUpdate
  • URL: https://bitrix-site.ru/local/pimcore-webhook.php
  • Secret для верифікації підпису

Обробник на стороні Бітрікс:

// /local/pimcore-webhook.php
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PIMCORE_SIGNATURE'] ?? '';

if (!verifyPimcoreSignature($payload, $signature, PIMCORE_WEBHOOK_SECRET)) {
    http_response_code(403);
    die('Невалідна підпис');
}

$data = json_decode($payload, true);
if ($data['className'] === 'Product') {
    $client  = new PimcoreClient(PIMCORE_URL, PIMCORE_API_KEY);
    $product = $client->getObjects('Product', 0, 1, json_encode(['id' => $data['id']]));
    if (!empty($product[0])) {
        importPimcoreProduct($product[0], $client);
    }
}

http_response_code(200);

Тривалість реалізації

Обсяг Склад Тривалість
1,000–10,000 SKU, базовий маппінг Клієнт + агент постраничної загрузки 1–2 тижня
50,000+ SKU + медіафайли + категорії Очередь + кеш ассетів + вебхуки 3–5 тижнів
Двомовний контент + product variants Локалізовані поля + торгові пропозиції додати 1–2 тижня