DB

object

%DB

/phlo/resources/DB/DB.phlo

Database engine class

The shape every driver fills in, and the reason a model can move between MySQL, PostgreSQL, SQLite and a JSON file untouched. Reads come in named flavours, so ask for what you want back: record for one, records keyed by id, rows in order, column, pair and item. Anything you pass as an argument is bound, never pasted into the SQL, so a value from a visitor is safe by construction. A connection that went away is reconnected and the query is tried once more, which is what keeps a long-lived worker alive.

databasepdosql
prop

%DB -> PDO:\PDO

line 12
如果未为数据库操作定义PDO连接器,则此函数会触发错误。
error('No PDO connector defined')
prop

%DB -> fieldQuotes:string

line 13
检索指定数据库字段的字段引用,以便正确格式化SQL查询。
bt
prop

%DB -> savepoint:int

line 14
在当前数据库事务中创建一个保存点,允许进行部分回滚。
prop

%DB -> insertIgnore:string

line 15
将新记录插入数据库,同时忽略任何会导致冲突的重复条目。
' IGNORE'
prop

%DB -> insertOnConflict:string

line 16
将新记录插入数据库,如果发生冲突,则更新现有记录。
void
method

%DB -> load (string $table, string $columns = '*', string $where = void, string $joins = void, string $group = void, string $limit = void, string $order = void, ...$args)

line 18
从指定的数据库表中加载数据,允许可选选择列、使用条件过滤、与其他表连接、分组、排序和限制结果。
$table = strpos($table, space) || strpos($table, dot) ? $table : "$this->fieldQuotes$table$this->fieldQuotes"
$args && $where = ($where ? "$where AND " : void).loop(array_keys($args), fn($column) => $table.dot.$this->quoteId($column).'=?', ' AND ')
$joins && $joins = " $joins"
$where && $where = " WHERE $where"
$group && $group = " GROUP BY $group"
$order && $order = " ORDER BY $order"
$limit && $limit = " LIMIT $limit"
$query = "SELECT $columns FROM $table$joins$where$group$order$limit"
return $this->query($query, ...array_values($args))
method

%DB -> query ($query, ...$args)

line 30
执行带有指定SQL语句和参数的数据库查询,并返回结果集。
$this->queryRun($query, $args, true)
method

%DB -> queryRun ($query, $args, $retry):\PDOStatement

line 37
Runs a statement, retrying once when the connection was lost.
try {
	if (!$args) $stmt = $this->PDO->query($query)
	else {
		$stmt = $this->PDO->prepare($query)
		$stmt->execute($args)
	}
	if (debug){
		$match = regex('/\b(UPDATE|INSERT INTO|DELETE FROM|FROM)\b\s+([`"\[]?\w+[`"\]]?)/i', strtr($query, [$this->fieldQuotes => void]))
		$where = strtr(regex('/\bWHERE (\b.+)/is', $query)[1] ?? void, [' ORDER BY' => void])
		$match && debug("Q: $match[1] $match[2]".strtr(rtrim(" $where "), [dq => void])." (".$stmt->rowCount().")")
	}
	return $stmt
}
catch (\PDOException $e){
	// Retry only idempotent read statements outside a transaction. WITH is excluded: a `WITH ... UPDATE`
	// or `WITH ... DELETE` CTE is a mutation that may already have run before the connection dropped
	// (error 2013), and a reconnect would start a fresh, transaction-less session.
	if (!$retry || !$this->goneAway($e) || $this->PDO->inTransaction() || !preg_match('/^\s*\(*\s*(SELECT|SHOW|EXPLAIN|DESCRIBE|DESC)\b/i', $query)) error('Database error'.colon.lf.$query.lf.lf.$e->getMessage())
	unset($this->PDO)
	return $this->queryRun($query, $args, false)
}
method

%DB -> goneAway ($e):bool

line 61
检查数据库连接错误是否表明连接已丢失或服务器不可用。
in_array((int)($e->errorInfo[1] ?? 0), [2006, 2013], true) || stripos($e->getMessage(), 'gone away') !== false || stripos($e->getMessage(), 'lost connection') !== false
method

%DB -> column (...$args):array

line 63
使用提供的参数从数据库查询的结果集中获取单列数据。
$this->load(...$args)->fetchAll(\PDO::FETCH_COLUMN)
method

%DB -> item (...$args)

line 64
使用提供的参数从数据库加载一个项目,并将其作为单列值返回,如果未找到则返回null。
($v = $this->load(...$args)->fetch(\PDO::FETCH_COLUMN)) === false ? null : $v
method

%DB -> pair (...$args):array

line 65
使用提供的参数从数据库中获取所有行作为键值对数组。
$this->load(...$args)->fetchAll(\PDO::FETCH_KEY_PAIR)
method

%DB -> group (...$args):array

line 66
从数据库中获取所有记录,按指定的列或列进行分组,并将结果作为指定类的对象数组返回。
$this->load(...$args)->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_CLASS, obj::class)
method

%DB -> records (...$args):array

line 67
从数据库中以指定类的对象形式获取所有记录,使用提供的参数进行查询。
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS|\PDO::FETCH_UNIQUE, obj::class)
method

%DB -> rows (...$args):array

line 68
使用提供的参数从数据库中获取所有行作为指定类的实例。
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS, obj::class)
method

%DB -> record (...$args):?obj

line 69
从数据库中获取指定类的单个记录作为对象,如果未找到记录,则返回null。
$this->load(...$args)->fetchObject(obj::class) ?: null
method

%DB -> quoteList (array $ids):string

line 70
对提供的ID数组中的每个元素进行引用,以安全地用于SQL查询,返回一个以逗号分隔的字符串。
loop($ids, fn($id) => $this->PDO->quote((string)$id), comma)
method

%DB -> quoteId ($id):string

line 75
Safely quotes a SQL identifier such as a column or table name.
$this->fieldQuotes.str_replace($this->fieldQuotes, $this->fieldQuotes.$this->fieldQuotes, (string)$id).$this->fieldQuotes
method

%DB -> create (string $table, ...$data)

line 77
将新记录插入到指定的表中,并使用提供的数据,基于'ignore'标志可选择忽略冲突。
if ($ignore = $data['ignore'] ?? false) unset($data['ignore'])
$columns = implode(comma, loop(array_keys($data), fn($k) => $this->quoteId($k)))
$values = implode(comma, array_fill(0, count($data), qm))
$query = "INSERT".($ignore ? $this->insertIgnore : void)." INTO $table ($columns) VALUES ($values)".($ignore ? $this->insertOnConflict : void)
$this->query($query, ...array_values(loop($data, fn($value) => is_a($value, obj::class) ? $value->id : $value)))
return $this->lastId() ?: ($data['id'] ?? null)
method

%DB -> lastId

line 86
返回数据库中最后插入行的ID。
$this->PDO->lastInsertId()
method

%DB -> change (string $table, string $where, ...$data):int

line 88
根据给定的条件和数据更新指定表中的记录。
$whereCount = substr_count($where, qm)
$updates = isset($data['updates']) ? $data['updates'] : void
unset($data['updates'])
$updates .= (($wheres = array_slice(array_keys($data), $whereCount)) && $updates ? comma : void).loop($wheres, fn($key) => $this->quoteId($key).'=?', comma)
$query = "UPDATE $table SET $updates WHERE $where"
$args = array_values([...array_slice($data, $whereCount), ...array_slice($data, 0, $whereCount)])
return $this->query($query, ...$args)->rowCount()
method

%DB -> delete (string $table, string $where, ...$args):int

line 98
根据给定条件从指定表中删除行。它返回受影响的行数。
$this->query("DELETE FROM $table WHERE $where", ...$args)->rowCount()
method

%DB -> begin:?bool

line 99
使用PDO开始一个新的数据库事务。
$this->PDO->beginTransaction()
method

%DB -> commit:?bool

line 100
提交数据库中的当前事务,使事务期间所做的所有更改永久生效。
$this->PDO->commit()
method

%DB -> rollback:?bool

line 101
如果当前事务处于活动状态,则回滚该事务,撤销在事务期间所做的任何更改。
$this->PDO->inTransaction() && $this->PDO->rollBack()
method

%DB -> transaction ($callback)

line 103
执行数据库事务,允许在事务上下文中运行回调函数。如果发生错误,它会回滚到最后一个保存点或事务的开始,以确保数据完整性。
if (!$this->PDO->inTransaction()){
	$this->begin
	try {
		$result = $callback()
		$this->commit
		return $result
	} catch (\Throwable $e){
		$this->rollback
		throw $e
	}
}
// Nested: a savepoint gives the inner unit its own rollback point, so its failure
// (e.g. an audit insert) is undone even when the outer transaction commits.
$sp = 'phlo_sp_'.(++$this->savepoint)
$this->PDO->exec('SAVEPOINT '.$sp)
try {
	$result = $callback()
	$this->PDO->exec('RELEASE SAVEPOINT '.$sp)
	$this->savepoint--
	return $result
} catch (\Throwable $e){
	$this->PDO->exec('ROLLBACK TO SAVEPOINT '.$sp)
	$this->PDO->exec('RELEASE SAVEPOINT '.$sp)
	$this->savepoint--
	throw $e
}
object

%JSONDB

/phlo/resources/DB/JSONDB.phlo

JSON file database driver. One JSONDB instance = one JSON file = one model table. No joins, no transactions, no schema introspection.

A model in a JSON file, for a set of records that stays small and readable: no joins, no transactions, and every write rewrites the whole file. It understands only equality and IN in a where, and raw SQL is refused outright, so keep the model plain. Move to SQLite the moment the file grows or two processes start writing.

jsondatabasefilestorage
static

JSONDB :: __handle

line 12
JSONDB::$__handle 是对用于访问由 $file 路径指定的 JSON 数据库的内部文件句柄的引用。
"JSONDB/$file"
method

%JSONDB -> __construct (private string $file)

line 13
构造函数初始化一个JSONDB实例,并确保指定文件的目录存在,如有必要则创建该目录。
$dir = dirname($this->file)
is_dir($dir) || mkdir($dir, 0755, true) || error("JSONDB: cannot create dir $dir")
prop

%JSONDB -> PDO:\PDO

line 17
此函数触发错误,指示JSONDB驱动程序与PDO不兼容。
error('JSONDB driver does not use PDO')
prop

%JSONDB -> fieldQuotes:string

line 18
检索JSONDB资源中指定字段的引用。
void
prop

%JSONDB -> lastInsertedId

line 19
返回JSONDB中最后插入记录的ID。
null
method

%JSONDB -> quoteList (array $ids):string

line 26
Builds the quoted id list an IN clause expects.
dq.implode(dq.comma.dq, $ids).dq
method

%JSONDB -> objRead:array

line 28
读取一个 JSON 文件并将其内容作为关联数组返回。如果文件不存在或为空,则返回一个空数组。
file_exists($this->file) ? json_decode(file_get_contents($this->file), true) ?: [] : []
method

%JSONDB -> objWrite (array $data):int|false

line 29
file_put_contents($this->file, json_encode(array_values($data), jsonPretty), LOCK_EX)
method

%JSONDB -> objNextId (array $data):int

line 30
通过查找给定数据数组中当前最大ID并加一,返回新对象的下一个可用ID,或者在数组为空时返回1。
$data ? (int)max(array_column($data, 'id')) + 1 : 1
method

%JSONDB -> objFilter (array $data, string $where = void, ...$args):array

line 32
根据 'where' 子句中指定的条件过滤数据数组,仅返回匹配的行。
if (!$where) return $data
$filtered = []
foreach ($data AS $row){
	$match = true
	$parts = preg_split('/\s+AND\s+/i', $where)
	$argIndex = 0
	foreach ($parts AS $part){
		if (preg_match('/^[`"]?(\w+)[`"]?\s*=\s*\?$/', trim($part), $m)){
			$column = $m[1]
			$value = $args[$argIndex++] ?? null
			if (($row[$column] ?? null) != $value) $match = false
		}
		elseif (preg_match('/^[`"]?(\w+)[`"]?\s+IN\s*\((.+)\)$/i', trim($part), $m)){
			$column = $m[1]
			$ids = array_map(fn($v) => trim($v, "\"' "), explode(comma, $m[2]))
			if (!in_array($row[$column] ?? null, $ids)) $match = false
		}
	}
	$match && $filtered[] = $row
}
return $filtered
method

%JSONDB -> objSelect (string $where = void, string $limit = void, string $order = void, ...$args):array

line 56
根据指定条件从JSON数据库中选择对象,支持可选的排序和结果限制。
$data = $this->objFilter($this->objRead(), $where, ...array_values($args))
if ($order){
	$desc = str_contains($order, 'DESC')
	$col = trim(preg_replace('/\s+(ASC|DESC)/i', void, $order), '` ')
	usort($data, fn($a, $b) => $desc ? ($b[$col] ?? 0) <=> ($a[$col] ?? 0) : ($a[$col] ?? 0) <=> ($b[$col] ?? 0))
}
$limit && $data = array_slice($data, 0, (int)$limit)
return $data
method

%JSONDB -> create (string $table, ...$data)

line 70
ignore compares ids loosely, so the string "7" and the number 7 count as one row.
if ($ignore = $data['ignore'] ?? false) unset($data['ignore'])
$all = $this->objRead()
$data['id'] ??= $this->objNextId($all)
foreach ($data AS $key => $value) is_a($value, 'obj') && $data[$key] = $value->id
if ($ignore){
	foreach ($all AS $row) if (($row['id'] ?? null) == $data['id']) return $data['id']
}
$all[] = $data
$this->objWrite($all)
$this->lastInsertedId = $data['id']
return $data['id']
method

%JSONDB -> change (string $table, string $where, ...$data):int

line 84
更新符合给定条件的指定表中的行,用新数据替换,并返回更改的行数。
$all = $this->objRead()
$whereCount = substr_count($where, qm)
$whereArgs = array_slice(array_values($data), 0, $whereCount)
$updates = array_slice($data, $whereCount, null, true)
$changed = 0
foreach ($all AS &$row){
	if ($this->objFilter([$row], $where, ...$whereArgs)){
		foreach ($updates AS $key => $value) $row[$key] = $value
		$changed++
	}
}
unset($row)
$this->objWrite($all)
return $changed
method

%JSONDB -> delete (string $table, string $where, ...$args):int

line 101
从指定的JSON数据库表中删除符合给定条件的记录。
$all = $this->objRead()
$matching = $this->objFilter($all, $where, ...$args)
$matchIds = array_column($matching, 'id')
$remaining = array_values(array_filter($all, fn($row) => !in_array($row['id'] ?? null, $matchIds)))
$this->objWrite($remaining)
return count($matching)
method

%JSONDB -> load (string $table, string $columns = '*', string $where = void, string $joins = void, string $group = void, string $limit = void, string $order = void, ...$args):JSON_result

line 110
从指定的JSONDB表中加载数据,允许选择列、使用条件过滤、与其他表连接、分组、限制结果和排序的可选项。
!$where && $args && $where = loop(array_keys($args), fn($column) => "$column=?", ' AND ')
$data = $this->objSelect($where, $limit, $order, ...array_values($args))
return %JSON_result($data)
method

%JSONDB -> query ($query, ...$args)

line 115
对JSONDB执行查询,但不支持原始SQL查询。
error('JSONDB driver does not support raw SQL queries')
method

%JSONDB -> begin:?bool

line 117
在 JSONDB 中开始一个事务,允许原子性地执行多个操作。
null
method

%JSONDB -> commit:?bool

line 118
将当前事务提交到JSONDB,保存事务期间所做的所有更改。
null
method

%JSONDB -> rollback:?bool

line 119
撤销JSONDB中的最后一个事务,将数据库恢复到之前的状态。
null
object

%JSON_result

/phlo/resources/DB/JSON.result.phlo

Minimal PDOStatement-like wrapper for JSONDB result arrays

Exists so JSONDB can hand back something that behaves like a PDO statement, which is what lets the ORM stay unaware of which driver answered. You do not build one yourself; you meet it as the return value of a JSONDB query.

jsondatabaseresult
static

JSON_result :: __handle

line 10
此属性用于访问 JSON_result 对象的内部句柄。
null
prop

%JSON_result -> data:array

line 11
访问 `JSON_result` 对象的 `$data` 属性,该属性包含来自 JSON 响应的解析数据。
[]
method

%JSON_result -> __construct (array $data)

line 12
使用提供的数据数组初始化 JSON_result 对象。
$this->data = $data
method

%JSON_result -> fetchAll ($mode = 2):array

line 14
根据指定模式从JSON资源中获取所有结果,允许不同格式,如单列、键值对或对象。
if ($mode === \PDO::FETCH_COLUMN) return loop($this->data, fn($row) => reset((array)$row))
if ($mode === \PDO::FETCH_KEY_PAIR){
	$out = []
	foreach ($this->data AS $row){
		$vals = array_values((array)$row)
		$out[$vals[0] ?? null] = $vals[1] ?? null
	}
	return $out
}
if (($mode & (\PDO::FETCH_CLASS | \PDO::FETCH_UNIQUE)) === (\PDO::FETCH_CLASS | \PDO::FETCH_UNIQUE)){
	$out = []
	foreach ($this->data AS $row){
		$o = new obj
		foreach ((array)$row AS $k => $v) $o->$k = $v
		$out[$row['id'] ?? count($out)] = $o
	}
	return $out
}
if (($mode & \PDO::FETCH_CLASS) === \PDO::FETCH_CLASS){
	$out = []
	foreach ($this->data AS $row){
		$o = new obj
		foreach ((array)$row AS $k => $v) $o->$k = $v
		$out[] = $o
	}
	return $out
}
return $this->data
method

%JSON_result -> fetchObject ($class = 'obj'):?obj

line 45
从JSON结果数据中获取指定类的单个对象,将对象的属性映射到数据第一行的值。
if (!$this->data) return null
$row = reset($this->data)
$o = new $class
foreach ((array)$row AS $k => $v) $o->$k = $v
return $o
method

%JSON_result -> fetch ($mode = 2)

line 53
从JSON数据中获取结果行,根据提供的模式返回整个行或特定列。
if (!$this->data) return null
$row = reset($this->data)
if ($mode === \PDO::FETCH_COLUMN) return reset((array)$row)
return $row
method

%JSON_result -> fetchColumn ($col = 0)

line 60
从 JSON 结果集中第一行中获取单列,返回指定列索引的值,如果未找到则返回 false。
if (!$this->data) return false
$row = reset($this->data)
$vals = array_values((array)$row)
return $vals[$col] ?? false
method

%JSON_result -> rowCount:int

line 67
返回 JSON 结果集中的行数。
count($this->data)
object

%model

/phlo/resources/DB/model.phlo

Phlo ORM class with unified columns and schema

A model is a class with fields, and everything else follows from that: columns, form, validation and relations. Named arguments in a read are equality, so records(active: 1) is a where and nothing more; reach for query() when you need a comparison, a LIKE or an IN. A parent field gives back the record itself rather than an id, and children and many-relations are fetched once for a whole result set instead of per row. Set objValidate to have field rules enforced on save, objAudit to log every change, and objCache to keep reads in APCu.

ormmodeldatabaserecordsschema
static

model :: DB

line 12
该属性访问模型的数据库引擎配置,如果没有配置则抛出错误。
error('No database engine configured for '.static::class)
static

model :: objCache

line 13
model::$objCache 属性保存模型对象的缓存,通过减少重复获取相同数据的需要来提高性能。
false
static

model :: objRecordLimit

line 14
设置模型可以检索的最大记录数。
10000
static

model :: objAudit

line 15
`model::$objAudit` 属性用于访问与模型相关联的审计对象,从而允许跟踪更改和修改。
false
static

model :: objValidate

line 16
model::$objValidate 属性指示对象验证是否启用或禁用,如果验证未激活,则返回 false。
false
static

model :: idColumn

line 17
model::$idColumn 属性指定模型中使用的标识符列的名称,默认为 'id'。
'id'
static

model :: idType

line 18
将模型的标识符的数据类型定义为整数。
'int'
static

model :: canView

line 20
此属性指示当前用户是否有权限查看模型。
true
static

model :: canCreate

line 21
model::$canCreate 属性指示是否可以创建模型的新实例。
true
static

model :: canChange

line 22
该属性指示模型是否可以更改,如果允许更改则返回true。
true
static

model :: canDelete

line 23
model::$canDelete 属性指示模型实例是否可以被删除。
true
static

model :: state:obj

line 25
`model::$state` 属性保存模型的当前状态,包括元数据、记录和错误。
%req->model ??= obj(meta: [], records: [], errors: [])
static

model :: columns:string

line 26
检索模型中定义的列,或者从static::$columns属性中获取,或者在存在时调用schema方法。
if (isset(static::$columns)) return static::$columns
if (!method_exists(static::class, 'schema')) return static::$table.'.*'
$state = static::state()
$key = spl_object_id(static::DB()).':'.static::DB()->fieldQuotes.':'.static::$table
return $state->meta[static::class]['columns'][$key] ??= static::_columns()
static

model :: _columns:string

line 33
检索模型关联数据库表的列名,并使用字段引号格式化。
$fq = static::DB()->fieldQuotes
$list = array_merge(...array_values(array_filter(loop(static::fields(), fn($field) => loop($field->objColumns, fn($col) => static::$table."$fq.$fq".$col)))))
return $fq.implode("$fq,$fq", $list).$fq
static

model :: fields:array

line 38
返回模型架构中定义的字段,如果不存在架构则返回空数组。如果架构可用,则从模型状态元数据中检索字段。
if (!method_exists(static::class, 'schema')) return static::$fields ?? []
$state = static::state()
return $state->meta[static::class]['fields'] ??= static::_fields()
static

model :: _fields:array

line 43
该属性检索模型架构中定义的字段,确保字段名称与保留关键字不冲突。
$reserved = ['table','order','fields','columns','create','change','delete','records','record','column','item','pair','DB','objCache','objState','objSave','objGet','objAudit','objValidate','objErrors','idColumn','idType']
$fields = loop(static::schema(), fn($field, $column) => last($field->name ??= $column, $field->type === 'parent' && $field->obj ??= $column, $field))
foreach ($reserved AS $word) isset($fields[$word]) && error("Reserved column name '$word' in ".static::class)
return $fields
static

model :: field ($name)

line 49
使用提供的名称访问在模型的静态字段数组中定义的特定字段。
static::fields()[$name]
static

model :: create (...$args):?static

line 51
创建模型的新实例,验证输入参数并在将记录保存到数据库之前执行任何定义的生命周期方法。
$class = static::class
if (static::objValidate() && !static::objRunValidation($args)) return null
$record = new $class(...$args)
method_exists(static::class, 'beforeSave') && $record->beforeSave()
method_exists(static::class, 'beforeCreate') && $record->beforeCreate()
$pk = static::idColumn()
return static::objAudit() ? static::transaction(fn() => static::objCreateCommit($record, $pk)) : static::objCreateCommit($record, $pk)
static

model :: objCreateCommit ($record, $pk):?static

line 61
在模型中创建一个新记录,并在存在时触发afterCreate和afterSave方法,同时记录创建事件以便审计。
$id = static::createRecord(...$record)
$record = static::record(...[$pk => $record->$pk ?? $id])
method_exists(static::class, 'afterCreate') && $record->afterCreate()
method_exists(static::class, 'afterSave') && $record->afterSave()
static::objAudit() && audit::log($record, 'create', [], $record->objData)
return $record
static

model :: objRunValidation ($data):bool

line 70
根据模型定义的字段验证提供的数据,收集在验证过程中遇到的任何错误。
$errors = []
$fields = static::fields()
foreach ($data AS $column => $value){
	if (!($field = $fields[$column] ?? null) || !method_exists($field, 'objValidate')) continue
	if ($error = $field->objValidate($value)) $errors[$column] = $error
}
static::state()->errors[static::class] = $errors
return empty($errors)
static

model :: objErrors:array

line 81
检索与当前模型实例相关的错误消息,如果未找到则返回空数组。
static::state()->errors[static::class] ?? []
static

model :: createRecord (...$args)

line 82
使用提供的参数在指定的数据库表中创建新记录。
static::DB()->create(static::$table, ...$args)
static

model :: change ($where, ...$args):int

line 83
该方法处理模型的变更操作,必要时执行审计并记录对数据库的更新。
if (!static::objAudit()) return static::DB()->change(static::$table, $where, ...$args)
$pk = static::idColumn()
$bindings = array_values(array_filter($args, 'is_int', ARRAY_FILTER_USE_KEY))
return static::transaction(function() use ($where, $args, $bindings, $pk){
	$old = static::DB()->query('SELECT '.static::$table.'.* FROM '.static::$table.' WHERE '.$where, ...$bindings)->fetchAll(\PDO::FETCH_CLASS, static::class)
	$result = static::DB()->change(static::$table, $where, ...$args)
	foreach ($old AS $record){
		$fresh = static::record(...[$pk => $record->$pk])
		$fresh && audit::log($fresh, 'update', $record->objData, $fresh->objData)
	}
	return $result
})
static

model :: delete ($where, ...$args):int

line 98
从与模型关联的数据库表中删除记录,如果存在,则调用 'beforeDelete' 和 'afterDelete' 方法,并根据需要处理审计和事务。
if (method_exists(static::class, 'beforeDelete') || method_exists(static::class, 'afterDelete') || static::objAudit()){
	$records = static::DB()->query('SELECT '.static::$table.'.* FROM '.static::$table.' WHERE '.$where, ...$args)->fetchAll(\PDO::FETCH_CLASS, static::class)
	foreach ($records AS $record) method_exists(static::class, 'beforeDelete') && $record->beforeDelete()
	return static::objAudit() ? static::transaction(fn() => static::objDeleteCommit($where, $args, $records)) : static::objDeleteCommit($where, $args, $records)
}
return static::DB()->delete(static::$table, $where, ...$args)
static

model :: objDeleteCommit ($where, $args, $records):int

line 107
根据指定条件从数据库中删除记录,并为每个记录执行可选的删除后方法,如果启用了审计,则记录删除操作。
$result = static::DB()->delete(static::$table, $where, ...$args)
foreach ($records AS $record){
	method_exists(static::class, 'afterDelete') && $record->afterDelete()
	static::objAudit() && audit::log($record, 'delete', $record->objData, [])
}
return $result
static

model :: objLogChange ($where, ...$args):int

line 116
记录对指定模型对象的更改,捕获修改前后的状态。
static::change($where, ...$args)
method

%model -> objSave:?static

