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 {
342 # create qualifier object using stored ID
343 $Qualifier = new Qualifier($this->QualifierId());
344 }
345 else
346 {
347 # return NULL to indicate no qualifier
348 $Qualifier = NULL;
349 }
350 }
351
352 # return qualifier to caller
353 return $Qualifier;
354 }
355
361 public function RecalcDepthAndFullName()
362 {
363 # start with full classification name set to our segment name
364 $FullClassName = $this->ValueCache["SegmentName"];
365
366 # assume to begin with that we're at the top of the hierarchy
367 $Depth = 0;
368
369 # while parent available
370 $ParentId = $this->ValueCache["ParentId"];
371 while ($ParentId != self::NOPARENT)
372 {
373 # retrieve classification information
374 $this->DB->Query("SELECT SegmentName, ParentId "
375 ."FROM Classifications "
376 ."WHERE ClassificationId=".$ParentId);
377 $Record = $this->DB->FetchRow();
378
379 # prepend segment name to full classification name
380 $FullClassName = $Record["SegmentName"]." -- ".$FullClassName;
381
382 # increment depth value
383 $Depth++;
384
385 # move to parent of current classification
386 $ParentId = $Record["ParentId"];
387 }
388
389 # for each child
390 $this->DB->Query("SELECT ClassificationId FROM Classifications"
391 ." WHERE ParentId = ".intval($this->Id));
392 while ($Record = $this->DB->FetchRow())
393 {
394 # perform depth and name recalc
395 $Child = new Classification($Record["ClassificationId"]);
396 $Child->RecalcDepthAndFullName();
397 }
398
399 # save new depth and full classification name
400 $this->UpdateValue("Depth", $Depth);
401 $this->UpdateValue("ClassificationName", $FullClassName);
402 }
403
407 public function UpdateLastAssigned()
408 {
409 $this->DB->Query("UPDATE Classifications SET LastAssigned=NOW() "
410 ."WHERE ClassificationId=".intval($this->Id));
411 }
412
420 public function RecalcResourceCount($IdsToSkip = NULL)
421 {
422 $IdsUpdated = array();
423
424 # if we don't have a skip list or we aren't in the skip list
425 if (!$IdsToSkip || !in_array($this->Id, $IdsToSkip))
426 {
427 # retrieve new count of resources directly associated with class
428 $this->DB->Query("SELECT R.ResourceId AS ResourceId, SchemaId"
429 ." FROM ResourceClassInts RCI, Resources R"
430 ." WHERE RCI.ClassificationId=".intval($this->Id)
431 ." AND RCI.ResourceId = R.ResourceId"
432 ." AND R.ResourceId > 0");
433
434 # pull out resources and bin them by schema
435 $Resources = array();
436 while ($Row = $this->DB->FetchRow())
437 {
438 $Resources[$Row["SchemaId"]][]= $Row["ResourceId"];
439 }
440
441 # filter out non-viewable resources from each schema
442 foreach ($Resources as $SchemaId => $ResourceIds)
443 {
444 $RFactory = new ResourceFactory($SchemaId);
445 $Resources[$SchemaId] = $RFactory->FilterNonViewableResources(
446 $ResourceIds, CWUser::GetAnonymousUser());
447 }
448
449 # total up resources from each schema
450 $ResourceCount = 0;
451 foreach ($Resources as $SchemaId => $ResourceIds)
452 {
453 $ResourceCount += count($ResourceIds);
454 }
455
456 # add on resources associated with all children
457 $ResourceCount += $this->DB->Query(
458 "SELECT SUM(ResourceCount) AS ResourceCountTotal "
459 ."FROM Classifications "
460 ."WHERE ParentId = ".intval($this->Id),
461 "ResourceCountTotal");
462
463 # save new count
464 $this->UpdateValue("ResourceCount", $ResourceCount);
465
466 # add our ID to list of IDs that have been recalculated
467 $IdsUpdated[] = $this->Id;
468 }
469
470 # update resource count for our parent (if any)
471 if (($this->ValueCache["ParentId"] != self::NOPARENT)
472 && (!$IdsToSkip || !in_array($this->ValueCache["ParentId"], $IdsToSkip)) )
473 {
474 $Class = new Classification($this->ValueCache["ParentId"]);
475 $IdsUpdated = array_merge($IdsUpdated, $Class->RecalcResourceCount());
476 }
477
478 # retrieve new count of all resources directly associated with class
479 $FullCount = $this->DB->Query("SELECT COUNT(*) AS ResourceCount"
480 ." FROM ResourceClassInts I, Resources R"
481 ." WHERE I.ClassificationId = ".intval($this->Id)
482 ." AND R.ResourceId > 0"
483 ." AND I.ResourceId = R.ResourceId",
484 "ResourceCount");
485
486 # add on resources associated with all children
487 $FullCount += $this->DB->Query(
488 "SELECT SUM(ResourceCount) AS ResourceCountTotal"
489 ." FROM Classifications"
490 ." WHERE ParentId = ".intval($this->Id),
491 "ResourceCountTotal");
492
493 # save new full count
494 $this->UpdateValue("FullResourceCount", $ResourceCount);
495
496 # return list of IDs of updated classifications to caller
497 return $IdsUpdated;
498 }
499
504 public function ChildCount()
505 {
506 # return count of classifications that have this one as parent
507 return $this->DB->Query("SELECT COUNT(*) AS ClassCount "
508 ."FROM Classifications "
509 ."WHERE ParentId=".intval($this->Id),
510 "ClassCount");
511 }
512
518 public function ChildList()
519 {
520 $ChildList = array();
521
522 $this->DB->Query("SELECT ClassificationId "
523 ."FROM Classifications "
524 ."WHERE ParentId=".intval($this->Id));
525
526 while ($Entry = $this->DB->FetchRow())
527 {
528 $ChildList[] = $Entry["ClassificationId"];
529 $Child = new Classification($Entry["ClassificationId"]);
530 if($Child->ChildCount() > 0)
531 {
532 $GrandChildList = $Child->ChildList();
533 $ChildList = array_merge($GrandChildList, $ChildList);
534 }
535 }
536 return array_unique($ChildList);
537 }
538
552 public function Delete($DeleteParents = FALSE,
553 $DeleteIfHasResources = FALSE, $DeleteIfHasChildren = FALSE)
554 {
555 # if no resources or okay to delete with resources
556 # and no children or okay to delete with children
557 $DeleteCount = 0;
558 if (($DeleteIfHasResources || ($this->ResourceCount() == 0))
559 && ($DeleteIfHasChildren || ($this->ChildCount() == 0)))
560 {
561 if ($this->ResourceCount() != 0)
562 {
563 $this->DB->Query("DELETE FROM ResourceClassInts"
564 ." WHERE ClassificationId = ".intval($this->Id));
565 $this->RecalcResourceCount();
566 }
567
568 # delete this classification
569 parent::Delete();
570 $DeleteCount++;
571
572 # delete parent classification (if requested)
573 $ParentId = $this->ValueCache["ParentId"];
574 if (($DeleteParents) && ($ParentId != self::NOPARENT))
575 {
576 $Parent = new Classification($ParentId);
577 $DeleteCount += $Parent->Delete(
578 TRUE, $DeleteIfHasResources, $DeleteIfHasChildren);
579 }
580 }
581
582 # return total number of classifications deleted to caller
583 return $DeleteCount;
584 }
585
586
587 # ---- PRIVATE INTERFACE -------------------------------------------------
588
589 static private $SegmentsCreated;
590 }
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:1038
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:262
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:188
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:504
Classification\RecalcResourceCount
RecalcResourceCount($IdsToSkip=NULL)
Recalculate number of resources assigned to class and any parent classes.
Definition: Classification.php:420
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:361
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:1706
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:189
Classification\Delete
Delete($DeleteParents=FALSE, $DeleteIfHasResources=FALSE, $DeleteIfHasChildren=FALSE)
Remove Classification (and accompanying associations) from database.
Definition: Classification.php:552
Classification\UpdateLastAssigned
UpdateLastAssigned()
Update the LastAssigned timestamp for this classification.
Definition: Classification.php:407
Classification
Metadata type representing hierarchical ("Tree") controlled vocabulary values.
Definition: Classification.php:13
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:518
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