閱讀869 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Phalcon入門教程之模型CURD(1)

原文發表於:Phalcon入門教程之模型CURD(1)

上一篇《Phalcon入門教程之模型》中介紹了數據庫模型操作的一些基礎功能,本篇將介紹模型的 selectinsert 用法。由於數據庫模型操作的內容比較多和細,所以本篇隻是粗略的介紹基礎用法,以及補充文檔中沒有提及的一些用法和注意點。因此,強烈建議大家在熟讀文檔的前提下,再閱讀此篇教程。

數據表

假設數據表名為 test_articles,數據結構及記錄下:

mysql> select * from test_articles;
+-----+--------------+--------------+--------+-------------+--------------+--------+-----------+---------------------+-----------+---------------------+
| aid | title        | introduce    | status | view_number | is_recommend | is_top | create_by | create_time         | modify_by | modify_time         |
+-----+--------------+--------------+--------+-------------+--------------+--------+-----------+---------------------+-----------+---------------------+
|   1 | 英語演講     | 純口語式       |      1 |           0 | 0            | 0      |         1 | 2017-05-21 05:13:46 |         1 | 2017-05-21 05:13:46 |
|   2 | 限購政策     | 快買房         |      1 |           0 | 0            | 0      |         1 | 2017-05-21 05:13:46 |         1 | 2017-05-21 05:13:46 |
+-----+--------------+--------------+--------+-------------+--------------+--------+-----------+---------------------+-----------+---------------------+

其中 aid 是主鍵,其他每個字段的意思就不做介紹了。

查找記錄

Phalcon\Mvc\Model 為數據查詢提供了多種函數,下麵將直接用demo來介紹其用法。

查找多條記錄

使用 find() 函數可以查找多條記錄:

$articleModel = new ArticlesModel();
//查詢所有記錄,返回一個對象
$result = $articleModel->find();
//循環輸出結果
foreach($result as $record){
  var_dump($record->aid); 
  var_dump($record->title);
}

find() 函數返回的是 Phalcon\Mvc\Model\Resultset\Simple 對象,我們可以通過 foreach 循環輸出結果。也可以將結果集對象轉成一個二維數組:

$records = $result->toArray();

還可以統計結果集對象的記錄總數:

$count = count($result);

查找單條記錄

查找單條記錄,可以通過使用 findFirst() 函數來實現:

$result1 = $articleModel->findFirst(1);
print_r($result1->toArray());

findFirst() 返回的就是當前模型對象(如果不明白,可以打印 $result1 即會明白),toArray() 會將其轉成一維數組。

細心的朋友可能會有疑問,findFirst(1) 是按什麼字段做查詢條件的? 通過監聽打印SQL語句,可以看到在 Phalcon 中會默認使用主鍵作為查詢條件:

SELECT * FROM `test_articles` WHERE `test_articles`.`aid` = 1 LIMIT :APL0

當然,我們也可以使用完整的查詢條件:

$result2 = $articleModel->findFirst("aid = 1");

返回的結果,和上麵的 findFirst(1) 是一樣的。

參數綁定

仔細觀察上麵的SQL語句,會發現查詢條件並沒有進行預處理。如果 aid 的值是通過外部數據(比如用戶輸入)或者變量傳輸進來,則有可能出現SQL注入的危險。我們必須要用參數綁定的方式來防止SQL注入:

$result2 = $articleModel->find([
  'conditions' => 'aid = :aid: AND status = :status:',
  'bind' => [
    'aid' => 2,
    'status' => 1,
  ],
]);

生成的SQL語句如下:

SELECT * FROM `test_articles` WHERE `test_articles`.`aid` = :aid AND `test_articles`.`status` = :status

經過參數替換後的SQL語句如下:

SELECT * FROM `test_articles` WHERE `test_articles`.`aid` = 2 AND `test_articles`.`status` = 1

參數綁定支持字符串和整數占位符,本篇隻介紹字符串占位符,整數占位符的用法可查閱文檔。

查詢選項

Phalcon 提供了很多查詢選項,常用的查詢選項demo如下:

$articleModel->find([
  'columns' => 'aid, title', //查詢字段
  'conditions' => 'aid = :aid:',  //查詢條件
  'bind' => [ //參數綁定
    'aid' => 2
  ],
  'order' => 'aid DESC', //排序
  'limit' => 10, //限製查詢結果的數量
  'offset' => 10, //偏移量
 ]);

全部的查詢選項,請查閱文檔。
很多朋友在群裏問 inlike 在參數綁定下的用法,下麵跟大家分享一下。

in的用法

直接上示例代碼:

$result3 = $articleModel->find([
  'conditions' => 'aid IN ({aids:array})',
    'bind' => [
      'aids' => [1, 2]
    ],
]);

like的用法

示例代碼如下:

$result4 = $articleModel->find([
  'conditions' => 'title like :title:',
  'bind' => [
    'title' => '%英語%',
  ],
]);

添加記錄

添加單條記錄

添加單條記錄可用 create() 函數:

$articleModel = new ArticlesModel();
$result = $articleModel->create([
    'title' => 'phalcon測試',
    'introduce' => 'Phalcon入門教程',
    'status' => 1,
    'view_number' => 1,
    'is_recommend' => 1,
    'is_top' => 1,
    'create_by' => 1,
    'create_time' => date('Y-m-d H:i:s'),
    'modify_by' => 1,
    'modify_time' => date('Y-m-d H:i:s')
]);
if (!$result) { 
    //添加記錄失敗,獲取錯誤信息
    $errorMessage = implode(',', $this->getMessages());
    echo $errorMessage;
}else {
    //添加記錄成功,獲取新增記錄的主鍵aid
    $aid = $articleModel->aid;
    echo $aid;
}