line 118
$pk = static::idColumn()
$pkValue = $this->$pk ?? $this->id ?? null
$pkValue || error('Can\'t save '.static::class.' record without '.$pk)
$old = static::record(...[$pk => $pkValue])
$isNew = !$old
method_exists(static::class, 'beforeSave') && $this->beforeSave($old)
if ($isNew){
	method_exists(static::class, 'beforeCreate') && $this->beforeCreate()
	$saved = static::objAudit() ? static::transaction(fn() => $this->objSaveCreate($pk, $pkValue)) : $this->objSaveCreate($pk, $pkValue)
}
else {
	method_exists(static::class, 'beforeChange') && $this->beforeChange($old)
	static::change($pk.'=?', $pkValue, ...$this)
	$saved = static::record(...[$pk => $pkValue])
	method_exists(static::class, 'afterChange') && $saved->afterChange($old)
}
method_exists(static::class, 'afterSave') && $saved->afterSave($old)
return $saved
method

%model -> objSaveCreate ($pk, $pkValue):?static

line 139
在模型中创建一个新记录,并在定义的情况下执行后续创建操作,例如日志记录和审计。
static::createRecord(...$this)
$saved = static::record(...[$pk => $pkValue])
method_exists(static::class, 'afterCreate') && $saved->afterCreate()
static::objAudit() && audit::log($saved, 'create', [], $saved->objData)
return $saved
static

model :: transaction ($callback)

line 147
使用提供的回调函数执行数据库事务,确保在提交之前事务内的所有操作都成功完成。
static::DB()->transaction($callback)
static

model :: query:query

line 148
在模型的数据库上执行查询,根据指定条件返回结果。
phlo('query', class: static::class)
static

model :: column (...$args):array

line 150
通过使用PDO的FETCH_COLUMN选项的fetchAll方法,访问模型加载的记录中的特定列。
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_COLUMN])
static

model :: item (...$args)

line 151
使用指定的参数和获取模式从数据库加载记录,返回单列数据。
static::recordsLoad($args, 'fetch', [\PDO::FETCH_COLUMN])
static

model :: pair (...$args):array

line 152
使用指定的提取模式从数据库加载记录为键值对数组。
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_KEY_PAIR])
static

model :: records (...$args):array

line 153
从模型中检索所有记录,将它们加载为模型类的实例。
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_CLASS|\PDO::FETCH_UNIQUE, static::class], true)
static

model :: recordCount (...$args)

line 154
返回模型数据库表中的记录总数。
static::item(...$args, columns: 'COUNT('.static::idColumn().')')
static

model :: record (...$args):?static

line 155
根据提供的参数从模型的记录中检索单个记录,如果找到多个记录则返回错误。
count($records = static::records(...$args)) > 1 ? error('Multiple records for '.static::class) : (current($records) ?: null)
static

model :: recordsLoad ($args, $fetch, $fetchMode, $saveRelations = false)

line 162
Loads records and keeps a full record read on the request-local state for relation reuse.
$pk = static::idColumn()
$args['table'] ??= static::$table
$saveRelations && $args['columns'] ??= static::$table.'.'.$pk.' as _,'.static::columns()
isset(static::$joins) && debug && error('DEPRECATED: static $joins in '.static::class.'. Use getParent/getChildren/getMany instead.')
isset(static::$joins) && $args['joins'] = static::$joins.(isset($args['joins']) ? " $args[joins]" : void)
method_exists(static::class, 'where') && $args['where'] = static::where().(isset($args['where']) ? " AND $args[where]" : void)
isset(static::$group) && $args['group'] ??= static::$group
isset(static::$order) && $args['order'] ??= static::$order
if ($cacheKey = $args['cacheKey'] ?? null) unset($args['cacheKey'])
if ($duration = $args['cache'] ?? static::objCache()){
	unset($args['cache'])
	$cacheArgs = $args
	ksort($cacheArgs)
	$records = apcu($cacheKey ?? static::class.slash.md5(json_encode($cacheArgs)), fn() => static::DB()->load(...$args)->$fetch(...$fetchMode), $duration === true ? 86400 : $duration)
}
else $records = static::DB()->load(...$args)->$fetch(...$fetchMode)
if ($saveRelations && $records){
	$state = static::state()
	$state->records[static::class] = array_replace($state->records[static::class] ?? [], array_column($records, null, $pk))
	count($state->records[static::class]) > static::objRecordLimit() && $state->records[static::class] = array_slice($state->records[static::class], -static::objRecordLimit(), preserve_keys: true)
}
return $records
static

model :: objRel ($key):array

line 187
访问模型中定义的关系对象,返回元数据或在存在时调用方法。
$state = static::state()
return $state->meta[static::class][$key] ??= method_exists(static::class, $key) ? static::$key() : static::$$key ?? []
prop

%model -> objState:array

line 192
模型的`$objState`属性保存对象的状态,包括其父级、子级和多重关系,初始化为空数组。
['parents' => [], 'children' => [], 'many' => []]
method

%model -> objGet ($key)

line 193
从模型的父级、子级或多个关系中检索与指定键关联的对象。
$this->getParent($key) ?? $this->getChildren($key) ?? $this->getMany($key)
method

%model -> objIn ($ids, $db = null):string

line 194
返回数据库中ID的引用列表,如果没有提供ID,则返回'NULL'。
$ids ? ($db ?? static::DB())->quoteList($ids) : 'NULL'
method

%model -> objMirror (string $bucket, $key)

line 200
Mirrors a freshly loaded relation onto a stale reference to the same record.
$pk = $this->objData[static::idColumn()] ?? null
if ($pk === null) return
$canonical = static::state()->records[static::class][$pk] ?? null
if (!$canonical || $canonical === $this) return
if (array_key_exists($key, $this->objState[$bucket] ?? [])) return
if (array_key_exists($key, $canonical->objState[$bucket] ?? [])) $this->objState[$bucket][$key] = $canonical->objState[$bucket][$key]
method

%model -> getParent ($key)

line 209
从模型的状态中检索与给定键关联的父对象,如有必要则加载它。
if (array_key_exists($key, $this->objState['parents'])) return $this->objState['parents'][$key]
$state = static::state()
$parents = self::objRel('objParents')
if (!$relation = $parents[$key] ?? null) return
$isArray = is_array($relation)
$class = $isArray ? $relation['obj'] : $relation
$column = $isArray ? $relation['key'] ?? $key : $key
if (!$parentId = $this->objData[$column] ?? null) return $this->objState['parents'][$key] = null
if (!isset($state->records[$class][$parentId])){
	$idsToLoad = [$parentId => true]
	$allObjData = array_map(fn($record) => $record->objData, $state->records[static::class] ?? [])
	foreach ($parents as $pKey => $pRelation){
		$pIsArray = is_array($pRelation)
		$pClass = $pIsArray ? $pRelation['obj'] : $pRelation
		if ($pClass === $class) foreach (array_column($allObjData, $pIsArray ? $pRelation['key'] ?? $pKey : $pKey) as $pId) $pId && !isset($state->records[$class][$pId]) && $idsToLoad[$pId] = true
	}
	if ($idsToLoad = array_keys($idsToLoad)) $class::records(where: $class::idColumn().' IN ('.$this->objIn($idsToLoad, $class::DB()).')')
}
$parentObject = $state->records[$class][$parentId] ?? null
return $this->objState['parents'][$key] = $parentObject
method

