/surosql/Surosql.class.php
PHP | 876 lines | 757 code | 117 blank | 2 comment | 162 complexity | f5136e260ce42b84c6e4d14e1764bc63 MD5 | raw file
Possible License(s): LGPL-3.0, AGPL-1.0, GPL-2.0, LGPL-2.1
- <?php
-
- // version: 3.3.0
-
- namespace ns;
-
- use \IteratorAggregate;
- use \ReflectionClass;
- use \ArrayIterator;
- use \Exception;
-
-
- class Surosql {
-
- /* table - global alias - (fieldname) - localalias */
-
- static $osql;
-
- public $aliases = array();
- public $class2info = array();
- public $connections = array();
- public $imported_query_functions = array();
- public $imported_osql_functions = array();
-
- function __construct() {
- $utils = array('connect', 'quote_rec', 'quote_lst', 'q', 'quote', 'logand', 'logor', 'count', 'select', 'selectoo', 'from', 'fromoo', 'update', 'delete', 'deleteoo');
- foreach($utils as $name) {
- $this->imported_osql_functions[$name] = array(__CLASS__, "${name}_util");
- }
-
- $bin_string_operators = array('in' => 'IN', 'nin' => 'NOT IN', 'eq' => '=', 'neq' => '!=', 'lt' => '<', 'gt' => '>', 'lte' => '<=', 'gte' => '>=', 'like' => 'LIKE', 'is' => '');
- foreach($bin_string_operators as $opname => $op) {
- $this->imported_osql_functions[$opname] = create_function('$osql, $key, $val = null', "return " . __CLASS__ . "::operator('$op', \$key, \$val);");
- $this->imported_query_functions["if{$opname}"] = create_function('$query, $key, $val = null', "return \$query->andwhere(" . __CLASS__ . "::operator('$op', \$key, \$val));");
- }
- }
-
- static function quote_rec_util($osql, $var, $maxdepth = PHP_INT_MAX, $depth = 0) {
- if(is_array($var) && $maxdepth > $depth) {
- foreach($var as $key => &$val) {
- $val = self::quote_rec_util($osql, $val, $maxdepth, $depth + 1);
- }
- return $var;
- } else if(is_object($var) && $maxdepth > $depth) {
- $obj = clone $var;
- foreach(get_object_vars($obj) as $field => $val) {
- $obj->$field = self::quote_rec_util($osql, $val, $maxdepth, $depth + 1);
- }
- return $obj;
- } else {
- return $osql->quote((string) $var);
- }
- }
-
- static function quote_lst_util($osql, $lst) {
- $lst = is_array($lst) ? self::array_flatten($lst) : explode(',', (string) $lst);
- return implode(',', self::quote_rec_util($osql, $lst, 1));
- }
-
- static function q_util($osql) {
- $args = func_get_args();
- return SurosqlBindable::q((array) array_slice($args, 1));
- }
-
- static function logand_util() {
- $args = func_get_args();
- return SurosqlBindable::merge('AND', (array) array_slice($args, 1));
- }
-
- static function logor_util() {
- $args = func_get_args();
- return SurosqlBindable::merge('OR', (array) array_slice($args, 1));
- }
-
- static function count_util($osql) {
- return SurosqlQuery::newinst($osql)->count();
- }
-
- static function select_util($osql, $args = '%*') {
- return SurosqlQuery::newinst($osql)->select($args);
- }
-
- static function selectoo_util($osql, $args = '%*') {
- return SurosqlQuery::newinst($osql)->selectoo($args);
- }
-
- static function from_util($osql, $from) {
- return $osql->select()->from($from);
- }
-
- function __invoke($from) {
- return $this->selectoo()->from($from);
- }
-
- static function fromoo_util($osql, $from) {
- return $osql->selectoo()->from($from);
- }
-
- static function update_util($osql, $from = null) {
- return SurosqlQuery::newinst($osql)->update($from);
- }
-
- static function delete_util($osql, $tables = '') {
- return SurosqlQuery::newinst($osql)->delete($tables);
- }
-
- static function deleteoo_util($osql, $tables = '') {
- return SurosqlQuery::newinst($osql)->deleteoo($tables);
- }
-
- function __call($method, $args) {
- return call_user_func_array($this->imported_osql_functions[$method], array_merge(array($this), $args));
- }
-
- static function __callStatic($method, $args) {
- return call_user_func_array(self::$osql->imported_osql_functions[$method], array_merge(array(self::$osql), $args));
- }
-
- static function operator($operator, $key, $val = null) {
- $conds = array();
- if(is_null($val)) {
- foreach($key as $col => $colval) {
- $conds[] = SurosqlBindable::q($col . ' ' . $operator, $colval);
- }
- } else {
- $keys = is_array($key) ? $key : array($key);
- foreach($keys as $col) {
- $conds[] = SurosqlBindable::q($col . ' ' . $operator, $val);
- }
- }
- return SurosqlBindable::merge('AND', $conds);
- }
-
- static function array_flatten($array) {
- if(!is_array($array)) {
- return $array;
- }
- $return_array = array();
- foreach($array as $key => $val) {
- if(is_array($val)) {
- $return_array = array_merge($return_array, self::array_flatten($val));
- } else if(is_int($key)) {
- $return_array[] = $val;
- } else {
- $return_array[$key] = $val;
- }
- }
- return $return_array;
- }
-
- static function field_serialization($field, $value, $info, $type = 'serialize') {
- $default_serialize = array('serialize', 'unserialize');
- $type = ($type == 'serialize' ? 0 : 1);
- if(!isset($info['serialization'])) {
- return $value;
- }
- foreach($info['serialization'] as $key => $val) {
- $field_name = is_array($val) ? $key : $val;
- if($field_name === $field) {
- $serialization_func = is_array($val) ? $val : $default_serialize;
- $value = call_user_func($serialization_func[$type], $value);
- }
- }
- return $value;
- }
-
- function glalias2table($glalias) {
- return !isset($this->aliases[$glalias]['table']) ? $glalias : $this->aliases[$glalias]['table'];
- }
-
- function connect_util($osql, $glalias, $connection, $extra = array()) {
- if(preg_match('/^(.*?)\s*-\s*(.*?)\s*(\(\s*(.*?)\s*\))? *$/', $glalias, $matches) != 1) {
- throw new Exception('Invalid connection string');
- }
- list($_, $base, $fieldname) = $matches;
- $basetable = $osql->glalias2table($base);
- $fieldglalias = (count($matches) == 5 ? $matches[4] : $fieldname);
- $fieldtable = $osql->glalias2table($fieldglalias);
- $connection = str_replace("%$base%", "%$basetable%", $connection);
- $extra = array_merge(array('jointype' => 'INNER'), $extra);
- $osql->connections["$base,$fieldname"] = array('sqljoin' => $connection, 'table' => $fieldtable, 'glalias' => $fieldglalias, 'extra' => $extra);
- return $osql;
- }
-
- function get_class_info($classname) {
- if(isset($this->class2info[$classname])) {
- return $this->class2info[$classname];
- }
- $refclass = new ReflectionClass($classname);
- $info = $refclass->getStaticPropertyValue('surosql', array());
- if(!is_null($refclass->getConstructor())) {
- $ooinit = array($refclass, 'newInstance');
- } else {
- $ooinit = create_function('$a', "return " . __CLASS__ . "::array_to_class(\$a, '$classname');");
- }
- $classvars = array_keys(array_diff_key(get_class_vars($classname), $refclass->getStaticProperties()));
- $info = array_merge(array('connections' => array(), 'table' => $classname, 'class' => $classname, 'ooinit' => $ooinit, 'classvars' => $classvars), $info);
- if(isset($info['alias'])) {
- $this->aliases[$info['alias']] = $info;
- foreach($info['connections'] as $connid => $connsql) {
- $this->connect("{$info['alias']} - $connid", $connsql);
- }
- }
- $this->class2info[$classname] = $info;
- return $info;
- }
-
- function addclass() {
- $func_args = func_get_args();
- foreach(self::array_flatten($func_args) as $classname) {
- $this->get_class_info($classname);
- }
- return $this;
- }
-
- function get_obj_info($obj) {
- $info = $this->get_class_info(get_class($obj));
- return isset($info['columns']) ? $info : array_merge($info, array('columns' => array_keys(get_object_vars($obj))));
- }
-
- static function array_to_class($arr, $classname) {
- $obj = new $classname();
- foreach($arr as $key => $value) {
- $obj->$key = $value;
- }
- return $obj;
- }
-
- function __get($from) {
- return $this->selectoo()->from($from);
- }
- }
-
- class SurosqlBindable {
-
- public $parts;
-
- function __construct($parts = array()) {
- $this->parts = array();
- $toadd = '';
- foreach($parts as $i => $part) {
- if(is_array($part)) {
- $this->parts[$i - 1] .= ' (';
- foreach($part as $i => $p) {
- $this->parts[] = $p;
- if($i != count($part) - 1) {
- $this->parts[] = ', ';
- }
- }
- $toadd = ') ';
- } else {
- if($toadd != '') {
- $this->parts[] = $toadd . $part;
- } else {
- $this->parts[] = $part;
- }
- $toadd = '';
- }
- }
- if($toadd != '') {
- $this->parts[] = $toadd;
- }
- }
-
- function andq() {
- $args = func_get_args();
- return self::merge('AND', $this, self::q($args));
- }
-
- function orq() {
- $args = func_get_args();
- return self::merge('OR', $this, self::q($args));
- }
-
- function logand() {
- $args = func_get_args();
- return self::merge('AND', $this, $args);
- }
-
- function logor() {
- $args = func_get_args();
- return self::merge('OR', $this, $args);
- }
-
- function append($boundable) {
- if(is_string($boundable)) {
- $boundable = new self(array($boundable));
- }
-
- if(count($boundable->parts) == 0) { return; }
-
- if($this->parts % 2 == 1) {
- $this->parts[count($this->parts) - 1] .= $boundable->parts[0];
- $this->parts = array_merge($this->parts, (array) array_slice($boundable->parts, 1));
- } else {
- $this->parts = array_merge($this->parts, $boundable->parts);
- }
- }
-
- function encapsulated($prefix = '(', $suffix = ')') {
- $ret = new self($this->parts);
- if(count($ret->parts) == 0) {
- return $ret;
- }
- $ret->parts[0] = $prefix . $ret->parts[0];
- if(count($ret->parts) % 2 == 1) {
- $ret->parts[count($ret->parts) - 1] = $ret->parts[count($ret->parts) - 1] . $suffix;
- } else {
- $ret->parts[] = $suffix;
- }
- return $ret;
- }
-
- static function merge($log_conn) {
- $args = func_get_args();
- return call_user_func_array(array(__CLASS__, 'merge_with_encapsulation_par'), array_merge(array('(', ')'), $args));
- }
-
- static function merge_no_encapsulation($log_conn) {
- $args = func_get_args();
- return call_user_func_array(array(__CLASS__, 'merge_with_encapsulation_par'), array_merge(array('', ''), $args));
- }
-
- static function merge_with_encapsulation_par($prefix, $suffix, $log_conn) {
- $args = func_get_args();
- $boundables = Surosql::array_flatten((array) array_slice($args, 3));
-
- if(count($boundables) == 1) {
- return is_string($boundables[0]) ? new self(array($boundables[0])) : $boundables[0];
- }
-
- $ret = new self(array());
- foreach($boundables as $boundable) {
- $toadd = is_string($boundable) ? new self(array($boundable)) : $boundable;
- $toadd = $toadd->encapsulated($prefix, $suffix);
- if(count($toadd->parts) > 0) {
- if(count($ret->parts) > 0) {
- $ret->append(" $log_conn ");
- }
- $ret->append($toadd);
- }
- }
- return $ret;
- }
-
- static function q() {
- $args = func_get_args();
- $args = count($args) == 1 && is_array($args[0]) ? $args[0] : $args;
- if(count($args) > 0 && is_array($args[0])) {
- return self::merge('AND', array_map(array(__CLASS__, 'q'), $args));
- } else {
- return new self($args);
- }
- }
-
- static function q4set() {
- $args = func_get_args();
- $args = count($args) == 1 && is_array($args[0]) ? $args[0] : $args;
- if(count($args) > 0 && is_array($args[0])) {
- return self::merge_no_encapsulation(',', array_map(array(__CLASS__, 'q4set'), $args));
- } else {
- return new self($args);
- }
- }
-
- function __toString() {
- return implode(' ', $this->parts);
- }
- }
-
- class SurosqlQuery implements IteratorAggregate {
-
- public $type, $set = '', $laliasinfo, $osql, $select, $select_unparsed, $from, $from_unparsed, $join, $where, $where_unparsed, $groupby, $orderby, $limit, $first_from_alias;
- public $table_extra_where = array();
- public $uid = 0;
-
- function __construct($osql) {
- $this->osql = $osql;
- $this->where = SurosqlBindable::q();
- }
-
- function __call($method, $args) {
- return call_user_func_array($this->osql->imported_query_functions[$method], array_merge(array($this), $args));
- }
-
- static function newinst($osql) {
- return new self($osql);
- }
-
- function array_to_oo($rows) {
- $r = array();
- foreach($rows as $row) {
- foreach($this->colmap as $lalias => $colmap) {
- foreach($colmap['maps'] as $from => $to) {
- $row[$lalias][$to] = $this->osql->field_serialization($to, $row[$from], $colmap['info'], 'unserialize');
- unset($row[$from]);
- }
- $row[$lalias] = call_user_func($colmap['ooinit'], $row[$lalias]);
- }
- $r[] = (count($row) == 1 && isset($lalias) ? current($row) : (object) $row);
- }
- return $r;
- }
-
- function is_oo() {
- return substr($this->type, -2) == 'oo';
- }
-
- function add_class_alias($glalias) {
- if(!isset($this->osql->aliases[$glalias])) {
- if($this->is_oo() && class_exists($glalias)) {
- $this->osql->aliases[$glalias] = array('class' => $glalias);
- } else {
- return;
- }
- }
- $curaliasinfo = $this->osql->aliases[$glalias];
- if($this->is_oo() && isset($curaliasinfo['class']) && count(array_diff(array('table', 'ooinit', 'classvars'), array_keys($curaliasinfo))) != 0) {
- $this->osql->aliases[$glalias] = array_merge($this->osql->get_class_info($curaliasinfo['class']), $this->osql->aliases[$glalias]);
- }
- }
-
- function getIterator() {
- return $this->getIteratorImpl();
- }
-
- function count() {
- return $this->select('COUNT(*)');
- }
-
- function select($select_unparsed = null) {
- if(is_null($select_unparsed)) {
- return $this->select_unparsed;
- }
- if($this->type === 'selectoo') {
- return $this->selectoo($select_unparsed);
- }
- $this->type = 'select';
- $this->select_unparsed = $select_unparsed;
- $this->select = null;
- return $this;
- }
-
- function selectoo($select_unparsed = null) {
- if(is_null($select_unparsed)) {
- return $this->select_unparsed;
- }
- if($this->type === 'select') {
- return $this->select($select_unparsed);
- }
- $this->type = 'selectoo';
- $this->select_unparsed = $select_unparsed;
- $this->select = null;
- return $this;
- }
-
- function parse_select_replace($matches) {
- if($matches[1] == '*') {
- $replacements = array();
- foreach($this->laliasinfo as $info) {
- $replacement = $this->parse_select_replace(array(false, $info['lalias'], ''));
- if($replacement === false && (!isset($replacements[0]) || $replacements[0] !== '*')) {
- $replacements = array_merge(array('*'), $replacements);
- } else if($replacement !== false) {
- $replacements[] = $replacement;
- }
- }
- return implode(', ', $replacements) . (count($replacements) > 0 ? $matches[2] : '');
- }
-
- $laliasinfo = $this->laliasinfo[$matches[1]];
- $classname = isset($laliasinfo['class']) ? $laliasinfo['class'] : null;
-
- if(isset($laliasinfo['columns'])) {
- $columns = $laliasinfo['columns'];
- } else if(!$this->is_oo() && isset($laliasinfo['classvars'])) {
- $columns = $laliasinfo['classvars'];
- } else if($this->is_oo() && !is_null($classname)) {
- if(!isset($this->osql->aliases[$classname]['classvars'])) {
- $this->add_class_alias($classname);
- }
- $columns = $this->osql->aliases[$classname]['classvars'];
- } else if($this->is_oo() && class_exists($laliasinfo['glalias'])) {
- $classname = $laliasinfo['glalias'];
- $this->add_class_alias($classname);
- $this->osql->aliases[$classname];
- $laliasinfo = $this->laliasinfo[$matches[1]] = array_merge($laliasinfo, $this->osql->aliases[$classname]);
- $columns = $this->osql->aliases[$classname]['classvars'];
- } else {
- return $matches[0];
- }
-
- $colmap = $newselect = array();
- foreach($columns as $defaultcol) {
- $newselect[] = "`{$laliasinfo['lalias']}`.`$defaultcol` AS `{$laliasinfo['lalias']}_$defaultcol`";
- $colmap["{$laliasinfo['lalias']}_$defaultcol"] = $defaultcol;
- }
- $ooinit = isset($laliasinfo['ooinit']) ? $laliasinfo['ooinit'] : create_function('$a', 'return (object) $a;');
- $this->colmap[$laliasinfo['lalias']] = array('maps' => $colmap, 'ooinit' => $ooinit, 'info' => $laliasinfo);
- return implode(', ', $newselect) . (count($newselect) > 0 ? $matches[2] : '');
- }
-
- function parse_select() {
- if(!is_null($this->select)) {
- return;
- }
- $this->colmap = array();
- $this->select = $this->select_unparsed;
- $strsplit = preg_split('/(["\'])(?:\\\\?.)*?\1/', $this->select_unparsed, -1, PREG_SPLIT_OFFSET_CAPTURE);
- $shift = 0;
- foreach($strsplit as $offset) {
- $repl = preg_replace_callback('/%([^ ,()]+)\s*(,|$)/', array($this, 'parse_select_replace'), substr($this->select, $offset[1] + $shift, strlen($offset[0])));
- $this->select = substr_replace($this->select, $repl, $offset[1] + $shift, strlen($offset[0]));
- $shift += strlen($repl) - strlen($offset[0]);
- }
- }
-
- function update($from = null) {
- if(is_null($from)) {
- return $this->from;
- }
- $this->type = 'update';
- $this->from = $from;
- return $this;
- }
-
- function delete($tables = '') {
- $this->type = 'delete';
- $this->select = $tables;
- return $this;
- }
-
- function deleteoo($tables = '') {
- $this->type = 'deleteoo';
- $this->select = $tables;
- return $this;
- }
-
- function from($from_unparsed = null) {
- if(is_null($from_unparsed)) {
- return $this->from_unparsed;
- }
- $this->from_unparsed = $from_unparsed;
- $this->from = null;
- return $this;
- }
-
- function parse_from() {
- if(!is_null($this->from)) {
- return;
- }
- $tablearr = preg_split('/(\s+|,|-|\(|\))/', $this->from_unparsed, -1, PREG_SPLIT_DELIM_CAPTURE);
- $tablearr = array_values(array_filter(array_map('trim', $tablearr), 'strlen'));
- $this->from = array();
- $this->laliasinfo = array();
-
- $parentstack = array();
- $this->first_from_alias = $from = null;
- while(($curstr = current($tablearr)) !== false) {
- $curstr = trim($curstr, '`');
- $connection = isset($this->osql->connections["{$from['glalias']},$curstr"]) ? $this->osql->connections["{$from['glalias']},$curstr"] : null;
- $connection = is_null($connection) && isset($this->osql->connections["{$from['table']},$curstr"]) ? $this->osql->connections["{$from['table']},$curstr"] : $connection;
- if(!is_null($from)) {
- $to = array('table' => $connection['table'], 'glalias' => $connection['glalias'], 'field' => $curstr, 'lalias' => $curstr);
- } else {
- $to = array('table' => $curstr, 'glalias' => $curstr, 'lalias' => $curstr);
- }
- if($connection['extra']['jointype'] == 'm2m') {
- $prev_index = key($tablearr);
- $m2m_repl = array();
- foreach(array_map('trim', explode('-', $connection['sqljoin'])) as $t) {
- $m2m_repl = array_merge($m2m_repl, array($t, $t . '_'. $this->uid++, '-'));
- }
- array_splice($tablearr, $prev_index, 1, array_slice($m2m_repl, 0, count($m2m_repl) - 2));
- while(key($tablearr) != $prev_index) { next($tablearr); }
- continue;
- }
-
- $this->add_class_alias($to['glalias']);
- $to = isset($this->osql->aliases[$to['glalias']]) ? array_merge($to, $this->osql->aliases[$to['glalias']]) : $to;
- $curstr = next($tablearr) == 'AS' ? next($tablearr) : current($tablearr);
- if($curstr !== false && strpos('(,-)', $curstr) === false) {
- $to['lalias'] = trim($curstr, '`');
- $curstr = next($tablearr);
- }
-
- if(isset($to['where'])) {
- $this->table_extra_where[] = str_replace("%{$to['glalias']}%", $to['lalias'], $to['where']);
- }
-
- $tablestr = ($to['table'] == $to['lalias'] ? "`{$to['table']}`" : "`{$to['table']}` AS `{$to['lalias']}`");
- $this->laliasinfo[$to['lalias']] = $to;
- if(is_null($from)) {
- $this->from[] = (count($this->from) == 0 ? '' : ',') . $tablestr;
- } else {
- $joinon = str_replace(array("%{$from['glalias']}%", "%{$from['table']}%", "%{$to['field']}%"), array($from['lalias'], $from['lalias'], $to['lalias']), $connection['sqljoin']);
- $this->from[] = "{$connection['extra']['jointype']} JOIN $tablestr ON $joinon";
- }
- if(is_null($this->first_from_alias)) {
- $this->first_from_alias = "`{$to['lalias']}`";
- }
-
- while(strpos('(,-)', $curstr) !== false) {
- if($curstr == '(') {
- $parentstack[] = $to;
- } else if($curstr == ')') {
- array_pop($parentstack);
- } else if($curstr == '-') {
- $from = $to;
- } else if($curstr == ',') {
- $from = count($parentstack) == 0 ? null : $parentstack[count($parentstack) - 1];
- }
- $curstr = next($tablearr);
- }
- }
- $this->from = implode(' ', $this->from);
- }
-
- function join($join = null) {
- if(is_null($join)) {
- return $this->join;
- }
- $this->join = $join;
- return $this;
- }
-
- function get_prepared_set() {
- $set = $this->set;
- if(is_array($set)) {
- $prepped_set = array();
- foreach($set as $col => $val) {
- $prepped_set = array_merge($prepped_set, array("$col = ", $val, ','));
- }
- $set = SurosqlBindable::q((array) array_slice($prepped_set, 0, -1));
- }
- if($set instanceof SurosqlBindable) {
- return $this->get_prepared_bindable($set, 'set');
- }
- return $set;
- }
-
- function set($set = null) {
- if(is_null($set)) {
- return $this->set;
- }
- $this->set = $set;
- return $this;
- }
-
- function setq() {
- $args = func_get_args();
- $this->set = SurosqlBindable::q4set($args);
- return $this;
- }
-
- function get_prepared_bindable($var, $type) {
- if(isset($this->osql->imported_query_functions['get_prepared_bindable'])) {
- return call_user_func($this->osql->imported_query_functions['get_prepared_bindable'], $this, $var, $type);
- }
- $prepped_bind = $var->parts;
- foreach($prepped_bind as $i => &$param) {
- if($i % 2 == 1) {
- $param = Surosql::quote($param);
- }
- }
- return implode(' ', $prepped_bind);
- }
-
- function where($where = null) {
- if(is_null($where)) {
- return $this->where_unparsed;
- }
- $this->where_unparsed = $where;
- $args = func_get_args();
- $this->where = SurosqlBindable::merge('AND', $args);
- return $this;
- }
-
- function andwhere($where) {
- $args = func_get_args();
- $this->where = $this->where_unparsed = SurosqlBindable::merge('AND', array_merge(array($this->where), $args));
- return $this;
- }
-
- function orwhere($where) {
- $func_args = func_get_args();
- $this->where = $this->where_unparsed = SurosqlBindable::merge('OR', array_merge(array($this->where), $args));
- return $this;
- }
-
- function whereq() {
- $args = func_get_args();
- return $this->where(count($args) == 0 ? null : SurosqlBindable::q($args));
- }
-
- function andwhereq() {
- $args = func_get_args();
- return $this->andwhere(SurosqlBindable::q($args));
- }
-
- function orwhereq() {
- $args = func_get_args();
- return $this->orwhere(SurosqlBindable::q($args));
- }
-
- function groupby($groupby = null) {
- if(is_null($groupby)) {
- return $this->groupby;
- }
- $this->groupby = $groupby;
- return $this;
- }
-
- function orderby($orderby = null) {
- if(is_null($orderby)) {
- return $this->orderby;
- }
- $this->orderby = $orderby;
- return $this;
- }
-
- function limit($start = null, $length = null) {
- if(is_null($start)) {
- return $this->limit;
- }
- $start = strpos($start, ',') !== false ? explode(',', $start) : $start;
- if(is_array($start)) {
- list($start, $length) = array_merge($start, array(null));
- }
- $this->limit = is_null($length) ? (string) $start : "$start,$length";
- return $this;
- }
-
- function sql() {
- if(in_array($this->type, array('select', 'selectoo'))) {
- $this->parse_from();
- $this->parse_select();
- $sql[] = "SELECT $this->select FROM $this->from";
- } else if(in_array($this->type, array('delete', 'deleteoo'))) {
- $this->parse_from();
- $select = strlen($this->select) == 0 ? $this->first_from_alias : $this->select;
- $sql[] = "DELETE FROM $select";
- } else if($this->type == 'update') {
- $from = $this->osql->glalias2table(trim(str_replace('`', '', $this->from)));
- $set = $this->get_prepared_set();
- $sql[] = "UPDATE `$from` SET $set";
- }
- if(!is_null($this->join)) {
- $sql[] = $this->join;
- }
- $where = $this->get_prepared_bindable(SurosqlBindable::merge('AND', $this->where, $this->table_extra_where), 'where');
- if($where != '') {
- $sql[] = "WHERE $where";
- }
- if(!is_null($this->groupby)) {
- $sql[] = "GROUP BY {$this->groupby}";
- }
- if(!is_null($this->orderby)) {
- $sql[] = "ORDER BY {$this->orderby}";
- }
- if(!is_null($this->limit)) {
- $sql[] = "LIMIT {$this->limit}";
- }
- return implode(' ', $sql);
- }
-
- function __toString() {
- return $this->sql();
- }
- }
-
- class SurosqlOOManager {
-
- static function init($osql) {
- $funcs = array(
- 'insertobj' => array(__CLASS__, 'insertobj'),
- 'replaceobj' => array(__CLASS__, 'replaceobj'),
- 'updateobj' => array(__CLASS__, 'updateobj'),
- 'deleteobj' => array(__CLASS__, 'deleteobj'),
- 'insertorupdateobj' => array(__CLASS__, 'insertorupdateobj'),
- );
- $osql->imported_osql_functions = array_merge($osql->imported_osql_functions, $funcs);
- }
-
- static function get_osql_inst($obj = null) {
- if(isset($obj->osql) && !is_null($obj->osql)) {
- return $obj->osql;
- }
-
- $cls = is_string($obj) ? $obj : get_class($obj);
- if(isset($cls::$surosql) && isset($cls::$surosql['osql']) && !is_null($cls::$surosql['osql'])) {
- return $cls::$surosql['osql'];
- }
-
- return Surosql::$osql;
- }
-
- static function update($obj, $fields = null, $values_unescaped = array()) {
- return self::updateobj(self::get_osql_inst($obj), $obj, $fields, $values_unescaped);
- }
-
- static function insert($obj, $fields = null, $values_unescaped = array()) {
- return self::insertobj(self::get_osql_inst($obj), $obj, $fields, $values_unescaped);
- }
-
- static function replace($obj, $fields = null, $values_unescaped = array()) {
- return self::replaceobj(self::get_osql_inst($obj), $obj, $fields, $values_unescaped);
- }
-
- static function insertorupdate($obj, $fields = null, $values_unescaped = array()) {
- return self::insertorupdateobj(self::get_osql_inst($obj), $obj, $fields, $values_unescaped);
- }
-
- static function delete($obj) {
- return self::deleteobj(self::get_osql_inst($obj), $obj);
- }
-
- static function updateobj($osql, $obj, $fields = null, $values_unescaped = array()) {
- $oo = $osql->get_obj_info($obj);
- $fields = is_null($fields) ? array_diff($oo['columns'], array($oo['primary'])) : $fields;
- $set = array();
- foreach($fields as $field) {
- $val = $osql->field_serialization($field, isset($obj->$field) ? $obj->$field : null, $oo);
- $set[] = array("`$field`=", $val);
- }
- foreach($values_unescaped as $field => $value) {
- $set[] = array("`$field` = $value");
- }
-
- $num_rows_updated = $osql->update($oo['table'])->setq($set)
- ->whereq("`{$oo['primary']}`=", $obj->{$oo['primary']})->exec();
-
- if($num_rows_updated !== 1) {
- throw new Exception('No rows found to update.');
- }
- return $num_rows_updated;
- }
-
- static function insertobj($osql, $obj, $fields = null, $values_unescaped = array()) {
- return self::insertreplaceobj('insert', $osql, $obj, $fields, $values_unescaped);
- }
-
- static function replaceobj($osql, $obj, $fields = null, $values_unescaped = array()) {
- return self::insertreplaceobj('replace', $osql, $obj, $fields, $values_unescaped);
- }
-
- static function insertreplaceobj($type, $osql, $obj, $fields = null, $values_unescaped = array()) {
- $oo = $osql->get_obj_info($obj);
- foreach($oo['columns'] as $field) {
- if(isset($obj->$field)) {
- $values_escaped[$field] = $osql->field_serialization($field, $obj->$field, $oo);
- }
- }
- if(isset($oo['primary']) && isset($values_escaped[$oo['primary']]) && is_null($values_escaped[$oo['primary']])) {
- unset($values_escaped[$oo['primary']]);
- }
- call_user_func(array($osql, $type), $oo['table'], $values_escaped, $values_unescaped);
- return isset($oo['primary']) ? ($obj->{$oo['primary']} = $osql->lastInsertId()) : null;
- }
-
- static function insertorupdateobj($osql, $obj, $fields = null, $values_unescaped = array()) {
- $oo = $osql->get_obj_info($obj);
- if(!isset($oo['primary']) || !isset($obj->{$oo['primary']}) || is_null($obj->{$oo['primary']})) {
- return self::insertobj($osql, $obj, $fields, $values_unescaped);
- } else {
- return self::updateobj($osql, $obj, $fields, $values_unescaped);
- }
- }
-
- static function deleteobj($osql, $obj) {
- $oo = $osql->get_obj_info($obj);
- return $osql->delete("`{$oo['table']}`")->whereq("`{$oo['primary']}`=", $obj->{$oo['primary']})->exec();
- }
- }
-
- ?>