zoukankan      html  css  js  c++  java
  • 构建自己的PHP框架--实现Model类(1)

    在之前的博客中,我们定义了ORM的接口,以及决定了使用PDO去实现。最后我们提到会有一个Model类实现ModelInterface接口。

    现在我们来实现这个接口,如下:

    <?php
    namespace sfdb;
    
    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 appmodels;
    
    use sfdbModel;
    
    /**
     * 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

  • 相关阅读:
    mupdf arm 交叉编译记录
    lua的closure创建和使用
    Lua函数执行流程及函数延续点问题的研究
    boost::statechart研究报告
    lambda,std::function, 函数对象,bind的使用备忘
    将博客搬至CSDN
    Impala的分布式查询
    轻量级文本搜索引擎的后台设计、实现与优化
    1 producer — n consumers 模型 实现
    1001. A+B Format (20)
  • 原文地址:https://www.cnblogs.com/CraryPrimitiveMan/p/5225686.html
Copyright © 2011-2022 走看看