/library/core.php

https://github.com/cookcrowd/Backend · PHP · 422 lines · 220 code · 69 blank · 133 comment · 15 complexity · e6157a006a926ea612da7d4007ab02a9 MD5 · raw file

  1. <?php
  2. namespace Zurv;
  3. /**
  4. * Basic registry.
  5. *
  6. * @author mau
  7. *
  8. */
  9. class Registry {
  10. private static $_instance = null;
  11. private $_data = array();
  12. /**
  13. * Singleton.
  14. */
  15. private final function __construct() {}
  16. private final function __clone() {}
  17. public static function getInstance() {
  18. if(self::$_instance === null) {
  19. self::$_instance = new self();
  20. }
  21. return self::$_instance;
  22. }
  23. /**
  24. * Magically get class properties
  25. *
  26. * @param mixed $key
  27. */
  28. public function __get($key) {
  29. if(isset($this->_data[$key])) {
  30. return $this->_data[$key];
  31. }
  32. return null;
  33. }
  34. /**
  35. * Magically set class properties
  36. *
  37. * @param string $key
  38. * @param mixed $value
  39. */
  40. public function __set($key, $value) {
  41. $this->_data[$key] = $value;
  42. }
  43. }
  44. /**
  45. * Base model entities and base mappers.
  46. *
  47. * @author mau
  48. */
  49. namespace Zurv\Model;
  50. interface Entity {
  51. /**
  52. * Check, if an entity has a property
  53. *
  54. * @param string $key
  55. * @return bool
  56. */
  57. function has($key);
  58. /**
  59. * Convert the entity object to an associative array
  60. *
  61. * @return array
  62. */
  63. function toArray();
  64. }
  65. /**
  66. * Mapper interface
  67. */
  68. interface Mapper {
  69. /**
  70. * Find entity by id
  71. * @param mixed $id
  72. */
  73. function findById($id);
  74. /**
  75. * Find entity by attribute
  76. *
  77. * @param string $attribute
  78. * @param mixed $value
  79. */
  80. function findByAttribute($attribute, $value);
  81. }
  82. namespace Zurv\Model\Mapper;
  83. /**
  84. * Base mapper
  85. *
  86. * @author mau
  87. */
  88. abstract class Base implements \Zurv\Model\Mapper {
  89. public function findById($id) {
  90. throw new Exception('To be implemented');
  91. }
  92. public function findByAttribute($attribute, $value) {
  93. throw new Exception('To be implemented');
  94. }
  95. }
  96. namespace Zurv\Model\Entity;
  97. abstract class Base implements \Zurv\Model\Entity, \ArrayAccess {
  98. protected $_attributes = array();
  99. /**
  100. * Constructor.
  101. * @param array $seed Optionally set the seed values
  102. */
  103. public function __construct($seed = array()) {
  104. if(! empty($seed)) {
  105. $this->_setAttributes($seed);
  106. }
  107. }
  108. /**
  109. * Convenience method for setting multiple attributes the same time
  110. * @param array $attributes
  111. */
  112. protected function _setAttributes($attributes) {
  113. foreach($attributes as $key => $value) {
  114. $this->{'set' . ucfirst($key)}($value);
  115. }
  116. }
  117. /**
  118. * Returns the entity data as array
  119. *
  120. * @return array
  121. */
  122. public function toArray() {
  123. return $this->_attributes;
  124. }
  125. /**
  126. * Checks, if two entities are equal by values
  127. *
  128. * @param Entity $e
  129. */
  130. public function equals(\Zurv\Model\Entity $e) {
  131. foreach($e->toArray() as $key => $value) {
  132. if(! $this->has($key)) {
  133. return false;
  134. }
  135. if($this[$key] !== $value) {
  136. return false;
  137. }
  138. }
  139. return true;
  140. }
  141. protected function _toArray($array) {
  142. $return = array();
  143. foreach($array as $key => $value) {
  144. if(is_object($value) && method_exists($value, "toArray")) {
  145. $value = $value->toArray();
  146. }
  147. $return[$key] = $value;
  148. }
  149. return $return;
  150. }
  151. /**
  152. * Magig getters and setters.
  153. * @param string $method
  154. * @param array $params
  155. * @throws \BadMethodCallException
  156. */
  157. public function __call($method, $params) {
  158. $do = strtolower(substr($method, 0, 3));
  159. $var = substr($method, 3);
  160. $var = $this->_getKey($var);
  161. switch($do) {
  162. case 'get':
  163. return $this->_getAttribute($var);
  164. break;
  165. case 'set':
  166. if(empty($params)) {
  167. throw new \BadMethodCallException('Missing parameter to set');
  168. }
  169. $this->_setAttribute($var, array_pop($params));
  170. break;
  171. case 'is':
  172. return $this->_getAttribute($var) ? true : false;
  173. break;
  174. default:
  175. throw new \BadMethodCallException("Could not invoke method {$method}");
  176. break;
  177. }
  178. }
  179. /**
  180. * Check for a given attribute.
  181. * @param string $key
  182. */
  183. public function has($key) {
  184. return array_key_exists($key, $this->_attributes);
  185. }
  186. /**
  187. * Get class attribute.
  188. * @param string $key
  189. * @throws \BadMethodCallException
  190. */
  191. protected function _getAttribute($key) {
  192. if(! $this->has($key)) {
  193. throw new \BadMethodCallException('Class' . __CLASS__ . ' has no attribute ' . $key);
  194. }
  195. return $this->_attributes[$key];
  196. }
  197. /**
  198. * Set class attribute.
  199. * @param string $key
  200. * @param mixed $param
  201. * @throws \BadMethodCallException
  202. */
  203. protected function _setAttribute($key, $param) {
  204. if(! $this->has($key)) {
  205. throw new \BadMethodCallException('Class' . __CLASS__ . ' has no attribute ' . $key);
  206. }
  207. $this->_attributes[$key] = $param;
  208. }
  209. /**
  210. * Convert a camel cased key to a underscored one. E.g. testKey converts to test_key
  211. *
  212. * @param string $key
  213. * @return string
  214. */
  215. protected function _getKey($key) {
  216. return strtolower(substr(preg_replace('/([A-Z])/', '_\1', $key), 1));
  217. }
  218. public function offsetExists($key) {
  219. return isset($this->_attributes[$key]);
  220. }
  221. public function offsetGet($key) {
  222. return $this->_attributes[$key];
  223. }
  224. public function offsetSet ($key, $value) {
  225. if(array_key_exists($key, $this->_attributes)) {
  226. $this->_attributes[$key] = $value;
  227. }
  228. else {
  229. throw new OutOfBoundsException("Invalid access to attribute {$key}");
  230. }
  231. }
  232. public function offsetUnset ($key) {
  233. $this->_attributes[$key] = null;
  234. }
  235. }
  236. /**
  237. * Basic view.
  238. */
  239. namespace Zurv\View;
  240. interface Adapter {
  241. /**
  242. * Render the view
  243. *
  244. * @param array $vars
  245. */
  246. function render(array $vars);
  247. }
  248. /**
  249. * Class for handling views
  250. *
  251. * @author mau
  252. */
  253. class View {
  254. /**
  255. * @var array
  256. */
  257. protected $_vars = array();
  258. /**
  259. * @var ViewAdapter
  260. */
  261. protected $_viewAdapter = null;
  262. public function __construct(Adapter $adapter = null) {
  263. $this->_viewAdapter = $adapter;
  264. }
  265. public function __get($key) {
  266. if(! array_key_exists($key, $this->_vars)) {
  267. return null;
  268. }
  269. return $this->_vars[$key];
  270. }
  271. public function __set($key, $value) {
  272. $this->_vars[$key] = $value;
  273. }
  274. public function render($vars = array()) {
  275. $vars = array_merge($this->_vars, $vars);
  276. $render = $this->_viewAdapter->render($vars);
  277. return $render;
  278. }
  279. public function display(array $vars = array()) {
  280. echo $this->render($vars);
  281. }
  282. public function getAdapter() {
  283. return $this->_viewAdapter;
  284. }
  285. public function setAdapter(\Zurv\View\Adapter $adapter) {
  286. $this->_viewAdapter = $adapter;
  287. }
  288. public function __toString() {
  289. return $this->render();
  290. }
  291. }
  292. namespace Zurv\View\Adapter;
  293. /**
  294. * ViewAdapter for file templates
  295. *
  296. * @author mau
  297. */
  298. class FileView implements \Zurv\View\Adapter {
  299. protected $_template = '';
  300. public function __construct($file) {
  301. if(! file_exists($file)) {
  302. throw new \InvalidArgumentException("Could not load view {$file}");
  303. }
  304. $this->_template = $file;
  305. }
  306. public function render(array $vars) {
  307. header('Content-Type: text/html; charset="utf8"');
  308. ob_start();
  309. extract($vars);
  310. include $this->_template;
  311. $render = ob_get_contents();
  312. ob_end_clean();
  313. return $render;
  314. }
  315. }
  316. /**
  317. * ViewAdapter for json encoded requests
  318. *
  319. * @author mau
  320. */
  321. class JSONView implements \Zurv\View\Adapter {
  322. public function render(array $vars) {
  323. header('Content-Type: application/json; charset="utf8"');
  324. return json_encode($vars);
  325. }
  326. }
  327. /**
  328. * Factory for creating ViewAdapters
  329. *
  330. * @author mau
  331. */
  332. class Factory {
  333. const FILE = 'file';
  334. const JSON = 'json';
  335. public static function create() {
  336. $args = func_get_args();
  337. $adapter = null;
  338. $type = array_shift($args);
  339. switch($type) {
  340. case self::FILE:
  341. $adapter = new \ReflectionClass('\Zurv\View\Adapter\FileView');
  342. $adapter = $adapter->newInstanceArgs($args);
  343. break;
  344. case self::JSON:
  345. $adapter = new JSONView();
  346. break;
  347. default:
  348. throw new \InvalidArgumentException("Could not load ViewAdapter for type {$type}");
  349. break;
  350. }
  351. return $adapter;
  352. }
  353. }