Source for file ResList.php

Documentation is available at ResList.php

  1. <?PHP
  2. // ----------------------------------------------------------------------------------
  3. // Class: ResList
  4. // ----------------------------------------------------------------------------------
  5.  
  6. /**
  7. * Implementation of an rdf:Collection (rdf:List)
  8. * Provides a convenience encapsulation for lists formed from
  9. * chains of RDF statements arranged to form a head/tail cons-cell
  10. * structure.
  11. *
  12. * A well-formed list has cells that are made up of three statements:
  13. * one denoting the rdf:type of the list cell, one denoting the link
  14. * to the value of the list at that point, and one pointing to the
  15. * list tail. If a list cell is not well-formed, list operations may
  16. * fail in unpredictable ways. However, to explicitly check that the
  17. * list is well-formed at all times is expensive, but you can call
  18. * the isValid() method to manually check, if the list is well formed.
  19. *
  20. *
  21. * <BR><BR>History:<UL>
  22. * <LI>10-01-2004 : First version of this class.</LI>
  23. *
  24. * @version V0.9.3
  25. * @author Daniel Westphal <mail at d-westphal dot de>
  26.  
  27. *
  28. * @package resModel
  29. * @todo nothing
  30. * @access public
  31. */
  32. class ResList extends ResResource
  33. {
  34. /**
  35. * Holds a ResResource with the uri rdf:rest
  36. * @var ResResource
  37. * @access private
  38. */
  39. var $rdfRestResource;
  40. /**
  41. * Holds a ResResource with the uri rdf:first
  42. * @var ResResource
  43. * @access private
  44. */
  45. var $rdfFirstResource;
  46. /**
  47. * Holds a ResResource with the uri rdf:nil
  48. * @var ResResource
  49. * @access private
  50. */
  51. var $rdfNilResource;
  52. /**
  53. * Constructor
  54. * You can supply a URI
  55. *
  56. * @param string $uri
  57. * @access public
  58. */
  59. function ResList($uri = null)
  60. {
  61. //call the parent''s constructor
  62. parent::ResResource($uri);
  63. //initialize vars
  64. $this->rdfRestResource = new ResResource(RDF_NAMESPACE_URI.RDF_REST);
  65. $this->rdfFirstResource = new ResResource(RDF_NAMESPACE_URI.RDF_FIRST);
  66. $this->rdfNilResource = new ResResource(RDF_NAMESPACE_URI.RDF_NIL);
  67. }
  68.  
  69. /**
  70. * Returns the value of the list element at the specified position or null.
  71. *
  72. * @param integer $position
  73. * @return ResResource
  74. * @access public
  75. */
  76. function get($position)
  77. {
  78. //init
  79. $listElement=$this;
  80. //walk through the list until the position in the list is reached
  81. for ($i=0;$i<$position;$i++)
  82. {
  83. $listElement=$this->_getRestElement($listElement);
  84. if($listElement===null)
  85. return null;
  86. }
  87. //return the associated value
  88. return $this->_getValue($listElement);
  89. }
  90.  
  91. /**
  92. * Add the given value to the end of the list.
  93. * it is only defined if this is not the empty list.
  94. *
  95. * @param object ResResource $resource
  96. * @return boolean
  97. * @access public
  98. */
  99. function add($resource)
  100. {
  101. //return false if this list is the empty list
  102. if($this->uri==RDF_NAMESPACE_URI.RDF_NIL)
  103. return false;
  104. //if this is the first value
  105. if ($this->isEmpty())
  106. {
  107. $newLastElement =& $this;
  108. } else
  109. //if there are other values in the list
  110. {
  111. //get the last list element
  112. $lastElement=$this->_getListElement();
  113. //remove the rdf:rest property
  114. $lastElement->removeAll($this->rdfRestResource);
  115. //create a new list element
  116. $newLastElement=$this->model->createResource();
  117. //concatenate the new list element with the list
  118. $lastElement->addProperty($this->rdfRestResource,$newLastElement);
  119. }
  120. //add the value
  121. $newLastElement->addProperty($this->rdfFirstResource,$resource);
  122. //ad the rdf:nil property to the last list element
  123. $newLastElement->addProperty($this->rdfRestResource,$this->rdfNilResource);
  124. return true;
  125. }
  126. /**
  127. * Update the head of the list to have the given value,
  128. * and return the previous value.
  129. *
  130. * @param object ResResource $value
  131. * @return ResResource
  132. * @access public
  133. */
  134. //todo: error handling, when empty list
  135. function setHead($value)
  136. {
  137. //save the old value
  138. $oldValue=$this->getHead();
  139. //remove the old value
  140. $this->removeAll($this->rdfFirstResource);
  141. //add the new value
  142. $this->addProperty($this->rdfFirstResource,$value);
  143. //return the old value
  144. return $oldValue;
  145. }
  146. /**
  147. * Get the value that is associated with the head of the list.
  148. *
  149. * @return ResResource
  150. * @access public
  151. */
  152. //todo: error handling, falls empty list
  153. function getHead()
  154. {
  155. return $this->_getValue($this);
  156. }
  157. /**
  158. * Remove the head of the list. The tail of the list
  159. * remains in the model. Note that no changes are made to
  160. * list cells that point to this list cell as their tail.
  161. *
  162. * @return ResList
  163. * @access public
  164. */
  165. function removeHead()
  166. {
  167. //get the second list element
  168. $rest=$this->_getRestElement($this);
  169. //remove the first element
  170. $this->removeAll($this->rdfFirstResource);
  171. $this->removeAll($this->rdfRestResource);
  172. //change this Resource URI to that of the second list element
  173. //thus makin it the fist element
  174. $this->uri=$rest->getURI();
  175. //return the new list
  176. return $this;
  177. }
  178.  
  179. /**
  180. * Get the Position of the first occurrence of the given value in the list,
  181. * or -1 if the value is not in the list.
  182. * You can supply an offset to search for values. (First element has offset 0)
  183. * Default is 0
  184. *
  185. * @param object ResResource $resource
  186. * @param integer $offset
  187. * @return integer
  188. * @access public
  189. */
  190. function indexOf($resource, $offset = 0)
  191. {
  192. //init
  193. $element=$this;
  194. $actualIndex=0;
  195.  
  196. //walk through the list until the value is found and the position is higher than
  197. //the offset
  198. while ($actualIndex < $offset || !$resource->equals($this->_getValue($element)))
  199. {
  200. //get next list element
  201. $element=$this->_getRestElement($element);
  202. $actualIndex++;
  203. //if the end of the list is reached and the value isn''t found
  204. if ($element===null)
  205. return null;
  206. }
  207. //return the index value
  208. return $actualIndex;
  209. }
  210. /**
  211. * Replace the value at the i''th position in the list with the given value
  212. *
  213. * @param integer $index
  214. * @param object ResResource $resource
  215. * @return object ResResource
  216. * @access public
  217. */
  218. function replace($index, $resource)
  219. {
  220. //get the list element at the $index position
  221. $listElement=$this->_getListElement($index);
  222. //get the old value
  223. $oldValue=$this->_getValue($listElement);
  224. //remove the old value
  225. $listElement->removeAll($this->rdfFirstResource);
  226. //add the new value
  227. $listElement->addProperty($this->rdfFirstResource,$resource);
  228. //return the old value
  229. return $oldValue;
  230. }
  231. /**
  232. * Answer true if the given node appears as the value of a value
  233. * of any of the cells of this list.
  234. *
  235. * @param object ResResource $value
  236. * @return boolean
  237. * @access public
  238. */
  239. function contains($value)
  240. {
  241. //return true, if a position was found.
  242. $result=$this->indexOf($value);
  243. return ($result!==null);
  244. }
  245. /**
  246. * Get the list that is the tail of this list.
  247. *
  248. * @return object ResList
  249. * @access public
  250. */
  251. function getTail()
  252. {
  253. //get the second list element
  254. $nextListElement= $this->_getRestElement($this);
  255. //return the second element as new list
  256. return $this->model->createList($nextListElement->getURI());
  257. }
  258. /**
  259. * Remove all of the components of this list from the model.
  260. * Note that this is operation is only removing the list cells
  261. * themselves, not the resources referenced by the list -
  262. * unless being the object of an rdf:first statement is the
  263. * only mention of that resource in the model.
  264. *
  265. * @return boolean
  266. * @access public
  267. */
  268. function removeList()
  269. {
  270. $element=$this;
  271.  
  272. while ($element!==null)
  273. {
  274. $nextElement=$this->_getRestElement($element);
  275. $element->removeAll($this->rdfFirstResource);
  276. $element->removeAll($this->rdfRestResource);
  277. if (($nextElement !== null) && ($nextElement->getURI()!==RDF_NAMESPACE_URI.RDF_NIL))
  278. {
  279. $element=$nextElement;
  280. } else
  281. {
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287. /**
  288. * Returns true, if this list is empty
  289. *
  290. * @param object Statement $statement
  291. * @return integer
  292. * @access public
  293. */
  294. function isEmpty()
  295. {
  296. return !$this->hasProperty($this->rdfFirstResource);
  297. }
  298. /**
  299. * Get all values in the list as an array of ResResources
  300. *
  301. * @return array
  302. * @access public
  303. */
  304. function getContentInArray()
  305. {
  306. $result=array();
  307. $element=$this;
  308.  
  309. while ($element!==null)
  310. {
  311. //add the value of the current element to the result if is set.
  312. $value=$this->_getValue($element);
  313. if ($value!==null)
  314. $result[]=$value;
  315. //walk through the list until it''s end
  316. $nextElement=$this->_getRestElement($element);
  317. if (($nextElement !== null) && ($nextElement->getURI()!==RDF_NAMESPACE_URI.RDF_NIL))
  318. {
  319. $element=$nextElement;
  320. } else
  321. {
  322. break;
  323. }
  324. }
  325. //return the result
  326. return $result;
  327. }
  328. /**
  329. * Change the tail of this list to point to the given list, so that this list
  330. * becomes the list of the concatenation of the elements of
  331. * both lists. This is a side-effecting operation on this list;
  332. * for a non side-effecting alternative, see append.
  333. *
  334. *
  335. * @param object ResList $ResList
  336. * @access public
  337. */
  338. function concatenate($ResList)
  339. {
  340. //get the last list element
  341. $lastElement=$this->_getListElement();
  342. //remove the old tail (rdf:nil)
  343. $lastElement->removeAll($this->rdfRestResource);
  344. //add the $ResList as new tail
  345. $lastElement->addProperty($this->rdfRestResource,$ResList);
  346. }
  347. /**
  348. * Answer a new list that is formed by adding each element of
  349. * this list to the head of the given list. This is a non
  350. * side-effecting operation on either this list or the given
  351. * list, but generates a copy of this list. For a more storage
  352. * efficient alternative, see concatenate
  353. *
  354. * @param object ResList $ResList
  355. * @return object ResList
  356. * @access public
  357. */
  358. function append($resList)
  359. {
  360. //get a copy of this list
  361. $newList=$this->copy();
  362. //add all values from the $resList to the new list
  363. foreach ($resList->getContentInArray() as $value)
  364. {
  365. $newList->add($value);
  366. }
  367. //return the new list
  368. return $newList;
  369. }
  370. /**
  371. * Answer a list that contains all of the elements of this
  372. * list in the same order, but is a duplicate copy in the
  373. * underlying model.
  374. *
  375. * @return object ResList
  376. * @access public
  377. */
  378. function copy()
  379. {
  380. //create a new list in the model
  381. $newList=$this->model->createList();
  382. //add all values from this list to the new list
  383. foreach ($this->getContentInArray() as $value)
  384. {
  385. $newList->add($value);
  386. }
  387. //return the new list
  388. return $newList;
  389. }
  390. /**
  391. * Return a reference to a new list cell whose head is value
  392. * and whose tail is this list.
  393. *
  394. * @param object ResResource $value
  395. * @return object ResList
  396. * @access public
  397. */
  398. function cons($value)
  399. {
  400. //create a new list
  401. $newList=$this->model->createList();
  402. //add the new value
  403. $newList->add($value);
  404. //set this list as the tail of the new list
  405. $newList->setTail($this);
  406. //return the new list
  407. return $newList;
  408. }
  409. /**
  410. * Update the list cell at the front of the list to have the
  411. * given list as tail. The old tail is returned, and remains
  412. * in the model.
  413. *
  414. * @param object ResList $resList
  415. * @return object Reslist
  416. * @access public
  417. */
  418. function setTail($resList)
  419. {
  420. //save the old tail
  421. $oldTail=$this->getTail();
  422. //remove the old tail
  423. $this->removeAll($this->rdfRestResource);
  424. //add the $resList as new Tail
  425. $this->addProperty($this->rdfRestResource,$resList);
  426. //return the old tail
  427. return $oldTail;
  428. }
  429. /**
  430. * Answer true if this list has the same elements in the
  431. * same order as the given list. Note that the standard equals
  432. * test just tests for equality of two given list cells.
  433. * While such a test is sufficient for many purposes, this
  434. * test provides a broader equality definition, but is
  435. * correspondingly more expensive to test.
  436. *
  437. * @param object ResList $resList
  438. * @return boolean
  439. * @access public
  440. */
  441. function sameListAs($resList)
  442. {
  443. //init
  444. $indexPos=0;
  445. do
  446. {
  447. //get the values for both lists at the actual position
  448. $thisValue=$this->get($indexPos);
  449. $thatValue=$resList->get($indexPos);
  450. //if the values aren''t equal, return false
  451. if (($thisValue !== null) && !$thisValue->equals($thatValue))
  452. return false;
  453. $indexPos++;
  454. //walk until this list reaches a null value (end)
  455. } while ($thisValue!==null);
  456. //if the other list has a null value at this position too, return true
  457. //else return false
  458. return ($thatValue===null);
  459. }
  460. /**
  461. * Remove the given value from this list.
  462. * If value does not occur in the list, no action is taken. Since removing the
  463. * head of the list will invalidate the list head cell, in
  464. * general the list must return the list that results from
  465. * this operation. However, in many cases the return value
  466. * will be the same as the object that this method is invoked
  467. * on.
  468. *
  469. * @param object ResResource $value
  470. * @return object ResList
  471. * @access public
  472. */
  473. function remove($value)
  474. {
  475. //if the value is the value of the first list element(head)
  476. //call the remove head position and return the new head
  477. if ($value->equals($this->_getValue($this)))
  478. return $this->removeHead();
  479. $element=$this;
  480. do
  481. {
  482. $newElement=$this->_getRestElement($element);
  483. //if the value equals the value of the current list element
  484. if ($newElement !== null && $value->equals($this->_getValue($newElement)))
  485. {
  486. //remove the link to the list element to be removed
  487. $element->removeAll($this->rdfRestResource);
  488. //add a link to the list element AFTER the element to be deleted
  489. $element->addProperty($this->rdfRestResource,$this->_getRestElement($newElement));
  490. //remove the list element with values
  491. $newElement->removeAll($this->rdfFirstResource);
  492. $newElement->removeAll($this->rdfRestResource);
  493. //return this ResList
  494. return $this;
  495. }
  496. $element=$newElement;
  497. } while ($element!==null);
  498. //return this list
  499. return $this;
  500. }
  501. /**
  502. * Answer true if the list is well-formed, by checking that each
  503. * node is correctly typed, and has a head and tail pointer from
  504. * the correct vocabulary
  505. *
  506. * @return boolean
  507. * @access public
  508. */
  509. function isValid()
  510. {
  511. $element=$this;
  512. if ($this->_getValue($this)=== null && $this->_getRestElement($this) === null)
  513. return true;
  514. do
  515. {
  516. //return true if the last element is a rdf:nil
  517. if ($element->getURI() == RDF_NAMESPACE_URI.RDF_NIL)
  518. return true;
  519. //return false, if the current element has no associated value
  520. if ($this->_getValue($element) === null)
  521. return false;
  522. $element=$this->_getRestElement($element);
  523. } while ($element !== null);
  524. //return false, if the current element has no rdf:rest property
  525. return false;
  526. }
  527. /**
  528. * Get the associated rdf:rest Resource from the suplied ResList element
  529. *
  530. * @param object ResList $listElement
  531. * @return object ResList
  532. * @access private
  533. */
  534. function _getRestElement($listElement)
  535. {
  536. //get the rdf:rest property
  537. $statement= $this->model->getProperty($listElement,$this->rdfRestResource);
  538. //return null, if this property isn''t set
  539. if ($statement === null)
  540. return null;
  541. //return the value of the rdf:rest property
  542. return $statement->getObject();
  543. }
  544. /**
  545. * Returns the list element at the $index position.
  546. *
  547. * If to $index is suplied, the last list element will be returned
  548. * @param integer $index
  549. * @return object ResResource
  550. * @access private
  551. */
  552. function _getListElement($index = null)
  553. {
  554. $element=$this;
  555. $actualIndex=0;
  556.  
  557. while ($element!=null)
  558. {
  559. //return the current element if index matches the current index
  560. if ($actualIndex === $index)
  561. return $element;
  562. //return the current element if it the last one
  563. if ($element->hasProperty($this->rdfRestResource,$this->rdfNilResource))
  564. return $element;
  565. $nextElement=$this->_getRestElement($element);
  566. if ($nextElement!==null)
  567. {
  568. $element=$nextElement;
  569. $actualIndex++;
  570. } else
  571. {
  572. break;
  573. }
  574. }
  575. return $element;
  576. }
  577. /**
  578. * Get the value associated to the $listResource by the rdf:first property
  579. *
  580. * @param object ResList $listResource
  581. * @return object ResResource
  582. * @access private
  583. */
  584. function _getValue($listResource)
  585. {
  586. //Return the value of the rdf:first property or null, if it isn''t set
  587. $statement=$this->model->getProperty($listResource,$this->rdfFirstResource);
  588. if ($statement===null)
  589. return null;
  590.  
  591. return $statement->getObject();
  592. }
  593. }
  594. ?>

Documentation generated on Fri, 13 Jan 2006 07:49:28 +0100 by phpDocumentor 1.3.0RC4