Skip to content

Instantly share code, notes, and snippets.

@lm
Created March 11, 2012 16:10
Show Gist options
  • Save lm/2016976 to your computer and use it in GitHub Desktop.
Save lm/2016976 to your computer and use it in GitHub Desktop.
PHPClosure2SQL
<?php
class Collection
{
private $items = array();
function add($item)
{
$this->items[] = $item;
}
function select($closure)
{
$selected = array();
foreach ($this->items as $item) {
if ($closure($item)) {
$selected[] = $item;
}
}
return $selected;
}
}
class DatabaseCollection
{
function select($closure)
{
echo $this->buildSql($closure), "\n";
}
function buildSql($closure)
{
$reflection = new ReflectionFunction($closure);
$parameters = $reflection->getParameters();
$staticVars = $reflection->getStaticVariables();
$table = reset($parameters)->name;
$sql = "SELECT *\nFROM " . $table;
$where = '';
$skip = TRUE;
$expectProperty = FALSE;
$join = NULL;
foreach (token_get_all('<?php ' . $this->getSourceOf($reflection)) as $token) {
if (is_string($token)) {
$token = array($token, $token, NULL);
}
//echo @token_name($token[0]), ' ', $token[1], "\n";
if ($skip) {
switch ($token[0]) {
case T_RETURN:
$skip = FALSE;
break;
}
} else {
switch ($token[0]) {
case T_VARIABLE:
$var = substr($token[1], 1);
$where .= isset($staticVars[$var]) ? '"' . $staticVars[$var] . '"' : $var;
break;
case T_OBJECT_OPERATOR:
if ($join) {
$sql .= "\nINNER JOIN $join ON $join.id = $table.{$join}_id ";
}
$where .= '.';
break;
case T_IS_IDENTICAL:
$where .= '=';
break;
case '}':
break 2;
case ';':
break;
case T_STRING:
if ($expectProperty) {
$join = $token[1];
}
default:
$where .= $token[1];
break;
}
$expectProperty = $token[0] === T_OBJECT_OPERATOR;
}
}
return $sql . "\nWHERE " . trim($where);
}
function getSourceOf($reflection)
{
$f = fopen($reflection->getFileName(), 'r');
$source = '';
for ($i = 1; $i <= $reflection->getEndLine(); $i++) {
$line = fgets($f);
if ($i >= $reflection->getStartLine()) {
$source .= $line;
}
}
return $source;
}
}
$pages = new DatabaseCollection;
$catName = 'news';
$pages->select(function($page) use ($catName)
{
return $page->category->name === $catName;
});
/* Output:
SELECT *
FROM page
INNER JOIN category ON category.id = page.category_id
WHERE page.category.name = "news"
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment