%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/tradingplatform/vk/api/
Upload File :
Create Path :
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/tradingplatform/vk/api/apihelper.php

<?php

namespace Bitrix\Sale\TradingPlatform\Vk\Api;

use Bitrix\Main\ArgumentNullException;
use Bitrix\Main\SystemException;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Json;
use Bitrix\Main\IO;
use Bitrix\Sale\TradingPlatform\Timer;
use Bitrix\Sale\TradingPlatform\Vk\Logger;
use Bitrix\Sale\TradingPlatform\Vk\Vk;
use Bitrix\Sale\TradingPlatform\TimeIsOverException;
use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

/**
 * Class ApiHelper - formatted and run requests to VK Api. Provide utility functions for help.
 * @package Bitrix\Sale\TradingPlatform\Vk\Api
 */
class ApiHelper
{
	private $vk;
	private $api;
	private $executer;
	private $exportId;
	private $logger;
	
	/**
	 * ApiHelper constructor.
	 * @param $exportId - int, ID of export profile
	 */
	public function __construct($exportId)
	{
		if (empty($exportId))
			throw new ArgumentNullException('exportId');
		
		$this->exportId = $exportId;
		$this->vk = Vk::getInstance();
		$this->api = $this->vk->getApi($exportId);
		$this->executer = $this->vk->getExecuter($exportId);
		$this->logger = new Logger($this->exportId);
	}
	
	
	/**
	 * Extract specified elements from array. Need to decrease of array size to post
	 *
	 * @param array $data - source array
	 * @param array $keys - array of keys, thst needed in new array
	 * @return array - array of extracted items
	 */
	public static function extractItemsFromArray($data = array(), $keys = array())
	{
		if (!isset($keys) || empty($keys))
			return $data;
		
		$newArr = array();
		foreach ($data as $value)
		{
			if (!is_array($value))
			{
				$newArr[] = $value;
			}
			else
			{
				$currArr = array();
				foreach ($keys as $k)
				{
					$currArr[$k] = $value[$k];
				}
				$newArr[] = $currArr;
			}
		}
		
		return $newArr;
	}
	
	
	/**
	 * Merge to arrays by reference key
	 *
	 * @param array $data
	 * @param array $result
	 * @param $referenceKey - main key in both arrays
	 * @return array
	 */
	public static function addResultToData($data = array(), $result = array(), $referenceKey)
	{
		if (empty($result) || !isset($referenceKey))
			return $data;
		
		foreach ($result as $item)
		{
			if (isset($data[$item[$referenceKey]]))
				$data[$item[$referenceKey]] += $item;
		}
		
		return $data;
	}
	
	
	/**
	 * Reformat array - change main (top level) key.
	 *
	 * @param array $data
	 * @param $mainKey
	 * @param string $keyRename - if isset, new main key will be rename
	 * @return array
	 */
	public static function changeArrayMainKey($data = array(), $mainKey, $keyRename = '')
	{
		if (!isset($mainKey))
			return $data;
		
		$result = array();
		foreach ($data as $item)
		{
			$result[$item[$mainKey]] = $item;
			if ($keyRename)
			{
				$result[$item[$mainKey]][$keyRename] = $result[$item[$mainKey]][$mainKey];
				unset($result[$item[$mainKey]][$mainKey]);
			}
		}
		
		return $result;
	}
	
	
	/**
	 * Check photo size, get upload server, upload photo and save them
	 *
	 * @param $data
	 * @param $vkGroupId
	 * @param $uploadType - type of photo. For other types used other params and methods
	 * @param null $timer - timer for control time of upload
	 * @return array - array of save photos results
	 * @throws SystemException
	 */
	public function uploadPhotos($data, $vkGroupId, $uploadType, Timer $timer = NULL)
	{
//		todo: this is a little kostyl. In cool variant we must separately do http-upload,
//		todo: and photo save run through execute method
//		todo: but now VK can't run savePhotoMethod through execute. Sadness ((

//		PARAMS set
		$photoSaveResults = array();
		switch ($uploadType)
		{
			case 'PRODUCT_MAIN_PHOTO':
				$uploadServerMethod = 'photos.getMarketUploadServer';
				$saveMethod = 'photos.saveMarketPhoto';
				$keyReference = 'BX_ID';
				$keyPhotoVk = 'PHOTO_MAIN_VK_ID';
				$keyPhotoBx = 'PHOTO_MAIN_BX_ID';
				break;
			
			case 'PRODUCT_PHOTOS':
				$uploadServerMethod = 'photos.getMarketUploadServer';
				$saveMethod = 'photos.saveMarketPhoto';
				$keyReference = 'PHOTO_BX_ID';
				$keyPhotoVk = 'PHOTO_VK_ID';
				$keyPhotoBx = 'PHOTO_BX_ID';
				break;
			
			case 'ALBUM_PHOTO':
				$uploadServerMethod = 'photos.getMarketAlbumUploadServer';
				$saveMethod = 'photos.saveMarketAlbumPhoto';
				$keyReference = 'SECTION_ID';
				$keyPhotoVk = 'PHOTO_VK_ID';
				$keyPhotoBx = 'PHOTO_BX_ID';
				break;
			
			default:
				throw new SystemException("Wrong photo upload type");
				break;
		}

//		PROCESSED
		foreach ($data as $item)
		{
//			check EXISTING photo
			if (!array_key_exists($keyPhotoBx, $item) || empty($item[$keyPhotoBx]))
				continue;

//			GET upload server by type
			$getServerParams = array("group_id" => str_replace("-", "", $vkGroupId));
			if ($uploadType == 'PRODUCT_MAIN_PHOTO')
				$getServerParams += self::setUploadServerMainPhotoParams($item[$keyPhotoBx]);
			
			$uploadServer = $this->api->run($uploadServerMethod, $getServerParams);
//			todo: may be this error in upload server response
			$this->logger->addLog("Get photo upload server", [
				'PARAMS' => $getServerParams,
				'RESULT' => $uploadServer,
			]);
			$uploadServer = $uploadServer["upload_url"];
			

//			UPLOAD photo by http
			$this->logger->addLog("Upload photo HTTP before", array(
				"UPLOAD_TYPE" => $uploadType,
				"ITEM" => array_key_exists("BX_ID", $item) ?
					$item["BX_ID"].': '.$item["NAME"] :
					$item["SECTION_ID"].': '.$item["TITLE"],
				"PHOTO_BX_ID" => array_key_exists("PHOTO_MAIN_BX_ID", $item) ? $item["PHOTO_MAIN_BX_ID"] : $item["PHOTO_BX_ID"],
				"PHOTO_URL" => array_key_exists("PHOTO_MAIN_URL", $item) ? $item["PHOTO_MAIN_URL"] : $item["PHOTO_URL"],
				"PHOTOS" => $item["PHOTOS"]	//only for products
			));
			$responseHttp = $this->uploadPhotoHttp($item, $uploadServer, $uploadType, $timer);
			$responseHttp = Json::decode($responseHttp);
			
//			SAVE upload result
			$photoSaveParams = array(
				"group_id" => str_replace('-', '', $vkGroupId),
				"photo" => $responseHttp["photo"],
				"server" => $responseHttp["server"],
				"hash" => $responseHttp["hash"],
			);
			
			// for product photo we need more params
			if ($saveMethod == "photos.saveMarketPhoto")
			{
				if (isset($responseHttp["crop_hash"]) && $responseHttp["crop_hash"])
					$photoSaveParams["crop_hash"] = $responseHttp["crop_hash"];
				if (isset($responseHttp["crop_data"]) && $responseHttp["crop_data"])
					$photoSaveParams["crop_data"] = $responseHttp["crop_data"];
			}
			
			$responsePhotoSave = $this->api->run($saveMethod, $photoSaveParams);
			
//			RESULT
			$photoSaveResults[] = array(
				$keyReference => $item[$keyReference],
				$keyPhotoVk => $responsePhotoSave[0]["id"],
			);

//			todo: photo mapping. po odnomu, navernoe, ved timer
		}
		
		return $photoSaveResults;
	}
	
	
	/**
	 * Formatted params and run http-upload process
	 *
	 * @param $data
	 * @param $uploadServer
	 * @param $uploadType
	 * @param null $timer
	 * @return bool|string
	 * @throws SystemException
	 * @throws TimeIsOverException
	 */
	private function uploadPhotoHttp($data, $uploadServer, $uploadType, Timer $timer = NULL)
	{
		switch ($uploadType)
		{
			case 'ALBUM_PHOTO':
				$postParams = array(
					"url" => $data["PHOTO_URL"],
					"filename" => IO\Path::getName($data["PHOTO_URL"]),
					"param_name" => 'file',
					"timer" => $timer,
				);
				break;
			
			case 'PRODUCT_MAIN_PHOTO':
				$postParams = array(
					"url" => $data["PHOTO_MAIN_URL"],
					"filename" => IO\Path::getName($data["PHOTO_MAIN_URL"]),
					"param_name" => 'file',
					"timer" => $timer,
				);
				break;
			
			case 'PRODUCT_PHOTOS':
				$postParams = array(
					"url" => $data["PHOTO_URL"],
					"filename" => IO\Path::getName($data["PHOTO_URL"]),
					"param_name" => 'file',
					"timer" => $timer,
				);
				break;
			
			default:
				throw new SystemException("Wrong upload type");
				break;
			
		}
		
		return $this->uploadHttp($uploadServer, $postParams);
	}
	
	
	/**
	 * Execute http requst
	 *
	 * @param $uploadServer
	 * @param $params
	 * @return bool|string - result of http request
	 * @throws TimeIsOverException
	 */
	private function uploadHttp($uploadServer, $params)
	{
		$http = new HttpClient();
		$boundary = md5(rand() . time());

		$file = $http->get($params["url"]);
		
		$data = '';
		$data .= '--' . $boundary . "\r\n";
		$data .= 'Content-Disposition: form-data; name="' . $params["param_name"] . '"; filename="' . $params["filename"] . '"' . "\r\n";
		$data .= 'Content-Type: application/octet-stream' . "\r\n\r\n";
		$data .= $file . "\r\n";
		$data .= '--' . $boundary . "--\r\n";
		
		$http->setHeader('Content-type', 'multipart/form-data; boundary=' . $boundary);
		$http->setHeader('Content-length', \Bitrix\Main\Text\BinaryString::getLength($data));
		
		$this->logger->addLog("Upload photo HTTP params", [
			'SERVER' => $uploadServer,
			'PARAMS' => $params,
			'FILE_OK' => $file ? 'Y' : 'N',
		]);
		$result = $http->post($uploadServer, $data);
		$this->logger->addLog("Upload photo HTTP response", $result);
		
//		check TIMER if set
		if (array_key_exists("timer", $params))
		{
			$timer = $params["timer"];
			if ($timer !== NULL && !$timer->check())
				throw new TimeIsOverException();
		}
		
		return $result;
	}
	
	
	
	public function getUserGroupsSelector($selectedValue = null, $name = null, $id = null)
	{
//		todo: maybe cached this values
		$groupsSelector = false;
		
		$gpoups = $this->getUserGroups();
		if(is_array($gpoups) && !empty($gpoups))
		{
			$groupsSelector = '<option value="-1">['.Loc::getMessage('SALE_VK_CHANGE_GROUP').']</option>';
			$selectedValue = str_replace('-', '', $selectedValue);
			$name = $name ? ' name="' . $name . '"' : '';
			$id = $id ? ' id="' . $id . '"' : '';
			
			foreach ($gpoups as $group)
			{
				$selected = $selectedValue == $group["id"] ? ' selected' : '';
				$groupsSelector .=
					'<option' . $selected . ' value="' . $group['id'] . '">' . $group['name'] . '</option>';
			}
			
			$groupsSelector =
				'<select id="vk_export_groupselector" onchange="BX.Sale.VkAdmin.changeVkGroupLink();"' . $id . $name . '>' .
				$groupsSelector .
				'</select>';
			$groupsSelector.=
				'<span style="padding-left:10px">
					<a href="https://vk.com/club'. $selectedValue .'" id="vk_export_groupselector__link">
						<img src="/bitrix/images/sale/vk/vk_icon.png">
					</a>
				</span>';
		}
		
		return $groupsSelector;
	}
	
	
	private function getUserGroups($offset = null)
	{
		$userGroups = array();
		$stepCount = 0;
		
//		max 1000 in one step.Check this value and run api again if needed
		while(true)
		{
			$params = array(
				'extended' => 1,
				'filter' => 'editor',
				'offset' => $stepCount,
				'count' => Vk::GROUP_GET_STEP,
			);
			$apiResult = $this->api->run('groups.get', $params);
			foreach($apiResult['items'] as $group)
			{
				$userGroups[$group['id']] = array(
					'id' => $group['id'],
					'name' => $group['name']
				);
			}
			
//			increment step items counter
			if($apiResult['count'] > Vk::GROUP_GET_STEP + $stepCount)
				$stepCount += Vk::GROUP_GET_STEP;
			else
				break;
		}
		
		return $userGroups;
	}
	
