Create your own shop importer

:entwickler:customizing_interface.png Shop interfaces (so-called "importers") can be created customer-specifically or they can simply be overloaded. This way, data can already be manipulated or enriched during the import process, and even the more complex conversion of data structures is possible.

Introduction

A major topic in Xentral is the connection and automatic processing of orders originating in online shops. Although many online shops already have a high degree of automation, new shop systems and their connection challenge us from time to time. Although almost every shop already has an interface, it often turns out that the interfaces to be connected are not compatible. Xentral already offers interfaces to various shops and, to be honest, it is not that complicated to develop an importer, the adapter between Xentral and the online shop interface. The importer acts as so-called middleware and translates order data from the shop into a format that enables Xentral to create orders. On the other hand the importer is also responsible for transferring the order status back to the shop, i.e. the status of the order processing and dispatching. Additionally, the importer transfers data like stock amounts and article related data to the shop. This is why the importer is more of a compact multi-talent than anything else.
A (short) excursion into the past
Before we start we have a short excursion into the past: In the beginning of the automated connection of online shops in Xentral (at times when it was still called Xentral) the importers were implemented in a technically different aapproach. The first importers were simply PHP files that were stored directly in the webspace of the online shop and also accessed the shop database directly if necessary, e.g. if the API could not return the necessary data. Today we call these importers, which are stored directly at the shop, "external importers" - in comparison to the importers that are stored in the file system of Xentral and aree therefore called "internal importers". Currently the trend moves to the internal importer, which is why we demonstrate here how an internal importer can easily be created by yourself.

The process within the shop importer

The process flow within the importer always follows a fixed schema. If, for example, orders are to be retrieved from the shop, the system first checks whether there is a connection to the shop interface. The system then determines whether and how many orders have to be retrieved from the shop. If there are orders to be fetched, these are imported and marked afterwards in the shop as "Currently being processed". If article data is imported from the shop or exported to the shop the scheme looks quite similar. First, a check is performed whether there is a connection between Xentral and the shop. Then the data is being transferred. :entwickler:customizing_custom_importer_10.png

Basics

