Last active
January 30, 2016 09:39
-
-
Save noclat/870e1971e0531cf7e138 to your computer and use it in GitHub Desktop.
KirbyCMS-inspired chainable object class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# Chainable objects | |
# Ex: echo $films->filterBy('rating', 5)->sortBy('release')->flip()->first()->title(); | |
class obj implements Iterator { | |
private $_ = array(); | |
public function __construct($arr = array()) { $this->_ = is_array($arr[0]) ? array_map(function($a) { return is_object($a) ? $a : new obj($a); }, $arr) : $arr; } | |
public function __set($k, $v) { $this->_[$k] = $v; } | |
public function __get($k) { return $this->get($this->_, $k); } | |
public function __call($k, $args) { return $this->get($this->_, $k, $args[0]); } | |
private function get($arr, $k, $date = false) { return isset($arr[$k]) ? (($date AND !is_numeric($arr[$k]) AND strtotime($arr[$k]))?new DateTime($arr[$k]):$arr[$k]) : false; } | |
public function rewind() { reset($this->_); } | |
public function current() { return current($this->_); } | |
public function key() { return key($this->_); } | |
public function next() { return next($this->_); } | |
public function prev() { return prev($this->_); } | |
public function valid() { $key = key($this->_); return ($key !== NULL && $key !== FALSE); } | |
public function first() { return array_shift($this->_); } | |
public function last() { return array_pop($this->_); } | |
public function nth($n) { $arr = array_values($this->_); return (isset($arr[$n-1])) ? $arr[$n-1] : false; } | |
public function indexOf($needle) { return array_search($needle, array_values($this->_)); } | |
public function count() { return count($this->_); } | |
public function toArray() { return $this->_; } | |
public function limit($n) { return new obj(array_slice($this->_, 0, $n)); } | |
public function slice($o, $n) { return new obj(array_slice($this->_, $o, $n)); } | |
public function shuffle() { $keys = array_keys($this->_); shuffle($keys); return new obj(array_replace(array_flip($keys), $this->_)); } | |
public function flip() { return new obj(array_reverse($this->_, true)); } | |
public function sortBy($k) { | |
$arr = $this->_; | |
$values = function($key) use ($arr) { return array_map(create_function('$a', "return (is_object(\$a) AND is_object(\$a->$key(true))) ? \$a->$key(true)->getTimestamp() : strtolower(\$a->$key);"), $arr); }; | |
if (preg_match('/([a-z]{1}[a-z0-9]*)(?:\s(ASC|DESC))?\s?,\s?([a-z]{1}[a-z0-9]*)(?:\s(ASC|DESC))?/i', $k, $m)) | |
array_multisort($values($m[1]), (strtolower($m[2])=='desc'?SORT_DESC:SORT_ASC), SORT_REGULAR, $values($m[3]), (strtolower($m[4])=='desc'?SORT_DESC:SORT_ASC), SORT_REGULAR, $arr); | |
else array_multisort($values($k), SORT_ASC, SORT_REGULAR, $arr); | |
return new obj($arr); | |
} | |
public function filter($c) { return new obj(array_filter($this->_, create_function('$a', 'extract(array_map(function($v) use ($a) { $k = array_search($v, $a->toArray()); return is_object($a->$k(true))?$a->$k(true):$v; }, $a->toArray())); return '.$c.';'))); } | |
public function filterBy($k, $v, $s = false) { return $s ? $this->filter("in_array('$v', array_map('trim', explode('$s', \$$k)))") : $this->filter("\$$k == \"$v\""); } | |
public function findBy($k, $v, $s = false) { return $this->filterBy($k, $v, $s)->first(); } | |
public function kickBy($k, $v, $s = false) { return $s ? $this->filter("!in_array('$v', array_map('trim', explode('$s', \$$k)))") : $this->filter("\$$k != \"$v\""); } | |
public function sum($k) { return array_sum(array_map(function($a) use ($k) { return $a->$k(); }, $this->_)); } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# Sample data | |
$films = array( | |
array( | |
'title' => 'Cloud Atlas', | |
'release' => '2013-3-13', | |
'rating' => 4.5 | |
), | |
array( | |
'title' => 'Oblivion', | |
'release' => '2013-4-10', | |
'rating' => 4.5 | |
), | |
array( | |
'title' => 'Lawless', | |
'release' => '2012-9-12', | |
'rating' => 5 | |
), | |
array( | |
'title' => 'Iron Man 3', | |
'release' => '2013-4-24', | |
'rating' => 3.5 | |
), | |
array( | |
'title' => 'Django Unchained', | |
'release' => '2013-1-16', | |
'rating' => 5 | |
), | |
array( | |
'title' => 'Looper', | |
'release' => '2012-10-31', | |
'rating' => 4 | |
) | |
); | |
# Examples | |
include 'chainable-objects.php'; | |
$films = new obj($films); | |
?> | |
<h1>Full movie list</h1> | |
<ul> | |
<?php foreach ($films->sortBy('release')->flip() as $film): ?> | |
<li> | |
<em><?php echo $film->title() ?></em> | |
released on <time datetime="<?php echo $film->release() ?>"><?php echo $film->release(true)->format('F j, Y') ?></time> | |
and rated <strong><?php echo $film->rating() ?></strong> | |
</li> | |
<?php endforeach ?> | |
</ul> | |
<h1>Info</h1> | |
<ul> | |
<li>Number of films: <?php echo $films->count() ?></li> | |
<li>Number of 5 rated films: <?php echo $films->filterBy('rating', 5)->count() ?></li> | |
<li>Number of < 5 rated films: <?php echo $films->kickBy('rating', 5)->count() ?></li> | |
<li>Number of 4+ rated films: <?php echo $films->filter('$rating >= 4')->count() ?></li> | |
<li>Random film title: <?php echo $films->shuffle()->first()->title() ?></li> | |
<li>Last watched film title: <?php echo $films->sortBy('release')->flip()->first()->title() ?></li> | |
<li>Second to last watched film title: <?php echo $films->sortBy('release')->flip()->nth(2)->title() ?></li> | |
<li>Last 5-rated watched film title: <?php echo $films->sortBy('rating DESC, release DESC')->first()->title() ?></li> | |
<li>First 5-rated watched film title: <?php echo $films->sortBy('release')->findBy('rating', 5)->title() ?></li> | |
<li>Number of films released on 2013: <?php echo $films->filter('$release->format("Y") >= 2013')->count() ?></li> | |
</ul> | |
<h1>Two last movies I watched</h1> | |
<ul> | |
<?php foreach ($films->sortBy('release')->flip()->limit(2) as $film): ?> | |
<li> | |
<em><?php echo $film->title() ?></em> | |
released on <time datetime="<?php echo $film->release() ?>"><?php echo $film->release(true)->format('F j, Y') ?></time> | |
and rated <strong><?php echo $film->rating() ?></strong> | |
</li> | |
<?php endforeach ?> | |
</ul> | |
<h1>Three previous movies I watched</h1> | |
<ul> | |
<?php foreach ($films->sortBy('release')->flip()->slice(2, 3) as $film): ?> | |
<li> | |
<em><?php echo $film->title() ?></em> | |
released on <time datetime="<?php echo $film->release() ?>"><?php echo $film->release(true)->format('F j, Y') ?></time> | |
and rated <strong><?php echo $film->rating() ?></strong> | |
</li> | |
<?php endforeach ?> | |
</ul> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment