- upgraded FatFreeFramework 3.6.1 -> 3.6.2
This commit is contained in:
@@ -39,7 +39,9 @@ class Mapper extends \DB\Cursor {
|
||||
//! Defined fields
|
||||
$fields,
|
||||
//! Adhoc fields
|
||||
$adhoc=[];
|
||||
$adhoc=[],
|
||||
//! Dynamic properties
|
||||
$props=[];
|
||||
|
||||
/**
|
||||
* Return database type
|
||||
@@ -57,15 +59,6 @@ class Mapper extends \DB\Cursor {
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if field is defined
|
||||
* @return bool
|
||||
* @param $key string
|
||||
**/
|
||||
function exists($key) {
|
||||
return array_key_exists($key,$this->fields+$this->adhoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if any/specified field value has changed
|
||||
* @return bool
|
||||
@@ -80,6 +73,15 @@ class Mapper extends \DB\Cursor {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return TRUE if field is defined
|
||||
* @return bool
|
||||
* @param $key string
|
||||
**/
|
||||
function exists($key) {
|
||||
return array_key_exists($key,$this->fields+$this->adhoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign value to field
|
||||
* @return scalar
|
||||
@@ -95,12 +97,14 @@ class Mapper extends \DB\Cursor {
|
||||
$this->fields[$key]['changed']=TRUE;
|
||||
return $this->fields[$key]['value']=$val;
|
||||
}
|
||||
// adjust result on existing expressions
|
||||
// Adjust result on existing expressions
|
||||
if (isset($this->adhoc[$key]))
|
||||
$this->adhoc[$key]['value']=$val;
|
||||
else
|
||||
elseif (is_string($val))
|
||||
// Parenthesize expression in case it's a subquery
|
||||
$this->adhoc[$key]=['expr'=>'('.$val.')','value'=>NULL];
|
||||
else
|
||||
$this->props[$key]=$val;
|
||||
return $val;
|
||||
}
|
||||
|
||||
@@ -116,6 +120,8 @@ class Mapper extends \DB\Cursor {
|
||||
return $this->fields[$key]['value'];
|
||||
elseif (array_key_exists($key,$this->adhoc))
|
||||
return $this->adhoc[$key]['value'];
|
||||
elseif (array_key_exists($key,$this->props))
|
||||
return $this->props[$key];
|
||||
user_error(sprintf(self::E_Field,$key),E_USER_ERROR);
|
||||
}
|
||||
|
||||
@@ -127,26 +133,22 @@ class Mapper extends \DB\Cursor {
|
||||
function clear($key) {
|
||||
if (array_key_exists($key,$this->adhoc))
|
||||
unset($this->adhoc[$key]);
|
||||
else
|
||||
unset($this->props[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP type equivalent of PDO constant
|
||||
* @return string
|
||||
* @param $pdo string
|
||||
* Invoke dynamic method
|
||||
* @return mixed
|
||||
* @param $func string
|
||||
* @param $args array
|
||||
**/
|
||||
function type($pdo) {
|
||||
switch ($pdo) {
|
||||
case \PDO::PARAM_NULL:
|
||||
return 'unset';
|
||||
case \PDO::PARAM_INT:
|
||||
return 'int';
|
||||
case \PDO::PARAM_BOOL:
|
||||
return 'bool';
|
||||
case \PDO::PARAM_STR:
|
||||
return 'string';
|
||||
case \DB\SQL::PARAM_FLOAT:
|
||||
return 'float';
|
||||
}
|
||||
function __call($func,$args) {
|
||||
return call_user_func_array(
|
||||
(array_key_exists($func,$this->props)?
|
||||
$this->props[$func]:
|
||||
$this->$func),$args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,14 +194,13 @@ class Mapper extends \DB\Cursor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build query string and execute
|
||||
* @return static[]
|
||||
* Build query string and arguments
|
||||
* @return array
|
||||
* @param $fields string
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
* @param $ttl int|array
|
||||
**/
|
||||
function select($fields,$filter=NULL,array $options=NULL,$ttl=0) {
|
||||
function stringify($fields,$filter=NULL,array $options=NULL) {
|
||||
if (!$options)
|
||||
$options=[];
|
||||
$options+=[
|
||||
@@ -224,7 +225,7 @@ class Mapper extends \DB\Cursor {
|
||||
$sql.=' GROUP BY '.implode(',',array_map(
|
||||
function($str) use($db) {
|
||||
return preg_replace_callback(
|
||||
'/\b(\w+)\h*(HAVING.+|$)/i',
|
||||
'/\b(\w+[._\-\w]*)\h*(HAVING.+|$)/i',
|
||||
function($parts) use($db) {
|
||||
return $db->quotekey($parts[1]).
|
||||
(isset($parts[2])?(' '.$parts[2]):'');
|
||||
@@ -235,47 +236,63 @@ class Mapper extends \DB\Cursor {
|
||||
explode(',',$options['group'])));
|
||||
}
|
||||
if ($options['order']) {
|
||||
$sql.=' ORDER BY '.implode(',',array_map(
|
||||
$order=' ORDER BY '.implode(',',array_map(
|
||||
function($str) use($db) {
|
||||
return preg_match('/^(\w+)(?:\h+(ASC|DESC))?\h*(?:,|$)/i',
|
||||
return preg_match('/^\h*(\w+[._\-\w]*)(?:\h+((?:ASC|DESC)[\w\h]*))?\h*$/i',
|
||||
$str,$parts)?
|
||||
($db->quotekey($parts[1]).
|
||||
(isset($parts[2])?(' '.$parts[2]):'')):$str;
|
||||
},
|
||||
explode(',',$options['order'])));
|
||||
}
|
||||
// SQL Server fixes
|
||||
if (preg_match('/mssql|sqlsrv|odbc/', $this->engine) &&
|
||||
($options['limit'] || $options['offset'])) {
|
||||
$pkeys=[];
|
||||
foreach ($this->fields as $key=>$field)
|
||||
if ($field['pkey'])
|
||||
$pkeys[]=$key;
|
||||
// order by pkey when no ordering option was given
|
||||
if (!$options['order'])
|
||||
foreach ($this->fields as $key=>$field)
|
||||
if ($field['pkey']) {
|
||||
$order=' ORDER BY '.$db->quotekey($key);
|
||||
break;
|
||||
}
|
||||
$ofs=$options['offset']?(int)$options['offset']:0;
|
||||
$lmt=$options['limit']?(int)$options['limit']:0;
|
||||
if (strncmp($db->version(),'11',2)>=0) {
|
||||
// SQL Server 2012
|
||||
if (!$options['order'])
|
||||
$sql.=' ORDER BY '.$db->quotekey($pkeys[0]);
|
||||
$sql.=' OFFSET '.$ofs.' ROWS';
|
||||
// SQL Server >= 2012
|
||||
$sql.=$order.' OFFSET '.$ofs.' ROWS';
|
||||
if ($lmt)
|
||||
$sql.=' FETCH NEXT '.$lmt.' ROWS ONLY';
|
||||
}
|
||||
else {
|
||||
// SQL Server 2008
|
||||
$sql=str_replace('SELECT',
|
||||
$sql=preg_replace('/SELECT/',
|
||||
'SELECT '.
|
||||
($lmt>0?'TOP '.($ofs+$lmt):'').' ROW_NUMBER() '.
|
||||
'OVER (ORDER BY '.
|
||||
$db->quotekey($pkeys[0]).') AS rnum,',$sql);
|
||||
'OVER ('.$order.') AS rnum,',$sql.$order,1);
|
||||
$sql='SELECT * FROM ('.$sql.') x WHERE rnum > '.($ofs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isset($order))
|
||||
$sql.=$order;
|
||||
if ($options['limit'])
|
||||
$sql.=' LIMIT '.(int)$options['limit'];
|
||||
if ($options['offset'])
|
||||
$sql.=' OFFSET '.(int)$options['offset'];
|
||||
}
|
||||
return [$sql,$args];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build query string and execute
|
||||
* @return object
|
||||
* @param $fields string
|
||||
* @param $filter string|array
|
||||
* @param $options array
|
||||
* @param $ttl int|array
|
||||
**/
|
||||
function select($fields,$filter=NULL,array $options=NULL,$ttl=0) {
|
||||
list($sql,$args)=$this->stringify($fields,$filter,$options);
|
||||
$result=$this->db->exec($sql,$args,$ttl);
|
||||
$out=[];
|
||||
foreach ($result as &$row) {
|
||||
@@ -285,8 +302,6 @@ class Mapper extends \DB\Cursor {
|
||||
$val=$this->db->value(
|
||||
$this->fields[$field]['pdo_type'],$val);
|
||||
}
|
||||
elseif (array_key_exists($field,$this->adhoc))
|
||||
$this->adhoc[$field]['value']=$val;
|
||||
unset($val);
|
||||
}
|
||||
$out[]=$this->factory($row);
|
||||
@@ -329,14 +344,17 @@ class Mapper extends \DB\Cursor {
|
||||
* @param $ttl int|array
|
||||
**/
|
||||
function count($filter=NULL,array $options=NULL,$ttl=0) {
|
||||
$expr='COUNT(*)';
|
||||
$field='rows';
|
||||
$this->adhoc[$field]=['expr'=>$expr,'value'=>NULL];
|
||||
$result=$this->select($expr.' AS '.$this->db->quotekey($field),
|
||||
$filter,$options,$ttl);
|
||||
$out=$result[0]->adhoc[$field]['value'];
|
||||
unset($this->adhoc[$field]);
|
||||
return $out;
|
||||
$adhoc='';
|
||||
foreach ($this->adhoc as $key=>$field)
|
||||
$adhoc.=','.$field['expr'].' AS '.$this->db->quotekey($key);
|
||||
$fields='*'.$adhoc;
|
||||
if (preg_match('/mssql|dblib|sqlsrv/',$this->engine))
|
||||
$fields='TOP 100 PERCENT '.$fields;
|
||||
list($sql,$args)=$this->stringify($fields,$filter,$options);
|
||||
$sql='SELECT COUNT(*) AS '.$this->db->quotekey('_rows').' '.
|
||||
'FROM ('.$sql.') AS '.$this->db->quotekey('_temp');
|
||||
$result=$this->db->exec($sql,$args,$ttl);
|
||||
return (int)$result[0]['_rows'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,28 +422,27 @@ class Mapper extends \DB\Cursor {
|
||||
$actr++;
|
||||
$ckeys[]=$key;
|
||||
}
|
||||
$field['changed']=FALSE;
|
||||
unset($field);
|
||||
}
|
||||
if ($fields) {
|
||||
$this->db->exec(
|
||||
$add='';
|
||||
if ($this->engine=='pgsql') {
|
||||
$names=array_keys($pkeys);
|
||||
$aik=end($names);
|
||||
$add=' RETURNING '.$this->db->quotekey($aik);
|
||||
}
|
||||
$lID=$this->db->exec(
|
||||
(preg_match('/mssql|dblib|sqlsrv/',$this->engine) &&
|
||||
array_intersect(array_keys($pkeys),$ckeys)?
|
||||
'SET IDENTITY_INSERT '.$this->table.' ON;':'').
|
||||
'INSERT INTO '.$this->table.' ('.$fields.') '.
|
||||
'VALUES ('.$values.')',$args
|
||||
'VALUES ('.$values.')'.$add,$args
|
||||
);
|
||||
$seq=NULL;
|
||||
if ($this->engine=='pgsql') {
|
||||
$names=array_keys($pkeys);
|
||||
$aik=end($names);
|
||||
if ($this->fields[$aik]['pdo_type']==\PDO::PARAM_INT)
|
||||
$seq=$this->source.'_'.$aik.'_seq';
|
||||
}
|
||||
if ($this->engine!='oci' && !($this->engine=='pgsql' && !$seq))
|
||||
$this->_id=$this->db->lastinsertid($seq);
|
||||
if ($this->engine=='pgsql' && $lID)
|
||||
$this->_id=$lID[0][$aik];
|
||||
elseif ($this->engine!='oci')
|
||||
$this->_id=$this->db->lastinsertid();
|
||||
// Reload to obtain default and auto-increment field values
|
||||
if ($inc || $filter)
|
||||
if ($reload=($inc || $filter))
|
||||
$this->load($inc?
|
||||
[$inc.'=?',$this->db->value(
|
||||
$this->fields[$inc]['pdo_type'],$this->_id)]:
|
||||
@@ -433,6 +450,13 @@ class Mapper extends \DB\Cursor {
|
||||
if (isset($this->trigger['afterinsert']))
|
||||
\Base::instance()->call($this->trigger['afterinsert'],
|
||||
[$this,$pkeys]);
|
||||
// reset changed flag after calling afterinsert
|
||||
if (!$reload)
|
||||
foreach ($this->fields as $key=>&$field) {
|
||||
$field['changed']=FALSE;
|
||||
$field['initial']=$field['value'];
|
||||
unset($field);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@@ -484,10 +508,17 @@ class Mapper extends \DB\Cursor {
|
||||
/**
|
||||
* Delete current record
|
||||
* @return int
|
||||
* @param $quick bool
|
||||
* @param $filter string|array
|
||||
**/
|
||||
function erase($filter=NULL) {
|
||||
function erase($filter=NULL,$quick=TRUE) {
|
||||
if (isset($filter)) {
|
||||
if (!$quick) {
|
||||
$out=0;
|
||||
foreach ($this->find($filter) as $mapper)
|
||||
$out+=$mapper->erase();
|
||||
return $out;
|
||||
}
|
||||
$args=[];
|
||||
if (is_array($filter)) {
|
||||
$args=isset($filter[1]) && is_array($filter[1])?
|
||||
@@ -497,7 +528,8 @@ class Mapper extends \DB\Cursor {
|
||||
list($filter)=$filter;
|
||||
}
|
||||
return $this->db->
|
||||
exec('DELETE FROM '.$this->table.($filter?' WHERE '.$filter:'').';',$args);
|
||||
exec('DELETE FROM '.$this->table.
|
||||
($filter?' WHERE '.$filter:'').';',$args);
|
||||
}
|
||||
$args=[];
|
||||
$ctr=0;
|
||||
@@ -561,7 +593,7 @@ class Mapper extends \DB\Cursor {
|
||||
**/
|
||||
function copyfrom($var,$func=NULL) {
|
||||
if (is_string($var))
|
||||
$var=\Base::instance()->get($var);
|
||||
$var=\Base::instance()->$var;
|
||||
if ($func)
|
||||
$var=call_user_func($func,$var);
|
||||
foreach ($var as $key=>$val)
|
||||
|
||||
Reference in New Issue
Block a user