我见过许多 PHP ORM 库。它们中大多数都要你为想保存在数据库里的每一项写一个类。无缘无故地继承这个、继承那个,而那些内容通常都是重复和反复无常的。
既然条目包含相似数据类型以及相似关系的字段,一个编写良好的类就可适用于所有情况。如果你需要一个库来简化这些事情,这就是我的方法。
arrayDB ORM 库只包含 5 个类。你基本上只使用其中一个,而其余类则在内部使用,仅此而已。缓存及其与数据库之间的同步全是自动的,你无需对其进行跟踪。
要开始使用这个库,你只需简单地定义:
- 你的数据模型(你需要保存哪几项,他们的字段以及字段间的关系)。
- 你的 MySQL 连接方式。
- 你的缓存配置。
定义数据模型
所有的数据模型定义被写成像这样的数组:
$model=array( 'user'=>array( 'conf'=>array('len'=>7), 'fields'=>array( 'name'=>array('len'=>50) ), 'has_many'=>array( 'posts'=>array('type'=>'post', 'foreign_name'=>'writer') ), 'many_to_many'=>array( 'liked_posts'=>array('type'=>'post', 'foreign_name'=>'likers'), ), 'self_ref'=>array('friends') ), 'post'=>array( 'conf'=>array('len'=>10), 'fields'=>array( 'text'=>array('len'=>200), 'view_count'=>array('type'=>'numeric', 'len'=>5) // 默认的字段类型是 text,这里将类型定义成 numeric ) ) );
这里我们有两张表:用户和帖子。
用户有姓名,有些用户发帖子而有些用户关注帖子。帖子有文本内容,浏览量以及关注者。
用户还有其他许多用户作为好友。
使用这个模型,我们想通过 $user[‘posts’] 获取用户发布的所有帖子,通过 $post[‘writer’] 获取帖子的作者。这是一对多关系。
我们还想通过 $user[‘liked_posts’] 获取用户关注过的帖子,通过 $post[‘likers’] 获取帖子的关注者。这是多对多关系。
最后我们想通过 $user[‘friends’] 获取用户的好友列表。这是自引用关系。
定义 MySQL 连接方式
定义 MySQL 连接方式也写成一个像这样的数组:
$db_config=array( 'hostname'=>'localhost', 'database'=>'social', 'username'=>'root', 'password'=>'' );
定义缓存配置
目前,我们有三种缓存类型实现:APC、Memcached 以及普通文本文件。 要使用 APC,这样的配置数组就够了:
$cache_config=array('type'=>'apc');
要使用 Memcached,你需要提供一些参数:
$cache_config=array('type'=>'memcached', 'host'=>'127.0.0.1', 'port'=>11211, 'timeout'=>1);
要使用普通文本文件,你需要创建一个可读可写的目录并提供其绝对路径:
$cache_config=array('type'=>'file', 'path'=>'/tmp/my_project_cache')
还有一个可选参数“prefix”。如果给定,它将用作缓存的键名。
开始使用
现在是时候使用那些我们定义过的数据了。初始化该库,我们只需要这几行代码。
DB::init($db_config); CACHE::init($cache_config); ADB::init($model); $adb=ADB::get_instance();
创建表
这项任务只需执行一次。我们告诉库去创建所需的数据库表。它就会负责完成关系等相关的复杂工作。
$adb->create_tables();
我们只需在发布的时候执行该方法一次。如果在插入数据之后,调用该方法将导致数据丢失。
使用记录
我们手头拥有这个 $adb 实例。我们将通过它来获取所有数据。
创建记录
我们提供表名和由字段名称及数据组成的键值对数组来创建一条记录。
$uid1=$adb->create('user', array('name'=>'John')); $uid2=$adb->create('user', array('name'=>'Marry')); $pid1=$adb->create('post', array( 'writer'=>$uid1, 'text'=>'What a wonderful world!' )); $pid2=$adb->create('post', array( 'writer'=>$uid2, 'text'=>'Life is beautiful!' ));
创建多对多关系
第一个参数是表名。第二个参数是被关联记录的局部名称。第三个参数是记录的 ID,第三个参数是被关联记录的 ID。
$adb->relate('user', 'friends', $uid1, $uid2); $adb->relate('user', 'liked_posts', $uid1, $pid1); // 关注自己的帖子 :) $adb->relate('user', 'liked_posts', $uid1, $pid2); $adb->relate('user', 'liked_posts', $uid2, $pid1);
列举数据
我们可在一个简单的循环中列举所有写过帖子的用户以及帖子的关注者:
foreach ($adb->id_list('user') as $uid) { // load user $user=$adb->load('user', $uid); echo '<h1>' . $user['name'] . '</h1>' . "\n"; echo '<h2>Posts: </h2>' . "\n"; echo '<ul>' . "\n"; foreach ($user['posts'] as $pid) { //load post of user $post=$adb->load('post', $pid); $likers=array(); foreach ($post['likers'] as $lid) { // load liker of post $liker=$adb->load('user', $lid); $likers[]=$liker['name']; } $likers=(count($likers)) ? '<br />' . implode(', ', $likers) . ' liked.' : ''; echo '<li>' . $post['text'] . ' ' . $likers . '</li>' . "\n"; } echo '</ul>' . "\n"; }
更新记录
我们能够像下面这样更新任意一个记录:
$user1=$adb->load('user', $uid1); $user1['name']='Jack'; // 无需调用任何保存方法,保存以及缓存的同步更新全是自动的。
如果我们需要一次更新多个字段,这是另一种方法:
$post1=$adb->load('post', $pid1); $post1->update(array('writer'=>$uid2, 'text'=>'Not a wonderful world!'));
删除关联
这和创建关联一样:
$adb->unrelate('user', 'friends', $uid1, $uid2); $adb->unrelate('user', 'liked_posts', $uid1, $pid1);
删除记录
我们可以删除记录,同时保存或删除与该记录相关联的数据。
$adb->delete('user', $uid1); // 用户删掉了,帖子成为匿名的了。 $adb->delete('user', $uid1, true); // 用户以及用户的帖子都删掉了。
查询更多
作为示例,我想获得最受关注的 5 篇帖子。如下是我们所有要做的:
foreach ($adb->id_list('post', false, 'likers DESC', 5) as $pid) { $post=$adb->load('post', $pid); // 可对帖子做任何操作 }
抑或是我们想要获取用户被关注次数超过 5 次的所有帖子,我们可以执行以下操作:
$user=$adb->load('user', $uid1); foreach ($user->id_list('post', 'view_count>5') as $pid) { $post=$adb->load('post', $pid); // 可对帖子做任何操作 }
主要目标
对于单独的帖子页面,我们的代码将会是这么简单:
$post=$adb->load('post', $pid1); $writer=$adb->load('user', $post['writer']); echo $writer['name'] . ' wrote' . "<br />\n"; echo $post['text'] . "<br />\n"; $post['view_count']++; // 是的,增大浏览量就是这么简单
这些代码里有任何查询或者缓存逻辑吗?没有,主要目标是保持简单。
市面上有很多著名的替代产品。他们文档完备,支持得也更好。该库不是他们中的一员,它目前还不是一部状态良好的机器。在我看来,这是最简单且容易上手的方法。如果 ORM 库的目的是为了让编码人员不用关心数据库逻辑,这个库是其他新兴库中最自信的一个。jQuery 是最简单的 javascript 框架,也因此成了标准。所以,易于使用的 PHP ORM 库也有这样的机会。
这个库的下载地址:[ arrayDB github ]
欢迎提出意见和建议。
关于作者
Mustafa Dokumaci 是一位来自土耳其伊斯坦布尔的软件工程师。他的专业是环境工程和会计学,但他目前就职于 sporcum.com 和 hipsin.com。Mustafa 拥有六年的 PHP、MySQL、Apache、Nginx、Python、CodeIgniter、Magento 等的使用经验。
查看英文原文: arrayDB, a New and Easy PHP ORM
感谢侯伯薇对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
评论