You don't need any expert knowledge to write your own importer. Basic PHP knowledge is sufficient if you stick to the given structure. However, there are a few things that need to be clarified beforehand:
1. Name
The name of the importer doesn't really matter. By convention, however, the class name is composed of Shopimporter_XXX. In this example we will develop a special importer for shopware, which is why the class is called Shopimporter_Shopwarespecial. The file itself is named corresponding to the class name in lower case letters and is stored in the www/pages/ directory of the Xentral installation, for example /var/home/www/html/xentral/www/pages/shopimporter_shopwarespecial.php.
2. Database Entry
If a new importer is added to the system via the user interface, a new entry is created in the "Shopexport" table of the database. Since this importer is a custom-made product, we have to enter the name of the importer in this table ourselves. It is important that the module name corresponds to the name of the PHP file. :entwickler:customizing_custom_importer_12.png
3. ShopimporterBase
All internal importers are based on the ShopimporterBase class. This class contains system-relevant functions that ensure that the importer is executed. Basically every importer should be derived from the base class ShopimporterBase to ensure that these functions are available:
class Shopimporter_Shopwarespecial extends ShopimporterBase
{
4. Boilerplate
Two variables are relevant for the use of importers. $app contains the application Xentrals itself and is passed in the constructor. This allows the importer to use the core functionality of Xentral. The variable $internal does not indicate whether it is an internal importer but whether the action handlers must be initialized for the object. This makes it possible to instantiate and use the object elsewhere without causing a conflict.
/**
 * @var bool
 */
public $intern = false;

/**
 * @var Application
 */
public $app;
5. Constructor
Two parameters are passed in the constructor, $app and $internal are stored directly in the object to be addressed later if necessary. Then the first logic takes place in the module: It is checked whether action handlers should be registered for the module. There are some action handlers that can be registered - but for this example we will use the basic functions that every shop importer should have. It is recommended to use the function names as given to ensure compatibility. A list of the functions as well as the role, which they take over in the Importer, follows further down in detail.
public function __construct($app, $intern = false)
{
  $this->app=$app;
  $this->intern = true;
  if($intern)
  {
    return;
  }
  $this->app->ActionHandlerInit($this);

  $this->app->ActionHandler('auth','ImportAuth');
  $this->app->ActionHandler('sendlist','ImportSendList');
  $this->app->ActionHandler('sendlistlager','ImportSendListLager');
  $this->app->ActionHandler('getauftraegeanzahl','ImportGetAuftraegeAnzahl');
  $this->app->ActionHandler('getauftrag','ImportGetAuftrag');
  $this->app->ActionHandler('deleteauftrag','ImportDeleteAuftrag');
  $this->app->ActionHandler('updateauftrag','ImportUpdateAuftrag');
    
  $this->app->DefaultActionHandler('list');
  $this->app->ActionHandlerListen($app);
}
6. Method EinstellungenStruktur
Since literally every shop interface has its own individual setting options, it is necessary to provide the importer with exactly these setting options. That happens in the function SettingsStructure(). Fields passed here are displayed in the surface form of the importer. If required, further fields can of course be created - for this example, however, the data required for the login should be sufficient.
public function EinstellungenStruktur()
{
  return
    array(
      'felder'=>array(
        'APIUser'=>array('typ'=>'text','bezeichnung'=>'{|API User:','size'=>40),
        'APIKey'=>array('typ'=>'text','bezeichnung'=>'{|API Key|}:','size'=>40),
        'APIUrl'=>array('typ'=>'text','bezeichnung'=>'{|API Url|}:','size'=>40),
      ));
}
In Xentrals User Interface that looks like this: :entwickler:customizing_custom_importer_08.png
7. Method getKonfig
The last function before you really get started is getKonfig(). In this method, data from the settings and the ID of the shop importer are passed to the object. The parameter $data is a remnant from the time of the external importers and contains instructions for the individual functions. This function is called by the system whenever the object is initialized.
public function getKonfig($shopid, $data)
{
  $this->shopid = $shopid;
  $this->data = $data;
  $einstellungen = $this->app->DB->Select("SELECT einstellungen_json FROM shopexport WHERE id = '$shopid' LIMIT 1");
  if($einstellungen){
    $einstellungen = json_decode($einstellungen,true);
    $this->apiUser = $einstellungen['felder']['APIUser'];
    $this->apiKey = $einstellungen['felder']['APIKey'];
    $this->apiUrl = $einstellungen['felder']['APIUrl'];
  }
}
After the basics for the importer have been completed, the actual connection to Shopware is established. Of course, it is possible to outsource the complete communication to a separate class or, in the case of Shopware, to copy the class from the documentation. For simplicity's sake, a short function that returns the API's answer is sufficient for this example:
protected function call($endpoint, $method, $data=array(),$params=array()){
  $queryString = '';
  if (!empty($params)) {
    $queryString = '?'.http_build_query($params);
  }
  $url = $this->apiUrl.$endpoint.$queryString;
  $dataString = json_encode($data);

  $curl = curl_init();
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
  curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_setopt($curl, CURLOPT_USERPWD, $this->apiUser . ':' . $this->apiKey);
  curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=utf-8']);
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $dataString);
  return curl_exec($curl);
}

ImportAuth

After all prerequisites for the function of the importer have been fulfilled it can be filled with life. First step towards this direction is the function ImportAuth(). In external importers this function is obligatory for the authentication from Xentral to the importer. In internal importers the function checks the connection call to the API. Since this function is called every time the importer is to take action, it usually contains a request or mechanism to create a token. Important is the return of the value success to indicate that the importer is ready to receive instructions and forward them to the shops API.
public function ImportAuth()
{
  $params = ['limit' => 1];
  $responseJson  =$this->call('articles','GET',null, $params);
  $response = json_decode($responseJson,true);

  if($response['success']){
    return 'success';
  }

  return '';
}

Method ImportSendListLager

