构建自己的PHP框架--实现Model类(1)
2016-02-28 22:11
676 查看
在之前的博客中,我们定义了ORM的接口,以及决定了使用PDO去实现。最后我们提到会有一个Model类实现ModelInterface接口。
现在我们来实现这个接口,如下:
当然现在里面还没有写任何的实现,只是继承了ModelInterface接口。
现在我们先来实现一下findOne方法,在开始实现之前我们要想,我们所有的model都要基于PDO,所以我们应该在model中有一个PDO的实例。所以我们需要在Model类中添加如下变量和方法。
用static变量可以保证所有继承该Model的类用的都是同一个PDO实例,getDb方法实现了单例模式(其中的配置暂时hard在这里,在之后的博客里会抽出来),保证了一个请求中,使用getDb只会取到一个PDO实例。
下面我们来实现findOne方法,我们现在定义的findOne有很多局限,例如不支持or,不支持select部分字段,不支持表关联等等。我们之后会慢慢完善这一些内容。其实findOne的实现就是拼接sql语句去执行,直接来看下代码:
我们需要来验证一下我们的代码是正确的,先在MySQL中设置一下用户及权限,mock一下数据。
相应的SQL语句如下:
然后再在models文件夹中创建一个User.php,代码如下:
最后只剩在Controller中使用findOne验证一下了。修改SiteController.php的actionTest方法如下:
打出的如下结果:
如果将findOne中的条件改成['age' => 20, 'name' => 'tom'],返回值就变为如下结果:
好了,今天就先到这里。项目内容和博客内容也都会放到Github上,欢迎大家提建议。
code:https://github.com/CraryPrimitiveMan/simple-framework/tree/0.5
blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework
现在我们来实现这个接口,如下:
<?php namespace sf\db; use PDO; /** * Model is the base class for data models. * @author Harry Sun <sunguangjun@126.com> */ class Model implements ModelInterface { /** * Declares the name of the database table associated with this Model class. * @return string the table name */ public static function tableName() { return get_called_class(); } /** * Returns the primary key **name(s)** for this Model class. * @return string[] the primary key name(s) for this Model class. */ public static function primaryKey() { return ['id']; } /** * Returns a single model instance by a primary key or an array of column values. * * ```php * // find the first customer whose age is 30 and whose status is 1 * $customer = Customer::findOne(['age' => 30, 'status' => 1]); * ``` * * @param mixed $condition a set of column values * @return static|null Model instance matching the condition, or null if nothing matches. */ public static function findOne($condition) { } /** * Returns a list of models that match the specified primary key value(s) or a set of column values. * * ```php * // find customers whose age is 30 and whose status is 1 * $customers = Customer::findAll(['age' => 30, 'status' => 1]); * ``` * * @param mixed $condition a set of column values * @return array an array of Model instance, or an empty array if nothing matches. */ public static function findAll($condition) { } /** * Updates models using the provided attribute values and conditions. * For example, to change the status to be 2 for all customers whose status is 1: * * ~~~ * Customer::updateAll(['status' => 1], ['status' => '2']); * ~~~ * * @param array $attributes attribute values (name-value pairs) to be saved for the model. * @param array $condition the condition that matches the models that should get updated. * An empty condition will match all models. * @return integer the number of rows updated */ public static function updateAll($condition, $attributes) { } /** * Deletes models using the provided conditions. * WARNING: If you do not specify any condition, this method will delete ALL rows in the table. * * For example, to delete all customers whose status is 3: * * ~~~ * Customer::deleteAll([status = 3]); * ~~~ * * @param array $condition the condition that matches the models that should get deleted. * An empty condition will match all models. * @return integer the number of rows deleted */ public static function deleteAll($condition) { } /** * Inserts the model into the database using the attribute values of this record. * * Usage example: * * ```php * $customer = new Customer; * $customer->name = $name; * $customer->email = $email; * $customer->insert(); * ``` * * @return boolean whether the model is inserted successfully. */ public function insert() { } /** * Saves the changes to this model into the database. * * Usage example: * * ```php * $customer = Customer::findOne(['id' => $id]); * $customer->name = $name; * $customer->email = $email; * $customer->update(); * ``` * * @return integer|boolean the number of rows affected. * Note that it is possible that the number of rows affected is 0, even though the * update execution is successful. */ public function update() { } /** * Deletes the model from the database. * * @return integer|boolean the number of rows deleted. * Note that it is possible that the number of rows deleted is 0, even though the deletion execution is successful. */ public function delete() { } }
当然现在里面还没有写任何的实现,只是继承了ModelInterface接口。
现在我们先来实现一下findOne方法,在开始实现之前我们要想,我们所有的model都要基于PDO,所以我们应该在model中有一个PDO的实例。所以我们需要在Model类中添加如下变量和方法。
/** * @var $pdo PDO instance */ public static $pdo; /** * Get pdo instance * @return PDO */ public static function getDb() { if (empty(static::$pdo)) { $host = 'localhost'; $database = 'sf'; $username = 'jun'; $password = 'jun'; static::$pdo = new PDO("mysql:host=$host;dbname=$database", $username, $password); static::$pdo->exec("set names 'utf8'"); } return static::$pdo; }
用static变量可以保证所有继承该Model的类用的都是同一个PDO实例,getDb方法实现了单例模式(其中的配置暂时hard在这里,在之后的博客里会抽出来),保证了一个请求中,使用getDb只会取到一个PDO实例。
下面我们来实现findOne方法,我们现在定义的findOne有很多局限,例如不支持or,不支持select部分字段,不支持表关联等等。我们之后会慢慢完善这一些内容。其实findOne的实现就是拼接sql语句去执行,直接来看下代码:
public static function findOne($condition) { // 拼接默认的前半段sql语句 $sql = 'select * from ' . static::tableName() . ' where '; // 取出condition中value作为参数 $params = array_values($condition); $keys = []; foreach ($condition as $key => $value) { array_push($keys, "$key = ?"); } // 拼接sql完成 $sql .= implode(' and ', $keys); $stmt = static::getDb()->prepare($sql); $rs = $stmt->execute($params); if ($rs) { $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!empty($row)) { // 创建相应model的实例 $model = new static(); foreach ($row as $rowKey => $rowValue) { // 给model的属性赋值 $model->$rowKey = $rowValue; } return $model; } } // 默认返回null return null; }
我们需要来验证一下我们的代码是正确的,先在MySQL中设置一下用户及权限,mock一下数据。
相应的SQL语句如下:
/*创建新用户*/ CREATE USER jun@localhost IDENTIFIED BY 'jun'; /*用户授权 授权jun用户拥有sf数据库的所有权限*/ GRANT ALL PRIVILEGES ON sf.* TO jun@'%' IDENTIFIED BY 'jun'; /*刷新授权*/ FLUSH PRIVILEGES; /*创建数据库*/ CREATE DATABASE IF NOT EXISTS `sf`; /*选择数据库*/ USE `sf`; /*创建表*/ CREATE TABLE IF NOT EXISTS `user` ( id INT(20) NOT NULL AUTO_INCREMENT, name VARCHAR(50), age INT(11), PRIMARY KEY(id) ); /*插入测试数据*/ INSERT INTO `user` (name, age) VALUES('harry', 20), ('tony', 23), ('tom', 24);
然后再在models文件夹中创建一个User.php,代码如下:
<?php namespace app\models; use sf\db\Model; /** * User model * @property integer $id * @property string $name * @property integer $age */ class User extends Model { public static function tableName() { return 'user'; } }
最后只剩在Controller中使用findOne验证一下了。修改SiteController.php的actionTest方法如下:
public function actionTest() { $user = User::findOne(['age' => 20, 'name' => 'harry']); $data = [ 'first' => 'awesome-php-zh_CN', 'second' => 'simple-framework', 'user' => $user ]; echo $this->toJson($data); }
打出的如下结果:
{"first":"awesome-php-zh_CN","second":"simple-framework","user":{"id":"1","name":"harry","age":"20"}}
如果将findOne中的条件改成['age' => 20, 'name' => 'tom'],返回值就变为如下结果:
{"first":"awesome-php-zh_CN","second":"simple-framework","user":null}
好了,今天就先到这里。项目内容和博客内容也都会放到Github上,欢迎大家提建议。
code:https://github.com/CraryPrimitiveMan/simple-framework/tree/0.5
blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework
相关文章推荐
- 【函数库】PHP RXData(RPGXP数据文件) 解析库 V1.0
- PHP实现多线程抓取网页
- 基于curl的php多线程类(异步请求)
- PHP Curl多线程原理实例详解
- PHP CURL 多线程 GET/POST 类
- php\symfony3 学习记录(三) 路由和控制器
- PHP文件上传实例
- ThinkPHP实现支付宝接口功能
- 对FileInputStream和FileOutputStream的应用
- ajax用法示例
- 对ByteArrayOutputStream和ByteArrayInputStream的应用
- 24.php中使用Iterator,ArrayAccess和Countable
- 在内网建一个FTP服务器,并且可以通过外网访问
- vsftpd虚拟用户配置【虚拟用户映射到系统账号vuser{禁止该账户登录}登录ftp】
- NSString+GetPath 类别
- 轻松实现PHP输出excel
- 自定义一个自己的ContentProvider程序
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的合用
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的合用
- 自定义一个自己的ContentProvider程序