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)
$criteria_2 = new Criteria ('getAge', Criteria::_SORT_DSC, Criteria::_SORT_INTEGER);
$sortObject = new SortObjectArray($users, array($criteria_1, $criteria_2));
var_dump ($sortObject->getSortedObjectArray());
Here the source code
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;
}
}
Aucun commentaire :
Enregistrer un commentaire