You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
7.5 KiB
388 lines
7.5 KiB
<?php
|
|
|
|
/*
|
|
|
|
Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved.
|
|
|
|
This file is part of the Fat-Free Framework (http://fatfreeframework.com).
|
|
|
|
This is free software: you can redistribute it and/or modify it under the
|
|
terms of the GNU General Public License as published by the Free Software
|
|
Foundation, either version 3 of the License, or later.
|
|
|
|
Fat-Free Framework is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
namespace DB;
|
|
|
|
//! Simple cursor implementation
|
|
abstract class Cursor extends \Magic implements \IteratorAggregate {
|
|
|
|
//@{ Error messages
|
|
const
|
|
E_Field='Undefined field %s';
|
|
//@}
|
|
|
|
protected
|
|
//! Query results
|
|
$query=[],
|
|
//! Current position
|
|
$ptr=0,
|
|
//! Event listeners
|
|
$trigger=[];
|
|
|
|
/**
|
|
* Return database type
|
|
* @return string
|
|
**/
|
|
abstract function dbtype();
|
|
|
|
/**
|
|
* Return field names
|
|
* @return array
|
|
**/
|
|
abstract function fields();
|
|
|
|
/**
|
|
* Return fields of mapper object as an associative array
|
|
* @return array
|
|
* @param $obj object
|
|
**/
|
|
abstract function cast($obj=NULL);
|
|
|
|
/**
|
|
* Return records (array of mapper objects) that match criteria
|
|
* @return array
|
|
* @param $filter string|array
|
|
* @param $options array
|
|
* @param $ttl int
|
|
**/
|
|
abstract function find($filter=NULL,array $options=NULL,$ttl=0);
|
|
|
|
/**
|
|
* Count records that match criteria
|
|
* @return int
|
|
* @param $filter array
|
|
* @param $options array
|
|
* @param $ttl int
|
|
**/
|
|
abstract function count($filter=NULL,array $options=NULL,$ttl=0);
|
|
|
|
/**
|
|
* Insert new record
|
|
* @return array
|
|
**/
|
|
abstract function insert();
|
|
|
|
/**
|
|
* Update current record
|
|
* @return array
|
|
**/
|
|
abstract function update();
|
|
|
|
/**
|
|
* Hydrate mapper object using hive array variable
|
|
* @return NULL
|
|
* @param $var array|string
|
|
* @param $func callback
|
|
**/
|
|
abstract function copyfrom($var,$func=NULL);
|
|
|
|
/**
|
|
* Populate hive array variable with mapper fields
|
|
* @return NULL
|
|
* @param $key string
|
|
**/
|
|
abstract function copyto($key);
|
|
|
|
/**
|
|
* Get cursor's equivalent external iterator
|
|
* Causes a fatal error in PHP 5.3.5 if uncommented
|
|
* return ArrayIterator
|
|
**/
|
|
abstract function getiterator();
|
|
|
|
|
|
/**
|
|
* Return TRUE if current cursor position is not mapped to any record
|
|
* @return bool
|
|
**/
|
|
function dry() {
|
|
return empty($this->query[$this->ptr]);
|
|
}
|
|
|
|
/**
|
|
* Return first record (mapper object) that matches criteria
|
|
* @return static|FALSE
|
|
* @param $filter string|array
|
|
* @param $options array
|
|
* @param $ttl int
|
|
**/
|
|
function findone($filter=NULL,array $options=NULL,$ttl=0) {
|
|
if (!$options)
|
|
$options=[];
|
|
// Override limit
|
|
$options['limit']=1;
|
|
return ($data=$this->find($filter,$options,$ttl))?$data[0]:FALSE;
|
|
}
|
|
|
|
/**
|
|
* Return array containing subset of records matching criteria,
|
|
* total number of records in superset, specified limit, number of
|
|
* subsets available, and actual subset position
|
|
* @return array
|
|
* @param $pos int
|
|
* @param $size int
|
|
* @param $filter string|array
|
|
* @param $options array
|
|
* @param $ttl int
|
|
* @param $bounce bool
|
|
**/
|
|
function paginate(
|
|
$pos=0,$size=10,$filter=NULL,array $options=NULL,$ttl=0,$bounce=TRUE) {
|
|
$total=$this->count($filter,$options,$ttl);
|
|
$count=(int)ceil($total/$size);
|
|
if ($bounce)
|
|
$pos=max(0,min($pos,$count-1));
|
|
return [
|
|
'subset'=>($bounce || $pos<$count)?$this->find($filter,
|
|
array_merge(
|
|
$options?:[],
|
|
['limit'=>$size,'offset'=>$pos*$size]
|
|
),
|
|
$ttl
|
|
):[],
|
|
'total'=>$total,
|
|
'limit'=>$size,
|
|
'count'=>$count,
|
|
'pos'=>$bounce?($pos<$count?$pos:0):$pos
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Map to first record that matches criteria
|
|
* @return array|FALSE
|
|
* @param $filter string|array
|
|
* @param $options array
|
|
* @param $ttl int
|
|
**/
|
|
function load($filter=NULL,array $options=NULL,$ttl=0) {
|
|
$this->reset();
|
|
return ($this->query=$this->find($filter,$options,$ttl)) &&
|
|
$this->skip(0)?$this->query[$this->ptr]:FALSE;
|
|
}
|
|
|
|
/**
|
|
* Return the count of records loaded
|
|
* @return int
|
|
**/
|
|
function loaded() {
|
|
return count($this->query);
|
|
}
|
|
|
|
/**
|
|
* Map to first record in cursor
|
|
* @return mixed
|
|
**/
|
|
function first() {
|
|
return $this->skip(-$this->ptr);
|
|
}
|
|
|
|
/**
|
|
* Map to last record in cursor
|
|
* @return mixed
|
|
**/
|
|
function last() {
|
|
return $this->skip(($ofs=count($this->query)-$this->ptr)?$ofs-1:0);
|
|
}
|
|
|
|
/**
|
|
* Map to nth record relative to current cursor position
|
|
* @return mixed
|
|
* @param $ofs int
|
|
**/
|
|
function skip($ofs=1) {
|
|
$this->ptr+=$ofs;
|
|
return $this->ptr>-1 && $this->ptr<count($this->query)?
|
|
$this->query[$this->ptr]:FALSE;
|
|
}
|
|
|
|
/**
|
|
* Map next record
|
|
* @return mixed
|
|
**/
|
|
function next() {
|
|
return $this->skip();
|
|
}
|
|
|
|
/**
|
|
* Map previous record
|
|
* @return mixed
|
|
**/
|
|
function prev() {
|
|
return $this->skip(-1);
|
|
}
|
|
|
|
/**
|
|
* Return whether current iterator position is valid.
|
|
*/
|
|
function valid() {
|
|
return !$this->dry();
|
|
}
|
|
|
|
/**
|
|
* Save mapped record
|
|
* @return mixed
|
|
**/
|
|
function save() {
|
|
return $this->query?$this->update():$this->insert();
|
|
}
|
|
|
|
/**
|
|
* Delete current record
|
|
* @return int|bool
|
|
**/
|
|
function erase() {
|
|
$this->query=array_slice($this->query,0,$this->ptr,TRUE)+
|
|
array_slice($this->query,$this->ptr,NULL,TRUE);
|
|
$this->skip(0);
|
|
}
|
|
|
|
/**
|
|
* Define onload trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function onload($func) {
|
|
return $this->trigger['load']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define beforeinsert trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function beforeinsert($func) {
|
|
return $this->trigger['beforeinsert']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define afterinsert trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function afterinsert($func) {
|
|
return $this->trigger['afterinsert']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define oninsert trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function oninsert($func) {
|
|
return $this->afterinsert($func);
|
|
}
|
|
|
|
/**
|
|
* Define beforeupdate trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function beforeupdate($func) {
|
|
return $this->trigger['beforeupdate']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define afterupdate trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function afterupdate($func) {
|
|
return $this->trigger['afterupdate']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define onupdate trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function onupdate($func) {
|
|
return $this->afterupdate($func);
|
|
}
|
|
|
|
/**
|
|
* Define beforesave trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function beforesave($func) {
|
|
$this->trigger['beforeinsert']=$func;
|
|
$this->trigger['beforeupdate']=$func;
|
|
return $func;
|
|
}
|
|
|
|
/**
|
|
* Define aftersave trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function aftersave($func) {
|
|
$this->trigger['afterinsert']=$func;
|
|
$this->trigger['afterupdate']=$func;
|
|
return $func;
|
|
}
|
|
|
|
/**
|
|
* Define onsave trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function onsave($func) {
|
|
return $this->aftersave($func);
|
|
}
|
|
|
|
/**
|
|
* Define beforeerase trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function beforeerase($func) {
|
|
return $this->trigger['beforeerase']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define aftererase trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function aftererase($func) {
|
|
return $this->trigger['aftererase']=$func;
|
|
}
|
|
|
|
/**
|
|
* Define onerase trigger
|
|
* @return callback
|
|
* @param $func callback
|
|
**/
|
|
function onerase($func) {
|
|
return $this->aftererase($func);
|
|
}
|
|
|
|
/**
|
|
* Reset cursor
|
|
* @return NULL
|
|
**/
|
|
function reset() {
|
|
$this->query=[];
|
|
$this->ptr=0;
|
|
}
|
|
|
|
}
|
|
|