PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/api/ProductAPI.php

https://github.com/octolab/Ecwid
PHP | 665 lines | 448 code | 34 blank | 183 comment | 55 complexity | 51146419b0bfb0b9c6e20df75f71b3e3 MD5 | raw file
  1. <?php
  2. /**
  3. * @author Samigullin Kamil <feedback@kamilsk.com>
  4. * @link http://www.kamilsk.com/
  5. */
  6. namespace Ecwid\api;
  7. use Ecwid\interfaces\iProductAPI,
  8. \Exception;
  9. /**
  10. * @package Ecwid.api
  11. * @since 1.0
  12. */
  13. class ProductAPI implements iProductAPI
  14. {
  15. /**
  16. * @var array
  17. */
  18. protected static $_defaultConfig = array(
  19. 'protocol' => 'http',
  20. 'base_url' => 'app.ecwid.com/api',
  21. 'api_version' => 1,
  22. 'store_id' => 1003,
  23. 'secure_auth_key' => null,
  24. );
  25. /**
  26. * @var array
  27. */
  28. protected $_config;
  29. /**
  30. * @var bool
  31. */
  32. protected $_silent = false;
  33. /**
  34. * @var string
  35. */
  36. protected $_url;
  37. /**
  38. * @var resource
  39. */
  40. protected $_curl;
  41. /**
  42. * Constructor.
  43. *
  44. * @param array $config
  45. * <code>
  46. * array(
  47. * 'protocol' => %s:http|https,
  48. * 'base_url' => %s:url,
  49. * 'api_version' => %i:version,
  50. * 'store_id' => %i:id,
  51. * 'secure_auth_key' => %s:key,
  52. * )
  53. * </code>
  54. * @throws Exception
  55. */
  56. public function __construct(array $config = array())
  57. {
  58. if ($this->_initConfig(array_merge(self::$_defaultConfig, $config))) {
  59. $this->_updateUrl();
  60. } else {
  61. throw new Exception('_init');
  62. }
  63. }
  64. /* iEcwid */
  65. /**
  66. * @return string
  67. */
  68. public function getProtocol()
  69. {
  70. return $this->_config['protocol'];
  71. }
  72. /**
  73. * @param string $protocol
  74. * @return self
  75. * @throws Exception
  76. */
  77. public function setProtocol($protocol)
  78. {
  79. if ($this->_validate('protocol', $protocol)) {
  80. $this->_config['protocol'] = $protocol;
  81. $this->_updateUrl();
  82. return $this;
  83. }
  84. throw new Exception('_invalid_protocol');
  85. }
  86. /**
  87. * @return string
  88. */
  89. public function getBaseUrl()
  90. {
  91. return $this->_config['base_url'];
  92. }
  93. /**
  94. * @param string $base_url
  95. * @return self
  96. * @throws Exception
  97. */
  98. public function setBaseUrl($base_url)
  99. {
  100. if ($this->_validate('base_url', $base_url)) {
  101. $this->_config['base_url'] = $base_url;
  102. $this->_updateUrl();
  103. return $this;
  104. }
  105. throw new Exception('_invalid_base_url');
  106. }
  107. /**
  108. * @return int
  109. */
  110. public function getApiVersion()
  111. {
  112. return $this->_config['api_version'];
  113. }
  114. /**
  115. * @param int $version
  116. * @return self
  117. * @throws Exception
  118. */
  119. public function setApiVersion($version)
  120. {
  121. if ($this->_validate('api_version', $version)) {
  122. $this->_config['api_version'] = $version;
  123. $this->_updateUrl();
  124. return $this;
  125. }
  126. throw new Exception('_invalid_api_version');
  127. }
  128. /**
  129. * @return int
  130. */
  131. public function getStoreId()
  132. {
  133. return $this->_config['store_id'];
  134. }
  135. /**
  136. * @param int $id
  137. * @return self
  138. * @throws Exception
  139. */
  140. public function setStoreId($id)
  141. {
  142. if ($this->_validate('store_id', $id)) {
  143. $this->_config['store_id'] = $id;
  144. $this->_updateUrl();
  145. return $this;
  146. }
  147. throw new Exception('_invalid_store_id');
  148. }
  149. /**
  150. * @return string
  151. */
  152. public function getUrl()
  153. {
  154. return $this->_url;
  155. }
  156. /**
  157. * @return string
  158. */
  159. public function getSecureAuthKey()
  160. {
  161. return $this->_config['secure_auth_key'];
  162. }
  163. /**
  164. * @param string $key
  165. * @return self
  166. * @throws Exception
  167. */
  168. public function setSecureAuthKey($key)
  169. {
  170. if ($this->_validate('secure_auth_key', $key)) {
  171. $this->_config['secure_auth_key'] = $key;
  172. return $this;
  173. }
  174. throw new Exception('_invalid_secure_auth_key');
  175. }
  176. /**
  177. * @return array
  178. */
  179. public function getConfig()
  180. {
  181. return $this->_config;
  182. }
  183. /**
  184. * @param array $config
  185. * @return bool
  186. * @throws Exception
  187. */
  188. protected function _initConfig(array $config)
  189. {
  190. $map = array(
  191. 'store_id' => 'setStoreId',
  192. 'protocol' => 'setProtocol',
  193. 'base_url' => 'setBaseUrl',
  194. 'api_version' => 'setApiVersion',
  195. 'secure_auth_key' => 'setSecureAuthKey',
  196. );
  197. $this->_silent = true;
  198. foreach ($config as $key => $value) {
  199. if (array_key_exists($key, $map)) {
  200. $set = $map[$key];
  201. $this->$set($value);
  202. }
  203. }
  204. $this->_silent = false;
  205. return true;
  206. }
  207. /**
  208. * @param string $key
  209. * @param mixed $value
  210. * @return bool
  211. */
  212. protected function _validate($key, $value)
  213. {
  214. $checksum = 0;
  215. switch ($key) {
  216. case 'store_id':
  217. if (is_int($value)) {
  218. $checksum += 1;
  219. }
  220. if ($value > 0) {
  221. $checksum += 2;
  222. }
  223. return ($checksum === 3);
  224. case 'protocol':
  225. if (is_string($value)) {
  226. $checksum += 1;
  227. }
  228. if (preg_match('/^http(s)?$/', $value)) {
  229. $checksum += 2;
  230. }
  231. return ($checksum === 3);
  232. case 'base_url':
  233. if (is_string($value)) {
  234. $checksum += 1;
  235. }
  236. return ($checksum === 1);
  237. case 'api_version':
  238. if (is_int($value)) {
  239. $checksum += 1;
  240. }
  241. if ($value > 0) {
  242. $checksum += 2;
  243. }
  244. return ($checksum === 3);
  245. case 'secure_auth_key':
  246. if (is_string($value) or is_null($value)) {
  247. $checksum += 1;
  248. }
  249. return ($checksum === 1);
  250. }
  251. return false;
  252. }
  253. /**
  254. * @return bool
  255. */
  256. protected function _updateUrl()
  257. {
  258. if ( ! $this->_silent) {
  259. $parts = array(
  260. "{$this->getProtocol()}:/",
  261. $this->getBaseUrl(),
  262. "v{$this->getApiVersion()}",
  263. $this->getStoreId(),
  264. );
  265. $this->_url = implode('/', $parts);
  266. }
  267. return true;
  268. }
  269. /* iProductAPI */
  270. /**
  271. * @param int|null $parent
  272. * @return string
  273. * @throws Exception
  274. */
  275. public function getCategories($parent = null)
  276. {
  277. $url = $this->getUrl();
  278. $url .= '/categories';
  279. if ( ! is_null($parent)) {
  280. if ( ! is_int($parent) or $parent < 0) {
  281. throw new Exception('_invalid_type');
  282. }
  283. $url .= "?parent={$parent}";
  284. }
  285. return $this->_fetch(array(
  286. CURLOPT_URL => $url,
  287. ));
  288. }
  289. /**
  290. * @param int $id
  291. * @return string
  292. * @throws Exception
  293. */
  294. public function getCategory($id)
  295. {
  296. if ( ! is_int($id) or $id < 1) {
  297. throw new Exception('_invalid_type');
  298. }
  299. $url = $this->getUrl();
  300. $url .= "/category?id={$id}";
  301. return $this->_fetch(array(
  302. CURLOPT_URL => $url,
  303. ));
  304. }
  305. /**
  306. * @param int|null $category
  307. * @return string
  308. * @throws Exception
  309. */
  310. public function getProducts($category = null)
  311. {
  312. $url = $this->getUrl();
  313. $url .= '/products';
  314. if ( ! is_null($category)) {
  315. if ( ! is_int($category) or $category < 0) {
  316. throw new Exception('_invalid_type');
  317. }
  318. $url .= "?category={$category}";
  319. }
  320. return $this->_fetch(array(
  321. CURLOPT_URL => $url,
  322. ));
  323. }
  324. /**
  325. * @param int $id
  326. * @return string
  327. * @throws Exception
  328. */
  329. public function getProduct($id)
  330. {
  331. if ( ! is_int($id) or $id < 1) {
  332. throw new Exception('_invalid_type');
  333. }
  334. $url = $this->getUrl();
  335. $url .= "/product?id={$id}";
  336. return $this->_fetch(array(
  337. CURLOPT_URL => $url,
  338. ));
  339. }
  340. /**
  341. * @param string $data
  342. * @return string
  343. * @throws Exception
  344. */
  345. public function putProducts($data)
  346. {
  347. if ( ! is_string($data) or empty($data)) {
  348. throw new Exception('_invalid_type');
  349. }
  350. $file = 'put.json';
  351. $url = $this->getUrl();
  352. $url .= "/products?secure_auth_key={$this->getSecureAuthKey()}";
  353. if (false === ($handle = @fopen($file, 'w+'))) {
  354. throw new Exception('_file_opening');
  355. }
  356. if (false === ($length = @fwrite($handle, $data))) {
  357. throw new Exception('_file_writing');
  358. }
  359. if (fseek($handle, 0) === -1) {
  360. throw new Exception('_file_pointing');
  361. }
  362. $result = $this->_fetch(array(
  363. CURLOPT_URL => $url,
  364. CURLOPT_PUT => 1,
  365. CURLOPT_HTTPHEADER => array(
  366. 'Content-Type: text/json',
  367. ),
  368. CURLOPT_INFILE => $handle,
  369. CURLOPT_INFILESIZE => $length,
  370. ));
  371. if ( ! fclose($handle)) {
  372. throw new Exception('_file_closing');
  373. }
  374. if ( ! @unlink($file)) {
  375. throw new Exception('_file_deleting');
  376. }
  377. return $result;
  378. }
  379. /**
  380. * @param int $id
  381. * @param string $data
  382. * @return string
  383. * @throws Exception
  384. */
  385. public function putProduct($id, $data)
  386. {
  387. if (( ! is_int($id) or $id < 1) or ( ! is_string($data) or empty($data))) {
  388. throw new Exception('_invalid_type');
  389. }
  390. $file = 'put.json';
  391. $url = $this->getUrl();
  392. $url .= '/product';
  393. $url .= "?id={$id}";
  394. $url .= "&secure_auth_key={$this->getSecureAuthKey()}";
  395. if (false === ($handle = @fopen($file, 'w+'))) {
  396. throw new Exception('_file_opening');
  397. }
  398. if (false === ($length = @fwrite($handle, $data))) {
  399. throw new Exception('_file_writing');
  400. }
  401. if (fseek($handle, 0) === -1) {
  402. throw new Exception('_file_pointing');
  403. }
  404. $result = $this->_fetch(array(
  405. CURLOPT_URL => $url,
  406. CURLOPT_PUT => 1,
  407. CURLOPT_HTTPHEADER => array(
  408. 'Content-Type: text/json',
  409. ),
  410. CURLOPT_INFILE => $handle,
  411. CURLOPT_INFILESIZE => $length,
  412. ));
  413. if ( ! fclose($handle)) {
  414. throw new Exception('_file_closing');
  415. }
  416. if ( ! @unlink($file)) {
  417. throw new Exception('_file_deleting');
  418. }
  419. return $result;
  420. }
  421. /**
  422. * @param int $count
  423. * @return string
  424. * @throws Exception
  425. */
  426. public function getRandomProducts($count)
  427. {
  428. if ( ! is_int($count) or $count < 1) {
  429. throw new Exception('_invalid_type');
  430. }
  431. $url = $this->getUrl();
  432. $url .= "/random_products?count={$count}";
  433. return $this->_fetch(array(
  434. CURLOPT_URL => $url,
  435. ));
  436. }
  437. /**
  438. * @return string
  439. * @throws Exception
  440. */
  441. public function getClasses()
  442. {
  443. $url = $this->getUrl();
  444. $url .= '/classes';
  445. return $this->_fetch(array(
  446. CURLOPT_URL => $url,
  447. ));
  448. }
  449. /**
  450. * @param int $id
  451. * @return string
  452. * @throws Exception
  453. */
  454. public function getClass($id)
  455. {
  456. if ( ! is_int($id) or $id < 0) {
  457. throw new Exception('_invalid_type');
  458. }
  459. $url = $this->getUrl();
  460. $url .= "/classes?id={$id}";
  461. return $this->_fetch(array(
  462. CURLOPT_URL => $url,
  463. ));
  464. }
  465. /**
  466. * @param string $data
  467. * @return string
  468. * @throws Exception
  469. */
  470. public function postClass($data)
  471. {
  472. if ( ! is_string($data) or empty($data)) {
  473. throw new Exception('_invalid_type');
  474. }
  475. $url = $this->getUrl();
  476. $url .= "/classes?secure_auth_key={$this->getSecureAuthKey()}";
  477. return $this->_fetch(array(
  478. CURLOPT_URL => $url,
  479. CURLOPT_POST => 1,
  480. CURLOPT_POSTFIELDS => $data,
  481. CURLOPT_HTTPHEADER => array(
  482. 'Content-Type: text/json',
  483. ),
  484. ));
  485. }
  486. /**
  487. * @param int $id
  488. * @param string $data
  489. * @return string
  490. * @throws Exception
  491. */
  492. public function putClass($id, $data)
  493. {
  494. if (( ! is_int($id) or $id < 1) or ( ! is_string($data) or empty($data))) {
  495. throw new Exception('_invalid_type');
  496. }
  497. $file = 'put.json';
  498. $url = $this->getUrl();
  499. $url .= '/classes';
  500. $url .= "?id={$id}";
  501. $url .= "&secure_auth_key={$this->getSecureAuthKey()}";
  502. if (false === ($handle = @fopen($file, 'w+'))) {
  503. throw new Exception('_file_opening');
  504. }
  505. if (false === ($length = @fwrite($handle, $data))) {
  506. throw new Exception('_file_writing');
  507. }
  508. if (fseek($handle, 0) === -1) {
  509. throw new Exception('_file_pointing');
  510. }
  511. $result = $this->_fetch(array(
  512. CURLOPT_URL => $url,
  513. CURLOPT_PUT => 1,
  514. CURLOPT_HTTPHEADER => array(
  515. 'Content-Type: text/json',
  516. ),
  517. CURLOPT_INFILE => $handle,
  518. CURLOPT_INFILESIZE => $length,
  519. ));
  520. if ( ! fclose($handle)) {
  521. throw new Exception('_file_closing');
  522. }
  523. if ( ! @unlink($file)) {
  524. throw new Exception('_file_deleting');
  525. }
  526. return $result;
  527. }
  528. /**
  529. * @param int $id
  530. * @return string
  531. * @throws Exception
  532. */
  533. public function deleteClass($id)
  534. {
  535. if ( ! is_int($id) or $id < 1) {
  536. throw new Exception('_invalid_type');
  537. }
  538. $url = $this->getUrl();
  539. $url .= '/classes';
  540. $url .= "?id={$id}";
  541. $url .= "&secure_auth_key={$this->getSecureAuthKey()}";
  542. return $this->_fetch(array(
  543. CURLOPT_URL => $url,
  544. CURLOPT_CUSTOMREQUEST => 'DELETE',
  545. ));
  546. }
  547. /**
  548. * @return string
  549. * @throws Exception
  550. */
  551. public function getProfile()
  552. {
  553. $url = $this->getUrl();
  554. $url .= '/profile';
  555. return $this->_fetch(array(
  556. CURLOPT_URL => $url,
  557. ));
  558. }
  559. /**
  560. * @param array $data
  561. * <code>
  562. * array(
  563. * %s:alias => %s:query,
  564. * ...
  565. * ),
  566. * </code>
  567. * @return string
  568. * @throws Exception
  569. */
  570. public function runBatch(array $data)
  571. {
  572. if (empty($data)) {
  573. throw new Exception('_empty_batch');
  574. }
  575. $url = $this->getUrl();
  576. $url .= '/batch?';
  577. while (current($data)) {
  578. $url .= key($data);
  579. $url .= '=';
  580. $url .= current($data);
  581. if (next($data)) {
  582. $url .= '&';
  583. }
  584. }
  585. return $this->_fetch(array(
  586. CURLOPT_URL => $url,
  587. ));
  588. }
  589. /**
  590. * @return bool
  591. */
  592. protected function _initCurl()
  593. {
  594. $this->_curl = curl_init();
  595. if ($this->_curl) {
  596. $config = array(
  597. CURLOPT_HEADER => 0,
  598. CURLOPT_RETURNTRANSFER => 1,
  599. );
  600. return curl_setopt_array($this->_curl, $config);
  601. }
  602. return false;
  603. }
  604. /**
  605. * @param array $config
  606. * @return string
  607. * @throws Exception
  608. */
  609. protected function _fetch(array $config = array())
  610. {
  611. if ( ! $this->_curl) {
  612. if ( ! $this->_initCurl()) {
  613. throw new Exception('_curl_undefined');
  614. }
  615. }
  616. if (curl_setopt_array($this->_curl, $config)) {
  617. $data = curl_exec($this->_curl);
  618. if ($data === false) {
  619. $code = curl_errno($this->_curl);
  620. $data = curl_error($this->_curl);
  621. throw new Exception($data, $code);
  622. }
  623. $code = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
  624. if ($code !== 200) {
  625. throw new Exception($data, $code);
  626. }
  627. return $data;
  628. }
  629. throw new Exception('_curl_config');
  630. }
  631. }