DB

object

%DB

/phlo/resources/DB/DB.phlo
version 1.0
creator q-ai.nl
summary Database engine class
type abstract class
package database
frontend false
backend true
requires php-ext:pdo
tags database pdo sql
prop

%DB -> PDO

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

%DB -> fieldQuotes

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

%DB -> savepoint

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

%DB -> insertIgnore

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

%DB -> insertOnConflict

line 15
将新记录插入数据库,如果发生冲突,则更新现有记录。
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 17
从指定的数据库表中加载数据,允许可选选择列、使用条件过滤、与其他表连接、分组、排序和限制结果。
$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 29
执行带有指定SQL语句和参数的数据库查询,并返回结果集。
$this->queryRun($query, $args, true)
method

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

line 35
执行数据库查询,带有可选参数,并在特定错误情况下对幂等读取语句进行重试。
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)

line 59
检查数据库连接错误是否表明连接已丢失或服务器不可用。
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)

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

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

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

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

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

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

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

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

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

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

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

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

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

%DB -> quoteList (array $ids)

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

%DB -> quoteId ($id)

line 72
对标识符进行转义,以便在 SQL 查询中使用,确保其正确引用以防止 SQL 注入。
$this->fieldQuotes.str_replace($this->fieldQuotes, $this->fieldQuotes.$this->fieldQuotes, (string)$id).$this->fieldQuotes
method

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

line 74
将新记录插入到指定的表中,并使用提供的数据,基于'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 83
返回数据库中最后插入行的ID。
$this->PDO->lastInsertId()
method

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

line 85
根据给定的条件和数据更新指定表中的记录。
$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)

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

%DB -> begin

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

%DB -> commit

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

%DB -> rollback

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

%DB -> transaction ($callback)

line 100
执行数据库事务,允许在事务上下文中运行回调函数。如果发生错误,它会回滚到最后一个保存点或事务的开始,以确保数据完整性。
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
version 1.0
creator q-ai.nl
summary JSON file database driver. One JSONDB instance = one JSON file = one model table. No joins, no transactions, no schema introspection.
extends DB
package database
frontend false
backend true
requires @DB @JSON_result
tags json database file storage
static

JSONDB :: __handle

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

%JSONDB -> __construct (private string $file)

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

%JSONDB -> PDO

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

%JSONDB -> fieldQuotes

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

%JSONDB -> lastInsertedId

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

%JSONDB -> quoteList (array $ids)

line 25
将一个ID数组连接成一个用逗号分隔的字符串,并用双引号包裹。
dq.implode(dq.comma.dq, $ids).dq
method

%JSONDB -> objRead

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

%JSONDB -> objWrite (array $data)

line 28
将提供的数组数据写入 JSON 文件,以美观的格式编码,同时确保不转义 Unicode 字符。
file_put_contents($this->file, json_encode(array_values($data), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX)
method

%JSONDB -> objNextId (array $data)

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

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

line 31
根据 '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)

line 55
根据指定条件从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 66
在指定的JSON数据库表中创建一个新条目,如果未提供ID,则分配一个ID,并可选择根据ID忽略重复项。
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)

line 80
更新符合给定条件的指定表中的行,用新数据替换,并返回更改的行数。
$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)

line 97
从指定的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)

line 106
从指定的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 111
对JSONDB执行查询,但不支持原始SQL查询。
error('JSONDB driver does not support raw SQL queries')
method

%JSONDB -> begin

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

%JSONDB -> commit

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

%JSONDB -> rollback

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

%JSON_result

/phlo/resources/DB/JSON.result.phlo
version 1.0
creator q-ai.nl
summary Minimal PDOStatement-like wrapper for JSONDB result arrays
package database
frontend false
backend true
tags json database result
static

JSON_result :: __handle

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

%JSON_result -> data

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

%JSON_result -> __construct (array $data)

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

%JSON_result -> fetchAll ($mode = 2)

line 13
根据指定模式从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')

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

%JSON_result -> rowCount

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

%model

/phlo/resources/DB/model.phlo
version 1.0
creator q-ai.nl
summary Phlo ORM class with unified columns and schema
type abstract class
package database
frontend false
backend true
requires @DB apcu? audit?
tags orm model database records schema
static

model :: DB

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

model :: objCache

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

model :: objRecordLimit

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

model :: objAudit

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

model :: objValidate

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

model :: idColumn

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

model :: idType

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

model :: canView

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

model :: canCreate

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

model :: canChange

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

model :: canDelete

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

model :: state

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

model :: columns

line 25
检索模型中定义的列,或者从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

line 32
检索模型关联数据库表的列名,并使用字段引号格式化。
$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

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

model :: _fields

line 42
该属性检索模型架构中定义的字段,确保字段名称与保留关键字不冲突。
$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 48
使用提供的名称访问在模型的静态字段数组中定义的特定字段。
static::fields()[$name]
static

model :: create (...$args)

line 50
创建模型的新实例,验证输入参数并在将记录保存到数据库之前执行任何定义的生命周期方法。
$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)

