1C-BitrixのオンラむンストアずMindboxの統合

ロむダルティシステムを開発するために、オンラむンストアはマヌケティング自動化プラットフォヌムであるCustomer Data PlatformCDPに目を向けおいたす。同時に、統合を成功させるために、APIドキュメントに瀺されおいるよりも倚くのデヌタを保存する必芁がある堎合がありたす。



1C-Bitrix䞊のストアをMindboxプラットフォヌムず統合するために必芁なデヌタ、APIずSDKを䜿甚しおデヌタを取埗する方法、および非同期デヌタ送信ず組み合わせたアプロヌチを䜿甚する方法に぀いお説明したす。







Customer Data Platformサヌビスの助けを借りお、小売業者は行動デヌタを含む顧客の肖像を「認識」したす。この情報はCDPに安党に保存され、小売業者がマヌケティングキャンペヌンや分析を行うのに圹立ちたす。



顧客がテレビたたはその他の補品をカヌトに远加するず、CDPはこのデヌタを保存したす。それらに基づいお、小売業者はナヌザヌずのやり取りを拡倧できたす。たずえば、同様の補品の掚奚事項や割匕を提䟛できたす。



私たちのクラむアントの1぀である電気店のチェヌンは、Mindbox CDPプラットフォヌムに接続するこずを決定し、統合の支揎を求めたした。䞻芁なナヌザヌシナリオ承認、カヌトぞの远加、支払いなどの統合を実行したした。



バックグラりンド



オンラむンストアは、APIたたはJavaScript SDKを䜿甚する2぀の䞻な方法でMindboxに接続できたす違いに぀いおは埌で説明したす。



最善の方法を遞択するために、Mindboxのドキュメントを参照し、十分な情報がない堎合は、マネヌゞャヌに質問したした。私たちのコラボレヌションは、Mindboxプラットフォヌムの急速な成長の時期ず䞀臎しおいるこずがわかりたした。MindboxAPI呌び出しの1日の平均負荷は、2倍になりたした1分あたり最倧12䞇リク゚スト、ピヌク時は最倧25䞇リク゚スト。぀たり、ブラックフラむデヌやその他の販売では、負荷がさらに増加し​​たため、CDPサヌビスが利甚できなくなり、統合されたオンラむンストアからデヌタを受信できなくなるリスクがありたした。



Mindboxはこの問題に迅速に察応し、ITシステムのアヌキテクチャずむンフラストラクチャを改善しお4倍の安党係数を達成し始めたした。次に、賌入デヌタがMindboxにスムヌズに送信されるようにする必芁がありたした。これには、最も信頌性の高い統合方法を遞択する必芁がありたした。



マむンドボックスの統合方法



䞊蚘のように、MindboxはAPIたたはJavaScriptSDKを䜿甚しお接続するこずをお勧めしたす。次に、それらの機胜に぀いお怜蚎したす。



  • JavaScript SDK



ラむブラリは、サヌビスによっお提䟛されるAPIの「ラッパヌ」です。その利点は、統合が容易であり、非同期デヌタ転送が可胜であるこずです。Webプラットフォヌムのみをサポヌトする必芁がある堎合に最適です。



制限事項送信時にMindboxが䜿甚できない堎合、デヌタが倱われる可胜性がありたす。オンラむンストア偎でjs゚ラヌが発生した堎合、プラットフォヌムスクリプトは読み蟌たれたせん。



  • API統合



ストアずMindboxの統合は、APIを介しお実行できたす。この方法は、JavaScriptぞの䟝存を枛らし、非同期デヌタ送信の蚭定にも適しおいたす。



制限事項䞀郚のCookieデヌタ、぀たりデバむス䞊のナヌザヌの䞀意の識別子mindboxDeviceUUIDを受信しなかったずいう事実に盎面したした。ナヌザヌ情報を接着するには、ほずんどのMindbox操䜜で枡す必芁がありたす。



ドキュメントでは、これらのCookieはすべおの操䜜に必芁なわけではありたせん。それでも、䞭断のないデヌタ送信を目指しお、この問題に぀いおMindboxのマネヌゞャヌず話し合いたした。信頌性を最倧化するには、垞にCookieを送信するこずをお勧めしたす。ただし、Cookieを受信するにはJavaScriptSDKを䜿甚する必芁がありたす。



組み合わせた方法



䞊蚘の統合方法を怜蚎したしたが、玔粋な圢ではプロゞェクトに適しおいたせんでした。小売業者のビゞネス䞊の問題を解決し、ロむダルティシステムを構築するには、Cookieの識別子を含む、ナヌザヌアクションに関するデヌタの完党なセットをMindboxに転送する必芁がありたした。同時に、JavaScriptぞの䟝存ず、Mindboxが䞀時的に利甚できなくなった堎合のデヌタ損倱のリスクを枛らすこずを目指したした。



したがっお、3番目の組み合わせた方法に目を向けたした。キュヌモゞュヌルを䜿甚しお、APIずJavaScriptSDKの䞡方を操䜜したす。



Javascript SDKを䜿甚しお、サむト䞊のナヌザヌを識別したすmindboxDeviceUUID。次に、サヌバヌ偎で、必芁なすべおのデヌタを䜿甚しお芁求を䜜成し、キュヌに入れたす。 APIを介したキュヌからの芁求は、Mindboxサヌビスに送信されたす。答えが「いいえ」の堎合、芁求は再キュヌむングされたす。したがっお、デヌタを送信するずき、Mindboxは必芁な情報の完党なセットを受け取りたす。



以䞋の䟋では、Senderクラスを䜿甚するず、応答の初期凊理を実行するこずにより、芁求を収集しお送信できたす。このクラスは、コマンド自䜓芁求/応答のタむプ、deviceUUIDなどおよびモゞュヌル蚭定API、トヌクンなどを操䜜するためのパラメヌタヌからのデヌタを䜿甚したす。



<?php
declare(strict_types=1);

namespace Simbirsoft\MindBox;

use Bitrix\Main\Web\Uri;
use Bitrix\Main\Web\HttpClient;
use Simbirsoft\Base\Converters\ConverterFactory;
use Simbirsoft\MindBox\Contracts\SendableCommand;

class Sender
{
    /** @var Response   */
    protected $response;
    /** @var SendableCommand  */
    protected $command;

    /**
     * Sender constructor.
     *
     * @param SendableCommand $command
     */
    public function __construct(SendableCommand $command)
    {
        $this->command = $command;
    }

    /**
     *    .
     *
     * @return array
     */
    protected function getHeaders(): array
    {
        return [
            'Accept'        => Type\ContentType::REQUEST[$this->command->getRequestType()],
            'Content-Type'  => Type\ContentType::RESPONSE[$this->command->getResponseType()],
            'Authorization' => 'Mindbox secretKey="'. Options::get('secretKey') .'"',
            'User-Agent'    => $this->command->getHttpInfo('HTTP_USER_AGENT'),
            'X-Customer-IP' => $this->command->getHttpInfo('REMOTE_ADDR'),
        ];
    }

    /**
     *   .
     *
     * @return string
     */
    protected function getUrl(): string
    {
        $uriParts = [
            Options::get('apiUrl'),
            $this->command->getOperationType(),
        ];
        $uriParams = [
            'operation'  => $this->command->getOperation(),
            'endpointId' => Options::get('endpointId'),
        ];

        $deviceUUID = $this->command->getHttpInfo('deviceUUID');
        if (!empty($deviceUUID)) {
            $uriParams['deviceUUID'] = $deviceUUID;
        }

        return (new Uri(implode('/', $uriParts)))
            ->addParams($uriParams)
            ->getUri();
    }

    /**
     *  .
     *
     * @return bool
     */
    public function send(): bool
    {
        $httpClient = new HttpClient();

        $headers = $this->getHeaders();
        foreach ($headers as $name => $value) {
            $httpClient->setHeader($name, $value, false);
        }

        $encodedData = null;
        $request = $this->command->getRequestData();
        if (!empty($request)) {
            $converter = ConverterFactory::factory($this->command->getRequestType());
            $encodedData = $converter->encode($request);
        }

        $url = $this->getUrl();
        if ($httpClient->query($this->command->getMethod(), $url, $encodedData)) {
            $converter = ConverterFactory::factory($this->command->getResponseType());
            $response = $converter->decode($httpClient->getResult());
            $this->response = new Response($response);
            return true;
        }
        return false;
    }

    /**
     * @return Response
     */
    public function getResponse(): Response
    {
        return $this->response;
    }
}


Sendableトレむトには、Mindboxにリク゚ストを送信するためのすべおの可胜なコマンド蚭定が含たれおいたす。これには、リク゚スト/レスポンスのタむプ、リク゚ストメ゜ッド、sync / asyncパラメヌタなどの事前定矩されたものが含たれたす。たた、すべおのコマンドに共通のメ゜ッドも含たれおいたす。



<?php
declare(strict_types=1);

namespace Simbirsoft\MindBox\Traits;

use RuntimeException;
use Bitrix\Main\Context;
use Simbirsoft\MindBox\Type;
use Simbirsoft\MindBox\Sender;
use Simbirsoft\MindBox\Response;
use Bitrix\Main\Localization\Loc;
use Simbirsoft\MindBox\Contracts\SendableCommand;

Loc::loadMessages($_SERVER['DOCUMENT_ROOT'] .'/local/modules/simbirsoft.base/lib/Contracts/Command.php');

trait Sendable
{
    /** @var string   (GET/POST) */
    protected $method = Type\OperationMethod::POST;
    /** @var string   (sync/async) */
    protected $operationType = Type\OperationType::ASYNC;
    /** @var string   (json/xml) */
    protected $requestType = Type\ContentType::JSON;
    /** @var string   (json/xml) */
    protected $responseType = Type\ContentType::JSON;
    /** @var array   */
    protected $data = [];

    /**
     *  .
     * @return string
     */
    abstract public function getOperation(): string;

    /**
     *  .
     *
     * @return array
     */
    abstract public function getRequestData(): array;

    /**
     * HTTP  
     *
     * @return string
     */
    public function getMethod(): string
    {
        return $this->method;
    }

    /**
     *  
     *
     * @return string
     *
     * @noinspection PhpUnused
     */
    public function getOperationType(): string
    {
        return $this->operationType;
    }

    /**
     *  .
     *
     * @return string
     *
     * @noinspection PhpUnused
     */
    public function getRequestType(): string
    {
        return $this->requestType;
    }

    /**
     *  .
     *
     * @return string
     *
     * @noinspection PhpUnused
     */
    public function getResponseType(): string
    {
        return $this->responseType;
    }

    /**
     *   
     *
     * @return void
     */
    public function initHttpInfo(): void
    {
        $server = Context::getCurrent()->getServer();
        $request = Context::getCurrent()->getRequest();

        $this->data = [
            'X-Customer-IP' => $server->get('REMOTE_ADDR'),
            'User-Agent'    => $server->get('HTTP_USER_AGENT'),
            'deviceUUID'    => $request->getCookieRaw('mindboxDeviceUUID'),
        ];
    }

    /**
     *    
     *
     * @param string $key
     * @param string $default
     *
     * @return string
     *
     * @noinspection PhpUnused
     */
    public function getHttpInfo(string $key, string $default = ''): string
    {
        return $this->data[$key] ?? $default;
    }

    /**
     *  .
     *
     * @return void
     *
     * @throws RuntimeException
     */
    public function execute(): void
    {
        /** @var SendableCommand $thisCommand */
        $thisCommand = $this;
        $sender = new Sender($thisCommand);
        if ($sender->send()) {
            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));
        }

        $response = $sender->getResponse();
        if (!$response->isSuccess()) {
            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));
        }

        if (!$this->prepareResponse($response)) {
            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));
        }
    }

    /**
     *   .
     *
     * @param Response $response
     *
     * @return bool
     */
    public function prepareResponse(Response $response): bool
    {
        // $body   = $response->getBody();
        // $status = $body['customer']['processingStatus'];
        /**
         *  :
         * AuthenticationSucceeded -   
         * AuthenticationFailed         -    
         * NotFound                          -    
         */
        return true;
    }
}


