<?php
/**
 * Created by PhpStorm.
 * User: alexey.tischenko
 * Date: 29-Jan-16
 * Time: 16:38
 */

namespace Calls2\Models\KartotekaAPI;

/**
 * Класс запроса к API
 * Class Request
 * @package Calls2\Models\KartotekaAPI
 */
class Request
{
	/**
	 * Максимальное количество итераций для авторизации
	 */
	const MAX_ITERATION = 5;

	/**
	 * Объект запроса
	 * @var Request
	 */
	static protected $instance = null;

	/**
	 * Объект конфига
	 * @var Config
	 */
	protected $config;

	/**
	 * ID сессии
	 * @var string
	 */
	protected $session_id;

	/**
	 * Объект SOAP
	 * @var \SoapClient
	 */
	protected $clientAPI;

	/**
	 * Итерация
	 * @var int
	 */
	protected $iteration = 0;

	/**
	 * Инициализировать конфиг
	 */
	protected function __construct()
	{
		$this->config = Config::getInstance();
	}

	/**
	 * Получить объект запроса
	 * @return Request
	 */
	public static function getInstance()
	{
		if (self::$instance === null) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Получение сессии для API
	 * @return string
	 */
	public function getSessionId()
	{
		if (!$this->session_id) {
			$this->setSessionId();
		}
		return $this->session_id;
	}

	/**
	 * Задать id сессии
	 * чтобы исключить множественную авторизацию
	 */
	public function setSessionId()
	{
		$this->session_id = $this->auth();
	}

	/**
	 * Процесс авторизации
	 * @return string
	 * @throws \Crm\Exceptions\Modules\KartotekaAPI
	 */
	protected function auth()
	{
		try {
			$resultId = $this->getClientAPI()->login($this->config->get('api_authorization'));
			if ($resultId && !empty($resultId->session->id)) {
				return $resultId->session->id;
			} else {
				$this->iteration++;
				if ($this->iteration > self::MAX_ITERATION) {
					throw new \Exception('Error Authorization', 501);
				}
				return $this->auth();
			}
		} catch (\Exception $e) {
			$this->iteration++;
			if ($this->iteration > self::MAX_ITERATION) {
				throw new \Exception('Error Authorization', 501);
			}
			return $this->auth();
		}
	}

	/**
	 * Реализация объекта SOAP клиента к FPI
	 * @return \SoapClient
	 * @throws \Crm\Exceptions\Modules\KartotekaAPI
	 */
	protected function getClientAPI()
	{
		if ($this->clientAPI === null) {
			\Asu\Logger::getInstance()->setDebug(\Asu\Logger::DEBUG_NONE);
			if (!file_get_contents($this->config->get('api_wsdl'), 0, stream_context_create(['http' => ['timeout' => 5]]))) {
				\Asu\Logger::getInstance()->setDebugDefault();
				throw new \Exception('Error access to WSDL', 503);
			}
			\Asu\Logger::getInstance()->setDebugDefault();
			$this->clientAPI = new \SoapClient($this->config->get('api_wsdl'));
		}
		return $this->clientAPI;
	}

	/**
	 * Выполнение запроса к API
	 * example: $param = ['inn'=>7713038962]
	 * @param array|string $param параметр(ы) запроса
	 * @param string $method метод API запрашиваемый
	 * @return mixed
	 * @throws \Crm\Exceptions\Modules\KartotekaAPI
	 */
	public function request($param, $method)
	{
		if (!$param) {
			throw new \Crm\Exceptions\Modules\KartotekaAPI('Empty input data', 401);
		}
		try {
			$this->getClientAPI()->__setSoapHeaders(new \SoapHeader($this->config->get('api_wsdl'), 'sessionId', $this->getSessionId())); //Устанавливаем заголовок чтобы работать с сессией
			$result = call_user_func_array([$this->getClientAPI(), $method], [$param]);
		} catch (\Exception $e) {
			return $this->tryRepeatRequest($param, $method, $e->getMessage(), 503);
		}
		if (!empty($result->detail->error)) {
			if ($result->detail->error->code == $this->config->get('api_auth_error_code')) {
				return $this->tryRepeatRequest($param, $method, 'Error Authorization in Request', 502);
			} else {
				throw new \Exception('Error in Request: ' . $result->detail->error->msg, 402);
			}
		}
		$this->iteration = 0; // когда есть положительный ответ надо сбросить счетчик итераций
		return $result;
	}

	/**
	 * Обертка для рекурсивного обращения к API. Попытка пробиться ;)
	 * @param array $param набор параметров
	 * @param string $method вызываемый в API метод
	 * @param string $msg сообщение с ошибкой
	 * @param int $code код ошибки
	 * @return array
	 * @throws \Crm\Exceptions\Modules\KartotekaAPI
	 */
	protected function tryRepeatRequest($param, $method, $msg, $code)
	{
		$this->session_id = null;
		$this->iteration++;
		if ($this->iteration > self::MAX_ITERATION) {
			throw new \Exception($msg, $code);
		}
		return $this->request($param, $method);
	}
}

<?php
/**
 * Created by PhpStorm.
 * User: alexey.tischenko
 * Date: 29-Jan-16
 * Time: 16:29
 */

namespace Calls2\Models\KartotekaAPI;

/**
 * Класс конфига для API
 * Class Config
 * @package Calls2\Models\KartotekaAPI
 */
class Config
{
	/**
	 * Объект конфига
	 * @var Config
	 */
	static protected $instance;

