private function equalRecurse(ClauseGroup $g1, ClauseGroup $g2, $level) { if ($g1->getType() != $g2->getType() || $g1->getCount() != $g2->getCount()) { return false; } $subClauses1 = $g1->getSubclauses(); $subClauses2 = $g2->getSubclauses(); $ok = true; for ($i = 0; $i < count($subClauses1); $i++) { $item1 = $subClauses1[$i]; $item2 = $subClauses2[$i]; if ($item1 instanceof ClauseGroup) { $ok = $this->equalRecurse($item1, $item2, $level + 1); } else { $ok = $item1 == $item2; } if (!$ok) { break; } } return $ok; }
/** * Merge two ClauseGroups * * NB: first param must be a ClauseGroup (ie not a null) * Second param can be either a ClauseGroup, a string clause, or null */ private function groupMerge(ClauseGroup $g1, $g2) { if (is_null($g2)) { return $g1; } elseif (is_string($g2)) { $clone = clone $g1; $clone->addSubclause($g2); return $clone; } else { // If one of the boolean types is null, it can be treated as empty $t1 = $g1->getType(); $t2 = $g2->getType(); if (is_null($t1)) { $t1 = $t2; } elseif (is_null($t2)) { $t2 = $t1; } // Can't merge two groups of differing bool operators if ($t1 != $t2) { throw new Exception("Can't merge two groups of differing boolean operators ({$t1}, {$t2})"); } else { $clone = clone $g1; $subClauses = $g2->getSubclauses(); foreach ($subClauses as $subClause) { //QuotedStringParser::insertStrings($subClause, $this->strings); $clone->addSubclause($subClause); } // We've made the two types the same, so use one on the clone $clone->setType($t1); return $clone; } } }
$g1->setType(ClauseGroup::BOOLEAN_AND); $t->ok($result->equal($g1), 'decode a valid bracketed string containing ANDs and ORs'); $clause1 = "person.age IN (17,18,19,20)"; $clause2 = "person.height IN (100, 101)"; $result = $ca->analyse($clause1); $rClause1 = $result->getFirstSubclause(); $g = new ClauseGroup(); $g->addSubclause($rClause1); $t->ok($result->equal($g), 'decode a simple IN statement'); try { $clause = $clause1 . ' OR ' . $clause2; $result = $ca->analyse($clause); $clauses = $result->getSubclauses(); $g->addSubclause($clauses[1]); $g->setType(ClauseGroup::BOOLEAN_OR); $ok = $result->equal($g); } catch (Exception $e) { $ok = false; } $t->ok($ok, 'decode a two IN statements'); $clause = "person.name IN ('person.age IN (1, 2, 3)')"; try { $result = $ca->analyse($clause); $rClause = $result->getFirstSubclause(); $g = new ClauseGroup(); $g->addSubclause($rClause); $ok = $result->equal($g); } catch (Exception $e) { $ok = false; } $t->ok($ok, 'decode a simple IN statement containing a misleading IN string');
/** * Recursive function to build the code from nested ClauseGroup objects */ private function buildRecursive(ClauseGroup $group, $level, &$cid, $simplifyOpts = null) { $lines = array(); $i = 0; foreach ($group->getSubclauses() as $subClause) { if ($subClause instanceof ClauseGroup) { // Pass the simplification options to the ClauseGroup $subClause->simplify($simplifyOpts); $block = $this->buildRecursive($subClause, $level + 1, $cid, $simplifyOpts); $type = $subClause->getType(); switch ($type) { case ClauseGroup::BOOLEAN_AND: break; case ClauseGroup::BOOLEAN_OR: break; default: throw new Exception('Unrecognised boolean operator found'); } // Copy code into lines foreach ($block as $pieces) { array_push($lines, $pieces); } } else { // Build a criterion statement SubclauseParser::parse($subClause, $col, $op, $value); // This is the name of the criterion object $crit = '$' . $this->cPrefix . $cid; // Modify the value if required $value = $this->valuePostProcess($op, $value); // Loop through the operators we presently know about $line = null; foreach ($this->ops as $thatOp => $syntax) { if ($op == $thatOp) { $cid++; // For the equality operator... if (is_null($syntax)) { $statement = "{$crit} = \$c->getNewCriterion({$col}, {$value});\n"; } elseif (is_null($value)) { $statement = "{$crit} = \$c->getNewCriterion({$col}, null, Criteria::{$syntax});\n"; } else { $statement = "{$crit} = \$c->getNewCriterion({$col}, {$value}, Criteria::{$syntax});\n"; } $line = $this->makeLine($statement, $level, $i == 0, $crit); array_push($lines, $line); break; } } // Moan if the operator is not found, as it was detected by SubclauseParser! if (is_null($line)) { throw new Exception("Unrecognised comparison operator ('{$op}') found"); } } $i++; } // OK, link up the criterions at our current level $crits = ''; $first = null; $code = ''; foreach ($lines as $line) { if ($line['level'] == $level) { $crit = $line['crit']; if (!$first) { $first = $crit; } else { $op = $this->boolOpToPropelOp($group->getType()); $code .= "{$first}->{$op}({$crit});\n"; } $crits .= $line['crit'] . ' '; } } // Trim off the last \n we've given the code block $code = substr($code, 0, strlen($code) - 1); $type = $group->getType(); $str = "{$code}\n"; if ($this->comments) { $str = "// Perform {$type} at level {$level} ({$crits})\n{$str}"; } $str = "\n{$str}"; $line = $this->makeLine($str, $level - 1, false, $first); array_push($lines, $line); // Link into $c if last item if ($level == 0) { // Determine the right select method and loop to use if ($this->returnType == self::RETURN_ARRAY) { $method = 'doSelect'; $loop = "foreach (\$result as \$obj)\n{\n\t//\$val = \$obj->getValue();\n}"; $postOp = ""; } else { // Determine fetch mode $fetchMode = $this->resultSetType; if ($fetchMode == self::RESULTSET_NUM) { $col1 = '1'; $col2 = '2'; } else { $col1 = "'col1'"; $col2 = "'col2'"; } $method = 'doSelectRS'; $loop = "while (\$result->next())\n{\n\t//\$str = \$result->getString({$col1});\n\t//\$int = \$result->getInt({$col2});\n}"; $postOp = "\$result->setFetchMode(ResultSet::{$fetchMode});\n"; } // OK, add the select part... $statement = "\n"; if ($this->comments) { $statement .= "// Remember to change the peer class here for the correct one in your model\n"; } $statement .= "\$c->add({$first});\n\$result = TablePeer::{$method}(\$c);\n{$postOp}\n"; // ... now add a demo loop if ($this->loop) { if ($this->comments) { $statement .= "// This loop will of course need to be edited to work\n"; } $statement .= $loop; } $line = $this->makeLine($statement, -1); array_push($lines, $line); } return $lines; }