<?php defined('HOSTCMS') || exit('HostCMS: access denied.'); /** * Класс для взаимодействия с Контентным API Яндекса. * * @author KAD Systems (©) 2017 */ class Kad_MarketContent_Controller extends Core_Servant_Properties { /** * Публичные свойства. * * @var array */ protected $_allowedProperties = array( 'geoId', 'cache', 'cachePath', 'cacheDays', 'log', ); /** * Адрес для API-запросов. * * @var string */ protected $_apiUrl; /** * Ключ для доступа к API. * * @var string */ protected $_apiKey; /** * Количество выполненных запросов. * * @var integer */ protected $_countRequests; /** * Обрабатывает ссылки в отзывах. * * @param string $text * @return string */ static public function processLinks($text) { return str_replace('href=', 'target="_blank" href=', $text); } /** * Конструктор. * * @param string $apiKey * @param string $apiUrl * @return void */ public function __construct($apiKey, $apiUrl = 'https://api.content.market.yandex.ru/v1') { parent::__construct(); $this->_apiUrl = $apiUrl; $this->_apiKey = $apiKey; $this->_countRequests = 0; $this->geoId = '10645'; $this->cache = FALSE; $this->cachePath = TMP_DIR . 'marketcontent/'; $this->cacheDays = 7; $this->log = FALSE; } /** * Возвращает количество выполненных запросов. * * @return integer */ public function getCountRequests() { return $this->_countRequests; } /** * Возвращает отзывы о модели. * * @param integer $modelId * @return array */ public function getModelOpinions($modelId) { $page = 1; $count = 30; // $oOpinionsJson = $this->_getResource("/model/{$modelId}/opinion", array( 'count' => $count ) ); $oModelOpinions = $oOpinionsJson->modelOpinions; $aOpinions = $oModelOpinions->opinion; while ($page * $count < $oModelOpinions->total) { $page = $oModelOpinions->page + 1; $oOpinionsJson = $this->_getResource("/model/{$modelId}/opinion", array( 'page' => $page, 'count' => $count ) ); $oModelOpinions = $oOpinionsJson->modelOpinions; $aOpinions = array_merge($aOpinions, $oModelOpinions->opinion); } return $aOpinions; } /** * Возвращает отзывы об интернет-магазине. * * @param integer $shopId * @return array */ public function getShopOpinions($shopId) { $page = 1; $count = 30; // $oOpinionsJson = $this->_getResource("/shop/{$shopId}/opinion", array( 'count' => $count ) ); $oShopOpinions = $oOpinionsJson->shopOpinions; $aOpinions = $oShopOpinions->opinion; while ($page * $count < $oShopOpinions->total) { $page = $oShopOpinions->page + 1; $oOpinionsJson = $this->_getResource("/shop/{$shopId}/opinion", array( 'page' => $page, 'count' => $count ) ); $oShopOpinions = $oOpinionsJson->shopOpinions; $aOpinions = array_merge($aOpinions, $oShopOpinions->opinion); } return $aOpinions; } /** * Возвращает информацию о регионе. * * @param string $geoId * @return object */ public function getRegionInfo($geoId) { $oRegionJson = $this->_getResource("/georegion/{$geoId}"); return isset($oRegionJson->georegion) ? $oRegionJson->georegion : NULL; } /** * Возвращает данные ресурса. * * @param string $resource * @param array $resourceParams * @param string $type * @return SimpleXmlElement */ protected function _getResource($resource, $resourceParams = array()) { $query = array('geo_id' => $this->geoId) + $resourceParams; $requestUrl = $this->_apiUrl . $resource . '.json' . '?' . http_build_query($query, '', '&'); $oData = NULL; $bFromRequest = FALSE; $dailyRemining = '(none)'; // Запрашиваем данные из кэша if ($this->cache) { $oData = @json_decode($this->_readCache($requestUrl)); } // Запрашиваем данные из API if (!$this->cache || !$oData) { usleep(0.1 * 1000000); $oCoreHttp = Core_Http::instance() ->clear() ->additionalHeader('Authorization', $this->_apiKey) ->additionalHeader('Accept', '*/*') ->url($requestUrl) ->execute(); if (preg_match('/X-RateLimit-Daily-Remaining: (\d+)\s/', $oCoreHttp->getHeaders(), $aMatches)) { $dailyRemining = intval($aMatches[1]); } $oData = @json_decode(strval($oCoreHttp->getBody())); $bFromRequest = TRUE; $this->_countRequests++; $this->_log("data from request '{$requestUrl}'"); } else { $this->_log("data from cache '{$requestUrl}'"); } if (!$oData) { throw new Core_Exception('Content Api returns invalid response.'); } elseif (isset($oData->errors)) { throw new Core_Exception("Content Api returns error: «{$oData->errors[0]}», daily limit remainig: {$dailyRemining}"); } $this->_log("daily limit remainig = {$dailyRemining}"); // Сохраняем запрос в кэш if ($this->cache && $bFromRequest) { $this->_writeCache($requestUrl, json_encode($oData)); } return $oData; } /** * Возвращает данные запроса из кэша. * * @param string $request * @return string */ protected function _readCache($request) { $cacheFile = $this->_getCacheFile($request); $bCacheTimeout = filemtime($cacheFile) > time() - $this->cacheDays * 24 * 60 * 60 // Запрос на получение информации о регионе никогда не устаривает || strpos($request, '/georegion/') !== FALSE ; if (file_exists($cacheFile) && $bCacheTimeout) { return file_get_contents($cacheFile); } return NULL; } /** * Записывает данные запроса в кэш. * * @param string $data * @param string $data * @return void */ protected function _writeCache($request, $data) { $cacheFile = $this->_getCacheFile($request); $cacheDir = substr($cacheFile, 0, strrpos($cacheFile, '/')); if (!is_dir($cacheDir)) { mkdir($cacheDir, 0777, TRUE); } file_put_contents($this->_getCacheFile($request), $data); } /** * Возвращает путь к кэш-файлу запроса. * * @param string $request * @return string */ protected function _getCacheFile($request) { return CMS_FOLDER . $this->cachePath . hash('sha256', $request); } /** * Логирует строку. * * @param string $string * @return void */ protected function _log($string) { if (!$this->log) { return; } print $string . "\n"; } }