create() 函數返回的是 boolean 值。如果返回值為 false ,我們可以通過模型的 getMessages() 函數來獲取錯誤信息;若返回值為 true ,則可以直接獲取最新的主鍵ID,即我們通常所說的 lastInsertId

批量添加記錄

Phalcon 中並沒有提供批量添加記錄的函數,需要開發者自己動手實現,本篇跟大家分享兩種實現批量添加記錄的方法。

循環逐條添加

通過循環逐次添加一條記錄,這種方法在性能上損耗較大,**不推薦使用**。但是這種方法牽涉到 Phalcon 模型的底層實現原理,所以這裏拿出來跟大家分析一下。上代碼:

$articleModel = new ArticlesModel();
//var_dump($articleModel->title);  //下麵測試用
for ($i = 1; $i <= 10; $i++) {
    $data = [
        'title' => "phalcon測試{$i}",
        'introduce' => "Phalcon入門教程{$i}",
        'status' => $i,
        'view_number' => $i,
        'is_recommend' => 1,
        'is_top' => 1,
        'create_by' => $i,
        'create_time' => date('Y-m-d H:i:s'),
        'modify_by' => $i,
        'modify_time' => date('Y-m-d H:i:s')
    ];
    $result = $articleModel->create($data);
    if (!$result) {
        $errorMessage = implode(',', $articleModel->getMessages());
        exit($errorMessage);
    }else {
        $aid = $articleModel->aid;
        echo $aid;
        //var_dump($articleModel->title);  //下麵測試用
    }
    echo '<br />';
}

這段代碼的運行結果可能會出乎很多人的意料,隻有循環中的第一條數據入庫成功,並返回了主鍵ID,其他的數據入庫時直接報錯:

Record cannot be created because it already exists

意思是因為記錄已經存在,所以無法再次入庫。在前麵 添加單條記錄 的時候,我們有提到獲取 lastInsertId 的方式,是直接通過模型的成員屬性方式獲取:

$aid = $articleModel->aid;

關鍵點就在這裏,Phalcon 模型對象會把當前入庫的數據,全部賦值給模型對象的成員屬性,包括主鍵ID。我們做個測試,打開上麵代碼中的兩處注釋部分,再次運行後可以看到,第一次打印 title 成員屬性的時候,會報一個 Notice 錯誤,提示信息是未定義的成員屬性。當第二次打印 title 成員屬性的時候,卻有值了,而且是循環中第一條記錄的 title 值。看到這裏,相信大家應該已經差不多能明白其中的實現原理了。**因為入庫成功那條記錄返回的主鍵ID也被賦值給模型對象的成員屬性,create() 函數內部會判斷當前對象的主鍵成員屬性是否有值,在有值的情況下,就不再生成SQL語句發送到Mysql服務端,直接拋出錯誤信息**。請記住這一點,Phalcon 模型的 update() 函數也是基於此原理實現的(下一篇教程會提到)。那麼,通過循環逐條添加記錄的方法要如何實現呢?請看代碼:

$articleModel = new ArticlesModel();
for ($i = 1; $i <= 10; $i++) {
    $data = [
        'title' => "phalcon測試{$i}",
        'introduce' => "Phalcon入門教程{$i}",
        'status' => $i,
        'view_number' => $i,
        'is_recommend' => 1,
        'is_top' => 1,
        'create_by' => $i,
        'create_time' => date('Y-m-d H:i:s'),
        'modify_by' => $i,
        'modify_time' => date('Y-m-d H:i:s')
    ];
    $clone = clone $articleModel; //克隆一個新對象,使用新對象來調用create()函數
    $result = $clone->create($data);
    if (!$result) {
        $errorMessage = implode(',', $clone->getMessages());
        exit($errorMessage);
    }else {
        $aid = $clone->aid;
        echo $aid;
    }
    echo '<br />';
}

每循環一次,就克隆出一個新對象,通過新對象來調用 create() 函數添加數據記錄。因為每個對象間的成員屬性都是獨立的,所以全部數據都會添加成功。

批量添加

我們常用的批量添加方式是生成一條 insert 語句把數據添加入庫,下麵跟大家分享我在項目中封裝的函數:

//文件路徑:Marser\app\frontend\models\ArticlesModel.php
class ArticlesModel extends \Marser\App\Frontend\Models\BaseModel {

    /*** 表名*/
    const TABLE_NAME = 'articles';

    public function initialize(){
        parent::initialize();
        $this->set_table_source(self::TABLE_NAME);
    }

    /**
     * 批量添加
     * @param array $data
     * @return boolean
     * @throws \Exception
     */
    public function batch_insert(array $data){
        if (count($data) == 0) {
            throw new \Exception('參數錯誤');
        }
        $keys = array_keys(reset($data));
        $keys = array_map(function ($key) {
            return "`{$key}`";
        }, $keys);
        $keys = implode(',', $keys);
        $sql = "INSERT INTO " . $this->getSource() . " ({$keys}) VALUES ";
        foreach ($data as $v) {
            $v = array_map(function ($value) {
                return "'{$value}'";
            }, $v);
            $values = implode(',', array_values($v));
            $sql .= " ({$values}), ";
        }
        $sql = rtrim(trim($sql), ',');
        //DI中注冊的數據庫服務名稱為"db"
        $result = $this->getDI()->get('db')->execute($sql);
        if (!$result) {
            throw new \Exception('批量入庫記錄');
        }
        return $result;
    }
}

以上代碼已托管在github:https://github.com/KevinJay/marser-phalcon-demo

最後,歡迎大家加入QQ群交流討論:

  • 廣州PHP高端交流群:158587573
  • Phalcon玩家群:150237524

最後更新:2017-07-20 17:02:54

  上一篇:go  Phalcon入門教程之模型CURD(2)
  下一篇:go  大數據與個人征信市場發展