Skip to content

Instantly share code, notes, and snippets.

@noclat
Last active January 30, 2016 09:39
Show Gist options
  • Save noclat/870e1971e0531cf7e138 to your computer and use it in GitHub Desktop.
Save noclat/870e1971e0531cf7e138 to your computer and use it in GitHub Desktop.
KirbyCMS-inspired chainable object class.
<?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->_)); }
}
<?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