Интеграция 1С-Битрикс с PIM-системой Pimcore

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Интеграция 1С-Битрикс с PIM-системой Pimcore
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1177
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • 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 Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Интеграция 1С-Битрикс с PIM-системой Pimcore

Pimcore — open-source платформа, совмещающая PIM (управление продуктами), DAM (цифровые активы) и CMS. В отличие от Akeneo, Pimcore может быть развёрнут на собственном сервере без облачной подписки, что важно для проектов с закрытой инфраструктурой. Интеграция с Битрикс строится через Pimcore REST API или через прямое взаимодействие с базой данных при расположении обеих систем в одной сети.

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. Типичная структура для e-commerce:

{
  "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('Invalid signature');
}

$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 недели