PageRenderTime 40ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Release/Last/Framework/Lib/model/base/BaseNotStorageEntityModel.php

https://github.com/sergiygladkyy/OEF
PHP | 401 lines | 227 code | 81 blank | 93 comment | 48 complexity | a35e9f7cf052e5f21201e3d4c0361019 MD5 | raw file
  1. <?php
  2. require_once('lib/model/base/BaseModel.php');
  3. abstract class BaseNotStorageEntityModel extends BaseModel
  4. {
  5. /* This entity params */
  6. protected $attributes = null;
  7. protected $isModified = false;
  8. protected $modified = array();
  9. protected $container = null;
  10. public function __construct($kind, $type, array& $options = array())
  11. {
  12. $this->container = Container::getInstance();
  13. $this->initialize($kind, $type);
  14. }
  15. /**
  16. * Initialize entity object (retrieve configuration)
  17. *
  18. * @param string $type - entity name
  19. * @return boolean
  20. */
  21. protected function initialize($kind, $type)
  22. {
  23. // Setup configuration
  24. if (!parent::initialize($kind, $type)) return false;
  25. $this->attributes = null;
  26. $this->isModified = false;
  27. $this->modified = array();
  28. return true;
  29. }
  30. /**
  31. *
  32. * @param string $name - attribute name
  33. * @return boolean
  34. */
  35. public function hasAttribute($name)
  36. {
  37. return in_array($name, $this->conf['attributes']);
  38. }
  39. /**
  40. * Set attribute value
  41. *
  42. * @throws Exception
  43. * @param string $name - attribute name
  44. * @param mixed $value
  45. * @return boolean
  46. */
  47. public function setAttribute($name, $value)
  48. {
  49. if (!$this->hasAttribute($name))
  50. {
  51. throw new Exception(__METHOD__.': Attribute "'.$name.'" not exists.');
  52. }
  53. if (!$this->checkAttributeValueType($name, $value)) return false;
  54. if (isset($this->attributes[$name]) && $this->attributes[$name] == $value) return true;
  55. $this->isModified = true;
  56. $this->modified[$name] = true;
  57. $this->attributes[$name] = $value;
  58. return true;
  59. }
  60. /**
  61. * Get attribute value
  62. *
  63. * @throws Exception
  64. * @param string $name - attribute name
  65. * @return mixed
  66. */
  67. public function getAttribute($name)
  68. {
  69. if (!$this->hasAttribute($name))
  70. {
  71. throw new Exception(__METHOD__.': Attribute "'.$name.'" not exists.');
  72. }
  73. // Not set
  74. if (!isset($this->attributes[$name])) return null;
  75. // Link (return object)
  76. if ($this->conf['types'][$name] == 'reference')
  77. {
  78. if ($this->attributes[$name] <= 0) return null; // Empty link
  79. $ref =& $this->conf['references'][$name];
  80. $model = $this->container->getModel($ref['kind'], $ref['type']);
  81. return ($model->load($this->attributes[$name]) ? $model : null);
  82. }
  83. // Simple attribute
  84. return $this->attributes[$name];
  85. }
  86. /**
  87. * Check value type
  88. *
  89. * @param string $name - attribute name
  90. * @param mixed& $value
  91. * @return boolean
  92. */
  93. protected function checkAttributeValueType($name, & $value)
  94. {
  95. $type = strtolower($this->conf['types'][$name]);
  96. switch($type)
  97. {
  98. case 'bool':
  99. $value = $value ? 1 : 0;
  100. break;
  101. case 'int':
  102. case 'timestamp':
  103. $val = (int) $value;
  104. if ($value != (string) $val) return false;
  105. $value = $val;
  106. break;
  107. case 'float':
  108. $val = (float) $value;
  109. if ($value != (string) $val) return false;
  110. $value = $val;
  111. break;
  112. // Types having string value
  113. case 'string':
  114. case 'password':
  115. case 'text':
  116. case 'date':
  117. case 'datetime':
  118. case 'time':
  119. case 'year':
  120. case 'file':
  121. $value = (string) $value;
  122. break;
  123. // Enumeration (int number >= 0 or string)
  124. case 'enum':
  125. $val = (int) $value;
  126. if ($value != (string) $val)
  127. {
  128. $value = (string) $value;
  129. }
  130. elseif ($val >= 0)
  131. {
  132. $value = $val;
  133. }
  134. else return false;
  135. break;
  136. // Link (object or int >= 0)
  137. case 'reference':
  138. if (!is_object($value))
  139. {
  140. $val = (int) $value;
  141. if ($value != (string) $val || $val < 0) return false;
  142. $value = $val;
  143. }
  144. break;
  145. default:
  146. throw new Exception(__METHOD__.': Not supported internal type "'.$type.'"');
  147. }
  148. return true;
  149. }
  150. /**
  151. * Check value precision for attribute $name
  152. *
  153. * @param mixed $names - array or string
  154. * @param array& $options
  155. * @return array - errors
  156. */
  157. protected function checkAttributesPrecision($names, array& $options = array())
  158. {
  159. if (!is_array($names)) $names = array($names);
  160. $result = array();
  161. $validator = $this->container->getValidator($options);
  162. foreach ($names as $attr)
  163. {
  164. // Validation
  165. if (empty($this->conf['precision'][$attr])) continue;
  166. foreach ($this->conf['precision'][$attr] as $prec => $params)
  167. {
  168. $errors = $validator->$prec($this->conf['types'][$attr], $this->attributes[$attr], $params);
  169. if (!empty($errors)) $result[$attr] = $errors;
  170. }
  171. }
  172. return $result;
  173. }
  174. /**
  175. * Check references
  176. *
  177. * @param mixed $names - array or string
  178. * @return array - errors
  179. */
  180. protected function checkReferences($names)
  181. {
  182. if (!is_array($names)) $names = array($names);
  183. $errors = array();
  184. foreach ($names as $attr)
  185. {
  186. // Validation
  187. if (empty($this->conf['references'][$attr]))
  188. {
  189. throw new Exception(__METHOD__.': attribute "'.$attr.'" ('.$this->type.') is not reference');
  190. }
  191. $ref =& $this->conf['references'][$attr];
  192. $val =& $this->attributes[$attr];
  193. // Can related ?
  194. if (is_object($val))
  195. {
  196. if (!is_a($val, 'BaseEntityModel'))
  197. {
  198. throw new Exception(__METHOD__.': not supported model class "'.get_class($val).'"');
  199. }
  200. if ($ref['kind'] != $val->getKind()) $err[] = '"'.$this->type.'" can\'t related with '.$val->getKind();
  201. if ($ref['type'] != $val->getType()) $err[] = '"'.$this->type.'" can\'t related with "'.$val->getType().'"';
  202. if (!empty($err))
  203. {
  204. $errors[$attr] = $err;
  205. continue;
  206. }
  207. $val = $val->getId();
  208. }
  209. // Has entity ?
  210. if ($val != 0 && !self::hasEntity($ref['kind'], $ref['type'], $val))
  211. {
  212. $errors[$attr] = '"'.ucfirst($ref['kind']).'.'.$ref['type'].'" with id "'.$val.'" is not exists';
  213. }
  214. }
  215. return $errors;
  216. }
  217. /**
  218. * Check required attributes
  219. *
  220. * @return array - errors
  221. */
  222. protected function checkRequired()
  223. {
  224. $errors = array();
  225. foreach ($this->conf['required'] as $attribute)
  226. {
  227. if (empty($this->attributes[$attribute]))
  228. {
  229. $errors[$attribute] = "Required";
  230. }
  231. }
  232. return $errors;
  233. }
  234. /**
  235. * Validate attribbutes
  236. *
  237. * @param mixed $names - array or string
  238. * @param array& $options
  239. * @return array - errors
  240. */
  241. protected function validateAttributes($names, array& $options = array())
  242. {
  243. $errors = array();
  244. $not_valid = array();
  245. /* Standard validation */
  246. // Check required
  247. $errors = $this->checkRequired();
  248. if (!empty($errors)) $not_valid = array_keys($errors);
  249. // Validation all fields
  250. $err = $this->checkAttributesPrecision(array_diff($names, $not_valid), $options);
  251. if (!empty($err))
  252. {
  253. $errors = array_merge($errors, $err);
  254. $not_valid = array_keys($errors);
  255. }
  256. // Validation references
  257. $references = array_intersect(array_diff($names, $not_valid), array_keys($this->conf['references']));
  258. $err = $this->checkReferences($references);
  259. if (!empty($err)) $errors = array_merge($errors, $err);
  260. if (!empty($errors)) return $errors;
  261. /* onAfterValidation */
  262. $event = $this->container->getEvent($this, $this->kind.'.'.$this->type.'.onBeforeAddingRecord');
  263. $event->setReturnValue(array());
  264. $this->container->getEventDispatcher()->notify($event);
  265. $errors = $event->getReturnValue();
  266. if (!empty($errors)) $errors = is_array($errors) ? $errors : array($errors);
  267. return $errors;
  268. }
  269. /**
  270. * Set entity params from array
  271. *
  272. * @param array $values
  273. * @param array $options
  274. * @return array - errors
  275. */
  276. public function fromArray(array $values, array $options = array())
  277. {
  278. $errors = array();
  279. // set attributes
  280. foreach ($this->conf['attributes'] as $name)
  281. {
  282. if (isset($values[$name]))
  283. {
  284. if (!$this->setAttribute($name, $values[$name]))
  285. {
  286. $errors[$name] = 'Invalid value type';
  287. }
  288. }
  289. }
  290. return $errors;
  291. }
  292. /**
  293. * Get entity params as array
  294. * [
  295. * options = array(
  296. * with_link_desc => [ true | false ]
  297. * )
  298. * ]
  299. * @param array& $options
  300. * @return array or null
  301. */
  302. public function toArray(array $options = array())
  303. {
  304. $result = $this->attributes;
  305. if (!empty($options['with_link_desc']))
  306. {
  307. foreach ($this->conf['references'] as $field => $param)
  308. {
  309. $cmodel = $this->container->getCModel($param['kind'], $param['type'], $options);
  310. if (!empty($result[$field]))
  311. {
  312. $data = $cmodel->retrieveLinkData($result[$field]);
  313. $result[$field] = $data[$result[$field]];
  314. }
  315. else $result[$field] = array();
  316. }
  317. }
  318. return $result;
  319. }
  320. }