line 60
在模型中创建一个新记录,并在存在时触发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)

line 69
根据模型定义的字段验证提供的数据,收集在验证过程中遇到的任何错误。
$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

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

model :: createRecord (...$args)

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

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

line 82
该方法处理模型的变更操作,必要时执行审计并记录对数据库的更新。
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)

line 97
从与模型关联的数据库表中删除记录,如果存在,则调用 '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)

line 106
根据指定条件从数据库中删除记录,并为每个记录执行可选的删除后方法,如果启用了审计,则记录删除操作。
$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)

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

%model -> objSave

line 117
将当前对象保存到数据库,处理新记录和现有记录,并适当处理保存操作的前后钩子。
$pk = static::idColumn()
$pkValue = $this->$pk ?? $this->id ?? null
$pkValue || error('Can\'t save '.static::class.' record without '.$pk)
// Hooks receive the persisted row as $old, never a clone of the already-mutated object.
$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)

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

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

model :: column (...$args)

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)

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

model :: records (...$args)

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)

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 157
根据指定的参数和缓存选项从数据库加载记录,同时可选择性地将相关记录保存在状态中。
$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)

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

%model -> objState

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

%model -> objGet ($key)

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

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

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

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

line 194
该方法根据指定的存储桶和键同步对象的状态与规范版本,确保对象的状态反映对规范对象所做的任何更改。
$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 203
从模型的状态中检索与给定键关联的父对象,如有必要则加载它。
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 226
从模型的状态中检索与给定键关联的子对象,如果尚未存在则加载它们。
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 244
根据指定的键从模型的状态中检索多个相关记录,如果尚未存在则加载它们。
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)

line 268
检索给定键的相关记录的计数,如有必要,从数据库加载数据并将结果缓存到对象状态中。
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 298
从模型的状态中检索与指定键关联的最后一个子对象,如有必要则加载它。
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)

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

model :: objShortName ($class = null)

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

model :: objParents

line 327
返回与当前模型关联的父对象,利用定义的模式并过滤类型为'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

line 333
返回与当前模型关联的子对象,利用定义的模式并过滤类型为'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

line 339
如果存在 '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
version 1.0
creator q-ai.nl
summary MySQL handler via DB class
extends DB
package database
frontend false
backend true
requires @DB creds:mysql php-ext:pdo php-ext:pdo_mysql
tags mysql pdo database sql
prop

%MySQL -> PDO

line 11
使用提供的凭据创建一个新的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
version 1.0
creator q-ai.nl
summary PostgreSQL resource
extends DB
package database
frontend false
backend true
requires @DB creds:postgresql php-ext:pdo php-ext:pdo_pgsql
tags postgresql pdo database sql
prop

%PostgreSQL -> PDO

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

%PostgreSQL -> fieldQuotes

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

%PostgreSQL -> insertIgnore

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

%PostgreSQL -> insertOnConflict

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

%PostgreSQL -> lastId

line 16
从PostgreSQL数据库中检索最后插入的ID,使用保存点以确保事务的完整性。
$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
version 1.0
creator q-ai.nl
summary Embeddings resource with Qdrant
package ai
frontend false
backend true
requires @AI creds:qdrant apcu
tags qdrant embeddings vector search ai
method

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

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

%Qdrant -> collections

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

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

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

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

line 14
此函数使用提供的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 15
根据ID从Qdrant集合中删除指定的点。
$this->request("collections/$collection/points/delete", POST: arr(points: $ids))->result
method

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

line 16
根据输入向量在指定的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 17
通过向适当的端点发送DELETE请求,从Qdrant中删除指定的集合。
$this->request("collections/$collection", DELETE: true)->result
method

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

line 19
向指定的 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
version 1.0
creator q-ai.nl
summary Fluent query builder for Phlo ORM
package database
frontend false
backend true
requires @DB
tags query builder orm database sql
prop

%query -> class

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

%query -> conditions

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

%query -> bindings

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

%query -> orderBy

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

%query -> limitVal

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

%query -> offsetVal

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

%query -> fq

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

%query -> q ($column)

line 17
验证指定的查询构建器列名,并通过用完全限定名称包围每个部分来格式化它。
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)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

%query -> isNull ($column)

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

%query -> notNull ($column)

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

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

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

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

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

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

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

%query -> order ($order)

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

%query -> limit ($limit)

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

%query -> offset ($offset)

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

%query -> build

line 55
根据指定的条件、顺序、限制和绑定构建查询参数数组,以用于数据库操作。
$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

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

%query -> record

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

%query -> column

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

%query -> item

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

%query -> count

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

%query -> delete

line 68
根据指定条件从数据库中删除记录。如果没有提供条件,则会引发错误。
$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
version 1.0
creator q-ai.nl
summary SQLite resource
extends DB
package database
frontend false
backend true
requires @DB php-ext:pdo php-ext:pdo_sqlite
tags sqlite pdo database sql
static

SQLite :: __handle

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

%SQLite -> __construct (private string $file)

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

%SQLite -> PDO

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

%SQLite -> insertIgnore

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

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