CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

Classification.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: Classification.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2002-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9
13 class Classification extends Item
14 {
15 # ---- PUBLIC INTERFACE --------------------------------------------------
16
18 const NOPARENT = -1;
19
31 public static function Create($Name, $FieldId, $ParentId = NULL)
32 {
33 static $IdCache;
34
35 # initialize state for creation
36 self::$SegmentsCreated = 0;
37
38 # if parent class supplied
39 $DB = new Database();
40 if ($ParentId !== NULL)
41 {
42 # error out if parent ID is invalid
43 if ($ParentId != self::NOPARENT)
44 {
45 if ($DB->Query("SELECT COUNT(*) AS NumberFound"
46 ." FROM Classifications"
47 ." WHERE ClassificationId = ".intval($ParentId),
48 "NumberFound") < 1)
49 {
50 throw new InvalidArgumentException("Invalid parent ID"
51 ." specified (".$ParentId.").");
52 }
53 }
54
55 # error out if name already exists
56 $Name = trim($Name);
57 $Count = $DB->Query("SELECT COUNT(*) AS NumberFound"
58 ." FROM Classifications"
59 ." WHERE ParentId = ".intval($ParentId)
60 ." AND FieldId = ".intval($FieldId)
61 ." AND LOWER(SegmentName) = '"
62 .addslashes(strtolower($Name))."'",
63 "NumberFound");
64 if ($Count > 0)
65 {
66 throw new Exception("Duplicate name specified for"
67 ." new classification (".$Name.").");
68 }
69
70 # determine full name and depth for new classification
71 if ($ParentId == self::NOPARENT)
72 {
73 $NewName = $Name;
74 $NewDepth = 0;
75 }
76 else
77 {
78 $DB->Query("SELECT ClassificationName, Depth"
79 ." FROM Classifications"
80 ." WHERE ClassificationId = ".intval($ParentId));
81 $ParentInfo = $DB->FetchRow();
82 $NewName = $ParentInfo["ClassificationName"]." -- ".$Name;
83 $NewDepth = $ParentInfo["Depth"] + 1;
84 }
85
86 # add classification to database
87 $InitialValues = array(
88 "FieldId" => $FieldId,
89 "ParentId" => $ParentId,
90 "SegmentName" => $Name,
91 "ResourceCount" => 0,
92 "Depth" => $NewDepth,
93 "ClassificationName" => $NewName);
94 $NewItem = parent::CreateWithValues($InitialValues);
95 }
96 else
97 {
98 # parse classification name into separate segments
99 $Segments = preg_split("/--/", $Name);
100
101 # start out with top as parent
102 $ParentId = self::NOPARENT;
103
104 # start off assuming we won't create anything
105 $NewItem = NULL;
106
107 # for each segment
108 $CurrentDepth = -1;
109 $CurrentFullName = "";
110 foreach ($Segments as $Segment)
111 {
112 # track segment depth and full classification name for use
113 # in adding new entries
114 $Segment = trim($Segment);
115 $CurrentDepth++;
116 $CurrentFullName .= (($CurrentFullName == "") ? "" : " -- ").$Segment;
117
118 # if we have added classifications
119 $Segment = addslashes($Segment);
120 if (self::$SegmentsCreated)
121 {
122 # we know that current segment will not be found
123 $ClassId = NULL;
124 }
125 else
126 {
127 # look up classification with current parent and segment name
128 if (!isset($IdCache[$FieldId][$ParentId][$Segment]))
129 {
130 if ($ParentId == self::NOPARENT)
131 {
132 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
133 "SELECT ClassificationId FROM Classifications"
134 ." WHERE ParentId = ".self::NOPARENT
135 ." AND SegmentName = '".addslashes($Segment)."'"
136 ." AND FieldId = ".intval($FieldId),
137 "ClassificationId");
138 }
139 else
140 {
141 $IdCache[$FieldId][$ParentId][$Segment] = $DB->Query(
142 "SELECT ClassificationId FROM Classifications "
143 ."WHERE ParentId = ".intval($ParentId)
144 ." AND SegmentName = '".addslashes($Segment)."'",
145 "ClassificationId");
146 }
147 }
148 $ClassId = $IdCache[$FieldId][$ParentId][$Segment];
149 }
150
151 # if classification not found
152 if ($ClassId === NULL)
153 {
154 # add new classification
155 $InitialValues = array(
156 "FieldId" => $FieldId,
157 "ParentId" => $ParentId,
158 "SegmentName" => $Segment,
159 "ResourceCount" => 0,
160 "Depth" => $CurrentDepth,
161 "ClassificationName" => $CurrentFullName);
162 $NewItem = parent::CreateWithValues($InitialValues);
163 $ClassId = $NewItem->Id();
164 $IdCache[$FieldId][$ParentId][$Segment] = $ClassId;
165
166 # track total number of new classification segments created
167 self::$SegmentsCreated++;
168 }
169
170 # set parent to created or found class
171 $ParentId = $ClassId;
172 }
173
174 # if it wasn't actually necessary to create anything
175 if ($NewItem === NULL)
176 {
177 throw new Exception(
178 "Duplicate name specified for"
179 ." new classification (".$Name.").");
180 }
181 }
182
183 # return new classification to caller
184 return new self($NewItem->Id());
185 }
186
191 public function Id()
192 {
193 return $this->Id;
194 }
195
200 public function FullName()
201 {
202 return $this->ValueCache["ClassificationName"];
203 }
204
211 public function Name($NewValue = DB_NOVALUE)
212 {
213 if ($NewValue !== DB_NOVALUE)
214 {
215 throw new InvalidArgumentException("Illegal argument supplied.");
216 }
217 return $this->FullName();
218 }
219
224 public function VariantName()
225 {
226 return NULL;
227 }
228
233 public function Depth()
234 {
235 return $this->ValueCache["Depth"];
236 }
237
243 public function ResourceCount()
244 {
245 return $this->ValueCache["ResourceCount"];
246 }
247
254 public function FullResourceCount()
255 {
256 return $this->ValueCache["FullResourceCount"];
257 }
258
263 public static function SegmentsCreated()
264 {
265 return self::$SegmentsCreated;
266 }
267
272 public function ParentId()
273 {
274 return $this->ValueCache["ParentId"];
275 }
276
282 public function SegmentName($NewValue = DB_NOVALUE)
283 {
284 return $this->UpdateValue("SegmentName", $NewValue);
285 }
286
294 public function LinkString($NewValue = DB_NOVALUE)
295 {
296 return $this->UpdateValue("LinkString", $NewValue);
297 }
298
305 public function QualifierId($NewValue = DB_NOVALUE)
306 {
307 return $this->UpdateValue("QualifierId", $NewValue);
308 }
309
315 public function FieldId($NewValue = DB_NOVALUE)
316 {
317 return $this->UpdateValue("FieldId", $NewValue);
318 }
319
326 public function Qualifier($NewValue = DB_NOVALUE)
327 {
328 # if new qualifier supplied
329 if ($NewValue !== DB_NOVALUE)
330 {
331 # set new qualifier ID
332 $this->QualifierId($NewValue->Id());
333
334 # use new qualifier for return value
335 $Qualifier = $NewValue;
336 }
337 else
338 {
339 # if qualifier is available
340 if (($this->QualifierId() !== NULL)
341 && Qualifier::ItemExists($this->QualifierId()))
342 {
343 # create qualifier object using stored ID
344 $Qualifier = new Qualifier($this->QualifierId());
345 }
346 else
347 {
348 # return NULL to indicate no qualifier
349 $Qualifier = NULL;
350 }
351 }
352
353 # return qualifier to caller
354 return $Qualifier;
355 }
356
362 public function RecalcDepthAndFullName()
363 {
364 # start with full classification name set to our segment name
365 $FullClassName = $this->ValueCache["SegmentName"];
366
367 # assume to begin with that we're at the top of the hierarchy
368 $Depth = 0;
369
370 # while parent available
371 $ParentId = $this->ValueCache["ParentId"];
372 while ($ParentId != self::NOPARENT)
373 {
374 # retrieve classification information
375 $this->DB->Query("SELECT SegmentName, ParentId "
376 ."FROM Classifications "
377 ."WHERE ClassificationId=".$ParentId);
378 $Record = $this->DB->FetchRow();
379
380 # prepend segment name to full classification name
381 $FullClassName = $Record["SegmentName"]." -- ".$FullClassName;
382
383 # increment depth value
384 $Depth++;
385
386 # move to parent of current classification
387 $ParentId = $Record["ParentId"];
388 }
389
390 # for each child
391 $this->DB->Query("SELECT ClassificationId FROM Classifications"
392 ." WHERE ParentId = ".intval($this->Id));
393 while ($Record = $this->DB->FetchRow())
394 {
395 # perform depth and name recalc
396 $Child = new Classification($Record["ClassificationId"]);
397 $Child->RecalcDepthAndFullName();
398 }
399
400 # save new depth and full classification name
401 $this->UpdateValue("Depth", $Depth);
402 $this->UpdateValue("ClassificationName", $FullClassName);
403 }
404
408 public function UpdateLastAssigned()
409 {
410 $this->DB->Query("UPDATE Classifications SET LastAssigned=NOW() "
411 ."WHERE ClassificationId=".intval($this->Id));
412 }
413
421 public function RecalcResourceCount($IdsToSkip = NULL)
422 {
423 $IdsUpdated = array();
424
425 # if we don't have a skip list or we aren't in the skip list
426 if (!$IdsToSkip || !in_array($this->Id, $IdsToSkip))
427 {
428 # retrieve new count of resources directly associated with class
429 $this->DB->Query("SELECT R.ResourceId AS ResourceId, SchemaId"
430 ." FROM ResourceClassInts RCI, Resources R"
431 ." WHERE RCI.ClassificationId=".intval($this->Id)
432 ." AND RCI.ResourceId = R.ResourceId"
433 ." AND R.ResourceId > 0");
434
435 # pull out resources and bin them by schema
436 $Resources = array();
437 while ($Row = $this->DB->FetchRow())
438 {
439 $Resources[$Row["SchemaId"]][]= $Row["ResourceId"];
440 }
441
442 # filter out non-viewable resources from each schema
443 foreach ($Resources as $SchemaId => $ResourceIds)
444 {
445 $RFactory = new ResourceFactory($SchemaId);
446 $Resources[$SchemaId] = $RFactory->FilterNonViewableResources(
447 $ResourceIds, CWUser::GetAnonymousUser());
448 }
449
450 # total up resources from each schema
451 $ResourceCount = 0;
452 foreach ($Resources as $SchemaId => $ResourceIds)
453 {
454 $ResourceCount += count($ResourceIds);
455 }
456
457 # add on resources associated with all children
458 $ResourceCount += $this->DB->Query(
459 "SELECT SUM(ResourceCount) AS ResourceCountTotal "
460 ."FROM Classifications "
461 ."WHERE ParentId = ".intval($this->Id),
462 "ResourceCountTotal");
463
464 # save new count
465 $this->UpdateValue("ResourceCount", $ResourceCount);
466
467 # add our ID to list of IDs that have been recalculated
468 $IdsUpdated[] = $this->Id;
469 }
470
471 # update resource count for our parent (if any)
472 if (($this->ValueCache["ParentId"] != self::NOPARENT)
473 && (!$IdsToSkip || !in_array($this->ValueCache["ParentId"], $IdsToSkip)) )
474 {
475 $Class = new Classification($this->ValueCache["ParentId"]);
476 $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
477 }
478
479 # retrieve new count of all resources directly associated with class
480 $FullCount = $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
481 ." FROM ResourceClassInts I, Resources R"
482 ." WHERE I.ClassificationId = ".intval($this->Id)
483 ." AND R.ResourceId > 0"
484 ." AND I.ResourceId = R.ResourceId",
485 "ResourceCount");
486
487 # add on resources associated with all children
488 $FullCount += $this->DB->Query(
489 "SELECT SUM(ResourceCount) AS ResourceCountTotal"
490 ." FROM Classifications"
491 ." WHERE ParentId = ".intval($this->Id),
492 "ResourceCountTotal");
493
494 # save new full count
495 $this->UpdateValue("FullResourceCount", $ResourceCount);
496
497 # return list of IDs of updated classifications to caller
498 return $IdsUpdated;
499 }
500
505 public function ChildCount()
506 {
507 # return count of classifications that have this one as parent
508 return $this->DB->Query("SELECT COUNT(*) AS ClassCount "
509 ."FROM Classifications "
510 ."WHERE ParentId=".intval($this->Id),
511 "ClassCount");
512 }
513
519 public function ChildList()
520 {
521 $ChildList = array();
522
523 $this->DB->Query("SELECT ClassificationId "
524 ."FROM Classifications "
525 ."WHERE ParentId=".intval($this->Id));
526
527 while ($Entry = $this->DB->FetchRow())
528 {
529 $ChildList[] = $Entry["ClassificationId"];
530 $Child = new Classification($Entry["ClassificationId"]);
531 if($Child->ChildCount() > 0)
532 {
533 $GrandChildList = $Child->ChildList();
534 $ChildList = array_merge($GrandChildList, $ChildList);
535 }
536 }
537 return array_unique($ChildList);
538 }
539
553 public function Delete($DeleteParents = FALSE,
554 $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
555 {
556 # if no resources or okay to delete with resources
557 # and no children or okay to delete with children
558 $DeleteCount = 0;
559 if (($DeleteIfHasResources || ($this->ResourceCount() == 0))
560 && ($DeleteIfHasChildren || ($this->ChildCount() == 0)))
561 {
562 if ($this->ResourceCount() != 0)
563 {
564 $this->DB->Query("DELETE FROM ResourceClassInts"
565 ." WHERE ClassificationId = ".intval($this->Id));
566 $this->RecalcResourceCount();
567 }
568
569 # delete this classification
570 parent::Delete();
571 $DeleteCount++;
572
573 # delete parent classification (if requested)
574 $ParentId = $this->ValueCache["ParentId"];
575 if (($DeleteParents) && ($ParentId != self::NOPARENT))
576 {
577 $Parent = new Classification($ParentId);
578 $DeleteCount += $Parent->Delete(
579 TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
580 }
581 }
582
583 # return total number of classifications deleted to caller
584 return $DeleteCount;
585 }
586
587
588 # ---- PRIVATE INTERFACE -------------------------------------------------
589
590 static private $SegmentsCreated;
591 }
Classification\LinkString
LinkString($NewValue=DB_NOVALUE)
Get or set the stored link string for the Classification.
Definition: Classification.php:294
User\GetAnonymousUser
static GetAnonymousUser()
Get the anonymous user (i.e., the User object that exists when no user is logged in), useful when a permission check needs to know if something should be visible to the general public.
Definition: User.php:948
Classification\SegmentsCreated
static SegmentsCreated()
Get number of new segments (Classifications) generated when creating a new Classification with a full...
Definition: Classification.php:263
Classification\FullName
FullName()
Get full classification name (all segments).
Definition: Classification.php:200
Classification\FullResourceCount
FullResourceCount()
Get number of all resources (minus temporary ones) having this classification assigned to them...
Definition: Classification.php:254
Item\UpdateValue
UpdateValue($ColumnName, $NewValue=DB_NOVALUE)
Convenience function to supply parameters to Database::UpdateValue().
Definition: Item.php:285
Database
SQL database abstraction object with smart query caching.
Definition: Database.php:22
Classification\Create
static Create($Name, $FieldId, $ParentId=NULL)
Add new classification to the hierarchy.
Definition: Classification.php:31
Classification\FieldId
FieldId($NewValue=DB_NOVALUE)
Get or set the ID of the MetadataField for the Classification.
Definition: Classification.php:315
Classification\VariantName
VariantName()
Get variant name of classification, if any.
Definition: Classification.php:224
Item\$DB
$DB
Definition: Item.php:210
Classification\Qualifier
Qualifier($NewValue=DB_NOVALUE)
Get or set the Qualifier associated with the Classification.
Definition: Classification.php:326
Classification\ChildCount
ChildCount()
Get number of classifications that have this Classification as their direct parent.
Definition: Classification.php:505
Classification\RecalcResourceCount
RecalcResourceCount($IdsToSkip=NULL)
Recalculate number of resources assigned to class and any parent classes.
Definition: Classification.php:421
Classification\NOPARENT
const NOPARENT
Parent value for classifications with no parent.
Definition: Classification.php:18
Classification\ParentId
ParentId()
Get ID of parent Classification.
Definition: Classification.php:272
Classification\RecalcDepthAndFullName
RecalcDepthAndFullName()
Rebuild classification full name and recalculate depth in hierarchy.
Definition: Classification.php:362
PHP
PHP
Definition: RSSClient--Test.php:12
Item
Common base class for persistent items store in database.
Definition: Item.php:13
DB_NOVALUE
const DB_NOVALUE
Definition: Database.php:1784
Classification\Depth
Depth()
Get depth of classification in hierarchy.
Definition: Classification.php:233
Classification\Name
Name($NewValue=DB_NOVALUE)
Get full classification name (all segments).
Definition: Classification.php:211
Classification\ResourceCount
ResourceCount()
Get number of released resources having this classification assigned to them.
Definition: Classification.php:243
Item\$Id
$Id
Definition: Item.php:211
Classification\Delete
Delete($DeleteParents=FALSE, $DeleteIfHasResources=FALSE, $DeleteIfHasChildren=FALSE)
Remove Classification (and accompanying associations) from database.
Definition: Classification.php:553
Classification\UpdateLastAssigned
UpdateLastAssigned()
Update the LastAssigned timestamp for this classification.
Definition: Classification.php:408
Classification
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
Definition: Classification.php:13
Item\ItemExists
static ItemExists($Id)
Check whether an item exists with the specified ID.
Definition: Item.php:162
ResourceFactory
Factory for Resource objects.
Definition: ResourceFactory.php:13
Classification\QualifierId
QualifierId($NewValue=DB_NOVALUE)
Get or set the Qualifier associated with the Classification by ID.
Definition: Classification.php:305
Classification\ChildList
ChildList()
Get list of IDs of Classifications that have this class as an "ancestor" (parent, grandparent...
Definition: Classification.php:519
Classification\SegmentName
SegmentName($NewValue=DB_NOVALUE)
Get or set the segment name.
Definition: Classification.php:282
Classification\Id
Id()
Get Classification ID.
Definition: Classification.php:191