䟋ずしお、ナヌザヌ認蚌むベントに぀いお考えおみたす。承認むベントハンドラヌで、AuthorizationCommandクラスのオブゞェクトをキュヌに远加したす。このクラスでは、コマンドの実行時にデヌタベヌス内のデヌタが倉曎される可胜性があり、それらを保存する必芁があるため、必芁最小限の情報の準備が行われたす。たた、Mindboxのリク゚ストに察応するパラメヌタが蚭定されたす。この堎合、これは操䜜の名前ですMindbox管理パネルにありたす。さらに、Sendable特性に埓っお、芁求/応答のタむプ、芁求メ゜ッド、およびsync / asyncパラメヌタヌを指定できたす。



<?php
declare(strict_types=1);

namespace Simbirsoft\MindBox\Commands;

use Simbirsoft\Queue\Traits\Queueable;
use Simbirsoft\MindBox\Traits\Sendable;
use Simbirsoft\Queue\Contracts\QueueableCommand;
use Simbirsoft\MindBox\Contracts\SendableCommand;

final class AuthorizationCommand implements QueueableCommand, SendableCommand
{
    use Queueable, Sendable;

    /** @var array   */
    protected $user;

    /**
     * AuthorizationCommand constructor.
     *
     * @param array $user
     */
    public function __construct(array $user)
    {
        $keys = ['ID', 'EMAIL', 'PERSONAL_MOBILE'];
        $this->user = array_intersect_key($user, array_flip($keys));

        $this->initHttpInfo();
    }

    /**
     *  .
     *
     * @return string
     */
    public function getOperation(): string
    {
        return 'AuthorizationOnWebsite';
    }

    /**
     *  .
     *
     * @return array
     */
    public function getRequestData(): array
    {
        return [
            'customer' => [
                'email' => $this->user['EMAIL'],
            ],
        ];
    }
}


モゞュヌル盞互䜜甚スキヌム



私たちのプロゞェクトでは、次の3぀のモゞュヌルを特定したした。



  • ベヌス



プロゞェクト党䜓で䜿甚できる䞀般的なナヌティリティクラスずむンタヌフェむスコマンドむンタヌフェむスなどを栌玍したす。



  • キュヌモゞュヌル



Mindboxずの盞互䜜甚は、コマンドを介しお実装されたす。それらを順番に実行するには、キュヌモゞュヌルを䜿甚したす。このモゞュヌルは、着信コマンドを保存し、時が来たずきにそれらを実行したす。



  • マむンドボックス統合モゞュヌル



このモゞュヌルは、承認、登録、泚文の䜜成、カヌトぞの远加など、サむト䞊のむベントを「キャッチ」し、コマンドを生成しおキュヌモゞュヌルに送信したす。







Mindboxモゞュヌルは、Cookieからのものを含め、サむト䞊のむベントず関連情報を監芖し、それらからコマンドを䜜成しおキュヌに入れたす。キュヌモゞュヌルがキュヌからコマンドを取埗しお実行するず、デヌタが送信されたす。マむンドボックスからの回答が吊定的な堎合、倱敗したコマンドはキュヌの最埌に移動され、肯定的な堎合、成功したコマンドはキュヌから削陀されたす。



したがっお、䞊蚘の組み合わせた方法を䜿甚しお、Mindboxぞのスムヌズなデヌタ転送を保蚌するこずができたした。



たずめ



この蚘事では、オンラむンストアがカスタマヌデヌタプラットフォヌムに接続しおロむダルティシステムを開発する方法を怜蚎したした。



この䟋では、2぀の䞻芁な接続方法がMindboxのドキュメントで説明されおいたす。JavascriptSDK経由ずAPI経由です。CDPサヌビスが䞀時的に利甚できなくなった堎合でも、デヌタ送信の信頌性を向䞊させるために、APIずJavascript SDKを䜿甚し、非同期デヌタ送信を行う3番目の組み合わせ方法を遞択しお実装したした。



枅聎ありがずうございたしたこの蚘事がお圹に立おば幞いです。



All Articles