I want to share with you a code that i have written to sort an Array of objects with multi-criteria
Example is a good teacher :
Example is a good teacher :
<?php
class User {
private $name; private $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } public function getName() { return $this->name; } public function getAge() { return $this->age; } } ?>
<?php $users = array(new User('Denis' , 25), new User('Anis' , 29), new User('Anis' , 26), new User('Nikita', 15), new User('Zelda' , 34), new User('Zelda' , 90)); // to sort your array based on name with ASC Order // 1st : Create the search criteria // the first parameter must be the getter, second : order by ASC or DSC, third the type of your data $criteria_1 = new Criteria ('getName', Criteria::_SORT_ASC, Criteria::_SORT_STRING); // create the sorter object. Note that the second parameter must be an array $sortObject = new SortObjectArray($users, array($criteria_1)); var_dump ($sortObject->getSortedObjectArray()); // Using Multi-Criteria (like ORDER BY NAME, AGE in SQL)Here the source code
$criteria_2 = new Criteria ('getAge', Criteria::_SORT_DSC, Criteria::_SORT_INTEGER); $sortObject = new SortObjectArray($users, array($criteria_1, $criteria_2)); var_dump ($sortObject->getSortedObjectArray());
class Criteria { const _SORT_INTEGER = 1; const _SORT_FLOAT = 2; const _SORT_STRING = 3; const _SORT_ASC = 1; const _SORT_DSC = 2; private $sortType; private $sortCriteria; private $sortOrder; private $strict; public function __construct($sortCriteria, $sortOrder, $sortType, $strict = FALSE) { $this->setSortCriteria($sortCriteria); $this->setSortOrder($sortOrder); $this->setSortType($sortType); $this->setStrict($strict); } public function setStrict($strict) { if(!is_bool($strict)) { throw new Exception("parameter must be a boolean"); } $this->strict = $strict; } public function isStrict() { return $this->strict; } public function getSortType() { return $this->sortType; } /** * the primitive type variables that will be used for sorting * @param1 sortType integer, must be on of (_SORT_INTEGER|_SORT_FLOAT|_SORT_STRING) * @throws Exception */ public function setSortType($sortType) { if(is_null($sortType)) { throw new Exception("MANDATORY_ATTRIBUTE"); } $sortType = (int)$sortType; if(!is_integer($sortType) || ($sortType != self::_SORT_INTEGER && $sortType != self::_SORT_FLOAT && $sortType != self::_SORT_STRING)) { throw new Exception("sort must be in integer. use theses defines : (_SORT_INTEGER|_SORT_FLOAT|_SORT_STRING)"); } $this->sortType = $sortType; } /** * @param1 string, must be the accessor of the object, example : getProject::getCmsserver::getId, or getProject::getFileserver::getName. Note : use the defined separator CRITERIA_SEPERATOR */ public function setSortCriteria($sortCriteria) { if(is_null($sortCriteria) || strlen($sortCriteria) == 0) { throw new Exception("MANDATORY_ATTRIBUTE"); } $this->sortCriteria = $sortCriteria; } public function getSortCriteria() { return $this->sortCriteria; } /** * @param1 the order of sort, must be one of (_SORT_ASC|_SORT_DSC) */ public function setSortOrder($sortOrder) { if(is_null($sortOrder)) { throw new Exception("MANDATORY_ATTRIBUTE"); } $sortOrder = (int)$sortOrder; if(!is_integer($sortOrder) || ($sortOrder != self::_SORT_ASC && $sortOrder != self::_SORT_DSC)) { throw new Exception("sort must be in integer. use theses defines : (_SORT_ASC|_SORT_DSC)"); } $this->sortOrder = $sortOrder; } public function getSortOrder() { return $this->sortOrder; } } class SortObjectArray { const CRITERIA_SEPERATOR = "::"; private $criteria; private $objectArray; private $sortedObjectArray; private function setObjectArray($objectArray) { if(is_null($objectArray) || !is_array($objectArray)) { throw new Exception("MANDATORY_ATTRIBUTE"); } if(count($objectArray) < 1) { throw new Exception('table to be sort must at least has 2 elements, current size = ' . count($objectArray)); } $this->objectArray = $objectArray; } private function getObjectArray() { return $this->objectArray; } private function setSortedObjectArray($sortedObjectArray) { $this->sortedObjectArray = $sortedObjectArray; } public function getSortedObjectArray() { return $this->sortedObjectArray; } private function setCriteria($criteria) { $this->criteria = $criteria; } private function getCriteria() { return $this->criteria; } /** * @param1 array of Objects to be sorted * @param2 array of Criteria's Object */ public function __construct($objectArray, $criteria) { $this->setObjectArray($objectArray); $this->setCriteria($criteria); $this->doSorting(); } /** * this function will create an interval that will be used by function to cut out the original array, that will be sorted independently * @param1 array of Objects * @param2 Criteria Object * @return array of integers, will be the computed interval */ public function computeInterval($objectArray, $criteria) { if(!is_array($objectArray) || count($objectArray) == 0) { throw new Exception("can not compute anything"); } if(count($objectArray) == 1) { return array(0, 0); } $interval = array(); $predecessor = NULL; $position = 0; foreach($objectArray as $object) { if(is_null($predecessor)) { $predecessor = $this->getValue($object, $criteria->getSortCriteria()); continue; } if($this->compare($predecessor, $this->getValue($object, $criteria->getSortCriteria()), $criteria) != 0) { $interval[] = $position; $predecessor = $this->getValue($object, $criteria->getSortCriteria()); } $position++; } //var_dump(array_merge(array(0), $interval, array(count($objectArray)-1))); return array_merge(array(-1), $interval, array(count($objectArray)-1)); } /** * bubble sort * @param1 array of Objects * @param2 Criteria Object * @return array of Objects, sorted */ public function sortArray($objectArray, $criteria) { for($i=0 ; $i<count($objectArray)-1 ; $i++) { for($j=($i+1) ; $j<count($objectArray) ; $j++) { $r = $this->compare($this->getValue($objectArray[$i], $criteria->getSortCriteria()), $this->getValue($objectArray[$j], $criteria->getSortCriteria()), $criteria); if($r < 0 && $criteria->getSortOrder() == Criteria::_SORT_DSC) { $temp = $objectArray[$i]; $objectArray[$i] = $objectArray[$j]; $objectArray[$j] = $temp; continue; } if($r > 0 && $criteria->getSortOrder() == Criteria::_SORT_ASC) { $temp = $objectArray[$i]; $objectArray[$i] = $objectArray[$j]; $objectArray[$j] = $temp; continue; } } } return $objectArray ; } public function doSorting() { $tempObjectArray = array(); $objectArray = $this->getObjectArray(); $criteriaArray = $this->getCriteria(); for($i=0 ; $i<count($criteriaArray) ; $i++) { if($i==0) { $objectArray = $this->sortArray($objectArray, $criteriaArray[$i]); continue; } $tempObjectArray = array(); $interval = $this->computeInterval($objectArray, $criteriaArray[$i-1]); $subArrays = $this->extractArraysByInterval($objectArray, $interval); foreach($subArrays as $arrayToSort) { $arrayToSort = $this->sortArray($arrayToSort, $criteriaArray[$i]); $tempObjectArray = array_merge($tempObjectArray, $arrayToSort); } $objectArray = $tempObjectArray; } $this->setSortedObjectArray($objectArray); } public function extractArraysByInterval($objectArray, $interval) { $extractedArrays = array(); for($i=0 ; $i<count($interval)-1 ; $i++) { $temp = array(); for($j=$interval[$i]+1 ; $j<=$interval[$i+1] ; $j++) { $temp[] = $objectArray[$j]; } $extractedArrays[] = $temp; } return $extractedArrays; } /** * @return integer == 0 if varOne & varTwo are equals, < 0 if varOne is less than varTwo, > 0 if varOne is greater than varTwo */ public function compare($varOne, $varTwo, $criteria) { switch($criteria->getSortType()) { case Criteria::_SORT_INTEGER : { $varOne = (int)$varOne; $varTwo = (int)$varTwo; return $varOne - $varTwo; } case Criteria::_SORT_FLOAT : { $varOne = (float)$varOne; $varTwo = (float)$varTwo; return $varOne - $varTwo; } default : { $varOne = (string)$varOne; $varTwo = (string)$varTwo; if($criteria->isStrict() === FALSE) { return strcmp($varOne, $varTwo); } return strcasecmp($varOne, $varTwo); } } } public function getValue($object, $sortCriteria) { $value = $object; $sortCriteria = explode(self::CRITERIA_SEPERATOR, $sortCriteria); foreach($sortCriteria as $criteria) { $value = $value->{$criteria}(); } return $value; } }