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

/WebProjectHelper/lib/class/uml/object.php

http://webprojecthelper.googlecode.com/
PHP | 508 lines | 238 code | 65 blank | 205 comment | 72 complexity | 5e2febdb32ea8ac8f9d1e8e3c70f899c MD5 | raw file
Possible License(s): CC-BY-3.0
  1. <?php
  2. /**
  3. * Object
  4. */
  5. class Object extends Element {
  6. /** @var $parent Object parent */
  7. private $parent = null;
  8. /** @var $children array children */
  9. private $children = array();
  10. /** @var $attributes array attributes */
  11. private $attributes = array();
  12. /** @var $options string options */
  13. private $options = null;
  14. /** @var $isAbstract bool object is abstract ? */
  15. private $isAbstract = false;
  16. /** @var $listOf Object contained object */
  17. private $listOf = null;
  18. // Options
  19. const OPT_COUNT = 'c'; // Add count method
  20. const OPT_SERIALIZE = 'z'; // Add serialize and unserialize methods
  21. const OPT_TO_XML = 'x'; // TODO Add toXml method
  22. const OPT_TO_STRING = 's'; // Add toString method
  23. const OPT_EQUALS = 'e'; // Add equals method
  24. const OPT_PAGINATE = 'p'; // TODO Add paginate method
  25. const OPT_DATABASE = 'd'; // Don't rename object's name in database
  26. /**
  27. * Constructor
  28. * @param $name string name
  29. * @param $description string description
  30. * @param $options string options
  31. * @throws Exception when name is not valid
  32. */
  33. public function __construct($name,$description=null,$options=null) {
  34. // Check if name is valid
  35. if (!PHP::valid_name($name)) { throw new Exception('The name <b>'.$name.'</b> for an object is not permitted'); }
  36. // Call parent constructor
  37. parent::__construct($name,$description);
  38. // Save attributes
  39. $this->options = $options;
  40. }
  41. // Adders
  42. /**
  43. * Add an element
  44. * @param $element Element element
  45. * @param $multiplicity ? multiplicity
  46. * @param $isId bool is identifier ?
  47. * @param $association Association association
  48. * @param $isListOf bool is owned as a list content ?
  49. * @param $options string options
  50. * @param $isExplicit bool is defined by user ?
  51. */
  52. public function addElem(Element $element,$multiplicity=Attribute::M_OPT,$isId=false,$association=null,$isListOf=false,$options=null,$isExplicit=true) {
  53. // Add elemen as an attribute
  54. $this->addAttr(new Attribute($element,$multiplicity,$isId,$association,$options,$isExplicit),$isListOf);
  55. }
  56. /**
  57. * Add an attribute
  58. * @param $attribute Attribute attribute
  59. * @param $isListOf bool is owned as a list content ?
  60. * @throws Exception when attribute is not valid
  61. */
  62. public function addAttr(Attribute $attribute,$isListOf=false) {
  63. // Set attribute owner
  64. $attribute->setOwner($this);
  65. // Check if parent is set and attribute is an identifier
  66. if ($this->parent != null && $attribute->isId()) {
  67. throw new Exception('The object <b>'.$this->getName().'</b> inherite an object and owns an id');
  68. }
  69. // Check if scalar is an identifier and type of time
  70. if ($attribute->isId() && $attribute->getElem() instanceof Scalar && in_array($attribute->getElem()->getType(),array(Scalar::T_DATE,Scalar::T_DATETIME,Scalar::T_TIME))) {
  71. throw new Exception('The object <b>'.$this->getName().'</b> owns a time scalar as an id, sorry but it\'s not supported');
  72. }
  73. // Checks on association if object already own element
  74. if ($this->has($attribute->getElem())) {
  75. // Check if association is given
  76. if ($attribute->getAssoc() == null) {
  77. throw new Exception('The object <b>'.$this->getName().'</b> owns the same object <b>'.$attribute->getElem()->getName().'</b> several times without association');
  78. } else {
  79. $matches = $this->getAttrsMatch($attribute->getElem());
  80. foreach ($matches as $match) {
  81. // Check if association is given
  82. if ($match->getAssoc() == null) {
  83. throw new Exception('The object <b>'.$this->getName().'</b> owns the same object <b>'.$attribute->getElem()->getName().'</b> several times without association');
  84. }
  85. // Check if associations are equals
  86. if ($match->getAssoc()->getName() == $attribute->getAssoc()->getName()) {
  87. throw new Exception('The object <b>'.$this->getName().'</b> owns the same object <b>'.$attribute->getElem()->getName().'</b> several times with the same association');
  88. }
  89. // Check if correspondance is given
  90. if (!$this->equals($attribute->getElem()) && !$match->getAssoc()->isCorrespondenceGiven()) {
  91. throw new Exception('The object <b>'.$this->getName().'</b> owns the same object <b>'.$attribute->getElem()->getName().'</b> several times without correspondence association');
  92. }
  93. }
  94. // Check if correspondance is given
  95. if (!$this->equals($attribute->getElem()) && !$attribute->getAssoc()->isCorrespondenceGiven()) {
  96. throw new Exception('The object <b>'.$this->getName().'</b> owns the same object <b>'.$attribute->getElem()->getName().'</b> several times without correspondence association');
  97. }
  98. }
  99. }
  100. // Check if association is given when family already own element
  101. if ($this->hasFamily($attribute->getElem()) && $attribute->getAssoc() == null) {
  102. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> already owned by family without association');
  103. }
  104. // Check names conflicts
  105. if ($attribute->getAssoc() == null) {
  106. if ($this->has_S($attribute->getElem()->getName())) {
  107. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> and it causes a name conflict');
  108. }
  109. if ($this->hasFamily_S($attribute->getElem()->getName())) {
  110. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> and it causes a name conflict in family');
  111. }
  112. } else {
  113. if ($this->has_S($attribute->getAssoc()->getName())) {
  114. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> with the association <b>'.$attribute->getAssoc()->getName().'</b> and it causes a name conflict');
  115. }
  116. if ($this->hasFamily_S($attribute->getAssoc()->getName())) {
  117. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> with the association <b>'.$attribute->getAssoc()->getName().'</b> and it causes a name conflict in family');
  118. }
  119. if (in_array($attribute->getAssoc()->getName(),array('fk','ext','id'))) {
  120. throw new Exception('The object <b>'.$this->getName().'</b> owns the object <b>'.$attribute->getElem()->getName().'</b> with an association named as a reserved word <b>'.$attribute->getAssoc()->getName().'</b>');
  121. }
  122. }
  123. // Add attribute
  124. $this->attributes[] = $attribute;
  125. // List of ?
  126. if ($isListOf) {
  127. // Check if a list content is not already set
  128. if($this->listOf != null) {
  129. throw new Exception('The object <b>'.$this->getName().'</b> cannot be a list of two objects, <b>'.$this->listOf->getElem()->getName().'</b> and <b>'.$attribute->getElem()->getName().'</b>, at the same time');
  130. }
  131. // Set attribute owned as a list content
  132. $this->listOf = $attribute;
  133. }
  134. // Check identifier and one multiplicity loops
  135. if ($attribute->getElem() instanceof Object) {
  136. if ($attribute->isId()) { $this->checkId($this); }
  137. if ($attribute->getMult() == Attribute::M_ONE) { $this->checkOne($this); }
  138. }
  139. }
  140. // Setters
  141. /**
  142. * Set object's parent
  143. * @param $parent Object parent
  144. * @throws Exception when errors occur
  145. */
  146. public function setParent(Object $parent) {
  147. /**
  148. * Check if object inherites not itself
  149. */
  150. if ($this->equals($parent)) {
  151. throw new Exception('The object <b>'.$this->getName().'</b> inherites itself, this may be problematic ...');
  152. }
  153. /**
  154. * Check if there no family loop
  155. */
  156. if ($this->isInFamily($parent)) {
  157. throw new Exception('The object <b>'.$this->getName().'</b> inherites the object <b>'.$parent->getName().'</b> already in family, this may be problematic ...');
  158. }
  159. /**
  160. * Check if object has not identifiers
  161. */
  162. if ($this->getAttrsIds()) {
  163. throw new Exception('The object <b>'.$this->getName().'</b> inherites an object and owns an id');
  164. }
  165. // Save parent
  166. $this->parent = $parent;
  167. // Add object to parent's children
  168. $parent->children[] = $this;
  169. // Set abstract
  170. $parent->setAbstract();
  171. }
  172. /**
  173. * Set object abstract
  174. * @param $isAbstract bool object abstract ?
  175. */
  176. public function setAbstract($isAbstract=true) {
  177. $this->isAbstract = $isAbstract;
  178. }
  179. // Checkers
  180. /**
  181. * Check identifier loop
  182. * @param $object Object initial object
  183. * @param $path array path
  184. * @throws Exception when an identifier loop is detected
  185. */
  186. private function checkId(Object $object,$path=array()) {
  187. foreach ($this->getAncestor()->getAttrsIds() as $attr) {
  188. if ($attr->getElem() instanceof Object) {
  189. $merge = array_merge($path,array($attr->getElem()->getName()));
  190. if ($object->equals($attr->getElem())) { throw new Exception('There is an id loop <b>'.implode('-',$merge).'</b>, this may be problematic ...'); }
  191. $attr->getElem()->checkId($object,$merge);
  192. }
  193. }
  194. }
  195. /**
  196. * Check one multiplicity loop
  197. * @param $object Object initial object
  198. * @param $path array path
  199. * @throws Exception when an one multiplicity loop is detected
  200. */
  201. private function checkOne(Object $object,$path=array()) {
  202. foreach ($this->getFamily(true) as $member) {
  203. foreach ($member->getAttrsMult(Attribute::M_ONE) as $attr) {
  204. if ($attr->getElem() instanceof Object) {
  205. $merge = array_merge($path,array($attr->getElem()->getName()));
  206. if (in_array_equals($attr->getElem(),$object->getFamily(true))) { throw new Exception('There is an "one multiplicity" loop <b>'.implode('-',$merge).'</b>, there is no possibility to create an object in this way ...'); }
  207. $attr->getElem()->checkOne($object,$merge);
  208. }
  209. }
  210. }
  211. }
  212. // Getters
  213. /**
  214. * Check if object is abstract
  215. * @return bool object is abstract ?
  216. */
  217. public function isAbstract() {
  218. return $this->isAbstract;
  219. }
  220. /**
  221. * Get content list
  222. * @return Object content list
  223. */
  224. public function getListOf() {
  225. return $this->listOf;
  226. }
  227. // Attributes
  228. /**
  229. * Get attributes list
  230. * @return array attributes list
  231. */
  232. public function getAttrs() {
  233. return $this->attributes;
  234. }
  235. /**
  236. * Get attributes list by multiplicity
  237. * @param $mult ? multiplicity
  238. * @return array attributes list
  239. */
  240. public function getAttrsMult($mult) {
  241. $attributes = array();
  242. foreach (array_merge($this->attributes) as $attribute) {
  243. if ($mult & $attribute->getMult()) { $attributes[] = $attribute; }
  244. }
  245. return $attributes;
  246. }
  247. /**
  248. * Get identifiers attributes list
  249. * @return array identifiers attributes list
  250. */
  251. public function getAttrsIds() {
  252. $attributes = array();
  253. foreach (array_merge($this->attributes) as $attribute) {
  254. if ($attribute->isId()) { $attributes[] = $attribute; }
  255. }
  256. return $attributes;
  257. }
  258. /**
  259. * Get list of attributes that match to an element
  260. * @param $element Element element
  261. * @return array list of attributes that match to an element
  262. */
  263. public function getAttrsMatch(Element $element) {
  264. $attributes = array();
  265. foreach (array_merge($this->attributes) as $attribute) {
  266. if ($attribute->getElem()->equals($element)) { $attributes[] = $attribute; }
  267. }
  268. return $attributes;
  269. }
  270. /**
  271. * Get list of scalar attributes that match to a type
  272. * @param $type ? type
  273. * @param $ancestors bool include ancestors ?
  274. */
  275. public function getAttrsScalar($type,$ancestors=false) {
  276. $attributes = array();
  277. if ($ancestors) {
  278. foreach ($this->getAncestors(false) as $ancestor) {
  279. $attributes = array_merge($attributes,$ancestor->getAttrsScalar($type,true));
  280. }
  281. }
  282. foreach (array_merge($this->attributes) as $attribute) {
  283. if ($attribute->getElem() instanceof Scalar && $attribute->getElem()->getType() == $type) { $attributes[] = $attribute; }
  284. }
  285. return $attributes;
  286. }
  287. // Content
  288. /**
  289. * Check if object has an element
  290. * @param $element Element element
  291. * @return bool object has element ?
  292. */
  293. public function has(Element $element) {
  294. foreach ($this->attributes as $attribute) {
  295. if ($attribute->getElem()->equals($element)) { return true; }
  296. }
  297. return false;
  298. }
  299. /**
  300. * Check if object has an element
  301. * @param $string string element's name
  302. * @return bool object has element ?
  303. */
  304. public function has_S($string) {
  305. foreach ($this->attributes as $attribute) {
  306. $name = $attribute->getAssoc() != null ? $attribute->getAssoc()->getName() : $attribute->getElem()->getName();
  307. if (strtolower($name) == strtolower($string)) { return true; }
  308. }
  309. return false;
  310. }
  311. /**
  312. * Check if object's family has an element
  313. * @param $element Element element
  314. * @param $itself bool include object itself ?
  315. * @return bool object's family has element ?
  316. */
  317. public function hasFamily(Element $element,$itself=false) {
  318. foreach ($this->getFamily($itself) as $member) {
  319. if ($member->has($element)) { return true; }
  320. }
  321. return false;
  322. }
  323. /**
  324. * Check if object's family has an element
  325. * @param $string string element's name
  326. * @param $itself bool include object itself ?
  327. * @return bool object's family has element ?
  328. */
  329. public function hasFamily_S($string,$itself=false) {
  330. foreach ($this->getFamily($itself) as $member) {
  331. if ($member->has_S($string)) { return true; }
  332. }
  333. return false;
  334. }
  335. // Options
  336. /**
  337. * Check if object has an option
  338. * @param $option string option
  339. * @return bool object has option ?
  340. */
  341. public function hasOption($option) {
  342. return $this->options != null && stripos($this->options,$option) !== false;
  343. }
  344. /**
  345. * Check if object's family has an option
  346. * @param $option string option
  347. * @return bool object family has option ?
  348. */
  349. public function familyHasOption($option) {
  350. foreach($this->getFamily(true) as $member) {
  351. if($member->hasOption($option)) { return true; }
  352. }
  353. return false;
  354. }
  355. // Family
  356. /**
  357. * Get parent
  358. * @return Object parent
  359. */
  360. public function getParent() {
  361. return $this->parent;
  362. }
  363. /**
  364. * Get ancestor
  365. * @return Object ancestor
  366. */
  367. public function getAncestor() {
  368. return $this->getParent() == null ? $this : $this->getParent()->getAncestor();
  369. }
  370. /**
  371. * Check if an object is an ancestor
  372. * @param $object Object potential ancestor
  373. * @param $itself include itself
  374. * @return bool object is an ancestor ?
  375. */
  376. public function isAncestor(Object $object,$itself=false) {
  377. return $itself && $this->equals($object) || $this->parent != null && $this->parent->isAncestor($object,true);
  378. }
  379. /**
  380. * Get children list
  381. * @return array children list
  382. */
  383. public function getChildren() {
  384. return $this->children;
  385. }
  386. /**
  387. * Check if an object is a descendant
  388. * @param $object Object object
  389. * @return bool object is a descendant
  390. */
  391. public function isDescendant(Object $object) {
  392. return $object->isAncestor($this);
  393. }
  394. /**
  395. * Check if an object is in family
  396. * @param $object Object object
  397. * @param $itself true include itself ?
  398. * @return bool object is in family ?
  399. */
  400. public function isInFamily(Object $object,$itself=false) {
  401. return $this->isDescendant($object,$itself) || $this->isAncestor($object,$itself);
  402. }
  403. /**
  404. * Get ancestor list
  405. * @param $itself bool include itself ?
  406. * @return array ancestors list
  407. */
  408. public function getAncestors($itself=false) {
  409. $ancestors = array();
  410. if ($this->parent != null) { $ancestors = $this->parent->getAncestors(true); }
  411. if ($itself) { $ancestors[] = $this; }
  412. return $ancestors;
  413. }
  414. /**
  415. * Get descendants list
  416. * @param $itself bool descendants list
  417. */
  418. public function getDescendants($itself=false) {
  419. $descendants = array();
  420. if ($itself) { $descendants[] = $this; }
  421. foreach ($this->children as $child) { $descendants = array_merge($descendants,$child->getDescendants(true)); }
  422. return $descendants;
  423. }
  424. /**
  425. * Get family
  426. * @param $itself bool include itself ?
  427. * @return array family
  428. */
  429. public function getFamily($itself=false) {
  430. return array_merge($this->getAncestors($itself),$this->getDescendants(false));
  431. }
  432. /**
  433. * Get leaf descendants
  434. * @param $itself bool include itself
  435. * @return array leaf descendants
  436. */
  437. public function getLeafs($itself=false) {
  438. $leafs = array();
  439. if ($itself && !count($this->children)) { $leafs[] = $this; }
  440. foreach ($this->children as $child) { $leafs = array_merge($leafs,$child->getLeafs(true)); }
  441. return $leafs;
  442. }
  443. }