%model -> getChildren ($key)

line 232
从模型的状态中检索与给定键关联的子对象,如果尚未存在则加载它们。
if (array_key_exists($key, $this->objState['children'])) return $this->objState['children'][$key]
$state = static::state()
if (!$relation = self::objRel('objChildren')[$key] ?? null) return
$isArray = is_array($relation)
$class = $isArray ? $relation['obj'] : $relation
$column = $isArray ? $relation['key'] : static::objShortName()
$toLoad = array_filter($state->records[static::class] ?? [], fn($p) => !array_key_exists($key, $p->objState['children']))
if ($toLoad){
	$fq = $class::DB()->fieldQuotes
	$children = $class::records(where: $fq.$column.$fq.' IN ('.$this->objIn(array_keys($toLoad), $class::DB()).')')
	foreach ($toLoad AS $parentRecord) $parentRecord->objState['children'][$key] = []
	foreach ($children AS $childId => $child) !is_null($pId = $child->objData[$column] ?? null) && isset($state->records[static::class][$pId]) && $state->records[static::class][$pId]->objState['children'][$key][$childId] = $child
}
$this->objMirror('children', $key)
return $this->objState['children'][$key] ?? []
method

%model -> getMany ($key)

line 250
根据指定的键从模型的状态中检索多个相关记录,如果尚未存在则加载它们。
if (array_key_exists($key, $this->objState['many'])) return $this->objState['many'][$key]
$state = static::state()
if (!$relation = self::objRel('objMany')[$key] ?? null) return
$class = $relation['obj']
$toLoad = array_filter($state->records[static::class] ?? [], fn($p) => !array_key_exists($key, $p->objState['many']))
if ($toLoad){
	$fq = static::DB()->fieldQuotes
	$lk = $relation['localKey']
	$fk = $relation['foreignKey']
	$pivotRows = static::DB()->rows(table: $relation['table'], columns: $fq.$lk.$fq.comma.$fq.$fk.$fq, where: $fq.$lk.$fq.' IN ('.$this->objIn(array_keys($toLoad)).')')
	$targetIds = array_unique(array_map(fn($row) => $row->{$relation['foreignKey']}, $pivotRows ?: []))
	$targetRecords = $targetIds ? $class::records(where: $class::idColumn().' IN ('.$this->objIn($targetIds, $class::DB()).')') : []
	foreach ($toLoad AS $parentRecord) $parentRecord->objState['many'][$key] = []
	foreach ($pivotRows ?: [] AS $row){
		$parentId = $row->$lk
		$foreignId = $row->$fk
		if (isset($state->records[static::class][$parentId]) && isset($targetRecords[$foreignId])) $state->records[static::class][$parentId]->objState['many'][$key][$foreignId] = $targetRecords[$foreignId]
	}
}
$this->objMirror('many', $key)
return $this->objState['many'][$key] ?? []
method

%model -> getCount ($key):int

line 274
检索给定键的相关记录的计数,如有必要,从数据库加载数据并将结果缓存到对象状态中。
if (array_key_exists($key, $this->objState['counts'] ?? [])) return $this->objState['counts'][$key]
$state = static::state()
if ($relation = self::objRel('objChildren')[$key] ?? null){
	$toLoad = array_filter($state->records[static::class] ?? [], fn($p) => !array_key_exists($key, $p->objState['counts'] ?? []))
	if ($toLoad){
		$isArray = is_array($relation)
		$class = $isArray ? $relation['obj'] : $relation
		$column = $isArray ? $relation['key'] : static::objShortName()
		$fq = $class::DB()->fieldQuotes
		$counts = $class::pair(columns: $fq.$column.$fq.', COUNT(*)', where: $fq.$column.$fq.' IN ('.$this->objIn(array_keys($toLoad), $class::DB()).')', group: $fq.$column.$fq)
		foreach ($toLoad as $id => $record) $record->objState['counts'][$key] = (int)($counts[$id] ?? 0)
	}
	$this->objMirror('counts', $key)
	return $this->objState['counts'][$key] ?? 0
}
if ($relation = self::objRel('objMany')[$key] ?? null){
	$toLoad = array_filter($state->records[static::class] ?? [], fn($p) => !array_key_exists($key, $p->objState['counts'] ?? []))
	if ($toLoad){
		$fq = static::DB()->fieldQuotes
		$localKey = $relation['localKey']
		$counts = static::DB()->load(table: $relation['table'], columns: $fq.$localKey.$fq.',COUNT(*)', where: $fq.$localKey.$fq.' IN ('.$this->objIn(array_keys($toLoad)).')', group: $fq.$localKey.$fq)->fetchAll(\PDO::FETCH_KEY_PAIR)
		foreach ($toLoad as $id => $record) $record->objState['counts'][$key] = (int)($counts[$id] ?? 0)
	}
	$this->objMirror('counts', $key)
	return $this->objState['counts'][$key] ?? 0
}
return 0
method

%model -> getLast ($key)

line 304
从模型的状态中检索与指定键关联的最后一个子对象,如有必要则加载它。
if (array_key_exists($key, $this->objState['last_child'] ?? [])) return $this->objState['last_child'][$key]
$state = static::state()
if ($relation = self::objRel('objChildren')[$key] ?? null){
	$toLoad = array_filter($state->records[static::class] ?? [], fn($p) => !array_key_exists($key, $p->objState['last_child'] ?? []))
	if ($toLoad){
		$isArray = is_array($relation)
		$class = $isArray ? $relation['obj'] : $relation
		$column = $isArray ? $relation['key'] : static::objShortName()
		$childTable = $class::$table
		$fq = $class::DB()->fieldQuotes
		$qt = $fq.$childTable.$fq
		$qc = $fq.$column.$fq
		$ids = $this->objIn(array_keys($toLoad), $class::DB())
		$childPk = $class::idColumn()
		$joins = ' INNER JOIN (SELECT MAX('.$fq.$childPk.$fq.') AS last_id, '.$qc.' AS parent_id FROM '.$qt.' WHERE '.$qc.' IN ('.$ids.') GROUP BY '.$qc.') AS lcmax ON '.$qt.'.'.$fq.$childPk.$fq.' = lcmax.last_id'
		$lastChildren = $class::records(joins: $joins)
		foreach ($toLoad as $record) $record->objState['last_child'][$key] = null
		foreach ($lastChildren as $child) if (isset($state->records[static::class][$parentId = $child->objData[$column]])) $state->records[static::class][$parentId]->objState['last_child'][$key] = $child
	}
	$this->objMirror('last_child', $key)
	return $this->objState['last_child'][$key] ?? null
}
return null
static

model :: objResolveClass ($name):string

line 330
解析指定模型对象的类名,从而允许在Phlo中动态处理类。
$name
static

model :: objShortName ($class = null):string

