CWIS Developer Documentation
Folder.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # FILE: Folder.php
5 #
6 # Part of the Collection Workflow Information System (CWIS)
7 # Copyright 2012 Edward Almasy and Internet Scout
8 # http://scout.wisc.edu
9 #
10 
18 class Folder {
19 
20  # ---- PUBLIC INTERFACE --------------------------------------------------
21  /*@(*/
23 
29  function Folder($FolderId)
30  {
31  # create our own DB handle
32  $this->DB = new Database();
33 
34  # store folder ID
35  $this->Id = intval($FolderId);
36 
37  # attempt to load in folder info
38  $this->DB->Query("SELECT * FROM Folders WHERE FolderId = ".$this->Id);
39  $Record = $this->DB->FetchRow();
40 
41  # if folder was not found
42  if ($Record === FALSE)
43  {
44  # bail out with exception
45  throw new Exception("Unknown Folder ID (".$FolderId.").");
46  }
47 
48  # save folder info
49  $this->OwnerId = $Record["OwnerId"];
50  $this->FolderName = $Record["FolderName"];
51  $this->NormalizedName = $Record["NormalizedName"];
52  $this->FolderNote = $Record["FolderNote"];
53  $this->IsShared = $Record["IsShared"];
54  $this->ContentType = $Record["ContentType"];
55  $this->UpdateValueCache = $Record;
56 
57  # load list of resources in folder from database
58  $this->DB->Query("SELECT ItemId, ItemTypeId, ItemNote FROM FolderItemInts"
59  ." WHERE FolderId = ".$this->Id);
60 
61  # create internal cache for item notes
62  $this->ItemNoteCache = array();
63  while ($Record = $this->DB->FetchRow())
64  {
65  $Index = self::GetCacheIndex($Record["ItemId"], $Record["ItemTypeId"]);
66  $this->ItemNoteCache[$Index] = $Record["ItemNote"];
67  }
68 
69  # load item ordering
70  if ($this->ContentType == self::MIXEDCONTENT)
71  {
72  $this->OrderList = new PersistentDoublyLinkedList(
73  "FolderItemInts", "ItemId", "FolderId = ".$this->Id, "ItemTypeId");
74  }
75  else
76  {
77  $this->OrderList = new PersistentDoublyLinkedList(
78  "FolderItemInts", "ItemId", "FolderId = ".$this->Id);
79  }
80  }
81 
85  function Delete()
86  {
87  # take folder out of global folder order
88  $Factory = new FolderFactory();
89  $Factory->RemoveItemFromOrder($this->Id);
90 
91  # remove resource listings from DB
92  $this->DB->Query("DELETE FROM FolderItemInts WHERE FolderId = ".$this->Id);
93 
94  # remove folder listing from DB
95  $this->DB->Query("DELETE FROM Folders WHERE FolderId = ".$this->Id);
96  }
97 
98  /*@)*/ /* Setup/Initialization */
99  # ------------------------------------------------------------------------
100  /*@(*/
101 
106  function Id()
107  {
108  return $this->Id;
109  }
110 
116  function Name($NewValue = DB_NOVALUE)
117  {
118  if ($NewValue != DB_NOVALUE)
119  {
120  $this->NormalizedName(self::NormalizeFolderName($NewValue));
121  }
122  return $this->UpdateValue("FolderName", $NewValue);
123  }
124 
132  function NormalizedName($NewValue = DB_NOVALUE)
133  {
134  $Name = $this->UpdateValue("NormalizedName", $NewValue);
135  # attempt to generate and set new normalized name if none found
136  if (!strlen($Name))
137  {
138  $Name = $this->UpdateValue("NormalizedName",
139  self::NormalizeFolderName($this->Name()));
140  }
141  return $Name;
142  }
143 
149  static function NormalizeFolderName($Name)
150  {
151  return preg_replace("/[^a-z0-9]/", "", strtolower($Name));
152  }
153 
160  function IsShared($NewValue = DB_NOVALUE)
161  {
162  return $this->UpdateValue("IsShared", $NewValue);
163  }
164 
170  function OwnerId($NewValue = DB_NOVALUE)
171  {
172  if ($NewValue !== DB_NOVALUE) { unset($this->Owner); }
173  return intval($this->UpdateValue("OwnerId", $NewValue));
174  }
175 
181  function Note($NewValue = DB_NOVALUE)
182  {
183  return $this->UpdateValue("FolderNote", $NewValue);
184  }
185 
186  /*@)*/ /* Attribute Setting/Retrieval */
187  # ------------------------------------------------------------------------
188  /*@(*/
189 
202  function InsertItemBefore($TargetItemOrItemId, $NewItemOrItemId,
203  $TargetItemType = NULL, $NewItemType = NULL)
204  {
205  $this->AddItem($NewItemOrItemId, $NewItemType);
206  $this->OrderList->InsertBefore($TargetItemOrItemId, $NewItemOrItemId,
207  self::GetItemTypeId($TargetItemType),
208  self::GetItemTypeId($NewItemType));
209  }
210 
222  function InsertItemAfter($TargetItemOrItemId, $NewItemOrItemId,
223  $TargetItemType = NULL, $NewItemType = NULL)
224  {
225  $this->AddItem($NewItemOrItemId, $NewItemType);
226  $this->OrderList->InsertAfter($TargetItemOrItemId, $NewItemOrItemId,
227  self::GetItemTypeId($TargetItemType),
228  self::GetItemTypeId($NewItemType));
229  }
230 
237  function PrependItem($ItemOrItemId, $ItemType = NULL)
238  {
239  $this->AddItem($ItemOrItemId, $ItemType);
240  $this->OrderList->Prepend($ItemOrItemId, self::GetItemTypeId($ItemType));
241  }
242 
249  function AppendItem($ItemOrItemId, $ItemType = NULL)
250  {
251  $this->AddItem($ItemOrItemId, $ItemType);
252  $this->OrderList->Append($ItemOrItemId, self::GetItemTypeId($ItemType));
253  }
254 
262  function GetItemIds()
263  {
264  # retrieve item ordered list of type IDs
265  $ItemIds = $this->OrderList->GetIds();
266 
267  # if this is a mixed-item-type folder
268  if ($this->ContentType == self::MIXEDCONTENT)
269  {
270  # convert item type IDs to corresponding type names
271  $NewItemIds = array();
272  foreach ($ItemIds as $ItemInfo)
273  {
274  $NewItemIds[] = array(
275  "ID" => $ItemInfo["ID"],
276  "Type" => self::GetItemTypeName($ItemInfo["Type"]),
277  );
278  }
279  $ItemIds = $NewItemIds;
280  }
281 
282  # return list of item type IDs (and possibly types) to caller
283  return $ItemIds;
284  }
285 
292  function RemoveItem($ItemId, $ItemType = NULL)
293  {
294  # if resource is in folder
295  if ($this->ContainsItem($ItemId, $ItemType))
296  {
297  # remove item from item order
298  $ItemTypeId = self::GetItemTypeId($ItemType);
299  $this->OrderList->Remove($ItemId, $ItemTypeId);
300 
301  # remove resource from folder locally
302  unset($this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)]);
303 
304  # remove resource from folder in DB
305  $this->DB->Query("DELETE FROM FolderItemInts"
306  ." WHERE FolderId = ".intval($this->Id)
307  ." AND ItemId = ".intval($ItemId)
308  ." AND ItemTypeId = ".intval($ItemTypeId));
309  }
310  }
311 
319  function NoteForItem($ItemId, $NewValue = DB_NOVALUE, $ItemType = NULL)
320  {
321  $ItemTypeId = self::GetItemTypeId($ItemType);
322  $Index = self::GetCacheIndex($ItemId, $ItemTypeId);
323  $DummyCache = array("ItemNote" => $this->ItemNoteCache[$Index]);
324 
325  $Value = $this->DB->UpdateValue("FolderItemInts", "ItemNote", $NewValue,
326  "FolderId = ".intval($this->Id)
327  ." AND ItemId = ".intval($ItemId)
328  ." AND ItemTypeId = ".intval($ItemTypeId),
329  $DummyCache);
330 
331  $this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)] = $Value;
332 
333  return $Value;
334  }
335 
342  function ContainsItem($ItemId, $ItemType = NULL)
343  {
344  $ItemTypeId = self::GetItemTypeId($ItemType);
345  return array_key_exists(self::GetCacheIndex($ItemId, $ItemTypeId),
346  $this->ItemNoteCache) ? TRUE : FALSE;
347  }
348 
349  /*@)*/ /* Item Operations */
350 
351  # ---- PRIVATE INTERFACE -------------------------------------------------
352 
353  private $DB;
354 
355  private $Id;
356 
357  # folder attributes - these much match field names in Folders DB table
358  private $OwnerId;
359  private $FolderName;
360  private $NormalizedName;
361  private $FolderNote;
362  private $IsShared;
363  private $ContentType;
364 
365  private $ItemNoteCache;
366  private $OrderList;
367  private $UpdateValueCache;
368 
369  # item type IDs (indexed by normalized type name)
370  static private $ItemTypeIds;
371  # item type names (indexed by type ID)
372  static private $ItemTypeNames;
373 
374  # content type that indicates folder contains mixed content types
375  const MIXEDCONTENT = -1;
376 
378  # map item type string to numerical value
379  # (not private because FolderFactory needs it)
380  static function GetItemTypeId($TypeName)
381  {
382  # return "no type" ID if null passed in
383  if ($TypeName === NULL) { return -1; }
384 
385  # make sure item type map is loaded
386  self::LoadItemTypeMap();
387 
388  # normalize item type name
389  $NormalizedTypeName = strtoupper(
390  preg_replace("/[^a-zA-Z0-9]/", "", $TypeName));
391 
392  # if name not already mapped
393  if (!array_key_exists($NormalizedTypeName, self::$ItemTypeIds))
394  {
395  # add name to database
396  if (!isset($DB)) { $DB = new Database(); }
397  $DB->Query("INSERT INTO FolderContentTypes SET"
398  ." TypeName = '".addslashes($TypeName)."',"
399  ." NormalizedTypeName = '".addslashes($NormalizedTypeName)."'");
400 
401  # add name to cached mappings
402  $NewTypeId = $DB->LastInsertId("FolderContentTypes");
403  self::$ItemTypeIds[$NormalizedTypeName] = $NewTypeId;
404  self::$ItemTypeNames[$NewTypeId] = $TypeName;
405  }
406 
407  # return item type ID to caller
408  return self::$ItemTypeIds[$NormalizedTypeName];
409  }
412  # map item type numerical value to string
413  private static function GetItemTypeName($TypeId)
414  {
415  # make sure item type map is loaded
416  self::LoadItemTypeMap();
417 
418  # if ID not present in mappings
419  if (!array_key_exists($TypeId, self::$ItemTypeNames))
420  {
421  # return null value
422  return NULL;
423  }
424  else
425  {
426  # return item type name to caller
427  return self::$ItemTypeNames[$TypeId];
428  }
429  }
430 
431  # load item type map from database
432  private static function LoadItemTypeMap()
433  {
434  # if name-to-number item type map not already loaded
435  if (!isset(self::$ItemTypeIds))
436  {
437  # load item type map from database
438  $DB = new Database();
439  $DB->Query("SELECT * FROM FolderContentTypes");
440  self::$ItemTypeIds = array();
441  self::$ItemTypeNames = array();
442  while ($Row = $DB->FetchRow())
443  {
444  self::$ItemTypeIds[$Row["NormalizedTypeName"]] = $Row["TypeId"];
445  self::$ItemTypeNames[$Row["TypeId"]] = $Row["TypeName"];
446  }
447  }
448  }
449 
450  # add resource to folder (does not add to ordered list)
451  private function AddItem($ItemOrItemId, $ItemType)
452  {
453  # convert item to ID if necessary
454  $ItemId = is_object($ItemOrItemId)
455  ? $ItemOrItemId->Id() : $ItemOrItemId;
456 
457  # convert item type to item type ID
458  $ItemTypeId = self::GetItemTypeId($ItemType);
459 
460  # convert null item type to "no type" value used in database
461  if ($ItemTypeId === NULL) { $ItemTypeId = -1; }
462 
463  # if resource is not already in folder
464  if (!$this->ContainsItem($ItemId, $ItemType))
465  {
466  # add resource to folder locally
467  $this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)] = NULL;
468 
469  # add resource to folder in DB
470  $this->DB->Query("INSERT INTO FolderItemInts SET"
471  ." FolderId = ".intval($this->Id)
472  .", ItemId = ".intval($ItemId)
473  .", ItemTypeId = ".intval($ItemTypeId));
474  }
475  }
476 
477  # get index to be used with item note cache array
478  private static function GetCacheIndex($ItemId, $ItemTypeId)
479  {
480  $ItemTypeId = ($ItemTypeId === NULL) ? -1 : $ItemTypeId;
481  return intval($ItemTypeId).":".intval($ItemId);
482  }
483 
484  # get/set value in database
485  private function UpdateValue($FieldName, $NewValue)
486  {
487  $this->$FieldName = $this->DB->UpdateValue("Folders", $FieldName, $NewValue,
488  "FolderId = ".$this->Id, $this->UpdateValueCache);
489  return $this->$FieldName;
490  }
491 }
492 
493 
494 ?>