CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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 ?>