line 331
此表达式检索当前模型的类名或指定类的类名(如果存在),使用静态上下文。
$class ?? static::class
static

model :: objParents:array

line 333
返回与当前模型关联的父对象,利用定义的模式并过滤类型为'parent'的字段。
if (property_exists(static::class, 'objParents')) return static::$objParents
if (!method_exists(static::class, 'schema')) return []
return loop(array_filter(static::fields(), fn($f) => $f->type === 'parent'), fn($f, $c) => $f->key ? arr(obj: static::objResolveClass($f->obj), key: $f->key) : (static::objResolveClass($f->obj ?? $c)))
static

model :: objChildren:array

line 339
返回与当前模型关联的子对象,利用定义的模式并过滤类型为'child'的字段。
if (property_exists(static::class, 'objChildren')) return static::$objChildren
if (!method_exists(static::class, 'schema')) return []
return loop(array_filter(static::fields(), fn($f) => $f->type === 'child'), fn($f, $c) => $f->key ? arr(obj: static::objResolveClass($f->obj), key: $f->key) : (static::objResolveClass($f->obj ?? $c)))
static

model :: objMany:array

line 345
如果存在 'objMany' 属性,则返回该属性;否则,根据模式定义检索相关对象的数组。
if (property_exists(static::class, 'objMany')) return static::$objMany
if (!method_exists(static::class, 'schema')) return []
return loop(array_filter(static::fields(), fn($f) => $f->type === 'many'), fn($f) => arr(obj: static::objResolveClass($f->obj), table: $f->table, localKey: $f->localKey ?? static::objShortName(), foreignKey: $f->foreignKey ?? $f->obj))
object

%MySQL

/phlo/resources/DB/MySQL.phlo

MySQL handler via DB class

Reads host, database, user and password from the mysql section of %creds. It is the default assumption of the ORM, so a model that names no engine of its own ends up here.

mysqlpdodatabasesql
prop

%MySQL -> PDO:\PDO

line 12
使用提供的凭据创建一个新的PDO实例以连接到MySQL数据库。
new \PDO('mysql:host='.%creds->mysql->host.';dbname='.%creds->mysql->database, %creds->mysql->user, %creds->mysql->password)
object

%PostgreSQL

/phlo/resources/DB/PostgreSQL.phlo

PostgreSQL resource

Quotes identifiers with double quotes rather than backticks and has no INSERT IGNORE, so a duplicate is skipped with ON CONFLICT DO NOTHING. Postgres folds an unquoted name to lower case, so a column called createdAt in a schema is not the same one you get back unquoted.

postgresqlpdodatabasesql
prop

%PostgreSQL -> PDO:\PDO

line 12
使用提供的凭据创建一个新的PDO实例,以连接到PostgreSQL数据库。
new PDO('pgsql:host='.%creds->postgresql->host.';dbname='.%creds->postgresql->database, %creds->postgresql->user, %creds->postgresql->password)
prop

%PostgreSQL -> fieldQuotes:string

line 13
返回字段名称,用双引号包裹,以兼容PostgreSQL。
dq
prop

%PostgreSQL -> insertIgnore:string

line 14
将新记录插入PostgreSQL数据库,如果已经存在相同唯一键的记录,则忽略该操作。
void
prop

%PostgreSQL -> insertOnConflict:string

line 15
向PostgreSQL数据库插入新记录,如果发生冲突(例如,重复键),则不执行任何操作,而不是抛出错误。
' ON CONFLICT DO NOTHING'
method

%PostgreSQL -> lastId

line 21
Asks for the last id inside a savepoint, so a failed lastval() cannot abort the transaction.
$savepoint = $this->PDO->inTransaction()
$savepoint && $this->PDO->exec('SAVEPOINT phlo_lastid')
try {
	$id = $this->PDO->lastInsertId()
} catch (\Throwable $e){
	$id = false
}
if ($savepoint) $this->PDO->exec($id === false ? 'ROLLBACK TO SAVEPOINT phlo_lastid' : 'RELEASE SAVEPOINT phlo_lastid')
return $id
object

%Qdrant

/phlo/resources/DB/Qdrant.phlo

Embeddings resource with Qdrant

Embeddings are cached in APCu for four weeks per input, so repeating a search costs nothing at the AI end. create() opens a collection at 1536 dimensions, the length of an OpenAI vector, so state the size yourself when another engine fills it. search() without input sends a zero vector, which lists a collection rather than searching it.

qdrantembeddingsvectorsearchai
method

%Qdrant -> get (string $input, ?string $model = null):array

line 11
使用指定的模型检索给定输入字符串的嵌入,并将结果缓存28天。
apcu('embedding/'.token(input: $input), fn($input) => %AI->embedding(input: $input, model: $model), 86400 * 28)
method

%Qdrant -> collections:array

line 13
从Qdrant API响应中检索集合名称的数组。
array_column($this->request('collections')->result->collections, 'name')
method

%Qdrant -> create ($collection, $size = 1536, $distance = 'Cosine'):bool

line 14
在Qdrant中创建一个新的集合,指定向量大小和距离度量。
$this->request("collections/$collection", PUT: arr(vectors: arr(size: $size, distance: $distance)))->status === 'ok'
method

%Qdrant -> upsert ($collection, $id, $input, ...$payload)

line 15
此函数使用提供的ID和输入向量更新或插入指定Qdrant集合中的点,并可以附加可选的负载数据。
$this->request("collections/$collection/points", PUT: arr(points: [arr(id: $id, vector: $this->get($input), payload: $payload ?: null)]))->result->operation_id
method

%Qdrant -> delete ($collection, ...$ids)

line 16
根据ID从Qdrant集合中删除指定的点。
$this->request("collections/$collection/points/delete", POST: arr(points: $ids))->result
method

%Qdrant -> search ($collection, $input = null, $top = 100):array

line 17
根据输入向量在指定的Qdrant集合中搜索点,并返回最佳结果。
create($this->request("collections/$collection/points/search", POST: arr(vector: is_null($input) ? array_fill(0, 1536, 0) : $this->get($input), top: $top, with_payload: true))->result, fn($record) => $record->id, fn($record) => last($record = array_merge(get_object_vars($record), get_object_vars($record->payload)), obj(...array_filter($record, fn($key) => $key !== 'payload', ARRAY_FILTER_USE_KEY))))
method

%Qdrant -> drop ($collection)

line 18
通过向适当的端点发送DELETE请求,从Qdrant中删除指定的集合。
$this->request("collections/$collection", DELETE: true)->result
method

%Qdrant -> request ($uri, ...$data)

line 20
向指定的 Qdrant 服务器 URI 发送 HTTP 请求,带有可选数据,并返回解码的 JSON 响应。
json_decode(HTTP(%creds->qdrant->server.$uri, %creds->qdrant->key ? ['api-key: '.%creds->qdrant->key] : [], true, ...$data))
object

%query

/phlo/resources/DB/query.phlo

