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

Documentation generated on Fri, 1 Jun 2007 16:51:29 +0200 by phpDocumentor 1.3.2