ObjectComparator.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\persistence;
12 
15 
16 /**
17  * ObjectComparator is used to compare persistent objects by given criterias.
18  *
19  * The following example shows the usage:
20  *
21  * @code
22  * $objectList = [...]; // array of PersistentObject instances
23  *
24  * // simple sort by creator attribute
25  * $comparator = new ObjectComparator('creator');
26  * usort($objectList, [$comparator, 'compare']);
27  *
28  * // sort by creator attribute with direction
29  * $comparator = new ObjectComparator('creator DESC');
30  * usort($objectList, [$comparator, 'compare']);
31  *
32  * // sort by multiple attributes with direction
33  * $comparator = new ObjectComparator(['creator DESC', 'created ASC']);
34  * usort($objectList, [$comparator, 'compare']);
35  *
36  * // more complex example with different attributes
37  * $sortCriteria = [
38  * ObjectComparator::ATTRIB_TYPE => ObjectComparator::SORTTYPE_ASC,
39  * 'created' => ObjectComparator::SORTTYPE_DESC
40  * ];
41  * $comparator = new ObjectComparator($sortCriteria);
42  * usort($objectList, [$comparator, 'compare']);
43  * @endcode
44  *
45  * @author ingo herwig <ingo@wemove.com>
46  */
48 
49  const SORTTYPE_ASC = -1; // sort children ascending
50  const SORTTYPE_DESC = -2; // sort children descending
51  const ATTRIB_OID = -3; // sort by oid
52  const ATTRIB_TYPE = -4; // sort by type
53 
54  private $sortCriteria = [];
55 
56  /**
57  * Constructor
58  * @param $sortCriteria An assoziative array of criteria - SORTTYPE constant pairs OR a single criteria string.
59  * possible criteria: ObjectComparator::OID, ObjectComparator::TYPE or any value/property name with optionally ASC or DESC appended
60  * (e.g. [ObjectComparator::OID => ObjectComparator::SORTTYPE_ASC, 'name' => ObjectComparator::SORTTYPE_DESC] OR 'name')
61  * @note If criteria is only a string we will sort by this criteria with ObjectComparator::SORTTYPE_ASC
62  */
63  public function __construct($sortCriteria) {
64  // build criteria array
65  $criteria = !is_array($sortCriteria) ? [$sortCriteria] : $sortCriteria;
66  foreach ($criteria as $attribute => $direction) {
67  if (is_int($attribute) && $attribute >= 0) {
68  // indexed array of attributes
69  $attrDir = explode(' ', $direction);
70  $attribute = $attrDir[0];
71  $direction = sizeof($attrDir) == 1 ? self::SORTTYPE_ASC :
72  (strtoupper(trim($attrDir[1])) == 'DESC' ? self::SORTTYPE_DESC : self::SORTTYPE_ASC);
73  }
74  $this->sortCriteria[trim($attribute)] = $direction;
75  }
76  }
77 
78  /**
79  * Compare function for sorting PersitentObject instances by the list of criterias
80  * @param $a First PersitentObject instance
81  * @param $b First PersitentObject instance
82  * @return -1, 0 or 1 whether a is less, equal or greater than b
83  * in respect of the criteria
84  */
85  public function compare(PersistentObject $a, PersistentObject $b) {
86  // we compare for each criteria and sum the results for $a, $b
87  // afterwards we compare the sums and return -1,0,1 appropriate
88  $sumA = 0;
89  $sumB = 0;
90  $maxWeight = sizeOf($this->sortCriteria);
91  $i = 0;
92  foreach ($this->sortCriteria as $criteria => $sortType) {
93  $weightedValue = ($maxWeight-$i)*($maxWeight-$i);
94  $aGreaterB = 0;
95  // sort by id
96  if ($criteria == self::ATTRIB_OID) {
97  if ($a->getOID() != $b->getOID()) {
98  ($a->getOID() > $b->getOID()) ? $aGreaterB = 1 : $aGreaterB = -1;
99  }
100  }
101  // sort by type
102  else if ($criteria == self::ATTRIB_TYPE) {
103  if ($a->getType() != $b->getType()) {
104  ($a->getType() > $b->getType()) ? $aGreaterB = 1 : $aGreaterB = -1;
105  }
106  }
107  // sort by value
108  else if($a->getValue($criteria) != null || $b->getValue($criteria) != null) {
109  $aValue = strToLower($a->getValue($criteria));
110  $bValue = strToLower($b->getValue($criteria));
111  if ($aValue != $bValue) {
112  ($aValue > $bValue) ? $aGreaterB = 1 : $aGreaterB = -1;
113  }
114  }
115  // sort by property
116  else if($a->getProperty($criteria) != null || $b->getProperty($criteria) != null) {
117  $aProperty = strToLower($a->getProperty($criteria));
118  $bProperty = strToLower($b->getProperty($criteria));
119  if ($aProperty != $bProperty) {
120  ($aProperty > $bProperty) ? $aGreaterB = 1 : $aGreaterB = -1;
121  }
122  }
123  // calculate result of current criteria depending on current sorttype
124  if ($sortType == self::SORTTYPE_ASC) {
125  if ($aGreaterB == 1) { $sumA += $weightedValue; }
126  else if ($aGreaterB == -1) { $sumB += $weightedValue; }
127  }
128  else if ($sortType == self::SORTTYPE_DESC) {
129  if ($aGreaterB == 1) { $sumB += $weightedValue; }
130  else if ($aGreaterB == -1) { $sumA += $weightedValue; }
131  }
132  else {
133  throw new IllegalArgumentException("Unknown SORTTYPE.");
134  }
135  $i++;
136  }
137  if ($sumA == $sumB) { return 0; }
138  return ($sumA > $sumB) ? 1 : -1;
139  }
140 }
141 ?>
getType()
Get the type of the object.
getOID()
Get the object id of the PersistentObject.
Persistence layer related interfaces and classes.
Definition: namespaces.php:42
compare(PersistentObject $a, PersistentObject $b)
Compare function for sorting PersitentObject instances by the list of criterias.
IllegalArgumentException signals an exception in method arguments.
getValue($name)
Get the value of an attribute.
__construct($sortCriteria)
Constructor.
PersistentObject defines the interface of all persistent objects.
getProperty($name)
Get the value of a named property in the object.
ObjectComparator is used to compare persistent objects by given criterias.