Search:

CWIS Developers Documentation

  • Main Page
  • Classes
  • Files
  • File List
  • File Members

DoublyLinkedItemList.php

Go to the documentation of this file.
00001 <?PHP
00002 
00003 #
00004 #   FILE:  SPT--DoublyLinkedList.php
00005 #
00006 #   METHODS PROVIDED:
00007 #       DoublyLinkedList()
00008 #           - constructor
00009 #       SomeMethod($SomeParameter, $AnotherParameter)
00010 #           - short description of method
00011 #
00012 #   AUTHOR:  
00013 #
00014 #   Part of the Scout Portal Toolkit
00015 #   Copyright 2007 Internet Scout
00016 #   http://scout.wisc.edu
00017 #
00018 
00019 class DoublyLinkedItemList {
00020 
00021     # ---- PUBLIC INTERFACE --------------------------------------------------
00022 
00023     # object constructor
00024     function DoublyLinkedItemList(
00025             $ItemTableName, $ItemIdFieldName, $SqlCondition = NULL)
00026     {
00027         # grab our own database handle
00028         $this->DB = new SPTDatabase();
00029 
00030         # save configuration
00031         $this->ItemIdFieldName = $ItemIdFieldName;
00032         $this->ItemTableName = $ItemTableName;
00033         $this->SqlCondition($SqlCondition);
00034     }
00035 
00036     # insert/move item to before specified item
00037     function InsertBefore($SourceItemOrItemId, $TargetItemOrItemId)
00038     {   
00039         # retrieve item IDs 
00040         $SourceItemId = is_object($SourceItemOrItemId)
00041                 ? $SourceItemOrItemId->Id() : $SourceItemOrItemId;
00042         $TargetItemId = is_object($TargetItemOrItemId)
00043                 ? $TargetItemOrItemId->Id() : $TargetItemOrItemId;
00044                 
00045         # remove source item from current position if necessary
00046         $this->Remove($SourceItemId);
00047     
00048         # update IDs to link in new item
00049         $CurrentTargetItemPreviousId = $this->GetPreviousItemId($TargetItemId);
00050         $this->SetPreviousItemId($TargetItemId, $SourceItemId);
00051         if ($CurrentTargetItemPreviousId != -1)
00052         {
00053             $this->SetNextItemId($CurrentTargetItemPreviousId, $SourceItemId);
00054         }
00055         $this->SetPreviousAndNextItemIds($SourceItemId,
00056                 $CurrentTargetItemPreviousId, $TargetItemId);
00057     }
00058 
00059     # insert/move item to after specified item
00060     function InsertAfter($SourceItemOrItemId, $TargetItemOrItemId)
00061     {
00062         # retrieve item IDs 
00063         $SourceItemId = is_object($SourceItemOrItemId)
00064                 ? $SourceItemOrItemId->Id() : $SourceItemOrItemId;
00065         $TargetItemId = is_object($TargetItemOrTargetItemId)
00066                 ? $TargetItemOrTargetItemId->Id() : $TargetItemOrTargetItemId;
00067 
00068         # remove source item from current position if necessary
00069         $this->Remove($SourceItemId);
00070 
00071         # update IDs to link in new item
00072         $CurrentTargetItemNextId = $this->GetNextItemIdInOrder($TargetItemId);
00073         $this->SetNextItemId($TargetItemId, $SourceItemId);
00074         if ($CurrentTargetItemNextId != -1)
00075         {
00076             $this->SetPreviousItemId($CurrentTargetItemNextId, $SourceItemId);
00077         }
00078         $this->SetPreviousAndNextItemIds($SourceItemId,
00079                 $TargetItemId, $CurrentTargetItemNextId);
00080     }
00081 
00082     # add/move item to beginning of list
00083     function Prepend($ItemOrItemId)
00084     {
00085         # get item ID
00086         $ItemId = is_object($ItemOrItemId) ? $ItemOrItemId->Id() : $ItemOrItemId;
00087 
00088         # remove new item from current position if necessary
00089         $this->Remove($ItemId);
00090 
00091         # if there are items currently in list
00092         $ItemIds = $this->GetIds(FALSE);
00093         if (count($ItemIds))
00094         {
00095             # link last item to source item
00096             $FirstItemId = array_shift($ItemIds);
00097             $this->SetPreviousItemId($FirstItemId, $ItemId);
00098             $this->SetPreviousAndNextItemIds($ItemId, -1, $FirstItemId);
00099         }
00100         else
00101         {
00102             # add item to list as only item
00103             $this->SetPreviousAndNextItemIds($ItemId, -1, -1);
00104         }
00105     }
00106 
00107     # add/move item to end of list
00108     function Append($ItemOrItemId)
00109     {
00110         # get item ID
00111         $ItemId = is_object($ItemOrItemId) ? $ItemOrItemId->Id() : $ItemOrItemId;
00112 
00113         # remove item from current position if necessary
00114         $this->Remove($ItemId);
00115 
00116         # if there are items currently in list
00117         $ItemIds = $this->GetIds(FALSE);
00118         if (count($ItemIds))
00119         {
00120             # link last item to source item
00121             $LastItemId = array_pop($ItemIds);
00122             $this->SetNextItemId($LastItemId, $ItemId);
00123             $this->SetPreviousAndNextItemIds($ItemId, $LastItemId, -1);
00124         }
00125         else
00126         {
00127             # add item to list as only item
00128             $this->SetPreviousAndNextItemIds($ItemId, -1, -1);
00129         }
00130     }
00131 
00132     # retrieve list of item IDs in order
00133     function GetIds($AddStrayItemsToOrder = TRUE)
00134     {
00135         # retrieve ordering IDs
00136         $this->DB->Query("SELECT ".$this->ItemIdFieldName
00137                 .", Previous".$this->ItemIdFieldName
00138                 .", Next".$this->ItemIdFieldName
00139                 ." FROM ".$this->ItemTableName
00140                 .$this->GetCondition(TRUE)
00141                 ." ORDER BY ".$this->ItemIdFieldName." ASC");
00142         $PreviousItemIds = array();
00143         $NextItemIds = array();
00144         while ($Record = $this->DB->FetchRow())
00145         {
00146             $ItemId = intval($Record[$this->ItemIdFieldName]);
00147             $PreviousItemIds[$ItemId] = 
00148                     intval($Record["Previous".$this->ItemIdFieldName]);
00149             $NextItemIds[$ItemId] = intval($Record["Next".$this->ItemIdFieldName]);
00150         }
00151 
00152         # pull unordered items out of list
00153         $StrayItemIds = array_keys($PreviousItemIds, -2);
00154         foreach ($StrayItemIds as $StrayItemId)
00155         {
00156             unset($PreviousItemIds[$StrayItemId]);
00157             unset($NextItemIds[$StrayItemId]);
00158         }
00159 
00160         # find first item
00161         $ItemId = array_search(-1, $PreviousItemIds);
00162 
00163         # if first item was found
00164         $ItemIds = array();
00165         if ($ItemId !== FALSE)
00166         {
00167             # traverse linked list to build list of item IDs
00168             do
00169             {
00170                 $ItemIds[] = $ItemId;
00171                 unset($PreviousItemIds[$ItemId]);
00172                 if (isset($NextItemIds[$ItemId])) {  $ItemId = $NextItemIds[$ItemId];  }
00173             }
00174             while (isset($NextItemIds[$ItemId]) && ($ItemId != -1)
00175                     && !in_array($ItemId, $ItemIds));
00176 
00177             # add any items left over to stray items list
00178             $StrayItemIds = array_unique($StrayItemIds + array_keys($PreviousItemIds));
00179         }
00180 
00181         # add any stray items to end of list (if so configured)
00182         if ($AddStrayItemsToOrder)
00183         {
00184             foreach ($StrayItemIds as $StrayItemId)
00185             {
00186                 $this->Append($StrayItemId);
00187                 $ItemIds[] = $StrayItemId;
00188             }
00189         }
00190 
00191         # return list of item IDs to caller
00192         return $ItemIds;
00193     }
00194 
00195     # remove item from existing order
00196     function Remove($ItemId)
00197     {
00198         $CurrentItemPreviousId = $this->GetPreviousItemId($ItemId);
00199         $CurrentItemNextId = $this->GetNextItemIdInOrder($ItemId);
00200         if ($CurrentItemPreviousId >= 0)
00201         {
00202             $this->SetNextItemId(
00203                     $CurrentItemPreviousId, $CurrentItemNextId);
00204         }
00205         if ($CurrentItemNextId >= 0)
00206         {
00207             $this->SetPreviousItemId(
00208                     $CurrentItemNextId, $CurrentItemPreviousId);
00209         }
00210     }
00211 
00212     # set SQL condition for ordering operations
00213     # (use NULL to clear condition)
00214     function SqlCondition($NewCondition)
00215     {
00216         $this->Condition = $NewCondition;
00217     }
00218 
00219 
00220     # ---- PRIVATE INTERFACE -------------------------------------------------
00221 
00222     var $DB;
00223     var $ItemIdFieldName;
00224     var $ItemTableName;
00225     var $Condition;
00226 
00227     # get/set ordering values
00228     function GetPreviousItemId($ItemId)
00229     {
00230         return $this->DB->Query("SELECT Previous".$this->ItemIdFieldName
00231                     ." FROM ".$this->ItemTableName
00232                     ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId)
00233                     .$this->GetCondition(),
00234                 "Previous".$this->ItemIdFieldName);
00235     }
00236     function GetNextItemIdInOrder($ItemId)
00237     {
00238         return $this->DB->Query("SELECT Next".$this->ItemIdFieldName
00239                     ." FROM ".$this->ItemTableName
00240                     ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId)
00241                     .$this->GetCondition(),
00242                 "Next".$this->ItemIdFieldName);
00243     }
00244     function SetPreviousItemId($ItemId, $NewValue)
00245     {
00246         $this->DB->Query("UPDATE ".$this->ItemTableName
00247                 ." SET Previous".$this->ItemIdFieldName." = ".intval($NewValue)
00248                 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId)
00249                 .$this->GetCondition());
00250     }
00251     function SetNextItemId($ItemId, $NewValue)
00252     {
00253         $this->DB->Query("UPDATE ".$this->ItemTableName
00254                 ." SET Next".$this->ItemIdFieldName." = ".intval($NewValue)
00255                 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId)
00256                 .$this->GetCondition());
00257     }
00258     function SetPreviousAndNextItemIds($ItemId, $NewPreviousId, $NewNextId)
00259     {
00260         $this->DB->Query("UPDATE ".$this->ItemTableName
00261                 ." SET Previous".$this->ItemIdFieldName." = ".intval($NewPreviousId)
00262                         .", Next".$this->ItemIdFieldName." = ".intval($NewNextId)
00263                 ." WHERE ".$this->ItemIdFieldName." = ".intval($ItemId)
00264                 .$this->GetCondition());
00265     }
00266 
00267     # return DB query condition (if any) with proper additional syntax
00268     function GetCondition($ThisIsOnlyCondition = FALSE)
00269     {
00270         return $this->Condition ? 
00271                 ($ThisIsOnlyCondition ? " WHERE " : " AND ").$this->Condition 
00272                 : "";
00273     }
00274 }
00275 
00276 
00277 ?>
CWIS logo doxygen
Copyright 2009 Internet Scout