	/**
	 * Get list of VK albums from VK API
	 *
	 * @param $vkGroupId
	 * @param bool $flip
	 * @return array - list of VK albums
	 */
	public function getALbumsFromVk($vkGroupId, $flip = true)
	{
//		todo: so slow api request. Try cached this data or other acceleration techniques
		$albumsFromVk = $this->executer->executeMarketAlbumsGet(array(
			"owner_id" => $vkGroupId,
			"offset" => 0,
			"count" => Vk::MAX_ALBUMS,
		));
		$albumsFromVk = $albumsFromVk["items"];        //		get only items from response
		foreach ($albumsFromVk as &$item)    //		get only IDs from response
		{
			$item = $item["id"];
		}
		if ($flip)
			$albumsFromVk = array_flip($albumsFromVk);        // we need albumID as keys
		
		return $albumsFromVk;
	}
	
	
	/**
	 * Get list of VK products from VK API
	 *
	 * @param $vkGroupId
	 * @return array -  list of VK products
	 */
	public function getProductsFromVk($vkGroupId)
	{
		$productsFromVk = array();
		$prodGetStep = 0;
		while ($prodGetStep < Vk::MAX_PRODUCTS_IN_ALBUM)
		{
			$productsFromVk += $this->executer->executeMarketProductsGet(array(
				"owner_id" => $vkGroupId,
				"offset" => $prodGetStep,
				"step" => Vk::PRODUCTS_GET_STEP)
			);
			$prodGetStep += Vk::PRODUCTS_GET_STEP;
			// exit from loop, if we reach end of VK-products
			if ($productsFromVk["end_products"])
			{
				unset($productsFromVk["end_products"]);
				break;
			}
		}
		
		$result = array();
		foreach($productsFromVk as $productFromVk)
			$result[$productFromVk] = array("VK_ID" => $productFromVk);
		
		return $result;
	}
	
	
	/**
	 * Check params for save products data.
	 * Check photos, description, vk-category
	 *
	 * @param $data
	 * @return array - prepared to save data array
	 */
	public static function prepareProductsDataToVk($data)
	{
		$result = array();
		foreach ($data as $item)
		{
//			check PHOTOS and formatted
			if (isset($item["PHOTOS"]) && is_array($item["PHOTOS"]))
			{
				$photosIds = array();
				foreach ($item["PHOTOS"] as $photo)
				{
					if (is_numeric($photo["PHOTO_VK_ID"]))
						$photosIds[] = $photo["PHOTO_VK_ID"];
				}
				
				if (!empty($photosIds))
					$item["PHOTOS"] = implode(",", $photosIds);
				else
					unset($item["PHOTOS"]);
			}
			
//			check VK_CATEGORY
			if (!(isset($item["CATEGORY_VK"]) && intval($item["CATEGORY_VK"]) > 0))
			{
				$item["CATEGORY_VK"] = Vk::VERY_DEFAULT_VK_CATEGORY;
			}    // we need some category
			
			$result[] = $item;
		}
		
		return $result;
	}
	
	
	/**
	 * Build params for http photo upload
	 *
	 * @param $photoId
	 * @return array
	 */
	private static function setUploadServerMainPhotoParams($photoId)
	{
		$result = array();
		$result["main_photo"] = 1;
		
		$photoParams = \CFile::GetFileArray($photoId);
		$w = $photoParams["WIDTH"];
		$h = $photoParams["HEIGHT"];
		
		if ($w >= $h)
		{
			$result["crop_x"] = ceil(($w + $h) / 2);
			$result["crop_y"] = 0;
			$result["crop_width"] = $h;
		}
		else
		{
			$result["crop_x"] = 0;
			$result["crop_y"] = ceil(($w + $h) / 2);
			$result["crop_width"] = $w;
		}
		
		return $result;
	}
	
	
	/**
	 * Get list of VK product categories from VK API
	 *
	 * @param int $count
	 * @param int $offset
	 * @return array - Get list of VK product categories. Return false if error
	 */
	public function getVkCategories($count = Vk::MAX_VK_CATEGORIES, $offset = 0)
	{
		$vkCats = $this->api->run('market.getCategories', array("count" => $count, "offset" => $offset));
		
		if (!empty($vkCats))
			return $vkCats["items"];
		
		else
			return false;
	}
}

Zerion Mini Shell 1.0