Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added sort methods to util\Collection and data\Collection

This is useful if you want to do application side sorting on data from a
 RecordSet or DocumentSet.  An example would be where you want to displa
y the top N most popular posts ordered by date.  To do this you would qu
ery the data layer for posts ordered by "popularity" and then limit the
query by N.  Now you must sort the data by date in your application, usi
ng RecordSet::sort('date').
  • Loading branch information...
commit 74514b870c13aac98236111c524ab5c1bc04656f 1 parent c433ae9
@jmccaffrey42 jmccaffrey42 authored
View
37 data/Collection.php
@@ -246,6 +246,43 @@ public function map($filter, array $options = array()) {
}
return $data;
}
+
+ /**
+ * Sorts the objects in the collection, useful in situations where
+ * you are already using the underlying datastore to sort results.
+ *
+ * Overriden to load any data that has not yet been loaded.
+ *
+ * @param mixed $field The field to sort the data on, can also be a callback
+ * to a custom sort function.
+ * @param array $options The available options are:
+ * - No options yet implemented
+ * @return $this, useful for chaining this with other methods.
+ */
+ public function sort($field = 'id', array $options = array()) {
+ // Populate the collection by forcing it to load all members, by default the
+ // collection is lazy loaded see offsetGet.
+ $this->offsetGet(null);
+
+ // Support for sorting by field or callback
+ if (is_string($field)) {
+ $sorter = function ($a, $b) use ($field) {
+ if (is_array($a)) {
+ $a = (object)$a;
+ }
+
+ if (is_array($b)) {
+ $b = (object)$b;
+ }
+
+ return strcmp($a->$field, $b->$field);
+ };
+ } else if (is_callable($field)) {
+ $sorter = $field;
+ }
+
+ return parent::sort($sorter, $options);
+ }
/**
* Converts the current state of the data structure to an array.
View
18 tests/cases/data/CollectionTest.php
@@ -9,6 +9,7 @@
namespace lithium\tests\cases\data;
use lithium\data\collection\DocumentSet;
+use lithium\data\entity\Document;
use lithium\data\Connections;
class CollectionTest extends \lithium\test\Unit {
@@ -107,6 +108,23 @@ public function testData() {
$collection->set($data);
$this->assertEqual($data, $collection->data());
}
+
+ // Tests the sort method in \lithium\data\Collection
+ public function testSort() {
+ $collection = new DocumentSet();
+ $collection->set(array(
+ array('id' => 1, 'name' => 'Annie'),
+ array('id' => 2, 'name' => 'Zilean'),
+ array('id' => 3, 'name' => 'Trynamere'),
+ array('id' => 4, 'name' => 'Katarina'),
+ array('id' => 5, 'name' => 'Nunu')
+ ));
+
+ $collection->sort('name');
+
+ $idsSorted = $collection->map(function ($v) { return $v['id']; })->to('array');
+ $this->assertEqual($idsSorted, array(1,4,5,3,2));
+ }
}
?>
View
35 tests/cases/util/CollectionTest.php
@@ -265,6 +265,41 @@ function($i) { return is_array($i) ? join(',', $i) : $i; }, $collection->to('arr
$expected = 'hello,goodbye,bar,dib';
$this->assertEqual($expected, $result);
}
+
+ /**
+ * Tests that the Collection::sort method works appropriately.
+ *
+ * @return void
+ */
+ public function testCollectionSort() {
+ // Typical numeric sort using the default "sort" PHP function
+ $collection = new Collection(array('data' => array(5,3,4,1,2)));
+ $collection->sort();
+ $expected = array(1,2,3,4,5);
+ $this->assertEqual($expected, $collection->to('array'));
+
+ // String sort using "sort"
+ $collection = new Collection(array('data' => array('alan','dave','betsy','carl')));
+ $collection->sort();
+ $expected = array('alan','betsy','carl','dave');
+ $this->assertEqual($expected, $collection->to('array'));
+
+ // String sort using strcasecmp
+ $collection = new Collection(array('data' => array('Alan','Dave','betsy','carl')));
+ $collection->sort('strcasecmp');
+ $expected = array('Alan','betsy','carl','Dave');
+ $this->assertEqual($expected, $collection->to('array'));
+
+ // Numeric sort using custom function
+ $collection = new Collection(array('data' => array(5,3,4,1,2)));
+ $collection->sort(function ($a,$b) { if ($a == $b) { return 0; } return ($b > $a ? 1 : -1); });
+ $expected = array(5,4,3,2,1);
+ $this->assertEqual($expected, $collection->to('array'));
+
+ // Test fail
+ $collection = new Collection(array('data' => array(5,3,4,1,2)));
+ $this->assertFalse($collection->sort('blahgah'));
+ }
}
?>
View
24 util/Collection.php
@@ -352,6 +352,30 @@ public function map($filter, array $options = array()) {
}
return $data;
}
+
+ /**
+ * Sorts the objects in the collection.
+ *
+ * @param mixed $field The field to sort the data on, can also be a callback
+ * to a custom sort function.
+ * @param array $options The available options are:
+ * - No options yet implemented
+ * @return $this, useful for chaining this with other methods.
+ */
+ public function sort($sorter = 'sort', array $options = array()) {
+ // Sort the data
+ if (is_string($sorter) && strpos($sorter, 'sort') !== false && is_callable($sorter)) {
+ call_user_func($sorter, &$this->_data);
+ } else if (is_callable($sorter)) {
+ usort($this->_data, $sorter);
+ } else {
+ // TODO: Complain
+ return false;
+ }
+
+ // Return $this so sort can be used in a chained fashion. $col->sort('name')->to('array');
+ return $this;
+ }
/**
* Checks whether or not an offset exists.
Please sign in to comment.
Something went wrong with that request. Please try again.