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
This function triggers an error if no PDO connector is defined for database operations.
error('No PDO connector defined')
prop

%DB -> fieldQuotes

line 12
Retrieves the field quotes for a specified database field, allowing for the correct formatting of SQL queries.
bt
method

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

line 14
Loads data from the specified database table, allowing for optional selection of columns, filtering conditions, joins, grouping, ordering, and limiting the results.
$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
Executes a database query using PDO, either directly or with prepared statements based on the presence of arguments. It also provides debugging information if enabled, including the type of query and affected rows.
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 $stmt
method

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

line 45
Fetches a single column from the result set of a database query, using the provided arguments to load the data.
$this->load(...$args)->fetchAll(\PDO::FETCH_COLUMN)
method

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

line 46
Fetches a single column from the database using the provided arguments, returning null if no value is found.
$this->load(...$args)->fetch(\PDO::FETCH_COLUMN) ?: null
method

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

line 47
Fetches all rows from the database as a key-value pair array using the provided arguments.
$this->load(...$args)->fetchAll(\PDO::FETCH_KEY_PAIR)
method

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

line 48
Fetches all records from the database grouped by a specified column or columns, returning the results as an array of objects of the specified class.
$this->load(...$args)->fetchAll(\PDO::FETCH_GROUP|\PDO::FETCH_CLASS, obj::class)
method

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

line 49
Fetches all records from the database as objects of the specified class, using the provided arguments for the query.
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS|\PDO::FETCH_UNIQUE, obj::class)
method

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

line 50
Fetches all rows from the database as instances of the specified class using the provided arguments.
$this->load(...$args)->fetchAll(\PDO::FETCH_CLASS, obj::class)
method

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

line 51
Fetches a single record from the database as an object of the specified class, returning null if no record is found.
$this->load(...$args)->fetchObject(obj::class) ?: null
method

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

line 53
Inserts a new record into the specified database table with the provided data, optionally ignoring duplicate entries.
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
Updates records in the specified database table based on the given conditions and data.
$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
Deletes rows from the specified table based on the given condition. It returns the number of affected rows.
$this->query("DELETE FROM $table WHERE $where", ...$args)->rowCount()
method

%DB -> begin

line 73
Starts a new database transaction using PDO.
$this->PDO->beginTransaction()
method

%DB -> commit

line 74
Commits the current transaction in the database, making all changes made during the transaction permanent.
$this->PDO->commit()
method

%DB -> rollback

line 75
Rolls back the current transaction if one is active, reverting any changes made during the transaction.
$this->PDO->inTransaction() && $this->PDO->rollBack()
method

%DB -> transaction ($callback)

line 77
Executes a database transaction by beginning the transaction, running the provided callback, and committing the transaction if successful; otherwise, it rolls back the transaction in case of an error.
$this->begin
try {
	$result = $callback()
	$this->commit
	return $result
} catch (\Throwable $e){
	$this->rollback
	throw $e
}
object

%JSONDB

/phlo/resources/DB/JSONDB.phlo
version 1.2
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 is a reference to the internal file handle used for accessing the JSON database specified by the $file path.
"JSONDB/$file"
method

%JSONDB -> __construct (private string $file)

line 12
The constructor initializes a JSONDB instance and ensures that the directory for the specified file exists, creating it if necessary.
$dir = dirname($this->file)
is_dir($dir) || mkdir($dir, 0755, true) || error("JSONDB: cannot create dir $dir")
prop

%JSONDB -> PDO

line 16
This function triggers an error indicating that the JSONDB driver is not compatible with PDO.
error('JSONDB driver does not use PDO')
prop

%JSONDB -> fieldQuotes

line 17
Retrieves the quotes for a specified field in a JSONDB resource.
''
prop

%JSONDB -> lastInsertedId

line 18
Returns the ID of the last inserted record in the JSONDB.
null
method

%JSONDB -> objRead

line 20
Reads a JSON file and returns its contents as an associative array. If the file does not exist or is empty, it returns an empty array.
file_exists($this->file) ? json_decode(file_get_contents($this->file), true) ?: [] : []
method

%JSONDB -> objWrite (array $data)

line 21
Writes the provided array data to a JSON file, encoding it in a pretty-printed format while ensuring Unicode characters are not escaped.
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
Returns the next available ID for a new object in the given array of data by finding the maximum current ID and adding one, or returns 1 if the array is empty.
$data ? (int)max(array_column($data, 'id')) + 1 : 1
method

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

line 24
Filters an array of data based on specified conditions in the 'where' clause, returning only the matching rows.
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 $filtered
method

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

line 48
Filters and retrieves objects from a JSON database based on specified conditions, with optional sorting and limiting of results.
$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 $data
method

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

line 59
Creates a new entry in the specified table of the JSON database, assigning an ID if not provided, and optionally ignoring duplicates based on the 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
Updates rows in the specified table that match the given condition with new data, returning the number of rows changed.
$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 $changed
method

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

line 90
Deletes records from the specified table in the JSON database that match the given condition.
$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
Loads data from a specified table in JSONDB, allowing for optional selection of columns, filtering with conditions, joining with other tables, grouping, limiting results, and ordering.
!$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
Executes a query against the JSONDB, but does not support raw SQL queries.
error('JSONDB driver does not support raw SQL queries')
method

%JSONDB -> begin

line 106
Begins a transaction in the JSONDB, allowing for multiple operations to be executed atomically.
null
method

%JSONDB -> commit

line 107
Commits the current transaction to the JSONDB, saving all changes made during the transaction.
null
method

%JSONDB -> rollback

line 108
Reverts the last transaction in the JSONDB, restoring the database to its previous state.
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
This property is used to access the internal handle of a JSON_result object.
null
prop

%JSON_result -> data

line 10
Accesses the `$data` property of the `JSON_result` object, which contains the parsed data from a JSON response.
[]
method

%JSON_result -> __construct (array $data)

line 11
Initializes a JSON_result object with the provided data array.
$this->data = $data
method

%JSON_result -> fetchAll ($mode = 2)

line 13
Fetches all results from the JSON resource according to the specified mode, allowing for different formats such as a single column, key-value pairs, or objects.
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
Fetches a single object of the specified class from the JSON result data, mapping the properties of the object to the values in the first row of the data.
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
Fetches a result row from the JSON data, returning either the entire row or a specific column based on the provided mode.
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
Fetches a single column from the first row of the JSON result set, returning the value at the specified column index or false if not found.
if (!$this->data) return false
$row = reset($this->data)
$vals = array_values((array)$row)
return $vals[$col] ?? false
method

%JSON_result -> rowCount

line 66
Returns the number of rows in the JSON result set.
count($this->data)
object

%migrate

/phlo/resources/DB/migrate.phlo
version 1.0
creator q-ai.nl
summary Database migration runner
package database
frontend false
backend true
requires @DB
tags database migrate migrations sql schema
static

migrate :: setup ($db = null)

line 10
Sets up the database by creating a `migrations` table if it does not already exist, which tracks migration records.
$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
Retrieves the names of applied migrations from the 'migrations' table in the MySQL database, ordered by their ID in ascending order.
$db ??= %MySQL
return $db->column(table: 'migrations', columns: 'name', order: 'id ASC')
static

migrate :: run (string $path, $db = null)

line 20
Runs database migrations by executing SQL files in a specified directory, tracking applied migrations in a 'migrations' table.
$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 $count
static

migrate :: rollback ($db = null)

line 39
Rolls back the last batch of migrations by deleting the corresponding entries from the 'migrations' table in the database.
$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
version 1.1
creator q-ai.nl
summary Phlo ORM class with unified columns and schema
type abstract class
package database
frontend false
backend true
requires @DB @MySQL apcu? audit?
tags orm model database records schema
static

model :: DB

line 11
Accesses the database connection for the model, defaulting to %MySQL if not explicitly set.
%app->DB ?? %MySQL
static

model :: objRecords

line 12
Accesses the records of the model as an array of objects.
[]
static

model :: objLoaded

line 13
Indicates whether the object has been loaded in the model.
[]
static

model :: objCache

line 14
The model::$objCache property holds a cache for model objects, allowing for improved performance by reducing the need to repeatedly fetch the same data.
false
static

model :: objRecordLimit

line 15
Sets the maximum number of records that can be retrieved by the model.
10000
static

model :: objSoftDelete

line 16
The model::$objSoftDelete property indicates whether soft deletion is enabled for the model instance, returning false if it is not enabled.
false
static

model :: objAudit

line 17
The `model::$objAudit` property is used to access the audit object associated with the model, allowing for tracking changes and modifications.
false
static

model :: objValidate

line 18
The model::$objValidate property indicates whether the object validation is enabled or disabled, returning false if validation is not active.
false
static

model :: objLastErrors

line 19
Accesses the last errors recorded for the model instance, returning an array of error messages.
[]
static

model :: idColumn

line 20
The model::$idColumn property specifies the name of the identifier column used in the model, defaulting to 'id'.
'id'
static

model :: idType

line 21
Defines the data type for the model's identifier as an integer.
'int'
static

model :: canView

line 23
This property indicates whether the current user has permission to view the model.
true
static

model :: canCreate

line 24
The model::$canCreate property indicates whether a new instance of the model can be created.
true
static

model :: canChange

line 25
This property indicates whether the model can be changed, returning true if changes are allowed.
true
static

model :: canDelete

line 26
The model::$canDelete property indicates whether the model instance can be deleted.
true
static

model :: state

line 28
The `model::$state` property holds the internal state of a model instance, including metadata, records, loading status, and deleted records inclusion.
%req->model ??= obj(meta: [], records: [], loaded: [], includeDeleted: [])
static

model :: columns

line 29
Retrieves the columns defined in the model, either from the static::$columns property or by calling the schema method if it exists.
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
Retrieves the column names of the model's associated database table, formatted with field quotes.
$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 41
Returns the fields defined in the model's schema, or an empty array if no schema exists. If the schema is available, it retrieves the fields from the model's state metadata.
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
This property retrieves the fields defined in the model's schema while checking for reserved column names to prevent conflicts.
$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 $fields
static

model :: field ($name)

line 52
Accesses a specific field defined in the model's static fields array using the provided name.
static::fields()[$name]
static

model :: create (...$args)

line 54
Creates a new record in the database after validating input and executing any defined lifecycle hooks such as beforeSave, beforeCreate, afterCreate, and 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 $record
static

model :: objRunValidation ($data)

line 68
Validates the provided data against the defined fields of the model, collecting any errors encountered during validation.
$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
Returns the last recorded errors for the model as an array. If no errors are recorded, it returns an empty array.
static::$objLastErrors ?? []
static

model :: createRecord (...$args)

line 80
Creates a new record in the specified database table using the provided arguments.
static::DB()->create(static::$table, ...$args)
static

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

line 81
Executes a change operation on the specified database table using the provided conditions and arguments.
static::DB()->change(static::$table, $where, ...$args)
static

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

line 83
Deletes records from the database table associated with the model, optionally triggering before and after delete hooks, and supporting soft deletes.
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
Logs changes made to a record in the database, auditing the previous and current state if auditing is enabled.
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 $result
method

%model -> objSave

line 110
Saves the current object to the database, either creating a new record or updating an existing one, while invoking lifecycle methods such as beforeSave, afterSave, beforeCreate, afterCreate, beforeChange, and afterChange as appropriate.
$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 $saved
static

model :: transaction ($callback)

line 134
Executes a database transaction using the provided callback function, ensuring that all operations within the transaction are completed successfully before committing.
static::DB()->transaction($callback)
static

model :: query

line 135
Executes a query on the model's database, returning the results based on the specified conditions.
phlo('query', class: static::class)
static

model :: objIncludeDeleted

line 137
This property determines whether deleted records should be included in the model's query results, defaulting to false if not specified.
static::state()->includeDeleted[static::class] ?? false
static

model :: objWithDeleted ($callback)

line 138
This method allows the model to include deleted records in the query results by temporarily modifying the state during the execution of a callback function.
$state = static::state()
$state->includeDeleted[static::class] = true
try {
	$result = $callback()
} finally {
	unset($state->includeDeleted[static::class])
}
return $result
static

model :: objRestore ($id)

line 148
Restores a soft-deleted record in the database by setting its 'deleted_at' timestamp to null.
static::DB()->change(static::$table, static::idColumn().'=?', $id, deleted_at: null)
static

model :: column (...$args)

line 150
Accesses a specific column from the records loaded by the model, using the fetchAll method with PDO's FETCH_COLUMN option.
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_COLUMN])
static

model :: item (...$args)

line 151
Loads records from the database using the specified arguments and fetch mode, returning a single column of data.
static::recordsLoad($args, 'fetch', [\PDO::FETCH_COLUMN])
static

model :: pair (...$args)

line 152
Loads records from the database as a key-value pair array using the specified fetch mode.
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_KEY_PAIR])
static

model :: records (...$args)

line 153
Retrieves all records from the model, loading them as instances of the model class.
static::recordsLoad($args, 'fetchAll', [\PDO::FETCH_CLASS|\PDO::FETCH_UNIQUE, static::class], true)
static

model :: recordCount (...$args)

line 154
Returns the total number of records in the model's database table.
static::item(...$args, columns: 'COUNT('.static::idColumn().')')
static

model :: record (...$args)

line 155
Retrieves a single record from the model's records based on the provided arguments, returning an error if multiple records are found.
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
Loads records from the database based on specified arguments, applying caching if configured, and manages the state of loaded records.
$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 $records
static

model :: objRel ($key)

line 182
Accesses the relationship object defined in the model, returning metadata or invoking a method if it exists.
$state = static::state()
return $state->meta[static::class][$key] ??= method_exists(static::class, $key) ? static::$key() : static::$$key ?? []
prop

%model -> objState

line 187
The `$objState` property of the model holds the state of the object, including its parents, children, and many relationships, initialized as empty arrays.
['parents' => [], 'children' => [], 'many' => []]
method

%model -> objGet ($key)

line 188
Retrieves an object associated with the specified key from the parent, children, or many relationships in the model.
$this->getParent($key) ?? $this->getChildren($key) ?? $this->getMany($key)
method

%model -> objIn ($ids)

line 189
Converts an array of IDs into a comma-separated string, or returns 'NULL' if the array is empty.
$ids ? dq.implode(dq.comma.dq, $ids).dq : 'NULL'
method

%model -> getParent ($key)

line 191
Retrieves the parent object associated with a given key from the model's state, loading it if necessary.
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] = $parentObject
method

%model -> getChildren ($key)

line 214
Retrieves the child objects associated with a given key from the model's state, loading them from the database if they are not already loaded.
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
Retrieves multiple related records associated with a specified key from the model's state, loading them from the database if they are not already loaded.
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
Retrieves the count of related objects for a specified key, caching the result to optimize future calls.
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 0
method

%model -> getLast ($key)

line 293
Retrieves the last child object associated with a specified key from the model's state, loading it if it has not been previously loaded.
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 null
static

model :: objResolveClass ($name)

line 320
Resolves the class name for the specified model object, allowing dynamic class handling in Phlo.
$name
static

model :: objShortName ($class = null)

line 321
This expression retrieves the class name of the current model or the specified class if it exists, using the static context.
$class ?? static::class
static

model :: objParents

line 323
Returns the parent objects associated with the current model, utilizing the defined schema and filtering fields of type '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
Returns the children objects associated with the current model, leveraging the defined schema and filtering fields of type '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
Returns the 'objMany' property if it exists; otherwise, it retrieves an array of related objects based on the schema definition.
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.1
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
Creates a new PDO instance for connecting to a MySQL database using the provided credentials.
new \PDO('mysql:host='.%creds->mysql->host.';dbname='.%creds->mysql->database, %creds->mysql->user, %creds->mysql->password)
prop

%MySQL -> objPers

line 12
This expression assigns the value 'true' to the property '$objPers' of the MySQL object.
true
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
Creates a new PDO instance for connecting to a PostgreSQL database using the provided credentials.
new PDO('pgsql:host='.%creds->postgresql->host.';dbname='.%creds->postgresql->database, %creds->postgresql->user, %creds->postgresql->password)
prop

%PostgreSQL -> fieldQuotes

line 12
Returns the field name wrapped in double quotes for PostgreSQL compatibility.
dq
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
Retrieves an embedding for the given input string using the specified model, caching the result for 28 days.
apcu('embedding/'.token(input: $input), fn($input) => %AI->embedding(input: $input, model: $model), 86400 * 28)
method

%Qdrant -> collections

line 12
Retrieves an array of collection names from the Qdrant API response.
array_column($this->request('collections')->result->collections, 'name')
method

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

line 13
Creates a new collection in Qdrant with specified vector size and distance metric.
$this->request("collections/$collection", PUT: arr(vectors: arr(size: $size, distance: $distance)))->status === 'ok'
method

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

line 14
This function updates or inserts a point in a specified Qdrant collection using the provided ID and input vector, along with optional payload data.
$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
Deletes specified points from a Qdrant collection based on their IDs.
$this->request("collections/$collection/points/delete", POST: arr(points: $ids))->result
method

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

line 16
Searches for points in the specified Qdrant collection based on the input vector and returns the top results.
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
Drops the specified collection from Qdrant by sending a DELETE request to the appropriate endpoint.
$this->request("collections/$collection", DELETE: true)->result
method

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

line 19
Sends an HTTP request to the specified Qdrant server URI with optional data and returns the decoded JSON response.
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
Retrieves the class type of the current query object.
prop

%query -> conditions

line 11
Defines conditions for filtering results in a query.
[]
prop

%query -> bindings