	/**
	 * Массив настроек
	 * @var array
	 */
	protected $settings;

	/**
	 * Инициализировать настройки
	 */
	function __construct()
	{
		$this->settings = $this->getSettings();
	}

	/**
	 * Получить объект конфига
	 * @return Config
	 */
	static public function getInstance()
	{
		if (static::$instance === null) {
			static::$instance = new static;
		}
		return static::$instance;
	}

	/**
	 * Получить параметр настроек
	 * @param string $param параметр
	 * @param null|mixed $default значение по умолчанию
	 * @return mixed
	 */
	public function get($param, $default = null)
	{
		if (array_key_exists($param, $this->settings)) {
			$value = $this->settings[$param];
		} else {
			$value = $default;
		}
		return $value;
	}

	/**
	 * Задать параметр
	 * @param string $param наименование параметра
	 * @param mixed $value значение параметра
	 */
	public function set($param, $value)
	{
		$this->settings[$param] = $value;
	}

	/**
	 * Получить настройки подключения к API
	 * @return array
	 */
	protected function getSettings()
	{
		return [
			'api_wsdl' => 'https://api.kartoteka.ru/search/v3/soap/search.wsdl',
			'api_authorization' => [
				'login' => 'service_account',
				'password' => 'ksj5567gbvchh'
			],
			'api_auth_error_code' => 207
		];
	}

}

<?php


namespace Uc\Controller\Order;


use Calls2\Models\KartotekaAPI\Essence;
use Calls2\Models\KartotekaAPI\Request;
use Crm\Exceptions\Modules\KartotekaAPI;
use stdClass;

/**
 * Взаимодействие с api
 * Trait ApiSoap
 * @package Uc\Controller\Order
 */
trait ApiSoap
{
    /**
     * Дата прекращения деятельности
     * @throws KartotekaAPI
     */
    public function actionSearchEndDateLiquidated()
    {
        $searchValue = filter_input(INPUT_POST, 'searchValue', FILTER_SANITIZE_STRING);
        $ctype = filter_input(INPUT_POST, 'ctype', FILTER_SANITIZE_STRING);

        if(!$searchValue || $ctype == 3){
            header('Content-Type: application/json');
            echo $this->safe_json_encode([
                'status' => 0,
                'endDate' => 0
            ]);exit;
        }

        $params = [
            'detailSearchRequest' => [
                'inn' => $searchValue,
                'filters' => [
                    'orgTypes' => [
                        'orgType' => [1,3] // Юр. лица и ИП
                    ]
                ]
            ]
        ];

        $request = Request::getInstance();
        $result = $request->request($params,'searchByRequisite');
        $essences = [];
        if (!empty($result->rowsCount) && $result->rowsCount > 0) {
            foreach ($result->rows as $groupResult) {
                if ($groupResult instanceof stdClass) {
                    $essences[] = new Essence($groupResult);
                } else {
                    foreach ($groupResult as $row) {
                        $essences[] = new Essence($row);
                    }
                }
            }
        }

        $clients = [];
        foreach ($essences as $essence) {
            switch ($essence->getType()) {
                case 1:
                    // Юр. лицо
                    if (!$essence->getINN() || !$essence->getKPP()) {continue;}
                    $clients = $essence->getInfoArray();
                    break;
                case 4:
                    // ИП
                    if (!$essence->getOGRN()) {continue;}
                    $clients = $essence->getInfoArray();
                    break;
            }
        }

        header('Content-Type: application/json');
        echo $this->safe_json_encode([
            'status' => !empty($clients['status']) ? $clients['status'] : 0,
            'endDate' => !empty($clients['endDate']) ? $clients['endDate'] : 0
        ]);exit;
    }
}