PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/decorators/ProductAPICaching.php

https://github.com/octolab/Ecwid
PHP | 320 lines | 190 code | 20 blank | 110 comment | 21 complexity | cf205e63ef8c03da027d966078a450d2 MD5 | raw file
  1. <?php
  2. /**
  3. * @author Samigullin Kamil <feedback@kamilsk.com>
  4. * @link http://www.kamilsk.com/
  5. */
  6. namespace Ecwid\decorators;
  7. use Ecwid\interfaces\iProductAPI,
  8. \Exception;
  9. /**
  10. * @package Ecwid.decorators
  11. * @since 1.0
  12. */
  13. class ProductAPICaching extends ProductAPIDecorator
  14. {
  15. /**
  16. * @var array
  17. */
  18. protected static $_defaultConfig = array(
  19. 'cache_path' => __DIR__,
  20. 'lifetime' => 7200,
  21. 'enabled' => true,
  22. );
  23. /**
  24. * Constructor.
  25. *
  26. * @param iProductAPI $product_api
  27. * @param array $config
  28. * <code>
  29. * array(
  30. * 'cache_path' => %s:path,
  31. * 'lifetime' => %i:seconds,
  32. * 'enabled' => %bool,
  33. * )
  34. * </code>
  35. * @throws Exception
  36. */
  37. public function __construct(iProductAPI $product_api, array $config = array())
  38. {
  39. if ($this->_initConfig(array_merge(self::$_defaultConfig, $config))) {
  40. parent::__construct($product_api);
  41. } else {
  42. throw new Exception('_init');
  43. }
  44. }
  45. /**
  46. * @return string
  47. */
  48. public function getCachePath()
  49. {
  50. return $this->_config['cache_path'];
  51. }
  52. /**
  53. * @param string $path
  54. * @return self
  55. * @throws Exception
  56. */
  57. public function setCachePath($path)
  58. {
  59. if ( ! is_string($path)) {
  60. throw new Exception('_invalid_type');
  61. }
  62. if (false === ($path = realpath($path)) or ! is_writable($path)) {
  63. throw new Exception('_invalid_path');
  64. }
  65. $this->_config['cache_path'] = $path;
  66. return $this;
  67. }
  68. /**
  69. * @return int
  70. */
  71. public function getLifetime()
  72. {
  73. return $this->_config['lifetime'];
  74. }
  75. /**
  76. * @param int $time
  77. * @return self
  78. * @throws Exception
  79. */
  80. public function setLifetime($time)
  81. {
  82. if ( ! is_int($time) or $time < 0) {
  83. throw new Exception('_invalid_type');
  84. }
  85. $this->_config['lifetime'] = $time;
  86. return $this;
  87. }
  88. /**
  89. * @return bool
  90. */
  91. public function isEnabled()
  92. {
  93. return $this->_config['enabled'];
  94. }
  95. /**
  96. * @param bool $condition
  97. * @return void
  98. * @throws Exception
  99. */
  100. protected function _setCondition($condition)
  101. {
  102. if ( ! is_bool($condition)) {
  103. throw new Exception('_invalid_type');
  104. }
  105. $this->_config['enabled'] = $condition;
  106. }
  107. /**
  108. * @param array $config
  109. * @return bool
  110. * @throws Exception
  111. */
  112. protected function _initConfig(array $config)
  113. {
  114. $map = array(
  115. 'cache_path' => 'setCachePath',
  116. 'lifetime' => 'setLifetime',
  117. 'enabled' => '_setCondition',
  118. );
  119. $this->_silent = true;
  120. foreach ($config as $key => $value) {
  121. if (array_key_exists($key, $map)) {
  122. $set = $map[$key];
  123. $this->$set($value);
  124. }
  125. }
  126. $this->_silent = false;
  127. return true;
  128. }
  129. /* iProductAPI */
  130. /**
  131. * @param int|null $parent
  132. * @return mixed
  133. * @throws Exception
  134. */
  135. public function getCategories($parent = null)
  136. {
  137. $response = $this->_fetch(__FUNCTION__, func_get_args());
  138. if ($response === false) {
  139. $response = $this->_product_api->getCategories($parent);
  140. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  141. }
  142. return $response;
  143. }
  144. /**
  145. * @param int $id
  146. * @return mixed
  147. * $throws Exception
  148. */
  149. public function getCategory($id)
  150. {
  151. $response = $this->_fetch(__FUNCTION__, func_get_args());
  152. if ($response === false) {
  153. $response = $this->_product_api->getCategory($id);
  154. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  155. }
  156. return $response;
  157. }
  158. /**
  159. * @param int|null $category
  160. * @return mixed
  161. * @throws Exception
  162. */
  163. public function getProducts($category = null)
  164. {
  165. $response = $this->_fetch(__FUNCTION__, func_get_args());
  166. if ($response === false) {
  167. $response = $this->_product_api->getProducts($category);
  168. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  169. }
  170. return $response;
  171. }
  172. /**
  173. * @param int $id
  174. * @return mixed
  175. * @throws Exception
  176. */
  177. public function getProduct($id)
  178. {
  179. $response = $this->_fetch(__FUNCTION__, func_get_args());
  180. if ($response === false) {
  181. $response = $this->_product_api->getProduct($id);
  182. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  183. }
  184. return $response;
  185. }
  186. /**
  187. * @param int $count
  188. * @return mixed
  189. * @throws Exception
  190. */
  191. public function getRandomProducts($count)
  192. {
  193. $response = $this->_fetch(__FUNCTION__, func_get_args());
  194. if ($response === false) {
  195. $response = $this->_product_api->getRandomProducts($count);
  196. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  197. }
  198. return $response;
  199. }
  200. /**
  201. * @return mixed
  202. * @throws Exception
  203. */
  204. public function getClasses()
  205. {
  206. $response = $this->_fetch(__FUNCTION__, func_get_args());
  207. if ($response === false) {
  208. $response = $this->_product_api->getClasses();
  209. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  210. }
  211. return $response;
  212. }
  213. /**
  214. * @param int $id
  215. * @return mixed
  216. * @throws Exception
  217. */
  218. public function getClass($id)
  219. {
  220. $response = $this->_fetch(__FUNCTION__, func_get_args());
  221. if ($response === false) {
  222. $response = $this->_product_api->getClass($id);
  223. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  224. }
  225. return $response;
  226. }
  227. /**
  228. * @return mixed
  229. * @throws Exception
  230. */
  231. public function getProfile()
  232. {
  233. $response = $this->_fetch(__FUNCTION__, func_get_args());
  234. if ($response === false) {
  235. $response = $this->_product_api->getProfile();
  236. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  237. }
  238. return $response;
  239. }
  240. /**
  241. * @param array $data
  242. * @return mixed
  243. * @throws Exception
  244. */
  245. public function runBatch(array $data)
  246. {
  247. $response = $this->_fetch(__FUNCTION__, func_get_args());
  248. if ($response === false) {
  249. $response = $this->_product_api->runBatch($data);
  250. return $this->_cache(__FUNCTION__, func_get_args(), $response);
  251. }
  252. return $response;
  253. }
  254. /**
  255. * @param string $method
  256. * @param array $params
  257. * @return bool|mixed
  258. */
  259. protected function _fetch($method, array $params)
  260. {
  261. $folder = "{$this->getCachePath()}/{$method}";
  262. $filename = md5(serialize($params));
  263. $file = "{$folder}/{$filename}";
  264. $timestamp = time();
  265. if (false !== ($cache = @file_get_contents($file))) {
  266. $cache = unserialize($cache);
  267. if ($cache['created'] !== $cache['expired'] && $cache['expired'] < $timestamp) {
  268. return false;
  269. }
  270. return $cache['data'];
  271. }
  272. return false;
  273. }
  274. /**
  275. * @param string $method
  276. * @param array $params
  277. * @param mixed $data
  278. * @return mixed
  279. * @throws Exception
  280. */
  281. protected function _cache($method, array $params, $data)
  282. {
  283. $folder = "{$this->getCachePath()}/{$method}";
  284. $filename = md5(serialize($params));
  285. $file = "{$folder}/{$filename}";
  286. $timestamp = time();
  287. if ( ! file_exists($folder)) {
  288. mkdir($folder);
  289. }
  290. $cache = array(
  291. 'created' => $timestamp,
  292. 'expired' => $timestamp + $this->getLifetime(),
  293. 'data' => $data,
  294. );
  295. if (false !== @file_put_contents($file, serialize($cache))) {
  296. return $data;
  297. }
  298. throw new Exception('_cache');
  299. }
  300. }