DB
object
%DB
/phlo/resources/DB/DB.phlo
prop
%DB -> PDO
line 11
如果未为数据库操作定义PDO连接器,则此函数会触发错误。
error('No PDO connector defined')prop
%DB -> fieldQuotes
line 12
检索指定数据库字段的字段引用,以便正确格式化SQL查询。
btmethod
%DB -> load (string $table, string $columns = '*', string $where = void, string $joins = void, string $group = void, string $limit = void, string $order = void, ...$args)
line 14
从指定的数据库表中加载数据,允许选择列、过滤条件、连接、分组、排序和限制结果的可选项。
$table = strpos($table, space) || strpos($table, dot) ? $table : "$this->fieldQuotes$table$this->fieldQuotes"
!$where && $args && $where = loop(array_keys($args), fn($column) => "$table.$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 26
使用PDO执行数据库查询,根据参数的存在直接或使用预处理语句。 如果启用调试,它还提供调试信息,包括查询类型和受影响的行数。
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().")")
}
}
catch (\PDOException $e){
error('Database error'.colon.lf.$query.lf.lf.$e->getMessage())
}
return $stmtmethod
%DB -> column (...$args)
line 45
使用提供的参数从数据库查询的结果集中获取单列数据。
$this->load(...$args)->fetchAll(\PDO::FETCH_COLUMN)method
%DB -> item (...$args)
line 46
使用提供的参数从数据库中获取单列,如果未找到值,则返回null。
$this->load(...$args)->fetch(\PDO::FETCH_COLUMN) ?: nullmethod
%DB -> pair (...$args)
line 47
使用提供的参数从数据库中获取所有行作为键值对数组。
$this->load(...$args)->fetchAll(\PDO::FETCH_KEY_PAIR)method
%DB -> group (...$args)
line 48
从数据库中获取所有记录,按指定的列或列进行分组,并将结果作为指定类的对象数组返回。
$this->load(...$args)->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_CLASS, obj::class)method
%DB -> records (...$args)
line 49
从数据库中以指定类的对象形式获取所有记录,使用提供的参数进行查询。
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS|\PDO::FETCH_UNIQUE, obj::class)method
%DB -> rows (...$args)
line 50
使用提供的参数从数据库中获取所有行作为指定类的实例。
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS, obj::class)method
%DB -> record (...$args)
line 51
从数据库中获取指定类的单个记录作为对象,如果未找到记录,则返回null。
$this->load(...$args)->fetchObject(obj::class) ?: nullmethod
%DB -> create (string $table, ...$data)
line 53
将新记录插入到指定的数据库表中,并提供数据,选项上可以忽略重复条目。
if ($ignore = $data['ignore'] ?? false) unset($data['ignore'])
$columns = $this->fieldQuotes.implode($this->fieldQuotes.comma.$this->fieldQuotes, array_keys($data)).$this->fieldQuotes
$values = implode(comma, array_fill(0, count($data), qm))
$query = "INSERT".($ignore ? ' IGNORE' : void)." INTO $table ($columns) VALUES ($values)"
$this->query($query, ...array_values(loop($data, fn($value) => is_a($value, obj::class) ? $value->id : $value)))
return $this->PDO->lastInsertId() ?: ($data['id'] ?? null)method
%DB -> change (string $table, string $where, ...$data)
line 62
根据给定的条件和数据更新指定数据库表中的记录。
$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) => $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 72
根据给定条件从指定表中删除行。它返回受影响的行数。
$this->query("DELETE FROM $table WHERE $where", ...$args)->rowCount()method
%DB -> begin
line 73
使用PDO开始一个新的数据库事务。
$this->PDO->beginTransaction()method
%DB -> commit
line 74
提交数据库中的当前事务,使事务期间所做的所有更改永久生效。
$this->PDO->commit()method
%DB -> rollback
line 75
如果当前事务处于活动状态,则回滚该事务,撤销在事务期间所做的任何更改。
$this->PDO->inTransaction() && $this->PDO->rollBack()method
%DB -> transaction ($callback)
line 77
通过开始事务、运行提供的回调并在成功时提交事务来执行数据库事务;否则,在发生错误时回滚事务。
$this->begin
try {
$result = $callback()
$this->commit
return $result
} catch (\Throwable $e){
$this->rollback
throw $e
}object
%JSONDB
/phlo/resources/DB/JSONDB.phlo
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资源中指定字段的引用。
''prop
%JSONDB -> lastInsertedId
line 18
返回JSONDB中最后插入记录的ID。
nullmethod
%JSONDB -> objRead
line 20
读取一个 JSON 文件并将其内容作为关联数组返回。如果文件不存在或为空,则返回一个空数组。
file_exists($this->file) ? json_decode(file_get_contents($this->file), true) ?: [] : []method
%JSONDB -> objWrite (array $data)
line 21
将提供的数组数据写入 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 22
通过查找给定数据数组中当前最大ID并加一,返回新对象的下一个可用ID,或者在数组为空时返回1。
$data ? (int)max(array_column($data, 'id')) + 1 : 1method
%JSONDB -> objFilter (array $data, string $where = void, ...$args)
line 24
根据 '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(',', $m[2]))
if (!in_array($row[$column] ?? null, $ids)) $match = false
}
}
$match && $filtered[] = $row
}
return $filteredmethod
%JSONDB -> objSelect (string $where = void, string $limit = void, string $order = void, ...$args)
line 48
根据指定条件从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', '', $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 $datamethod
%JSONDB -> create (string $table, ...$data)
line 59
在指定的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 73
更新符合给定条件的指定表中的行,用新数据替换,并返回更改的行数。
$all = $this->objRead()
$whereCount = substr_count($where, '?')
$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 $changedmethod
%JSONDB -> delete (string $table, string $where, ...$args)
line 90
从指定的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 99
从指定的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 104
对JSONDB执行查询,但不支持原始SQL查询。
error('JSONDB driver does not support raw SQL queries')method
%JSONDB -> begin
line 106
在 JSONDB 中开始一个事务,允许原子性地执行多个操作。
nullmethod
%JSONDB -> commit
line 107
将当前事务提交到JSONDB,保存事务期间所做的所有更改。
nullmethod
%JSONDB -> rollback
line 108
撤销JSONDB中的最后一个事务,将数据库恢复到之前的状态。
nullobject
%JSON_result
/phlo/resources/DB/JSON.result.phlo
static
JSON_result :: __handle
line 9
此属性用于访问 JSON_result 对象的内部句柄。
nullprop
%JSON_result -> data
line 10
访问 `JSON_result` 对象的 `$data` 属性,该属性包含来自 JSON 响应的解析数据。
[]method
%JSON_result -> __construct (array $data)
line 11
使用提供的数据数组初始化 JSON_result 对象。
$this->data = $datamethod
%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->datamethod
%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 $omethod
%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 $rowmethod
%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] ?? falsemethod
%JSON_result -> rowCount
line 66
返回 JSON 结果集中的行数。
count($this->data)object
%migrate
/phlo/resources/DB/migrate.phlo
static
migrate :: setup ($db = null)
line 10
通过创建一个 `migrations` 表来设置数据库(如果尚不存在),该表跟踪迁移记录。
$db ??= %MySQL
$db->query("CREATE TABLE IF NOT EXISTS `migrations` (`id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `batch` int unsigned NOT NULL, `applied_at` int unsigned NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY (`name`))")static
migrate :: applied ($db = null)
line 15
从MySQL数据库的'migrations'表中检索已应用迁移的名称,按ID升序排列。
$db ??= %MySQL
return $db->column(table: 'migrations', columns: 'name', order: 'id ASC')static
migrate :: run (string $path, $db = null)
line 20
通过执行指定目录中的SQL文件来运行数据库迁移,并在'migrations'表中跟踪已应用的迁移。
$db ??= %MySQL
static::setup($db)
$applied = static::applied($db)
$files = glob($path.'/*.sql')
sort($files)
$batch = $applied ? ($db->item(table: 'migrations', columns: 'MAX(batch)') + 1) : 1
$count = 0
foreach ($files AS $file){
$name = basename($file, '.sql')
if (in_array($name, $applied)) continue
$sql = file_get_contents($file)
foreach (array_filter(array_map('trim', explode(';', $sql))) AS $statement) $db->query($statement)
$db->create('migrations', name: $name, batch: $batch, applied_at: time())
$count++
}
return $countstatic
migrate :: rollback ($db = null)
line 39
通过从数据库中的'migrations'表中删除相应的条目来回滚最后一批迁移。
$db ??= %MySQL
$batch = $db->item(table: 'migrations', columns: 'MAX(batch)')
if (!$batch) return 0
$names = $db->query('SELECT name FROM migrations WHERE batch=?', $batch)->fetchAll(\PDO::FETCH_COLUMN)
$db->delete('migrations', 'batch=?', $batch)
return count($names)object
%model
/phlo/resources/DB/model.phlo
static
model :: DB
line 11
访问模型的数据库连接,如果未明确设置,则默认为 %MySQL。
%app->DB ?? %MySQLstatic
model :: objRecords
line 12
访问模型的记录,作为对象数组。
[]static
model :: objLoaded
line 13
指示对象是否已在模型中加载。
[]static
model :: objCache
line 14
model::$objCache 属性保存模型对象的缓存,通过减少重复获取相同数据的需要来提高性能。
falsestatic
model :: objRecordLimit
line 15
设置模型可以检索的最大记录数。
10000static
model :: objSoftDelete
line 16
model::$objSoftDelete 属性指示模型实例是否启用了软删除,如果未启用,则返回 false。
falsestatic
model :: objAudit
line 17
`model::$objAudit` 属性用于访问与模型相关联的审计对象,从而允许跟踪更改和修改。
falsestatic
model :: objValidate
line 18
model::$objValidate 属性指示对象验证是否启用或禁用,如果验证未激活,则返回 false。
falsestatic
model :: objLastErrors
line 19
访问模型实例记录的最后错误,返回错误消息的数组。
[]static
model :: idColumn
line 20
model::$idColumn 属性指定模型中使用的标识符列的名称,默认为 'id'。
'id'static
model :: idType
line 21
将模型的标识符的数据类型定义为整数。
'int'static
model :: canView
line 23
此属性指示当前用户是否有权限查看模型。
truestatic
model :: canCreate
line 24
model::$canCreate 属性指示是否可以创建模型的新实例。
truestatic
model :: canChange
line 25
该属性指示模型是否可以更改,如果允许更改则返回true。
truestatic
model :: canDelete
line 26
model::$canDelete 属性指示模型实例是否可以被删除。
truestatic
model :: state
line 28
`model::$state` 属性保存模型实例的内部状态,包括元数据、记录、加载状态和已删除记录的包含情况。
%req->model ??= obj(meta: [], records: [], loaded: [], includeDeleted: [])static
model :: columns
line 29
检索模型中定义的列,或者从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 36
检索模型关联数据库表的列名,并使用字段引号格式化。
$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).$fqstatic
model :: fields
line 41
返回模型架构中定义的字段,如果不存在架构则返回空数组。如果架构可用,则从模型状态元数据中检索字段。
if (!method_exists(static::class, 'schema')) return static::$fields ?? []
$state = static::state()
return $state->meta[static::class]['fields'] ??= static::_fields()static
model :: _fields
line 46
该属性检索模型架构中定义的字段,同时检查保留的列名以防止冲突。
$reserved = ['table','order','fields','columns','create','change','delete','records','record','column','item','pair','DB','objRecords','objLoaded','objCache','objState','objSave','objGet','objAudit','objValidate','objLastErrors','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 $fieldsstatic
model :: field ($name)
line 52
使用提供的名称访问在模型的静态字段数组中定义的特定字段。
static::fields()[$name]static
model :: create (...$args)
line 54
在验证输入并执行任何定义的生命周期钩子(如beforeSave、beforeCreate、afterCreate和afterSave)后,在数据库中创建新记录。
$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()
$id = static::createRecord(...$args)
$record = static::record(id: $id)
method_exists(static::class, 'afterCreate') && $record->afterCreate()
method_exists(static::class, 'afterSave') && $record->afterSave()
static::objAudit() && %audit->log($record, 'create', [], (array)$record)
return $recordstatic
model :: objRunValidation ($data)
line 68
根据模型定义的字段验证提供的数据,收集在验证过程中遇到的任何错误。
$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::$objLastErrors = $errors
return empty($errors)static
model :: objErrors
line 79
返回模型的最后记录错误作为数组。如果没有记录错误,则返回空数组。
static::$objLastErrors ?? []static
model :: createRecord (...$args)
line 80
使用提供的参数在指定的数据库表中创建新记录。
static::DB()->create(static::$table, ...$args)static
model :: change ($where, ...$args)
line 81
使用提供的条件和参数在指定的数据库表上执行更改操作。
static::DB()->change(static::$table, $where, ...$args)static
model :: delete ($where, ...$args)
line 83
从与模型关联的数据库表中删除记录,选项触发删除前和删除后钩子,并支持软删除。
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()
if (static::objSoftDelete()) $result = static::DB()->change(static::$table, $where, ...array_values($args), deleted_at: time())
else $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', (array)$record, [])
}
return $result
}
if (static::objSoftDelete()) return static::DB()->change(static::$table, $where, ...array_values($args), deleted_at: time())
return static::DB()->delete(static::$table, $where, ...$args)static
model :: objLogChange ($where, ...$args)
line 99
记录对数据库中记录所做的更改,如果启用了审计,则审计之前和当前的状态。
if (!static::objAudit()) return static::change($where, ...$args)
$old = static::records(where: $where)
$result = static::DB()->change(static::$table, $where, ...$args)
foreach ($old AS $record){
$fresh = static::record(id: $record->id)
$fresh && %audit->log($fresh, 'update', (array)$record, (array)$fresh)
}
return $resultmethod
%model -> objSave
line 110
将当前对象保存到数据库中,创建新记录或更新现有记录,同时根据需要调用生命周期方法,如 beforeSave、afterSave、beforeCreate、afterCreate、beforeChange 和 afterChange。
$pk = static::idColumn()
$pkValue = $this->$pk ?? $this->id ?? null
$pkValue || error('Can\'t save '.static::class.' record without '.$pk)
$isNew = !static::item([$pk => $pkValue, 'columns' => $pk])
$old = $isNew ? null : clone $this
method_exists(static::class, 'beforeSave') && $this->beforeSave($old)
if ($isNew){
method_exists(static::class, 'beforeCreate') && $this->beforeCreate()
static::createRecord(...$this)
$saved = static::record([$pk => $pkValue])
method_exists(static::class, 'afterCreate') && $saved->afterCreate()
}
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)
static::objAudit() && %audit->log($saved, 'update', (array)$old, (array)$saved)
}
method_exists(static::class, 'afterSave') && $saved->afterSave($old)
return $savedstatic
model :: transaction ($callback)
line 134
使用提供的回调函数执行数据库事务,确保在提交之前事务内的所有操作都成功完成。
static::DB()->transaction($callback)static
model :: query
line 135
在模型的数据库上执行查询,根据指定条件返回结果。
phlo('query', class: static::class)static
model :: objIncludeDeleted
line 137
该属性决定是否应将已删除的记录包含在模型的查询结果中,如果未指定,则默认为 false。
static::state()->includeDeleted[static::class] ?? falsestatic
model :: objWithDeleted ($callback)
line 138
此方法允许模型在查询结果中包含已删除的记录,通过在执行回调函数期间临时修改状态。
$state = static::state()
$state->includeDeleted[static::class] = true
try {
$result = $callback()
} finally {
unset($state->includeDeleted[static::class])
}
return $resultstatic
model :: objRestore ($id)
line 148
通过将 'deleted_at' 时间戳设置为 null 来恢复软删除的记录。
static::DB()->change(static::$table, static::idColumn().'=?', $id, deleted_at: null)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)
static::objSoftDelete() && !static::objIncludeDeleted() && $args['where'] = 'deleted_at IS NULL'.(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] = ($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 $recordsstatic
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)
line 189
将ID数组转换为以逗号分隔的字符串,如果数组为空则返回'NULL'。
$ids ? dq.implode(dq.comma.dq, $ids).dq : 'NULL'method
%model -> getParent ($key)
line 191
从模型的状态中检索与给定键关联的父对象,如有必要则加载它。
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).')')
}
$parentObject = $state->records[$class][$parentId] ?? null
return $this->objState['parents'][$key] = $parentObjectmethod
%model -> getChildren ($key)
line 214
从模型的状态中检索与给定键关联的子对象,如果尚未加载,则从数据库中加载它们。
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()
if (!isset($state->loaded[static::class]['children'][$key])){
$parentIds = array_keys($state->records[static::class] ?? [])
if ($parentIds){
$fq = static::DB()->fieldQuotes
$children = $class::records(where: $fq.$column.$fq.' IN ('.$this->objIn($parentIds).')')
foreach ($state->records[static::class] 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
}
$state->loaded[static::class]['children'][$key] = true
}
return $this->objState['children'][$key] ?? []method
%model -> getMany ($key)
line 234
从模型的状态中检索与指定键关联的多个相关记录,如果尚未加载,则从数据库中加载它们。
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']
if (!isset($state->loaded[static::class]['many'][$key])){
$parentIds = array_keys($state->records[static::class] ?? [])
if ($parentIds){
$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($parentIds).')')
$targetIds = array_unique(array_map(fn($row) => $row->{$relation['foreignKey']}, $pivotRows ?: []))
$targetRecords = $targetIds ? $class::records(where: $class::idColumn().' IN ('.$this->objIn($targetIds).')') : []
foreach ($state->records[static::class] 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]
}
}
$state->loaded[static::class]['many'][$key] = true
}
return $this->objState['many'][$key] ?? []method
%model -> getCount ($key)
line 259
检索指定键的相关对象的计数,并缓存结果以优化未来的调用。
if (array_key_exists($key, $this->objState['counts'] ?? [])) return $this->objState['counts'][$key]
$state = static::state()
if ($relation = self::objRel('objChildren')[$key] ?? null){
if (!isset($state->loaded[static::class]['children_count'][$key])){
$parentIds = array_keys($state->records[static::class] ?? [])
if ($parentIds){
$isArray = is_array($relation)
$class = $isArray ? $relation['obj'] : $relation
$column = $isArray ? $relation['key'] : static::objShortName()
$fq = static::DB()->fieldQuotes
$counts = $class::pair(columns: $fq.$column.$fq.', COUNT(*)', where: $fq.$column.$fq.' IN ('.$this->objIn($parentIds).')', group: $fq.$column.$fq)
foreach ($state->records[static::class] as $id => $record) $record->objState['counts'][$key] = (int)($counts[$id] ?? 0)
}
$state->loaded[static::class]['children_count'][$key] = true
}
return $this->objState['counts'][$key] ?? 0
}
if ($relation = self::objRel('objMany')[$key] ?? null){
if (!isset($state->loaded[static::class]['many_count'][$key])){
$parentIds = array_keys($state->records[static::class] ?? [])
if ($parentIds){
$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($parentIds).')', group: $fq.$localKey.$fq)->fetchAll(\PDO::FETCH_KEY_PAIR)
foreach ($state->records[static::class] as $id => $record) $record->objState['counts'][$key] = (int)($counts[$id] ?? 0)
}
$state->loaded[static::class]['many_count'][$key] = true
}
return $this->objState['counts'][$key] ?? 0
}
return 0method
%model -> getLast ($key)
line 293
从模型的状态中检索与指定键关联的最后一个子对象,如果尚未加载,则进行加载。
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){
if (!isset($state->loaded[static::class]['last_child'][$key])){
if ($parentIds = array_keys($state->records[static::class] ?? [])){
$isArray = is_array($relation)
$class = $isArray ? $relation['obj'] : $relation
$column = $isArray ? $relation['key'] : static::objShortName()
$childTable = $class::$table
$fq = static::DB()->fieldQuotes
$qt = $fq.$childTable.$fq
$qc = $fq.$column.$fq
$ids = $this->objIn($parentIds)
$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 ($state->records[static::class] 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
}
$state->loaded[static::class]['last_child'][$key] = true
}
return $this->objState['last_child'][$key] ?? null
}
return nullstatic
model :: objResolveClass ($name)
line 320
解析指定模型对象的类名,从而允许在Phlo中动态处理类。
$namestatic
model :: objShortName ($class = null)
line 321
此表达式检索当前模型的类名或指定类的类名(如果存在),使用静态上下文。
$class ?? static::classstatic
model :: objParents
line 323
返回与当前模型关联的父对象,利用定义的模式并过滤类型为'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 329
返回与当前模型关联的子对象,利用定义的模式并过滤类型为'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 335
如果存在 '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
prop
%MySQL -> PDO
line 11
使用提供的凭据创建一个新的PDO实例以连接到MySQL数据库。
new \PDO('mysql:host='.%creds->mysql->host.';dbname='.%creds->mysql->database, %creds->mysql->user, %creds->mysql->password)prop
%MySQL -> objPers
line 12
此表达式将值'true'分配给MySQL对象的属性'$objPers'。
trueobject
%PostgreSQL
/phlo/resources/DB/PostgreSQL.phlo
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。
dqobject
%Qdrant
/phlo/resources/DB/Qdrant.phlo
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_idmethod
%Qdrant -> delete ($collection, ...$ids)
line 15
根据ID从Qdrant集合中删除指定的点。
$this->request("collections/$collection/points/delete", POST: arr(points: $ids))->resultmethod
%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)->resultmethod
%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
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 : btmethod
%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(',', array_fill(0, count($values), '?')).")", ...$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 $thismethod
%query -> order ($order)
line 41
使用指定的$order值设置查询的顺序,并返回当前实例。
$this->orderBy = $order
return $thismethod
%query -> limit ($limit)
line 46
设置从查询中返回的结果的最大数量,由 $limit 参数定义。
$this->limitVal = $limit
return $thismethod
%query -> offset ($offset)
line 51
设置查询的偏移值,从而允许结果的分页。
$this->offsetVal = $offset
return $thismethod
%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 $argsprop
%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
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)