In the next step the function ImportSendListLager() is added. If the option for transferring stock numbers is enabled in the import settings, this method synchronizes the stock numbers in the shop with the stock amounts in Xentral. In this example, that is done using the item number. Please note that for this function, the data parameter of the importer object contains all data for the item to be updated.
public function ImportSendListLager()
{
  $updatedArticles = 0;
  $tmp = $this->CatchRemoteCommand('data');
  foreach ($tmp as $article){
    $nummer = $article['nummer'];
    $lageranzahl = $article['anzahl_lager'];

    $updateInStock = [
      'mainDetail' => [
        'inStock' => $lageranzahl
      ]
    ];

    $params = [
      'useNumberAsId'=>true
    ];

    $result = $this->call('articles/'.$nummer, 'PUT',$updateInStock, $params);
    if($result['success']){
      $updatedArticles++;
    }
  }
  return $updatedArticles;
}
:entwickler:customizing_custom_importer_04.png

Method ImportSendList

The function ImportSendList() is basically an extended version of ImportSendListLager(). The function transfers articles to the shop - or updates their data. Which data can be transferred and how this can be done depends mainly on the shop interface. This way product properties or images can be transferred to the shop. One should pay attention to the separation of the two functions, since ImportSendList is called only in two cases:
  1. Manual export of the article
  2. Export of the article via the article transfer in the importer
$articleData = [
  'name' => $name,
  'lastStock' => $laststock,
  'tax' => $tax, // alternativ 'taxId' => 1,
  'supplier' => $supplier, // alternativ 'supplierId' => 2,
  'description' => $description,
  'descriptionLong' => $description_long,
  'keywords' => $keywords,
  'metaTitle' => $metatitle,
  'highlight' => $topseller,
  'mainDetail' => [
    'number' => $articleNumber,
    'active' => $active,
    'ean' => $ean,
    'weight' => $weight,
    'width' => $width,
    'len' => $length,
    'height' => $height,
    'supplierNumber' => $supplierNumber,
    'inStock' => $lageranzahl,
    'prices' => $prices
  ]
];

Method ImportGetAuftraegeAnzahl

This function determines how many pending orders are available in the shop that have to be collected. You might retrieve orders depending om their status, starting with a certain order number or a specific order date. Please note that depending on the shop interface not all options might be available.
public function ImportGetAuftraegeAnzahl()
{
  $result = $this->getOrders($this->data);

  return count($result['data']);
}

Method ImportGetAuftrag

The most important basic function of all importers is to pick up and translate orders from the shop into Xentral's more generic shopping cart format. After the next order has been picked up by the shops API, the customer's address data is transferred to the shopping cart in the first step:
$cart['anrede'] = 'herr';
$cart['strasse'] = $order['data']['billing']['street'];
$cart['plz'] = $order['data']['billing']['zipCode'];
$cart['ort'] = $order['data']['billing']['city'];
$cart['land'] = $order['data']['billing']['country']['iso'];
$cart['email'] = $order['data']['customer']['email'];
$cart['name'] = $order['data']['billing']['firstName'] . ' ' . $order['data']['billing']['lastName'];
If there is a different delivery address this also has to be handed over to the order in Xentral. Additionally the field alternative delivery address must then be filled with the value true so that the order can be carried out to the correct recipient. Additionally there is a whole range of important data that needss to be stored for further processing.
$cart['auftrag'] = $orderFromCollection['id'];
$cart['gesamtsumme'] = $orderFromCollection['invoiceAmount'];
$cart['transaktionsnummer'] = $orderFromCollection['transactionId'];
$cart['onlinebestellnummer'] = $orderFromCollection['number'];
...
$cart['zahlungsweise'] = $order['data']['payment']['name'];
$cart['lieferung'] = $order['data']['dispatch']['name'];
$cart['bestelldatum'] = substr($order['data']['orderTime'],0,10);
$cart['versandkostennetto'] = $order['data']['invoiceShippingNet'];
Total amount (Gesamtsumme):
The total amount of the order serves as protection against an incorrectly assembled shopping basket. If item data has not been transferred correctly or there was a problem with taxation, the total amount of the order differs from the total amount of the shopping cart and the Auto Shipping option (also called "Autoversand") is deactivated for the order. This ensures that no shipment leaves the warehouse that not exactly corresponds to the purchase order.
Transaction number (Transaktionsnummer):
The transaction number is relevant for the automation of accounting and helps to assign paid orders.
Order (Auftrag):
".In this field, the unique identification of the order for the shop is transferred. Not all shop interfaces allow you to change the shipping status of an order using the order number. Occasionally an internal ID is required, which can be transferred and stored at this point. The value used here is later referred to when changes in the order status have to be transferred from the shop to Xentral.
Online purchase order number (Onlinebestellnummer):
This field contains the order number that the customer also knows from the purchase. This facilitates the assignment and in case of a inquiry an order from the shop can be assigned directly to an order in Xentral.
Method of payment (Zahlungsweise):
\Transferring the payment method allows you to activate or deactivate settings such as automated shipment ("Autoversand"), Fast-Lane or the generation of invoices specifically for certain payment methods in Xentral.
Delivery (Lieferung):
\Similar to the payment method, a match can be established in Xentral when the delivery method is transferred.
Shipping cost gross amount (Versandkostenbrutto):
Basically the shipping costs can be transferred with an order like an item in the shopping cart. However, by using this special field the shipping costs are posted directly to the postage item set in the importer and included in the order.
Order date (Bestelldatum):
\The order date indicates the date on which the order was received.
foreach ($order['data']['details'] as $article)
{
  $articlearray[] = [
    'articleid' => $article['articleNumber'],
    'name' => $article['articleName'],
    'price' => $article['price'],
    'quantity' => $article['quantity']
  ];
}

