kingsoft / persist-db
Implementation of Kingsoft/IPersist for databases using Kingsoft/Database as a backend.
Installs: 320
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 11
pkg:composer/kingsoft/persist-db
Requires
- php: >=8.3
- kingsoft/db: ^2.7
- kingsoft/persist: ^3.2
- kingsoft/utils: ^2.7
- dev-main
- 2.13.5
- 2.13.4
- 2.13.3
- 2.13.2
- 2.13.1
- 2.13.0
- 2.12.10
- 2.12.9
- 2.12.8
- 2.12.7
- 2.12.6
- 2.12.5
- 2.12.4
- 2.12.3
- 2.12.2
- 2.12.1
- 2.12.0
- 2.11.0
- 2.10.0
- 2.9.3
- 2.9.2
- 2.9.1
- 2.9.0
- 2.8.25
- 2.8.24
- 2.8.23
- 2.8.22
- 2.8.21
- 2.8.20
- 2.8.19
- 2.8.18
- 2.8.17
- 2.8.16
- 2.8.15
- 2.8.14
- 2.8.13
- 2.8.12
- 2.8.11
- 2.8.10
- 2.8.9
- 2.8.8
- 2.8.7
- 2.8.6
- 2.8.5
- 2.8.4
- 2.8.3
- 2.8.2
- 2.8.1
- 2.8.0
- 2.7.5
- 2.7.4
- 2.7.3
- 2.7.2
- 2.7.1
- 2.7.0
- 2.6.9
- 2.6.8
- 2.6.7
- 2.6.6
- 2.6.5
- 2.6.4
- 2.6.3
- 2.6.2
- 2.6.1
- 2.5.0
- 2.1.2
- 2.1.0
- 2.0
- 1.3.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.0
- dev-copilot/update-documentation-for-simple-resources
- dev-copilot/fix-missing-slash-in-docs
- dev-94-strict-__set-testing-brings-havoc-to-persist-rest
This package is auto-updated.
Last update: 2025-10-22 15:47:41 UTC
README
This implementation of the abstract Persist/Base
uses a Db
connection to make tables in the database available as persistent PHP objects. This generates a class for every table or view in the database extracting PK, possibly with auto increment from tables. With Mariadb it is not possible to extract PK from a view so manual setting the getPrimaryKey() is needed.
Discover
To create the PHP proxies to the tables and views create a discover.php
in the root like:
<?php declare(strict_types=1); require_once 'config.php'; require 'vendor/autoload.php'; use \Kingsoft\Persist\Db\Bootstrap; $bootstrap = new Bootstrap( 'Realm\Namespace', ROOT ); $bootstrap->discover();
Or if you don't pass classFolderRoot
, it will use the ROOT
constant if defined:
$bootstrap = new Bootstrap( 'Realm\Namespace' ); $bootstrap->discover();
Currently it expects the static class providing the proper global SETTINGS['db']
for \Kingsoft\Db\Database\
in either a config.php
or settings.ini
file.
Naming
Table and view names in SHOUTING_SNAKE_CASE
are converted to camelCase
the field names are currently left untouched as mapping of field names to properties is currently not implemented.
config.php in root
Sample config.php
file
// Database Configuration $db = [ 'hostname' => 'localhost', 'database' => 'db', 'username' => 'user', 'password' => 'pass' ]; // Output the configuration as an array (if needed for debugging) define( 'SETTINGS', [ 'db' => $db, ]); unset($db);
Opening the file will generate the class files for all tables and views the user has access rights to. The page itself contains clues about these and and the end sections to use for \Kingsoft\PersistRest\
.
https://example.com/discover.php
If a PK is not auto increment, a string is generated with bin2hex(random_bytes(12)) with the tablename- as prefix. The atrribute length should be larger than CHAR(str_len(tablename) + 1 + 24)
.
This will create a folder discovered/Realm/Namespace
in the root with subfolders based on namespace in the settings file. It also responds with a page listing what is available. The contents of the folder may be moved to another but make sure to adapt the composer.json
- section conformly.
Views
Views are created but not updatable. Also as PK cannot be established these are commented out. Make sure to copy and adapt the create classfiles.
Handling Missing Primary Keys
Tables and Views Without Primary Keys
When working with tables or views that don't have a primary key defined, the discover()
process will generate classes with the following default implementations:
public static function getPrimaryKey():string { return ''; } public static function isPrimaryKeyAutoIncrement():bool { return false; }
Limitations
Objects generated from tables/views without primary keys have significant limitations:
- No
thaw()
operation: You cannot load individual records by ID since there's no primary key to identify them - No
update()
operation: Updates require a primary key to identify which record to modify - No
delete()
operation: Deletions require a primary key to identify which record to remove - No
freeze()
for existing records: Only inserting new records may work if the table structure allows it
What Still Works
Even without a primary key, you can still use:
findAll()
: Retrieve all records matching specific criteria usingwhere
clausesfind()
: Find the first record matching specific criteria- Iterator operations: Use
findFirst()
andfindNext()
to traverse result sets
Recommended Approach
For views without primary keys:
- Use the generated class as-is for read-only operations (
findAll()
,find()
) - Do not attempt CRUD operations that require a primary key
For tables without primary keys:
- Best practice: Add a primary key to your table schema
- If you cannot modify the schema, manually edit the generated class to define a unique field combination as the primary key:
public static function getPrimaryKey():string { return 'your_unique_field'; }
- Ensure the field you choose uniquely identifies each record
Example: Working with Views
// This works - reading all records from a view foreach( ViewName::findAll() as $record ) { echo $record->field_name; } // This works - finding specific records $record = ViewName::find(['field' => '=value']); // This will NOT work - views don't support updates // $record->freeze(); // Don't do this! // This will NOT work - no primary key to identify records // $record = new ViewName(123); // Don't do this!
Composer file section
To have the proxies autoloaded add the psr-4 section to your composer.json
and run
composer dump-autoload
Than the classes will autoload when new \Realm\Namespace\TableName()
is called.
Document
To create a API documentation page
<?php declare(strict_types=1); require_once 'config.php'; require 'vendor/autoload.php'; use \Kingsoft\Persist\Db\Bootstrap; $bootstrap = new Bootstrap( 'Kingsoft\LinkQr', ROOT ); $bootstrap->document( ROOT.'doc-header.html', ROOT.'doc-footer.html' );
Copy the template files to the root.
Configuration
The allowedEndPoints
array created by a discover can be used for a persist-rest
settings section.
The proxy objects work as a facade for database tables and can now used to (CRUD)
- Created a record, set the attributes and call
Persist::freeze()
to store it in the database - Read by constructor( ) using the record's id as the single parameter
- Update by reading, changing the properties and IPersist::freeze()
- Delete by
thaw
ing andIPersist::delete
ing the php object
We have turened a normal PHP object in a CRUD object in this way. Yaj!
Searching
Searching is also possible be setting a where and order with a static findall
which gets a Generator
interface to use with foreach. A findFirst
, fineNext
, can be used in an Iterator
context using the Persist\IteratorTrait
. The object itself is a generater and can be used in a yield
loop.
Services
Persist\Base::createFromArray()
creates a record from an array representationPersist\Base::getJson()
creates a json representation of the objectPersist\Base::createFromJson()
does the reverse