CWIS Developer Documentation
Folder.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Folder.php
4 #
5 # Part of the Collection Workflow Information System (CWIS)
6 # Copyright 2012-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
17 class Folder {
18 
19  # ---- PUBLIC INTERFACE --------------------------------------------------
20  /*@(*/
22 
28  function Folder($FolderId)
29  {
30  # create our own DB handle
31  $this->DB = new Database();
32 
33  # store folder ID
34  $this->Id = intval($FolderId);
35 
36  # attempt to load in folder info
37  $this->DB->Query("SELECT * FROM Folders WHERE FolderId = ".$this->Id);
38  $Record = $this->DB->FetchRow();
39 
40  # if folder was not found
41  if ($Record === FALSE)
42  {
43  # bail out with exception
44  throw new Exception("Unknown Folder ID (".$FolderId.").");
45  }
46 
47  # save folder info
48  $this->OwnerId = $Record["OwnerId"];
49  $this->FolderName = $Record["FolderName"];
50  $this->NormalizedName = $Record["NormalizedName"];
51  $this->FolderNote = $Record["FolderNote"];
52  $this->IsShared = $Record["IsShared"];
53  $this->ContentType = $Record["ContentType"];
54  $this->UpdateValueCache = $Record;
55 
56  # load list of resources in folder from database
57  $this->DB->Query("SELECT ItemId, ItemTypeId, ItemNote FROM FolderItemInts"
58  ." WHERE FolderId = ".$this->Id);
59 
60  # create internal cache for item notes
61  $this->ItemNoteCache = array();
62  while ($Record = $this->DB->FetchRow())
63  {
64  $Index = self::GetCacheIndex($Record["ItemId"], $Record["ItemTypeId"]);
65  $this->ItemNoteCache[$Index] = $Record["ItemNote"];
66  }
67 
68  # load item ordering
69  if ($this->ContentType == self::MIXEDCONTENT)
70  {
71  $this->OrderList = new PersistentDoublyLinkedList(
72  "FolderItemInts", "ItemId", "FolderId = ".$this->Id, "ItemTypeId");
73  }
74  else
75  {
76  $this->OrderList = new PersistentDoublyLinkedList(
77  "FolderItemInts", "ItemId", "FolderId = ".$this->Id);
78  }
79  }
80 
84  function Delete()
85  {
86  # take folder out of global folder order
87  $Factory = new FolderFactory();
88  $Factory->RemoveItemFromOrder($this->Id);
89 
90  # remove resource listings from DB
91  $this->DB->Query("DELETE FROM FolderItemInts WHERE FolderId = ".$this->Id);
92 
93  # remove folder listing from DB
94  $this->DB->Query("DELETE FROM Folders WHERE FolderId = ".$this->Id);
95  }
96 
97  /*@)*/ /* Setup/Initialization */
98  # ------------------------------------------------------------------------
99  /*@(*/
100 
105  function Id()
106  {
107  return $this->Id;
108  }
109 
115  function Name($NewValue = DB_NOVALUE)
116  {
117  if ($NewValue != DB_NOVALUE)
118  {
119  $this->NormalizedName(self::NormalizeFolderName($NewValue));
120  }
121  return $this->UpdateValue("FolderName", $NewValue);
122  }
123 
131  function NormalizedName($NewValue = DB_NOVALUE)
132  {
133  $Name = $this->UpdateValue("NormalizedName", $NewValue);
134  # attempt to generate and set new normalized name if none found
135  if (!strlen($Name))
136  {
137  $Name = $this->UpdateValue("NormalizedName",
138  self::NormalizeFolderName($this->Name()));
139  }
140  return $Name;
141  }
142 
148  static function NormalizeFolderName($Name)
149  {
150  return preg_replace("/[^a-z0-9]/", "", strtolower($Name));
151  }
152 
159  function IsShared($NewValue = DB_NOVALUE)
160  {
161  return $this->UpdateValue("IsShared", $NewValue);
162  }
163 
169  function OwnerId($NewValue = DB_NOVALUE)
170  {
171  if ($NewValue !== DB_NOVALUE) { unset($this->Owner); }
172  return intval($this->UpdateValue("OwnerId", $NewValue));
173  }
174 
180  function Note($NewValue = DB_NOVALUE)
181  {
182  return $this->UpdateValue("FolderNote", $NewValue);
183  }
184 
185  /*@)*/ /* Attribute Setting/Retrieval */
186  # ------------------------------------------------------------------------
187  /*@(*/
188 
201  function InsertItemBefore($TargetItemOrItemId, $NewItemOrItemId,
202  $TargetItemType = NULL, $NewItemType = NULL)
203  {
204  $this->AddItem($NewItemOrItemId, $NewItemType);
205  $this->OrderList->InsertBefore($TargetItemOrItemId, $NewItemOrItemId,
206  self::GetItemTypeId($TargetItemType),
207  self::GetItemTypeId($NewItemType));
208  }
209 
221  function InsertItemAfter($TargetItemOrItemId, $NewItemOrItemId,
222  $TargetItemType = NULL, $NewItemType = NULL)
223  {
224  $this->AddItem($NewItemOrItemId, $NewItemType);
225  $this->OrderList->InsertAfter($TargetItemOrItemId, $NewItemOrItemId,
226  self::GetItemTypeId($TargetItemType),
227  self::GetItemTypeId($NewItemType));
228  }
229 
237  function PrependItem($ItemOrItemId, $ItemType = NULL)
238  {
239  $this->AddItem($ItemOrItemId, $ItemType);
240  $this->OrderList->Prepend($ItemOrItemId, self::GetItemTypeId($ItemType));
241  }
242 
250  function AppendItem($ItemOrItemId, $ItemType = NULL)
251  {
252  $this->AddItem($ItemOrItemId, $ItemType);
253  $this->OrderList->Append($ItemOrItemId, self::GetItemTypeId($ItemType));
254  }
255 
262  function AppendItems($ItemsOrItemIds, $ItemTypes = NULL)
263  {
264  # convert ItemTypes to an array if it wasn't one
265  if (!is_array($ItemTypes))
266  {
267  $NewItemTypes = array();
268  foreach ($ItemsOrItemIds as $Id)
269  {
270  $NewItemTypes[] = $ItemTypes;
271  }
272  $ItemTypes = $NewItemTypes;
273  }
274 
275  # get items ids
276  $ItemIds = array();
277  foreach ($ItemsOrItemIds as $ItemOrId)
278  {
279  $ItemIds[] = is_object($ItemOrId) ? $ItemOrId->Id() : $ItemOrId;
280  }
281 
282  # add all the itmes to our folder
283  foreach ($ItemIds as $Index => $ItemId)
284  {
285  $this->AddItem( $ItemId, $ItemTypes[ $Index ] );
286  }
287 
288  # and add them to our ordering list
289  $this->OrderList->Append($ItemIds, $ItemTypes);
290  }
291 
299  function GetItemIds()
300  {
301  # retrieve item ordered list of type IDs
302  $ItemIds = $this->OrderList->GetIds();
303 
304  # if this is a mixed-item-type folder
305  if ($this->ContentType == self::MIXEDCONTENT)
306  {
307  # convert item type IDs to corresponding type names
308  $NewItemIds = array();
309  foreach ($ItemIds as $ItemInfo)
310  {
311  $NewItemIds[] = array(
312  "ID" => $ItemInfo["ID"],
313  "Type" => self::GetItemTypeName($ItemInfo["Type"]),
314  );
315  }
316  $ItemIds = $NewItemIds;
317  }
318 
319  # return list of item type IDs (and possibly types) to caller
320  return $ItemIds;
321  }
322 
329  function GetItemCount()
330  {
331  return $this->OrderList->GetCount();
332  }
333 
340  function RemoveItem($ItemId, $ItemType = NULL)
341  {
342  # if resource is in folder
343  if ($this->ContainsItem($ItemId, $ItemType))
344  {
345  # remove item from item order
346  $ItemTypeId = self::GetItemTypeId($ItemType);
347  $this->OrderList->Remove($ItemId, $ItemTypeId);
348 
349  # remove resource from folder locally
350  unset($this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)]);
351 
352  # remove resource from folder in DB
353  $this->DB->Query("DELETE FROM FolderItemInts"
354  ." WHERE FolderId = ".intval($this->Id)
355  ." AND ItemId = ".intval($ItemId)
356  ." AND ItemTypeId = ".intval($ItemTypeId));
357  }
358  }
359 
367  function NoteForItem($ItemId, $NewValue = DB_NOVALUE, $ItemType = NULL)
368  {
369  $ItemTypeId = self::GetItemTypeId($ItemType);
370  $Index = self::GetCacheIndex($ItemId, $ItemTypeId);
371  $DummyCache = array("ItemNote" => $this->ItemNoteCache[$Index]);
372 
373  $Value = $this->DB->UpdateValue("FolderItemInts", "ItemNote", $NewValue,
374  "FolderId = ".intval($this->Id)
375  ." AND ItemId = ".intval($ItemId)
376  ." AND ItemTypeId = ".intval($ItemTypeId),
377  $DummyCache);
378 
379  $this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)] = $Value;
380 
381  return $Value;
382  }
383 
390  function ContainsItem($ItemId, $ItemType = NULL)
391  {
392  $ItemTypeId = self::GetItemTypeId($ItemType);
393  return array_key_exists(self::GetCacheIndex($ItemId, $ItemTypeId),
394  $this->ItemNoteCache) ? TRUE : FALSE;
395  }
396 
397  /*@)*/ /* Item Operations */
398 
399  # ---- PRIVATE INTERFACE -------------------------------------------------
400 
401  private $DB;
402  private $Id;
403 
404  # folder attributes - these much match field names in Folders DB table
405  private $OwnerId;
406  private $FolderName;
407  private $NormalizedName;
408  private $FolderNote;
409  private $IsShared;
410  private $ContentType;
411 
412  private $ItemNoteCache;
413  private $OrderList;
414  private $UpdateValueCache;
415 
416  # item type IDs (indexed by normalized type name)
417  static private $ItemTypeIds;
418  # item type names (indexed by type ID)
419  static private $ItemTypeNames;
420 
421  # content type that indicates folder contains mixed content types
422  const MIXEDCONTENT = -1;
423 
431  static function GetItemTypeId($TypeName)
432  {
433  # return "no type" ID if null passed in
434  if ($TypeName === NULL) { return -1; }
435 
436  # make sure item type map is loaded
437  self::LoadItemTypeMap();
438 
439  # normalize item type name
440  $NormalizedTypeName = strtoupper(
441  preg_replace("/[^a-zA-Z0-9]/", "", $TypeName));
442 
443  # if name not already mapped
444  if (!array_key_exists($NormalizedTypeName, self::$ItemTypeIds))
445  {
446  # add name to database
447  if (!isset($DB)) { $DB = new Database(); }
448  $DB->Query("INSERT INTO FolderContentTypes SET"
449  ." TypeName = '".addslashes($TypeName)."',"
450  ." NormalizedTypeName = '".addslashes($NormalizedTypeName)."'");
451 
452  # add name to cached mappings
453  $NewTypeId = $DB->LastInsertId();
454  self::$ItemTypeIds[$NormalizedTypeName] = $NewTypeId;
455  self::$ItemTypeNames[$NewTypeId] = $TypeName;
456  }
457 
458  # return item type ID to caller
459  return self::$ItemTypeIds[$NormalizedTypeName];
460  }
468  private static function GetItemTypeName($TypeId)
469  {
470  # make sure item type map is loaded
471  self::LoadItemTypeMap();
472 
473  # if ID not present in mappings
474  if (!array_key_exists($TypeId, self::$ItemTypeNames))
475  {
476  # return null value
477  return NULL;
478  }
479  else
480  {
481  # return item type name to caller
482  return self::$ItemTypeNames[$TypeId];
483  }
484  }
485 
490  private static function LoadItemTypeMap()
491  {
492  # if name-to-number item type map not already loaded
493  if (!isset(self::$ItemTypeIds))
494  {
495  # load item type map from database
496  $DB = new Database();
497  $DB->Query("SELECT * FROM FolderContentTypes");
498  self::$ItemTypeIds = array();
499  self::$ItemTypeNames = array();
500  while ($Row = $DB->FetchRow())
501  {
502  self::$ItemTypeIds[$Row["NormalizedTypeName"]] = $Row["TypeId"];
503  self::$ItemTypeNames[$Row["TypeId"]] = $Row["TypeName"];
504  }
505  }
506  }
507 
513  private function AddItem($ItemOrItemId, $ItemType)
514  {
515  # convert item to ID if necessary
516  $ItemId = is_object($ItemOrItemId)
517  ? $ItemOrItemId->Id() : $ItemOrItemId;
518 
519  # convert item type to item type ID
520  $ItemTypeId = self::GetItemTypeId($ItemType);
521 
522  # convert null item type to "no type" value used in database
523  if ($ItemTypeId === NULL) { $ItemTypeId = -1; }
524 
525  # if resource is not already in folder
526  if (!$this->ContainsItem($ItemId, $ItemType))
527  {
528  # add resource to folder locally
529  $this->ItemNoteCache[self::GetCacheIndex($ItemId, $ItemTypeId)] = NULL;
530 
531  # add resource to folder in DB
532  $this->DB->Query("INSERT INTO FolderItemInts SET"
533  ." FolderId = ".intval($this->Id)
534  .", ItemId = ".intval($ItemId)
535  .", ItemTypeId = ".intval($ItemTypeId));
536  }
537  }
538 
545  private static function GetCacheIndex($ItemId, $ItemTypeId)
546  {
547  $ItemTypeId = ($ItemTypeId === NULL) ? -1 : $ItemTypeId;
548  return intval($ItemTypeId).":".intval($ItemId);
549  }
550 
558  private function UpdateValue($FieldName, $NewValue)
559  {
560  $this->$FieldName = $this->DB->UpdateValue("Folders", $FieldName, $NewValue,
561  "FolderId = ".$this->Id, $this->UpdateValueCache);
562  return $this->$FieldName;
563  }
564 }
NormalizedName($NewValue=DB_NOVALUE)
Get/set normalized version of folder name.
Definition: Folder.php:131
const MIXEDCONTENT
Definition: Folder.php:422
AppendItem($ItemOrItemId, $ItemType=NULL)
Add item to folder as the last item.
Definition: Folder.php:250
NoteForItem($ItemId, $NewValue=DB_NOVALUE, $ItemType=NULL)
Get/set note text for specific item within folder.
Definition: Folder.php:367
Id()
Get folder ID.
Definition: Folder.php:105
SQL database abstraction object with smart query caching.
IsShared($NewValue=DB_NOVALUE)
Get/set whether folder is publically-viewable.
Definition: Folder.php:159
const DB_NOVALUE
GetItemIds()
Retrieve array of IDs of items in folder, in the order that they appear in the folder.
Definition: Folder.php:299
Factory object for Folder class, used to retrieve and manage Folders and groups of Folders...
Folder object used to create and manage groups of items.
Definition: Folder.php:17
RemoveItem($ItemId, $ItemType=NULL)
Remove item from folder, if present.
Definition: Folder.php:340
static NormalizeFolderName($Name)
Convert folder name to normalized form (lower-case alphanumeric only).
Definition: Folder.php:148
InsertItemAfter($TargetItemOrItemId, $NewItemOrItemId, $TargetItemType=NULL, $NewItemType=NULL)
Insert item into folder after specified item.
Definition: Folder.php:221
Note($NewValue=DB_NOVALUE)
Get/set note text for folder.
Definition: Folder.php:180
GetItemCount()
Get number of items in folder.
Definition: Folder.php:329
AppendItems($ItemsOrItemIds, $ItemTypes=NULL)
Add multiple items to the folder at the end.
Definition: Folder.php:262
static GetItemTypeId($TypeName)
Definition: Folder.php:431
ContainsItem($ItemId, $ItemType=NULL)
Check whether specified item is contained in folder.
Definition: Folder.php:390
Folder($FolderId)
Object constructor – load an existing folder.
Definition: Folder.php:28
InsertItemBefore($TargetItemOrItemId, $NewItemOrItemId, $TargetItemType=NULL, $NewItemType=NULL)
Insert item into folder before specified item.
Definition: Folder.php:201
Persistent doubly-linked-list data structure, with its data stored in a specified database table...
OwnerId($NewValue=DB_NOVALUE)
Get/set user ID of folder owner.
Definition: Folder.php:169
Delete()
Delete folder.
Definition: Folder.php:84
PrependItem($ItemOrItemId, $ItemType=NULL)
Add item to folder as the first item.
Definition: Folder.php:237
Name($NewValue=DB_NOVALUE)
Get/set folder name.
Definition: Folder.php:115