line 12
The `query->$bindings` retrieves the bindings associated with a query in Phlo, allowing access to the parameters used in the query execution.
[]
prop

%query -> orderBy

line 13
Specifies the field by which the results of a query should be ordered.
prop

%query -> limitVal

line 14
Sets the maximum number of results to return from a query in Phlo.
prop

%query -> offsetVal

line 15
Retrieves the current offset value for pagination in a query.
method

%query -> fq

line 16
This expression retrieves the field quotes from the database class associated with the current instance, or defaults to 'bt' if the class is not set.
($class = $this->class) ? $class::DB()->fieldQuotes : bt
method

%query -> q ($column)

line 17
Validates the specified column name for the query builder and formats it by surrounding each part with the fully qualified name.
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
Filters the query results to include only those where the specified column equals the given value.
$this->where($this->q($column)." = ?", $value)
method

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

line 24
Filters results where the specified column is not equal to the given value.
$this->where($this->q($column)." != ?", $value)
method

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

line 25
Adds a condition to the query that filters results where the specified column is greater than the given value.
$this->where($this->q($column)." > ?", $value)
method

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

line 26
Generates a query condition that checks if the value of the specified column is greater than or equal to a given value.
$this->where($this->q($column)." >= ?", $value)
method

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

line 27
Adds a condition to the query to filter results where the specified column is less than the given value.
$this->where($this->q($column)." < ?", $value)
method

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

line 28
Adds a condition to the query that filters results where the specified column is less than or equal to the given value.
$this->where($this->q($column)." <= ?", $value)
method

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

line 29
Adds a condition to the query that checks if the specified column contains a value similar to the provided value using the SQL LIKE operator.
$this->where($this->q($column)." LIKE ?", $value)
method

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

line 30
Filters the query results to include only those records where the specified column's value is in the provided array of values.
$this->where($this->q($column)." IN (".implode(',', array_fill(0, count($values), '?')).")", ...$values)
method

%query -> isNull ($column)

line 31
Checks if the specified column in the query is null.
$this->where($this->q($column)." IS NULL")
method

%query -> notNull ($column)

line 32
Adds a condition to the query to ensure that the specified column is not null.
$this->where($this->q($column)." IS NOT NULL")
method

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

line 33
Filters results to include only those where the specified column's value is between the given minimum and maximum values.
$this->where($this->q($column)." BETWEEN ? AND ?", $min, $max)
method

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

line 34
Executes a raw SQL query with the provided bindings, allowing for dynamic query construction.
$this->where($sql, ...$bindings)
method

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

line 35
Adds a condition to the query with the specified values for binding. It allows for dynamic filtering of results based on the provided condition.
$this->conditions[] = $condition
foreach ($values AS $v) $this->bindings[] = $v
return $this
method

%query -> order ($order)

line 41
Sets the order for the query using the specified $order value and returns the current instance.
$this->orderBy = $order
return $this
method

%query -> limit ($limit)

line 46
Sets the maximum number of results to return from a query, defined by the $limit parameter.
$this->limitVal = $limit
return $this
method

%query -> offset ($offset)

line 51
Sets the offset value for the query, allowing for pagination of results.
$this->offsetVal = $offset
return $this
method

%query -> build

line 55
Builds a query argument array based on specified conditions, order, limit, and bindings for use in database operations.
$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
Retrieves a collection of records from the specified class using the provided build parameters.
($class = $this->class) && $class::records(...$this->build)
prop

%query -> record

line 64
Retrieves a record from the specified class using the provided build parameters.
($class = $this->class) && $class::record(...$this->build)
prop

%query -> column

line 65
Accesses a specific column from a query result set using the defined class and build parameters.
($class = $this->class) && $class::column(...$this->build)
prop

%query -> item

line 66
Retrieves an item from a class using the provided build parameters.
($class = $this->class) && $class::item(...$this->build)
prop

%query -> count

line 67
Returns the total number of records in the specified class using the recordCount method.
($class = $this->class) && $class::recordCount(...$this->build)
method

%query -> delete

line 68
Deletes records from the database based on specified conditions. If no conditions are provided, an error is raised.
$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
This property holds the handle to the SQLite database connection, allowing interaction with the database.
"SQLite/$file"
method

%SQLite -> __construct (private string $file)

line 12
Initializes a new SQLite instance with the specified database file.
prop

%SQLite -> PDO

line 13
Creates a new PDO instance for SQLite using the specified file.
new PDO('sqlite:'.$this->file)

We use essential cookies to make this site work. With your permission we also use analytics to improve the site.