Last active
December 11, 2015 03:58
-
-
Save jeffturcotte/4541246 to your computer and use it in GitHub Desktop.
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 | |
/** | |
* A class to help with adding build methods | |
* to your fActiveRecord models. | |
* | |
* @author Jeff Turcotte <[email protected]> | |
* @license MIT | |
* @version 1.0 | |
* | |
* Usage: | |
* | |
* $builder = Builder::create('Page'); | |
* | |
* $builder->setDefaultOrder(array('name' => 'asc')); | |
* | |
* $builder->register('buildActive', function(&$where) { | |
* $where['status='] = 'active'; | |
* }); | |
* | |
* $builder->extend('buildActive', 'buildActivePublished', function(&$where) { | |
* $where['published='] = TRUE; | |
* }); | |
* | |
* Page::buildActivePublished(10, 1); | |
* | |
*/ | |
class Builder { | |
static protected $registry; | |
protected $callbacks; | |
protected $class; | |
protected $default_order; | |
/** | |
* Create a Builder based off of the class name. | |
* If a Builder for the supplied class exists, it will | |
* return that. | |
* | |
* @param $class string The fActiveRecord class to use | |
* | |
* @return Builder | |
*/ | |
public function create($class) { | |
if (isset(self::$registry[$class])) { | |
return $registry[$class]; | |
} | |
$instance = new self(); | |
$instance->callbacks = array(); | |
$instance->class = $class; | |
self::$registry[$class] = $instance; | |
return $instance; | |
} | |
/** | |
* Set a default order by clause for all build | |
* methods. Can be altered by the registered build | |
* methods if necessary. | |
* | |
* @param $order Array The order by | |
* | |
* @return void | |
*/ | |
public function setDefaultOrder($order) | |
{ | |
$this->default_order = (array) $order; | |
} | |
/** | |
* Register a build method on the record | |
* | |
* The callback can take four references: | |
* &$where The where clauses to modify | |
* &$order The order by clauses to modify | |
* &$limit The limit to modify | |
* &$page The page to modify | |
* | |
* @param $method string The method name to register | |
* @param $callback callable The builder callback, see method desc. | |
* | |
* @return void | |
*/ | |
public function register($method, $callback=NULL) | |
{ | |
$this->callbacks[$method] = $callback; | |
fORM::registerActiveRecordStaticMethod( | |
$this->class, $method, $this->makeBuilder($callback) | |
); | |
} | |
/** | |
* Extends an existing build method. | |
* | |
* @param $parent string The existing method name to extend | |
* @param $method string The new method name to register | |
* @param $callback callable The builder callback, see register() docs for desc. | |
* | |
* @return void | |
*/ | |
public function extend($parent, $method, $callback=NULL) | |
{ | |
$parent_callback = $this->callbacks[$parent]; | |
$this->register($method, function(&$where, &$order, &$limit, &$page) use ($parent_callback, $callback) { | |
$parent_callback($where, $order, $limit, $page); | |
$callback($where, $order, $limit, $page); | |
}); | |
} | |
/** | |
* Makes a builder callback to register on fActiveRecord | |
* | |
* This creates an fActiveRecord method that takes the following parameters: | |
* | |
* $limit | |
* The custom limit for the returned fRecordSet | |
* $page | |
* The custom page to limit to | |
* $order | |
* The custom order array for the fRecordSet | |
* $inline_callback | |
* A callback in the same form as when registering a builder. | |
* Can be in any argument position, as long as it's last. | |
* For inline extensions, such as search. | |
* | |
* @param $callback callable The builder callback, see register() docs for desc | |
* | |
* @return Closure | |
*/ | |
protected function makeBuilder($callback=NULL) | |
{ | |
$default_order = $this->default_order; | |
return function($class, $method, $args) use ($callback, &$default_order) { | |
$where = array(); | |
$order = array(); | |
$limit = NULL; | |
$page = NULL; | |
$inline_callback = NULL; | |
$arg_names = array( | |
'limit', | |
'page', | |
'order', | |
'inline_callback' | |
); | |
foreach($arg_names as $key => $value) { | |
if (isset($args[$key])) { | |
if (count($args)-1 == $key && is_callable($args[$key])) { | |
$inline_callback = $args[$key]; | |
break; | |
} | |
$$value = $args[$key]; | |
} | |
} | |
call_user_func_array($callback, array( | |
&$where, &$order, &$limit, &$page | |
)); | |
if ($inline_callback) { | |
call_user_func_array($inline_callback, array( | |
&$where, &$order, &$limit, &$page | |
)); | |
} | |
foreach($default_order as $column => $dir) { | |
if (!isset($order[$column])) { | |
$order[$column] = $dir; | |
} | |
} | |
return fRecordSet::build( | |
$class, $where, $order, $limit, $page | |
); | |
}; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Did you give any thought to also building out such methods in traits? Just curious. Not sure how many servers are running 5.4, but I'd imagine a few traits might offer a pretty good build*() collection on most classes. I was just thinking about this cause I was writing that documentation stuff, and remembered I was aiming to get away from a lot of hidden methods like this in my own code: