simple-crud / simple-crud
轻松实现创建/读取/更新/删除
Requires
- php: >=7.2
- atlas/pdo: ^1.1
- atlas/query: ^1.2
- psr/event-dispatcher: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.11
- oscarotero/php-cs-fixer-config: ^1.0
- phpstan/phpstan: ^0.12.84
- phpunit/phpunit: ^8.0|^9.0
- dev-master
- v7.5.3
- v7.5.2
- v7.5.1
- v7.5.0
- v7.4.2
- v7.4.1
- v7.4.0
- v7.3.6
- v7.3.5
- v7.3.4
- v7.3.3
- v7.3.2
- v7.3.1
- v7.3.0
- v7.2.5
- v7.2.4
- v7.2.3
- v7.2.2
- v7.2.1
- v7.2.0
- v7.1.0
- v7.0.0
- 6.x-dev
- v6.13.2
- v6.13.1
- v6.13.0
- v6.12.1
- v6.12.0
- v6.11.3
- v6.11.2
- v6.11.1
- v6.11.0
- v6.10.0
- v6.9.0
- v6.8.1
- v6.8.0
- v6.7.0
- v6.6.2
- v6.6.1
- v6.6.0
- 6.5.0
- 6.4.2
- v6.4.1
- v6.4.0
- v6.3.1
- v6.3.0
- v6.2.1
- v6.2.0
- v6.1.0
- v6.0.1
- v6.0.0
- 5.x-dev
- v5.4.5
- v5.4.4
- v5.4.3
- v5.4.2
- v5.4.1
- v5.4.0
- v5.3.0
- v5.2.4
- v5.2.3
- v5.2.2
- v5.2.1
- v5.2.0
- v5.1.3
- v5.1.2
- v5.1.1
- v5.1.0
- v5.0.0
- v4.1.0
- v4.0.0
- v3.1
- v3.0
- v2.1.1
- v2.1.0
- v2.0.2
- v2.0.1
- v2.0.0
- v1.8.2
- v1.8.1
- v1.8.0
- v1.7.0
- v1.6.0
- v1.5.0
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.0
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v0.1.0
This package is auto-updated.
Last update: 2024-09-08 22:29:11 UTC
README
PHP库,用于在MySQL/Sqlite数据库中(创建、读取、更新、删除)数据,无需配置和少量魔法。
命名约定
此库依赖于一些约定以避免配置。
- 表名应使用单数和驼峰式
- 字段名应使用单数和驼峰式
- 所有表的主键必须是
id
。 - 外键必须是
[tableName]_id
。例如,post
表使用post_id
作为外键。 - 关联表必须使用下划线将两个表按字母顺序连接起来。例如,
post
和tag
之间的关系是post_tag
,而post
和category
是category_post
。
安装
此包可通过Composer安装和自动加载,名称为simple-crud/simple-crud。
$ composer require simple-crud/simple-crud
类
SimpleCrud有以下类
- Database: 管理数据库连接。内部使用Atlas.PDO
- Query: 创建数据库查询。SimpleCrud与MySQL和SQLite进行了测试,但由于内部使用Atlas.Query,理论上还应支持Postgres和Microsoft SQL。
- Table: 管理数据库表
- Field: 管理数据库字段。用于格式化和验证值
- Row: 用于存储和修改一行
- RowCollection: 是行的集合
使用示例
假设我们有以下数据库模式
CREATE TABLE "post" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `title` TEXT, `category_id` INTEGER, `type` TEXT, FOREIGN KEY(`category_id`) REFERENCES category(id) ); CREATE TABLE `category` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `name` TEXT ); CREATE TABLE `tag` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `name` TEXT ); CREATE TABLE `post_tag` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `tag_id` INTEGER NOT NULL, `post_id` INTEGER NOT NULL, FOREIGN KEY(`tag_id`) REFERENCES tag(id), FOREIGN KEY(`post_id`) REFERENCES post(id) );
首先,创建一个SimpleCrud\Database
实例,传入PDO
连接。
use SimpleCrud\Database; $pdo = new PDO($dsn, $username, $password); $db = new Database($pdo); //To get any table, use magic properties, they will be instantiated on demand: $post = $db->post;
SimpleCrud加载数据库模式并自动检测表中所有关系,使用上述命名约定。例如,表“post”有一个名为“category_id”的字段,因此SimpleCrud知道每个帖子都有一个类别。
注意:在生产环境中,您可能希望缓存模式以避免执行这些查询并提高性能。您可以这样做
use SimpleCrud\Scheme\Cache; use SimpleCrud\Scheme\Mysql; if ($cache->has('db_scheme')) { $array = $cache->get('db_scheme'); $scheme = new Cache($array); } else { $scheme = new Mysql($pdo); $cache->save('db_scheme', $scheme->toArray()); } $db = new Database($pdo, $scheme);
使用库
基本CRUD
您可以直接与表交互以插入/更新/删除/选择数据
使用ArrayAccess
接口通过id
访问数据
//Get the post id = 3; $post = $db->post[3]; //Check if a row exists if (isset($db->post[3])) { echo 'exists'; } //Delete a post unset($db->post[3]); //Update a post $db->post[3] = [ 'title' => 'Hello world' ]; //Insert a new post $db->post[] = [ 'title' => 'Hello world 2' ]; //Tables implements the Countable interface $totalPost = count($db->post);
通过其他字段选择
如果您想通过除id
之外的其他键选择行,只需使用get
方法即可
$post = $db->post->get(['slug' => 'post-slug']);
选择或创建
有时,您可能想要获取一个行或创建它(如果不存在)。您可以使用getOrCreate
方法轻松完成此操作
$post = $db->post->getOrCreate(['slug' => 'post-slug']);
行
Row
对象表示数据库行,用于读取和修改其数据
//get a row by id $post = $db->post[34]; //Get/modify fields values echo $post->title; $post->title = 'New title'; //Update the row into database $post->save(); //Remove the row in the database $post->delete(); //Create a new row $newPost = $db->post->create(['title' => 'The title']); //Insert the row in the database $newPost->save();
查询
Query
对象表示数据库查询。SimpleCrud使用魔法方法创建查询。例如,$db->post->select()
返回一个在post
表中的新Select
查询实例。其他示例:$db->comment->update()
、$db->category->delete()
等。每个查询都有修饰符,如orderBy()
、limit()
。
//Create an UPDATE query with the table post $updateQuery = $db->post->update(['title' => 'New title']); //Add conditions, limit, etc $updateQuery ->where('id = ', 23) ->limit(1); //get the query as string echo $updateQuery; //UPDATE `post` ... //execute the query and returns a PDOStatement with the result $PDOStatement = $updateQuery();
方法 get()
执行查询并返回查询的处理结果。例如,使用 insert()
返回新行的 id。
//insert a new post $id = $db->post ->insert([ 'title' => 'My first post', 'text' => 'This is the text of the post' ]) ->get(); //Delete a post $db->post ->delete() ->where('id = ', 23) ->get(); //Count all posts $total = $db->post ->selectAggregate('COUNT') ->get(); //note: this is the same like count($db->post) //Sum the ids of all posts $total = $db->post ->selectAggregate('SUM', 'id') ->get();
select()->get()
返回一个包含结果的 RowCollection
实例。
$posts = $db->post ->select() ->where('id > ', 10) ->orderBy('id ASC') ->limit(100) ->get(); foreach ($posts as $post) { echo $post->title; }
如果您只需要第一行,请使用修饰符 one()
。
$post = $db->post ->select() ->one() ->where('id = ', 23) ->get(); echo $post->title;
select()
有一些有趣的修饰符,如 relatedWith()
,可自动添加所需的 WHERE
子句来选择与其他行或行集合相关的数据。
//Get the post id = 23 $post = $db->post[23]; //Select the category related with this post $category = $db->category ->select() ->relatedWith($post) ->one() ->get();
查询 API
查询使用 Atlas.Query 库构建最终查询,因此您可以查看所有可用选项的文档。
选择 / 选择聚合
更新
插入
删除
懒加载
两者 Row
和 RowCollection
都可以自动加载其他相关行。只需使用名为相关表的属性。例如
//Get the category id=34 $category = $db->category[34]; //Load the posts of this category $posts = $category->post; //This is equivalent to: $posts = $db->post ->select() ->relatedWith($category) ->get(); //But the result is cached so the database query is executed only the first time $posts = $category->post;
这允许这样做
$titles = $db->post[34]->tag->post->title; //Get the post id=34 //Get the tags of the post //Then the posts related with these tags //And finally, the titles of all these posts
使用魔法方法获取返回相关行的 Select
查询
$category = $db->category[34]; //Magic property: Returns all posts of this category: $posts = $category->post; //Magic method: Returns the query instead the result $posts = $category->post() ->where('pubdate > ', date('Y-m-d')) ->limit(10) ->get();
解决 n+1 问题
可以通过以下方式解决 n+1 问题
//Get some posts $posts = $db->post ->select() ->get(); //preload all categories $posts->category; //now you can iterate with the posts foreach ($posts as $post) { echo $post->category; }
您可以自行执行选择以包含修饰符
//Get some posts $posts = $db->post ->select() ->get(); //Select the categories but ordered alphabetically descendent $categories = $posts->category() ->orderBy('name DESC') ->get(); //Save the result in the cache and link the categories with each post $posts->link($categories); //now you can iterate with the posts foreach ($posts as $post) { echo $post->category; }
对于多对多关系,您需要执行一个额外的步骤
//Get some posts $posts = $db->post ->select() ->get(); //Select the post_tag relations $tagRelations = $posts->post_tag()->get(); //And now the tags of these relations $tags = $tagRelations->tag() ->orderBy('name DESC') ->get(); //Link the tags with posts using the relations $posts->link($tags, $tagRelations); //now you can iterate with the posts foreach ($posts as $post) { echo $post->tag; }
关联和解关联数据
要保存相关行到数据库,您需要这样做
//Get a comment $comment = $db->comment[5]; //Get a post $post = $db->post[34]; //Relate $post->relate($comment); //Unrelate $post->unrelate($comment); //Unrelate all comments of the post $post->unrelateAll($db->comment);
分页
查询 select
有一个特殊的修饰符用于分页结果
$query = $db->post->select() ->page(1) ->perPage(50); $posts = $query->get(); //To get the page info: $pagination = $query->getPageInfo(); echo $pagination['totalRows']; //125 echo $pagination['totalPages']; //3 echo $pagination['currentPage']; //1 echo $pagination['previousPage']; //NULL echo $pagination['nextPage']; //2
事件
SimpleCrud 使用 PSR-14 Event Dispatcher 来分发事件。事件附加到表上,允许验证数据、修改查询等。
use SimpleCrud\Events\BeforeSaveRow; use SimpleCrud\Events\CreateSelectQuery; //Get the event dispatcher $dispatcher = $db->post->getEventDispatcher(); //Assign the BeforeSaveRow event listener $dispatcher->listen(BeforeSaveRow::class, function (BeforeSaveRow $event) { $row = $event->getRow(); if (!$row->createdAt) { $row->createdAt = new Datetime(); } }); //Assign a CreateSelectQuery $dispatcher->listen(CreateSelectQuery::class, function (CreateSelectQuery $event) { $query = $event->getQuery(); //Add automatically a where clause in all selects $query->where('active = true'); }); //Create a new post $post = $db->post->create(['title' => 'Hello world']); //Save the post, so BeforeSaveRow event is triggered $post->save(); $post->createdAt; //This field was filled and saved //Select a post, so CreateSelectQuery is triggered and only active posts are selected $posts = $db->post->select()->get();
您可以提供自己的事件分发器
$myDispatcher = new Psr14EventDispatcher(); $db->post->setEventDispatcher($myDispatcher);
可用的事件有
SimpleCrud\Events\BeforeSaveRow
:在执行$row->save()
保存行之前执行。SimpleCrud\Events\BeforeCreateRow
:在执行$table->create()
创建新行之前执行。SimpleCrud\Events\CreateDeleteQuery
:在执行$table->delete()
创建 DELETE 查询时执行。SimpleCrud\Events\CreateInsertQuery
:在执行$table->insert()
创建 INSERT 查询时执行。SimpleCrud\Events\CreateSelectQuery
:在执行$table->select()
创建 SELECT 查询时执行。SimpleCrud\Events\CreateUpdateQuery
:在执行$table->update()
创建 UPDATE 查询时执行。
字段
SimpleCrud\Fields
类的目的是将数据从数据库转换为用于其使用的格式。例如,在 MySQL 中,存储 datetime 值的格式是 "Y-m-d H:i:s",因此 SimpleCrud\Fields\Datetime
类将任何字符串或 Datetime
实例转换为该格式,并在选择此值时返回一个 Datetime 实例。可用的字段有
- 布尔值:用于管理布尔值
- 日期:用于管理日期值。将数据库值转换为
Datetime
- 日期时间:用于管理日期时间值。将数据库值转换为
Datetime
- 十进制:将值转换为浮点数或 NULL
- 字段:这是默认字段,不转换值
- 整数:将值转换为整数或 NULL
- JSON:用于存储 JSON 结构。
- 可序列化:用于存储数组或任何其他可序列化数据结构。
- 集合:管理多个值。例如:['red', 'blue', 'green'] 将在数据库中存储为 "red,blue,green"。
- 点:管理几何点 更多信息
- 其他高级字段可以在这里找到:https://github.com/oscarotero/simple-crud-extra-fields
字段类会根据数据库中的字段类型自动分配。还有一些具有特定类型分配的“特殊名称”。
- 任何命名为
id
或以_id
结尾的字段将被分配整型格式。 - 任何命名为
pubdate
或以At
结尾的字段(例如:createdAt
、updatedAt
等)将被分配日期时间格式。 - 任何命名为
active
或以is
或has
开头的字段(例如:isActived
、hasContent
、等)将被分配布尔格式。
示例
$post = $db->post->create([ 'title' => 'My post', 'text' => 'My post text', 'createdAt' => new Datetime('now'), 'isActive' => true ]); $post->save(); //Use magic properties to get the Field instance $titleField = $db->post->title;
配置
您可能想要存储一些数据库配置,例如默认语言或存储资源的基路径。为此,可以使用 getConfig
和 setConfig
方法。
$db->setConfig('name', 'value'); echo $db->getConfig('name'); //value
可本地化字段
如果您需要在多种语言中保存值,只需为每种语言创建一个带有语言后缀的字段即可。例如,要保存英文(en)和加利西亚语(gl)的标题,只需创建字段 title_en
和 title_gl
。
然后,您必须使用 SimpleCrud::ATTR_LOCALE
属性配置当前语言。
//Set the current language as "en" $db->setConfig(SimpleCrud::CONFIG_LOCALE, 'en'); //Select a post $post = $db->post[23]; //Get the title in the current language echo $post->title; //Returns the value of title_en //You can access to any languages using the full name: echo $post->title_en; echo $post->title_gl; //And assign a diferent value to the current language $post->title = 'New title in english';
调试
SimpleCrud
在内部使用 Atlas.PDO 来管理连接并在数据库中执行查询。有关更多详细信息,请参阅文档。
$db->getConnection()->logQueries(true); //-- Run queries --// $queries = $db->getConnection()->getQueries();
定制
您可以使用自己的自定义类来处理表、行和行集合。
自定义表
使用 setTableClasses
为表分配自定义类。
$db = new SimpleCrud\Database($pdo); $db->setTableClasses([ 'post' => CustomPost::class, 'comment' => CustomComment::class, ]); $db->post; //Returns an instance of CustomPost
FieldFactory
为了创建字段实例,SimpleCrud 使用 SimpleCrud\Field\FieldFactory
工厂类,您可以对其实例化或用您自己的工厂替换。
use SimpleCrud\Fields\FieldFactory; use SimpleCrud\Fields\Boolean; $db = new SimpleCrud\Database($pdo); //Create a factory for your custom field $factory = new FieldFactory( Year::class, //Your custom field class name ['integer'], //All fields of type integer will use this class ['year', '/$year/'], //All fields named "year" or matching this regex will use this class ['min' => 2000], //Default config ); $db->setFieldFactory($factory); //Modify a existing field $db->getFieldFactory(Boolean::class)->addNames('enabled'); //Use it: $db->post->fields['year']; //returns an instance of Year $db->post->fields['enabled']; //returns an instance of SimpleCrud\Fields\Boolean
创建您的 Rows 和 RowCollections
要定义特定表中使用的 Rows 和 RowCollections 类,首先创建一个自定义表,并使用 ROW_CLASS
和 ROWCOLLECTION_CLASS
受保护常量来设置类。
namespace MyModels; use SimpleCrud\Table; class Post extends Table { protected const ROW_CLASS = PostRow::class; protected const ROWCOLLECTION_CLASS = PostRowCollection::class; protected function init() { //Insert code to be executed after the instantion } public function selectLatest() { return $this->select() ->orderBy('createdAt DESC') ->limit(10); } }
现在配置数据库以使用此类处理表 post
。
$db = new SimpleCrud\Database($pdo); $db->setTableClasses([ 'post' => MyModels\Post::class, ]); $latests = $db->post->selectLatest()->get(); //Returns an instance of MyModels\PostRowCollection foreach ($latests as $post) { //Instances of MyModels\PostRow }