Source for file ResList.php

Documentation is available at ResList.php

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

Documentation generated on Fri, 17 Dec 2004 16:17:53 +0100 by phpDocumentor 1.3.0RC3