Fluent query builder for Phlo ORM

For everything named arguments cannot say: eq, gt, like, in, isNull, order, limit and offset, chained and closed with records, record, column, item or count. Column names are quoted for the driver you are on, so the same chain works on MySQL and Postgres. Values go in as bindings, so a search box can be passed straight through.

querybuilderormdatabasesql
prop

%query -> class

line 11
检索当前查询对象的类类型。
prop

%query -> conditions

line 12
定义查询中结果过滤的条件。
[]
prop

%query -> bindings

line 13
`query->$bindings` 用于检索与 Phlo 中的查询相关联的绑定,从而访问查询执行中使用的参数。
[]
prop

%query -> orderBy

line 14
指定查询结果应按哪个字段排序。
prop

%query -> limitVal

line 15
设置从 Phlo 查询中返回的最大结果数量。
prop

%query -> offsetVal

line 16
检索查询中用于分页的当前偏移值。
method

%query -> fq:string

line 17
该表达式从与当前实例关联的数据库类中检索字段引用,如果未设置类,则默认为 'bt'。
($class = $this->class) ? $class::DB()->fieldQuotes : bt
method

%query -> q ($column):string

line 18
验证指定的查询构建器列名,并通过用完全限定名称包围每个部分来格式化它。
preg_match('/^[A-Za-z_][A-Za-z0-9_.]*$/', $column) || error("Invalid column for query builder: $column")
$fq = $this->fq
return implode(dot, array_map(fn($part) => $fq.$part.$fq, explode(dot, $column)))
method

%query -> eq ($column, $value):static

line 24
过滤查询结果,仅包括指定列等于给定值的记录。
$this->where($this->q($column)." = ?", $value)
method

%query -> neq ($column, $value):static

line 25
过滤结果,其中指定的列不等于给定的值。
$this->where($this->q($column)." != ?", $value)
method

%query -> gt ($column, $value):static

line 26
向查询添加条件,过滤出指定列大于给定值的结果。
$this->where($this->q($column)." > ?", $value)
method

%query -> gte ($column, $value):static

line 27
生成一个查询条件,检查指定列的值是否大于或等于给定值。
$this->where($this->q($column)." >= ?", $value)
method

%query -> lt ($column, $value):static

line 28
向查询添加条件,以过滤结果,其中指定的列小于给定值。
$this->where($this->q($column)." < ?", $value)
method

%query -> lte ($column, $value):static

line 29
向查询添加条件,过滤结果,其中指定的列小于或等于给定值。
$this->where($this->q($column)." <= ?", $value)
method

%query -> like ($column, $value):static

line 30
向查询添加一个条件,检查指定列是否包含与提供的值相似的值,使用SQL LIKE运算符。
$this->where($this->q($column)." LIKE ?", $value)
method

%query -> in ($column, array $values):static

line 31
向查询添加条件,以过滤结果,其中指定列的值在提供的值数组中。
$this->where($this->q($column)." IN (".implode(comma, array_fill(0, count($values), qm)).")", ...$values)
method

%query -> isNull ($column):static

line 32
检查查询中指定的列是否为 null。
$this->where($this->q($column)." IS NULL")
method

%query -> notNull ($column):static

line 33
向查询添加条件,以确保指定的列不为 null。
$this->where($this->q($column)." IS NOT NULL")
method

%query -> between ($column, $min, $max):static

line 34
过滤结果,仅包括指定列的值在给定的最小值和最大值之间的记录。
$this->where($this->q($column)." BETWEEN ? AND ?", $min, $max)
method

%query -> raw ($sql, ...$bindings):static

line 35
使用提供的绑定执行原始 SQL 查询,允许动态查询构建。
$this->where($sql, ...$bindings)
method

%query -> where ($condition, ...$values):static

line 36
将条件添加到查询中,并为绑定指定值。它允许根据提供的条件动态过滤结果。
$this->conditions[] = $condition
foreach ($values AS $v) $this->bindings[] = $v
return $this
method

%query -> order ($order):static

line 42
使用指定的$order值设置查询的顺序,并返回当前实例。
$this->orderBy = $order
return $this
method

%query -> limit ($limit):static

line 47
设置从查询中返回的结果的最大数量,由 $limit 参数定义。
$this->limitVal = $limit
return $this
method

%query -> offset ($offset):static

line 52
设置查询的偏移值,从而允许结果的分页。
$this->offsetVal = $offset
return $this
method

%query -> build:array

line 56
根据指定的条件、顺序、限制和绑定构建查询参数数组,以用于数据库操作。
$where = $this->conditions ? implode(' AND ', $this->conditions) : void
$limit = $this->limitVal ? ($this->offsetVal ? "$this->offsetVal,$this->limitVal" : "$this->limitVal") : void
$args = ['where' => $where ?: void, 'order' => $this->orderBy ?: void, 'limit' => $limit ?: void]
foreach ($this->bindings AS $b) $args[] = $b
return $args
prop

%query -> records:array

line 64
使用提供的构建参数从指定类中检索记录集合。
($class = $this->class) && $class::records(...$this->build)
prop

%query -> record:?model

line 65
使用提供的构建参数从指定类中检索记录。
($class = $this->class) && $class::record(...$this->build)
prop

%query -> column:array

line 66
使用定义的类和构建参数访问查询结果集中的特定列。
($class = $this->class) && $class::column(...$this->build)
prop

%query -> item

line 67
使用提供的构建参数从类中检索项。
($class = $this->class) && $class::item(...$this->build)
prop

%query -> count

line 68
使用recordCount方法返回指定类中的记录总数。
($class = $this->class) && $class::recordCount(...$this->build)
method

%query -> delete:int

line 69
根据指定条件从数据库中删除记录。如果没有提供条件,则会引发错误。
$class = $this->class
$where = $this->conditions ? implode(' AND ', $this->conditions) : error('Cannot delete without conditions')
return $class::delete($where, ...$this->bindings)
object

%SQLite

/phlo/resources/DB/SQLite.phlo

SQLite resource

One file, one database, given as a path: %SQLite('/path/db.sqlite'). It writes with a lock over the whole file, so it fits a single site or a worker but not a set of processes writing at once. Perfect where you want the ORM without a server.

sqlitepdodatabasesql
static

SQLite :: __handle

line 12
此属性保存与SQLite数据库连接的句柄,允许与数据库进行交互。
"SQLite/$file"
method

%SQLite -> __construct (private string $file)

line 13
使用指定的数据库文件初始化一个新的SQLite实例。
prop

%SQLite -> PDO:\PDO

line 14
使用指定的文件为SQLite创建一个新的PDO实例。
new PDO('sqlite:'.$this->file)
prop

%SQLite -> insertIgnore:string

line 15
将新记录插入SQLite数据库,如果已存在相同主键的记录,则忽略该操作。
' OR IGNORE'

最近更新于 2026年8月8日

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。