...

$orderData =[
  'id' => $cart['auftrag'],
  'warenkorb' => base64_encode(serialize($cart)),
  'warenkorbjson' => base64_encode(json_encode($cart))
];
When the required basic data of the order have been transferred to the shopping cart, it is time to add the individual items to the shopping cart. In the field articleid the article number is transferred. In the other fields you can see the respective equivalent originating from the order item. After the shopping cart has been filled with all data to be transferred from the order, the method returns all the data.

Methods ImportDeleteAuftrag / ImportUpdateAuftrag

The method ImportDeleteAuftrag is not used for deleting orders from the shop but marks a pending order as "In Process". The partner function ImportUpdateAuftrag marks the order as "Sent" or "Processed".
public function ImportDeleteAuftrag()
{
  $orderId = $this->data['auftrag'];
  $update = [
    'orderStatusId' => 1
  ];

  $this->call('orders/'.$orderId, 'PUT',$update);

  return true;
}

Code of the example

Here you can find the entire PHP source code of the example described above for your own use. This serves as a starting point for your development - but we do not guarantee the correctness or the expected functionality.
<?php

class Shopimporter_Shopwarespecial extends ShopimporterBase
{
  /**
   * @var bool
   */
  public $intern = false;
  
  /**
   * @var Application
   */
  public $app;

  /** @var string*/
  public $apiUrl;
  
  /** @var string*/
  public $apiKey;
  
  /**  @var string*/
  public $apiUser;
  
  /** @var int */
  public $shopid;

  /** @var mixed */
  public $data;
  
  /**
   * Shopimporter_Shopwarespecial constructor.
   *
   * @param      $app
   * @param bool $intern
   */
  public function __construct($app, $intern = false)
  {
    $this->app=$app;
    $this->intern = true;
    if($intern)
    {
      return;
    }
    $this->app->ActionHandlerInit($this);

    $this->app->ActionHandler('auth','ImportAuth');
    $this->app->ActionHandler('sendlist','ImportSendList');
    $this->app->ActionHandler('sendlistlager','ImportSendListLager');
    $this->app->ActionHandler('getauftraegeanzahl','ImportGetAuftraegeAnzahl');
    $this->app->ActionHandler('getauftrag','ImportGetAuftrag');
    $this->app->ActionHandler('deleteauftrag','ImportDeleteAuftrag');
    $this->app->ActionHandler('updateauftrag','ImportUpdateAuftrag');
    
    $this->app->DefaultActionHandler('list');
    $this->app->ActionHandlerListen($app);
  }

  /**
   * @return array
   */
  public function EinstellungenStruktur()
  {
    return
      array(
        'felder'=>array(
          'APIUser'=>array('typ'=>'text','bezeichnung'=>'{|API User:','size'=>40),
          'APIKey'=>array('typ'=>'text','bezeichnung'=>'{|API Key|}:','size'=>40),
          'APIUrl'=>array('typ'=>'text','bezeichnung'=>'{|API Url|}:','size'=>40),
        ));
  }


  /**
   * @param $shopid
   * @param $data
   */
  public function getKonfig($shopid, $data)
  {
    $this->shopid = $shopid;
    $this->data = $data;
    $einstellungen = $this->app->DB->Select("SELECT einstellungen_json FROM shopexport WHERE id = '$shopid' LIMIT 1");
    if($einstellungen){
      $einstellungen = json_decode($einstellungen,true);
      $this->apiUser = $einstellungen['felder']['APIUser'];
      $this->apiKey = $einstellungen['felder']['APIKey'];
      $this->apiUrl = $einstellungen['felder']['APIUrl'];
    }
  }

  /**
   * @param       $endpoint
   * @param       $method
   * @param array $data
   * @param array $params
   *
   * @return bool|string
   */
  protected function call($endpoint, $method, $data=array(),$params=array()){
    $queryString = '';
    if (!empty($params)) {
      $queryString = '?'.http_build_query($params);
    }
    $url = $this->apiUrl.$endpoint.$queryString;
    $dataString = json_encode($data);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($curl, CURLOPT_USERPWD, $this->apiUser . ':' . $this->apiKey);
    curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=utf-8']);
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $dataString);
    return curl_exec($curl);
  }


  /**
   * @return int
   */
  public function ImportSendListLager()
  {
    $updatedArticles = 0;
    $tmp = $this->CatchRemoteCommand('data');
    foreach ($tmp as $article){
      $nummer = $article['nummer'];
      $lageranzahl = $article['anzahl_lager'];

      $updateInStock = [
        'mainDetail' => [
          'inStock' => $lageranzahl
        ]
      ];

      $params = [
        'useNumberAsId'=>true
      ];

      $result = $this->call('articles/'.$nummer, 'PUT',$updateInStock, $params);
      if($result['success']){
        $updatedArticles++;
      }
    }
    return $updatedArticles;
  }


  /**
   * @return int|string
   */
  public function ImportSendList()
  {
    $tmp = $this->CatchRemoteCommand('data');
    $successCount = 0;

    foreach ($tmp as $article){
      $name = $article['name_de'];
      $articleNumber = $article['nummer'];
      $active = !$article['inaktiv'];
      $length = $article['laenge'];
      $width = $article['breite'];
      $height = $article['hoehe'];
      $weight = $article['gewicht'];
      $tax = $article['steuersatz'];
      $ean = $article['ean'];

      $lageranzahl = $article['anzahl_lager'];
      $laststock = $article['restmenge'];
      $supplier = $article['hersteller'];
      $supplierNumber = $article['herstellernummer'];
      $description = $article['metadescription_de'];
      $description_long = htmlspecialchars_decode($article['uebersicht_de']);
      $keywords = $article['metakeywords_de'];
      $metatitle = $article['metatitle_de'];

      $preis = $article['bruttopreis'];

      $topseller=0;
      if($article['topseller'])
      {
        $topseller=1;
      }


      $prices[] = [
        'customerGroupKey' => 'EK',
        'price' => $preis
      ];

      $articleData = [
        'name' => $name,
        'lastStock' => $laststock,
        'tax' => $tax, // alternativ 'taxId' => 1,
        'supplier' => $supplier, // alternativ 'supplierId' => 2,
        'description' => $description,
        'descriptionLong' => $description_long,
        'keywords' => $keywords,
        'metaTitle' => $metatitle,
        'highlight' => $topseller,
        'mainDetail' => [
          'number' => $articleNumber,
          'active' => $active,
          'ean' => $ean,
          'weight' => $weight,
          'width' => $width,
          'len' => $length,
          'height' => $height,
          'supplierNumber' => $supplierNumber,
          'inStock' => $lageranzahl,
          'prices' => $prices
        ]
      ];

      $params = [
        'useNumberAsId' => true
      ];
      $responseJson = $this->call('articles/'.$articleNumber, 'GET',null,$params);
      $response = json_decode($responseJson,true);

      if(empty($response['data']['id'])){
        $responseJson = $this->call('articles', 'POST' ,$articleData);
      }else{
        $responseJson = $this->call('articles/'.$articleNumber, 'PUT' ,$articleData,$params);
      }

      $response = json_decode($responseJson,true);
      if($response['success']){
        $successCount++;
      }else{
        return 'error: '.print_r($response,true);
      }
    }

    return $successCount;
  }


  /**
   * @return int
   */
  public function ImportGetAuftraegeAnzahl()
  {
    $result = $this->getOrders($this->data);

    return count($result['data']);
  }

  /**
   * @return bool
   */
  public function ImportUpdateAuftrag()
  {
    $orderId = $this->data['auftrag'];
    $update = [
      'orderStatusId' => 2
    ];

    $this->call('orders/'.$orderId, 'PUT',$update);

    return true;
  }

  /**
   * @return bool
   */
  public function ImportDeleteAuftrag()
  {
    $orderId = $this->data['auftrag'];
    $update = [
      'orderStatusId' => 1
    ];

    $this->call('orders/'.$orderId, 'PUT',$update);

    return true;
  }

  /**
   * @param $data
   *
   * @return array
   */
  protected function getOrders($data){
    $toNumber = $data['bis_nummer'];

    if(empty($toNumber)){
      $filter[] = [
        'property' => 'status',
        'value' => 0,
      ];
    }else{
      $filter[] = [
        'property' => 'number',
        'expression' => '<=',
        'value' => $toNumber,
      ];
    }

    $params = [
      'filter' => $filter
    ];
    $resultJson = $this->call('orders', 'GET', null, $params);
    return json_decode($resultJson,true);
  }
  
  /**
   * @return array
   */
  public function ImportGetAuftrag()
  {
    $result = $this->getOrders($this->data);

    $allOrders = [];
    foreach ($result['data'] as $orderFromCollection){
      $cart = [];
      $cart['auftrag'] = $orderFromCollection['id'];
      $cart['gesamtsumme'] = $orderFromCollection['invoiceAmount'];
      $cart['transaktionsnummer'] = $orderFromCollection['transactionId'];
      $cart['onlinebestellnummer'] = $orderFromCollection['number'];
      $orderJson = $this->call('orders/'.$orderFromCollection['id'],'GET');
      $order = json_decode($orderJson,true);

      $cart['anrede'] = 'herr';
      $cart['strasse'] = $order['data']['billing']['street'];
      $cart['plz'] = $order['data']['billing']['zipCode'];
      $cart['ort'] = $order['data']['billing']['city'];
      $cart['land'] = $order['data']['billing']['country']['iso'];
      $cart['email'] = $order['data']['customer']['email'];
      $cart['name'] = $order['data']['billing']['firstName'] . ' ' . $order['data']['billing']['lastName'];

      $cart['zahlungsweise'] = $order['data']['payment']['name'];
      $cart['lieferung'] = $order['data']['dispatch']['name'];
      $cart['bestelldatum'] = substr($order['data']['orderTime'],0,10);
      $cart['versandkostennetto'] = $order['data']['invoiceShippingNet'];


      $articlearray = [];

      foreach ($order['data']['details'] as $article)
      {
        $articlearray[] = [
          'articleid' => $article['articleNumber'],
          'name' => $article['articleName'],
          'price' => $article['price'],
          'quantity' => $article['quantity']
        ];
      }

      $cart['articlelist']=$articlearray;

      $orderData =[
        'id' => $cart['auftrag'],
        'warenkorb' => base64_encode(serialize($cart)),
        'warenkorbjson' => base64_encode(json_encode($cart))
      ];

      $allOrders[] = $orderData;
    }

    return $allOrders;
  }

  /**
   * @return string
   */
  public function ImportAuth()
  {
    $params = ['limit' => 1];
    $responseJson  =$this->call('articles','GET',null, $params);
    $response = json_decode($responseJson,true);

    if($response['success']){
      return 'success';
    }

    return '';
  }
}
War der Artikel hilfreich?
Vielen Dank für Ihr Feedback!

Made with ❤ at zwetschke.de