mzsongyan / database
一个简单的库,用于使用多个数据库适配器管理应用程序持久性
Requires
- php: >=8.0
- ext-mbstring: *
- ext-pdo: *
- utopia-php/cache: 0.9.*
- utopia-php/framework: 0.33.*
- utopia-php/mongo: 0.3.*
Requires (Dev)
- fakerphp/faker: ^1.14
- laravel/pint: 1.13.*
- pcov/clobber: ^2.0
- phpstan/phpstan: 1.10.*
- phpunit/phpunit: ^9.4
- rregeer/phpunit-coverage-check: ^0.3.1
- swoole/ide-helper: 4.8.0
- utopia-php/cli: ^0.14.0
This package is auto-updated.
Last update: 2024-09-29 05:56:40 UTC
README
Utopia 框架的数据库库是一个简单、轻量级的库,用于通过多个数据库适配器管理应用程序持久性。此库旨在尽可能简单,易于学习和使用。此库由 Appwrite 团队 维护。
尽管此库是 Utopia 框架 项目的组成部分,但它不依赖任何库,可以独立于任何其他 PHP 项目或框架使用。
入门
使用 composer 安装
composer require utopia-php/database
概念
utopia/php 概念及其在不同适配器上的相关等效项列表
- 数据库 - utopia/database 库的一个实例,它抽象了一个支持的适配器,并为在底层数据库中特定模式或隔离范围内的 CRUD 操作和查询提供统一的 API。
- 适配器 - 此库可以支持的底层数据库引擎的实现 - 下面是支持的数据库列表和每个数据库的支持功能。
- 集合 - 存储在相同适配器作用域中的一组文档。对于基于 SQL 的适配器,这相当于一个表。对于 No-SQL 适配器,这相当于一个本地集合。
- 文档 - 将存储在 utopia/database 集合中的一个简单的 JSON 对象。对于基于 SQL 的适配器,这相当于一行。对于 No-SQL 适配器,这相当于一个本地文档。
- 属性 - 简单的文档属性。对于基于 SQL 的适配器,这相当于一列。对于 No-SQL 适配器,这相当于一个本地文档字段。
- 索引 - 简单的集合索引,用于提高数据库查询的性能。
- 权限 - 使用权限,您可以决定哪些角色对特定文档具有读取、创建、更新和删除访问权限。特殊属性
$permissions
用于存储集合中每个文档的权限元数据。权限角色可以是任何字符串。您可以使用Authorization::setRole()
将新角色委派给您的用户,一旦获得新角色,用户将获得对相关文档的读取、创建、更新或删除访问权限。
过滤器
属性过滤器是在将属性保存到数据库之前和从数据库检索之后操作属性的函数。您可以使用 Database::addFilter($name, $encode, $decode)
添加过滤器,其中 $name
是可以稍后添加到属性 filters
数组的过滤器名称。 $encode
和 $decode
分别是用于编码和解码属性的函数。还有实例级过滤器,只能在构造 Database
实例时定义。实例级过滤器在具有相同名称的情况下会覆盖静态过滤器。
保留属性
$id
- 文档的唯一 ID,您可以设置自己的自定义 ID 或库将生成随机 UID。$createdAt
- 文档创建日期,该属性在创建文档时自动设置。$updatedAt
- 文档更新日期,该属性在更新文档时自动设置。$collection
- 包含文档存储的集合名称的属性。$permissions
- 一个包含字符串数组的属性。每个字符串代表一个特定的动作和角色。如果用户获得了该动作的该角色,他们将有权访问此文档。
属性类型
数据库文档接口仅支持原始类型(字符串
、整数
、浮点数
和布尔值
),并转换为每个相关数据库适配器的本地数据库类型。复杂类型如数组或对象在存储时将被编码为JSON字符串,在从适配器检索时将解码回原格式。
支持数据库
以下是支持数据库及其兼容测试版本,以及支持的特性和相关限制的列表。
✅ - 支持
🛠 - 进行中
限制
MariaDB、MySQL、Postgres、SQLite
- ID最大大小为255字节
- ID只能包含[^A-Za-z0-9]和符号
_
-
- 文档最大大小为65535字节
- 集合可以拥有最多1017个属性
- 集合可以拥有最多64个索引
- 索引值最大大小为768字节。超过768字节的值将被截断
- 字符串最大大小为4294967295个字符
- 整数最大大小为4294967295
MongoDB
- ID最大大小为255字节
- ID只能包含[^A-Za-z0-9]和符号
_
-
- 文档可以拥有无限制的大小
- 集合可以拥有无限制数量的属性
- 集合可以拥有最多64个索引
- 索引值可以拥有无限制的大小
- 字符串最大大小为2147483647个字符
- 整数最大大小为4294967295
用法
连接到数据库
MariaDB
require_once __DIR__ . '/vendor/autoload.php'; use PDO; use Utopia\Database\Database; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Memory; use Utopia\Database\Adapter\MariaDB; $dbHost = 'mariadb'; $dbPort = '3306'; $dbUser = 'root'; $dbPass = 'password'; $pdoConfig = [ PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true, ]; $pdo = new PDO("mysql:host={$dbHost};port={$dbPort};charset=utf8mb4", $dbUser, $dbPass, $pdoConfig); $cache = new Cache(new Memory()); // or use any cache adapter you wish $database = new Database(new MariaDB($pdo), $cache);
MySQL
require_once __DIR__ . '/vendor/autoload.php'; use PDO; use Utopia\Database\Database; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Memory; use Utopia\Database\Adapter\MySQL; $dbHost = 'mysql'; $dbPort = '3306'; $dbUser = 'root'; $dbPass = 'password'; $pdoConfig = [ PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true, ]; $pdo = new PDO("mysql:host={$dbHost};port={$dbPort};charset=utf8mb4", $dbUser, $dbPass, $pdoConfig); $cache = new Cache(new Memory()); // or use any cache adapter you wish $database = new Database(new MySql($pdo), $cache);
Postgres
require_once __DIR__ . '/vendor/autoload.php'; use PDO; use Utopia\Database\Database; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Memory; use Utopia\Database\Adapter\Postgres; $dbHost = 'postgres'; $dbPort = '5432'; $dbUser = 'root'; $dbPass = 'password'; $pdoConfig = [ PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true, ]; $pdo = new PDO("pgsql:host={$dbHost};port={$dbPort};charset=utf8mb4", $dbUser, $dbPass, $pdoConfig); $cache = new Cache(new Memory()); // or use any cache adapter you wish $database = new Database(new Postgres($pdo), $cache);
SQLite
require_once __DIR__ . '/vendor/autoload.php'; use PDO; use Utopia\Database\Database; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Memory; use Utopia\Database\Adapter\SQLite; $dbPath = '/path/to/database.sqlite'; $pdoConfig = [ PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true, ]; $pdo = new PDO("{$dbPath}", $pdoConfig); $cache = new Cache(new Memory()); // or use any cache adapter you wish $database = new Database(new SQLite($pdo), $cache);
MongoDB
require_once __DIR__ . '/vendor/autoload.php'; use Utopia\Database\Database; use Utopia\Cache\Cache; use Utopia\Cache\Adapter\Memory; use Utopia\Database\Adapter\Mongo; use Utopia\Mongo\Client; // from utopia-php/mongo $dbHost = 'mongo'; $dbPort = 27017; $dbUser = 'root'; $dbPass = 'password'; $dbName = 'dbName'; $mongoClient = new Client($dbName, $dbHost, $dbPort, $dbUser, $dbPass, true); $cache = new Cache(new Memory()); // or use any cache adapter you wish $database = new Database(new Mongo($client), $cache);
数据库方法
// Get namespace $database->getNamespace(); // Sets namespace that prefixes all collection names $database->setNamespace( namespace: 'namespace' ); // Get default database $database->getDatabase(); // Sets default database $database->setDatabase( name: 'dbName' ); // Creates a new database. // Uses default database as the name. $database->create(); // Returns an array of all databases $database->list(); // Delete database $database->delete( name: 'mydb' ); // Ping database it returns true if the database is alive $database->ping(); // Check if database exists $database->exists( database: 'mydb' ); // Check if collection exists $database->exists( database: 'mydb', collection: 'users' ); // Listen to events // Event Types Database::EVENT_ALL Database::EVENT_DATABASE_CREATE, Database::EVENT_DATABASE_LIST, Database::EVENT_COLLECTION_CREATE, Database::EVENT_COLLECTION_LIST, Database::EVENT_COLLECTION_READ, Database::EVENT_ATTRIBUTE_CREATE, Database::EVENT_ATTRIBUTE_UPDATE, Database::EVENT_INDEX_CREATE, Database::EVENT_DOCUMENT_CREATE, Database::EVENT_DOCUMENT_UPDATE, Database::EVENT_DOCUMENT_READ, Database::EVENT_DOCUMENT_FIND, Database::EVENT_DOCUMENT_FIND, Database::EVENT_DOCUMENT_COUNT, Database::EVENT_DOCUMENT_SUM, Database::EVENT_DOCUMENT_INCREASE, Database::EVENT_DOCUMENT_DECREASE, Database::EVENT_INDEX_DELETE, Database::EVENT_DOCUMENT_DELETE, Database::EVENT_ATTRIBUTE_DELETE, Database::EVENT_COLLECTION_DELETE, Database::EVENT_DATABASE_DELETE, $database->on( Database::EVENT_ALL, function($event, $data) { // Do something } ); // Get Database Adapter $database->getAdapter(); // Get List of keywords that cannot be used $database->getKeywords();
集合方法
// Creates two new collection named '$namespace_$collectionName' with attribute names '_id', '_uid', '_createdAt', '_updatedAt', '_permissions' // The second collection is named '$namespace_$collectionName_perms' with attribute names '_id', '_type', '_permission', '_document' $database->createCollection( name: 'users' ); // Create collection with attributes and indexes $attributes = [ new Document([ '$id' => ID::unique(), '$permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()) ], 'name' => 'Jhon', 'age' => 20 ]), new Document([ '$id' => ID::unique(), '$permissions' => [ Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()) ], 'name' => 'Doe', 'age' => 34 ]), ] $indexes = [ new Document([ '$id' => ID::unique(), 'type' => Database::INDEX_KEY, 'attributes' => ['name'], 'lengths' => [256], 'orders' => ['ASC'], ]), new Document([ '$id' => ID::unique(), 'type' => Database::INDEX_KEY, 'attributes' => ['name', 'age'], 'lengths' => [128, 128], 'orders' => ['ASC'], ]) ]; $database->createCollection( name: 'users', attributes: $attributes, indexes: $indexes ); // Update Collection Permissions $database->updateCollection( id: 'users', permissions: [ Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()) ], documentSecurity: true ); // Get Collection $database->getCollection( id: 'users' ); // List Collections $database->listCollections( limit: 25, offset: 0 ); // Deletes the two collections named 'namespace_$collectionName' and 'namespace_$collectionName_perms' $database->deleteCollection( id: 'users' ); // Delete cached documents of a collection $database->purgeCachedCollection( collection: 'users' );
属性方法
// Data types Database::VAR_STRING Database::VAR_INTEGER Database::VAR_FLOAT Database::VAR_BOOLEAN Database::VAR_DATETIME // Creates a new attribute named '$attributeName' in the '$namespace_$collectionName' collection. $database->createAttribute( collection: 'movies', id: 'name', type: Database::VAR_STRING, size: 128, required: true ); // New attribute with optional parameters $database->createAttribute( collection: 'movies', id: 'genres', type: Database::VAR_STRING, size: 128, required: true, default: null, signed: true, array: false, format: null, formatOptions: [], filters: [] ); // Updates the attribute named '$attributeName' in the '$namespace_$collectionName' collection. $database-> updateAttribute( collection: 'movies', id: 'genres', type: Database::VAR_STRING, size: 128, required: true, default: null, signed: true, array: false, format: null, formatOptions: [], filters: [] ); // Update the required status of an attribute $database->updateAttributeRequired( collection: 'movies', id: 'genres', required: true ); // Update the attribute format $database->updateAttributeFormat( collection: 'movies', id: 'genres', format: null, ); // Update the attribute format options $database->updateAttributeFormatOptions( collection: 'movies', id: 'genres', formatOptions: [] ); // Update the attribute filters $database->updateAttributeFilters( collection: 'movies', id: 'genres', filters: [] ); // Update the default value of an attribute $database->updateAttributeDefault( collection: 'movies', id: 'genres', default: 'sci-fi' ); // Check if attribute can be added to a collection $collection = $database->getCollection('movies'); $attribute = new Document([ '$id' => ID::unique(), 'type' => Database::VAR_INTEGER, 'size' => 256, 'required' => true, 'default' => null, 'signed' => true, 'array' => false, 'filters' => [], ]); $database->checkAttribute( collection: $collection, attribute: $attribute ); // Get Adapter attribute limit $database->getLimitForAttributes(); // if 0 then no limit // Get Adapter index limit $database->getLimitForIndexes(); // Renames the attribute from old to new in the '$namespace_$collectionName' collection. $database->renameAttribute( collection: 'movies', old: 'genres', new: 'genres2' ); // Deletes the attribute in the '$namespace_$collectionName' collection. $database->deleteAttribute( collection: 'movies', id: 'genres' );
索引方法
// Index types Database::INDEX_KEY, Database::INDEX_FULLTEXT Database::INDEX_UNIQUE Database::INDEX_SPATIAL Database::INDEX_ARRAY // Insertion Order Database::ORDER_ASC Database::ORDER_DESC // Creates a new index named '$indexName' in the '$namespace_$collectionName' collection. // Note: The size for the index will be taken from the size of the attribute $database->createIndex( collection: 'movies', id: 'index1', Database::INDEX_KEY, attributes: ['name', 'genres'], lengths: [128,128], orders: [Database::ORDER_ASC, Database::ORDER_DESC] ); // Rename index from old to new in the '$namespace_$collectionName' collection. $database->renameIndex( collection: 'movies', old: 'index1', new: 'index2' ); // Deletes the index in the '$namespace_$collectionName' collection. $database->deleteIndex( collection: 'movies', id: 'index2' );
关系方法
// Relationship types Database::RELATION_ONE_TO_ONE Database::RELATION_ONE_TO_MANY Database::RELATION_MANY_TO_ONE Database::RELATION_MANY_TO_MANY // Creates a relationship between the two collections with the default reference attributes $database->createRelationship( collection: 'movies', relatedCollection: 'users', type: Database::RELATION_ONE_TO_ONE, twoWay: true ); // Create a relationship with custom reference attributes $database->createRelationship( collection: 'movies', relatedCollection: 'users', type: Database::RELATION_ONE_TO_ONE, twoWay: true, id: 'movies_id', twoWayKey: 'users_id' ); // Relationship onDelete types Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_SET_NULL, Database::RELATION_MUTATE_RESTRICT, // Update the relationship with the default reference attributes $database->updateRelationship( collection: 'movies', id: 'users', onDelete: Database::RELATION_MUTATE_CASCADE ); // Update the relationship with custom reference attributes $database->updateRelationship( collection: 'movies', id: 'users', onDelete: Database::RELATION_MUTATE_CASCADE, newKey: 'movies_id', newTwoWayKey: 'users_id', twoWay: true ); // Delete the relationship with the default or custom reference attributes $database->deleteRelationship( collection: 'movies', id: 'users' );
文档方法
use Utopia\Database\Document; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; // Id helpers ID::unique(padding: 12) // Creates an id of length 7 + padding ID::custom(id: 'my_user_3235') // Role helpers Role::any() Role::guests() Role::user( identifier: ID::unique() status: 'active' //optional ) Role::users() Role::team( identifier: ID::unique() ) Role::team( identifier: ID::unique() dimension: '123' //team:id/dimension ) Role::label( identifier: 'admin' ) Role::members( identifier: ID::unique() ) // Permission helpers Permission::read(Role::any()), Permission::create(Role::user(ID::unique())), Permission::update(Role::user(ID::unique(padding: 23))), Permission::delete(Role::user(ID::custom(id: 'my_user_3235')) // To create a document $document = new Document([ '$permissions' => [ Permission::read(Role::any()), Permission::create(Role::user(ID::custom('1x'))), Permission::update(Role::user(ID::unique(12))), Permission::delete(Role::user($customId)), ], '$id' => ID::unique(), 'name' => 'Captain Marvel', 'director' => 'Anna Boden & Ryan Fleck', 'year' => 2019, 'price' => 25.99, 'active' => true, 'genres' => ['science fiction', 'action', 'comics'], ]); $document = $database->createDocument( collection: 'movies', document: $document ); // Get which collection a document belongs to $document->getCollection(); // Get document id $document->getId(); // Check whether document in empty $document->isEmpty(); // Increase an attribute in a document $database->increaseDocumentAttribute( collection: 'movies', id: $document->getId(), attribute: 'name', value: 24, max: 100 ); // Decrease an attribute in a document $database->decreaseDocumentAttribute( collection: 'movies', id: $document->getId(), attribute: 'name', value: 24, min: 100 ); // Update the value of an attribute in a document // Set types Document::SET_TYPE_ASSIGN, // Assign the new value directly Document::SET_TYPE_APPEND, // Append the new value to end of the array Document::SET_TYPE_PREPEND // Prepend the new value to start of the array Note: Using append/prepend with an attribute which is not an array, it will be set to an array containing the new value. $document->setAttribute(key: 'name', 'Chris Smoove') ->setAttribute(key: 'age', 33, Document::SET_TYPE_ASSIGN); $database->updateDocument( collection: 'users', id: $document->getId(), document: $document ); // Update the permissions of a document $document->setAttribute('$permissions', Permission::read(Role::any()), Document::SET_TYPE_APPEND) ->setAttribute('$permissions', Permission::create(Role::any()), Document::SET_TYPE_APPEND) ->setAttribute('$permissions', Permission::update(Role::any()), Document::SET_TYPE_APPEND) ->setAttribute('$permissions', Permission::delete(Role::any()), Document::SET_TYPE_APPEND) $database->updateDocument( collection: 'users', id: $document->getId(), document: $document ); // Info regarding who has permission to read, create, update and delete a document $document->getRead(); // returns an array of roles that have permission to read the document $document->getCreate(); // returns an array of roles that have permission to create the document $document->getUpdate(); // returns an array of roles that have permission to update the document $document->getDelete(); // returns an array of roles that have permission to delete the document // Get document with all attributes $database->getDocument( collection: 'movies', id: $document->getId() ); // Get document with a sub-set of attributes $database->getDocument( collection: 'movies', id: $document->getId(), queries: [ Query::select(['name', 'director', 'year']) ] ); // Find documents // Query Types Query::equal(attribute: "...", values: ["...", "..."]), Query::notEqual(attribute: "...", value: "..."), Query::lessThan(attribute: "...", value: 100), Query::lessThanEqual(attribute: "...", value: 1000), Query::greaterThan(attribute: "...", value: 1000), Query::greaterThanEqual(attribute: "...", value: ...), Query::contains(attribute: "...", values: ["...", "..."]), Query::between(attribute: "...", start: 100, end: 1000), Query::search(attribute: "...", value: "..."), Query::select(attributes: ["...", "..."]), Query::orderDesc(attribute: "..."), Query::orderAsc(attribute: "..."), Query::isNull(attribute: "..."), Query::isNotNull(attribute: "..."), Query::startsWith(attribute: "...", value: "..."), Query::endsWith(attribute: "...", value: "..."), Query::limit(value: 35), Query::offset(value: 0), $database->find( collection: 'movies', queries: [ Query::equal(attribute: 'name', values: ['Captain Marvel']), Query::notEqual(attribute: 'year', values: [2019]) ], timeout: 1 //timeout is optional ); // Find a document $database->findOne( collection: 'movies', queries: [ Query::equal(attribute: 'name', values: ['Captain Marvel']), Query::lessThan(attribute: 'year', value: 2019) ] ); // Get count of documents $database->count( collection: 'movies', queries: [ Query::equal(attribute: 'name', values: ['Captain Marvel']), Query::greaterThan(attribute: 'year', value: 2019) ], max: 1000 // Max is optional ); // Get the sum of an attribute from all the documents $database->sum( collection: 'movies', attribute: 'price', queries: [ Query::greaterThan(attribute: 'year', value: 2019) ], max: null // max = null means no limit ); // Delete a document $database->deleteDocument( collection: 'movies', id: $document->getId() ); // Delete a cached document Note: Cached Documents or Collections are automatically deleted when a document or collection is updated or deleted $database->purgeCachedDocument( collection: 'movies', id: $document->getId() );
系统要求
Utopia框架要求PHP 8.0或更高版本。我们建议尽可能使用最新的PHP版本。
贡献
感谢您考虑为Utopia框架做出贡献!有关更多信息,请查看CONTRIBUTING.md文件。
版权和许可
MIT许可证(MIT) https://open-source.org.cn/licenses/mit-license.php