Phalcon7 模型的使用

2018-10-21 07:15 更新

模型代表了應(yīng)用程序中的信息(數(shù)據(jù))和處理數(shù)據(jù)的規(guī)則。模型主要用于管理與相應(yīng)數(shù)據(jù)庫(kù)表進(jìn)行交互的規(guī)則。 大多數(shù)情況中,在應(yīng)用程序中,數(shù)據(jù)庫(kù)中每個(gè)表將對(duì)應(yīng)一個(gè)模型。 應(yīng)用程序中的大部分業(yè)務(wù)邏輯都將集中在模型里。

Phalcon\Mvc\Model 是 Phalcon 應(yīng)用程序中所有模型的基類。它保證了數(shù)據(jù)庫(kù)的獨(dú)立性,基本的 CURD 操作, 高級(jí)的查詢功能,多表關(guān)聯(lián)等功能。Phalcon\Mvc\Model 不需要直接使用 SQL 語句,因?yàn)樗霓D(zhuǎn)換方法,會(huì)動(dòng)態(tài)的調(diào)用相應(yīng)的數(shù)據(jù)庫(kù)引擎進(jìn)行處理。

模型是數(shù)據(jù)庫(kù)的高級(jí)抽象層。如果您想進(jìn)行低層次的數(shù)據(jù)庫(kù)操作,您可以查看 Phalcon\Db 組件文檔。

創(chuàng)建模型

模型是一個(gè)繼承自 Phalcon\Mvc\Model 的一個(gè)類。 它必須放到 models 文件夾。一個(gè)模型文件必須包含一個(gè)類, 同時(shí)它的類名必須符合駝峰命名法:

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{

}

上面的例子顯示了 “Robots” 模型的實(shí)現(xiàn)。 需要注意的是 Robots 繼承自 Phalcon\Mvc\Model 。 因此,Robots 模型擁有了大量繼承自該組件功能,包括基本的數(shù)據(jù)庫(kù) CRUD (Create, Read, Update, Delete) 操作,數(shù)據(jù)驗(yàn)證以及復(fù)雜的搜索支持,并且可以同時(shí)關(guān)聯(lián)多個(gè)模型。

默認(rèn)情況下,模型 “Robots” 對(duì)應(yīng)的是數(shù)據(jù)庫(kù)表 “robots”, 如果想映射到其他數(shù)據(jù)庫(kù)表,可以使用 getSource() 方法:

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public function getSource()
    {
        return "the_robots";
    }
}

模型 Robots 現(xiàn)在映射到了 “the_robots” 表。initialize() 方法可以幫助在模型中建立自定義行為,例如指定不同的數(shù)據(jù)庫(kù)表。 initialize() 方法在請(qǐng)求期間只被調(diào)用一次。

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public function initialize()
    {
        $this->setSource("the_robots");
    }
}

initialize() 方法在請(qǐng)求期間僅會(huì)被調(diào)用一次,目的是為應(yīng)用中所有該模型的實(shí)例進(jìn)行初始化。如果需要為每一個(gè)實(shí)例在創(chuàng)建的時(shí)候單獨(dú)進(jìn)行初始化, 可以使用 ‘onConstruct’ 事件:

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public function onConstruct()
    {
        // ...
    }
}

公共屬性對(duì)比設(shè)置與取值 Setters/Getters

模型可以通過公共屬性的方式實(shí)現(xiàn),意味著模型的所有屬性在實(shí)例化該模型的地方可以無限制的讀取和更新。

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public $price;
}

通過使用 getters/setters 方法,可以控制哪些屬性可以公開訪問,并且對(duì)屬性值執(zhí)行不同的形式的轉(zhuǎn)換,同時(shí)可以保存在模型中的數(shù)據(jù)添加相應(yīng)的驗(yàn)證規(guī)則。

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    protected $id;

    protected $name;

    protected $price;

    public function getId()
    {
        return $this->id;
    }

    public function setName($name)
    {
        // The name is too short?
        if (strlen($name) < 10) {
            throw new \InvalidArgumentException('The name is too short');
        }
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPrice($price)
    {
        // Negative prices aren't allowed
        if ($price < 0) {
            throw new \InvalidArgumentException('Price can\'t be negative');
        }
        $this->price = $price;
    }

    public function getPrice()
    {
        // Convert the value to double before be used
        return (double) $this->price;
    }
}

公共屬性的方式可以在開發(fā)中降低復(fù)雜度。而 getters/setters 的實(shí)現(xiàn)方式可以顯著的增強(qiáng)應(yīng)用的可測(cè)試性、擴(kuò)展性和可維護(hù)性。 開發(fā)人員可以自己決定哪一種策略更加適合自己開發(fā)的應(yīng)用。ORM同時(shí)兼容這兩種方法。

模型放入命名空間

命名空間可以用來避免類名的沖突。ORM通過類名來映射相應(yīng)的表名。比如 ‘Robots’:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    // ...
}

Namespaces make part of model names when they are within strings:

<?php

namespace Store\Toys;

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany('id', 'Store\Toys\RobotsParts', 'robots_id');
    }
}

理解記錄對(duì)象

每個(gè)模型的實(shí)例對(duì)應(yīng)一條數(shù)據(jù)表中的記錄??梢苑奖愕耐ㄟ^讀取對(duì)象的屬性來訪問相應(yīng)的數(shù)據(jù)。比如, 一個(gè)表 “robots” 有如下數(shù)據(jù):

mysql> select * from robots;
+----+------------+------------+------+
| id | name       | type       | year |
+----+------------+------------+------+
|  1 | Robotina   | mechanical | 1972 |
|  2 | Astro Boy  | mechanical | 1952 |
|  3 | Terminator | cyborg     | 2029 |
+----+------------+------------+------+
3 rows in set (0.00 sec)

你可以通過主鍵找到某一條記錄并且打印它的名稱:

<?php

// Find record with id = 3
$robot = Robots::findFirst(3);

// Prints "Terminator"
echo $robot->name;

一旦記錄被加載到內(nèi)存中之后,你可以修改它的數(shù)據(jù)并保存所做的修改:

<?php

$robot       = Robots::findFirst(3);
$robot->name = "RoboCop";
$robot->save();

如上所示,不需要寫任何SQL語句。Phalcon\Mvc\Model 為web應(yīng)用提供了高層數(shù)據(jù)庫(kù)抽象。

查找記錄

Phalcon\Mvc\Model 為數(shù)據(jù)查詢提供了多種方法。下面的例子將演示如何從一個(gè)模型中查找一條或者多條記錄:

<?php

// How many robots are there?
$robots = Robots::find();
echo "There are ", count($robots), "\n";

// How many mechanical robots are there?
$robots = Robots::find("type = 'mechanical'");
echo "There are ", count($robots), "\n";

// Get and print virtual robots ordered by name
$robots = Robots::find(
    array(
        "type = 'virtual'",
        "order" => "name"
    )
);
foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Get first 100 virtual robots ordered by name
$robots = Robots::find(
    array(
        "type = 'virtual'",
        "order" => "name",
        "limit" => 100
    )
);
foreach ($robots as $robot) {
   echo $robot->name, "\n";
}
如果需要通過外部數(shù)據(jù)(比如用戶輸入)或變量來查詢記錄,則必須要用`Binding Parameters`(綁定參數(shù))的方式來防止SQL注入.

你可以使用 findFirst() 方法獲取第一條符合查詢條件的結(jié)果:

<?php

// What's the first robot in robots table?
$robot = Robots::findFirst();
echo "The robot name is ", $robot->name, "\n";

// What's the first mechanical robot in robots table?
$robot = Robots::findFirst("type = 'mechanical'");
echo "The first mechanical robot name is ", $robot->name, "\n";

// Get first virtual robot ordered by name
$robot = Robots::findFirst(
    array(
        "type = 'virtual'",
        "order" => "name"
    )
);
echo "The first virtual robot name is ", $robot->name, "\n";

find() 和 findFirst() 方法都接受關(guān)聯(lián)數(shù)組作為查詢條件:

<?php

$robot = Robots::findFirst(
    array(
        "type = 'virtual'",
        "order" => "name DESC",
        "limit" => 30
    )
);

$robots = Robots::find(
    array(
        "conditions" => "type = ?1",
        "bind"       => array(1 => "virtual")
    )
);

可用的查詢選項(xiàng)如下:

參數(shù)描述舉例
conditions查詢操作的搜索條件。用于提取只有那些滿足指定條件的記錄。默認(rèn)情況下Phalcon\Mvc\Model 假定第一個(gè)參數(shù)就是查詢條件。"conditions" => "name LIKE'steve%'"
columns只返回指定的字段,而不是模型所有的字段。 當(dāng)用這個(gè)選項(xiàng)時(shí),返回的是一個(gè)不完整的對(duì)象。"columns" => "id, name"
bind綁定與選項(xiàng)一起使用,通過替換占位符以及轉(zhuǎn)義字段值從而增加安全性。"bind" => array("status" =>"A", "type" => "some-time")
bindTypes當(dāng)綁定參數(shù)時(shí),可以使用這個(gè)參數(shù)為綁定參數(shù)定義額外的類型限制從而更加增強(qiáng)安全性。"bindTypes" =>array(Column::BIND_PARAM_STR,Column::BIND_PARAM_INT)
order用于結(jié)果排序。使用一個(gè)或者多個(gè)字段,逗號(hào)分隔。"order" => "name DESC,status"
limit限制查詢結(jié)果的數(shù)量在一定范圍內(nèi)。"limit" => 10
offsetOffset the results of the query by a certain amount"offset" => 5
group從多條記錄中獲取數(shù)據(jù)并且根據(jù)一個(gè)或多個(gè)字段對(duì)結(jié)果進(jìn)行分組。"group" => "name, status"
for_update通過這個(gè)選項(xiàng), Phalcon\Mvc\Model 讀取最新的可用數(shù)據(jù),并且為讀到的每條記錄設(shè)置獨(dú)占鎖。"for_update" => true
shared_lock通過這個(gè)選項(xiàng), Phalcon\Mvc\Model 讀取最新的可用數(shù)據(jù),并且為讀到的每條記錄設(shè)置共享鎖。"shared_lock" => true
cache緩存結(jié)果集,減少了連續(xù)訪問數(shù)據(jù)庫(kù)。"cache" => array("lifetime"=> 3600, "key" => "my-find-key")
hydrationSets the hydration strategy to represent each returned record in the result"hydration" =>Resultset::HYDRATE_OBJECTS

如果你愿意,除了使用數(shù)組作為查詢參數(shù)外,還可以通過一種面向?qū)ο蟮姆绞絹韯?chuàng)建查詢:

<?php

$robots = Robots::query()
    ->where("type = :type:")
    ->andWhere("year < 2000")
    ->bind(array("type" => "mechanical"))
    ->order("name")
    ->execute();

靜態(tài)方法 query() 返回一個(gè)對(duì)IDE自動(dòng)完成友好的 Phalcon\Mvc\Model\Criteria 對(duì)象。

所有查詢?cè)趦?nèi)部都以 PHQL 查詢的方式處理。PHQL是一個(gè)高層的、面向?qū)ο蟮念怱QL語言。通過PHQL語言你可以使用更多的比如join其他模型、定義分組、添加聚集等特性。

最后,還有一個(gè) findFirstBy<property-name>() 方法。這個(gè)方法擴(kuò)展了前面提及的 findFirst() 方法。它允許您利用方法名中的屬性名稱,通過將要搜索的該字段的內(nèi)容作為參數(shù)傳給它,來快速?gòu)囊粋€(gè)表執(zhí)行檢索操作。

還是用上面用過的 Robots 模型來舉例說明:

<?php

use Phalcon\Mvc\Model;

class Robots extends Model
{
    public $id;

    public $name;

    public $price;
}

我們這里有3個(gè)屬性:$id$name 和 $price。因此,我們以想要查詢第一個(gè)名稱為 ‘Terminator’ 的記錄為例,可以這樣寫:

<?php

$name  = "Terminator";
$robot = Robots::findFirstByName($name);

if ($robot) {
    $this->flash->success("The first robot with the name " . $name . " cost " . $robot->price ".");
} else {
    $this->flash->error("There were no robots found in our table with the name " . $name ".");
}

請(qǐng)注意我們?cè)诜椒ㄕ{(diào)用中用的是 ‘Name’,并向它傳遞了變量 $name, $name 的值就是我們想要找的記錄的名稱。另外注意,當(dāng)我們的查詢找到了符合的記錄后,這個(gè)記錄的其他屬性也都是可用的。

模型結(jié)果集

findFirst() 方法直接返回一個(gè)被調(diào)用對(duì)象的實(shí)例(如果有結(jié)果返回的話),而 find() 方法返回一個(gè) Phalcon\Mvc\Model\Resultset\Simple 對(duì)象。這個(gè)對(duì)象也封裝進(jìn)了所有結(jié)果集的功能,比如遍歷、查找特定的記錄、統(tǒng)計(jì)等等。

這些對(duì)象比一般數(shù)組功能更強(qiáng)大。最大的特點(diǎn)是 Phalcon\Mvc\Model\Resultset 每時(shí)每刻只有一個(gè)結(jié)果在內(nèi)存中。這對(duì)操作大數(shù)據(jù)量時(shí)的內(nèi)存管理相當(dāng)有幫助。

<?php

// Get all robots
$robots = Robots::find();

// Traversing with a foreach
foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Traversing with a while
$robots->rewind();
while ($robots->valid()) {
    $robot = $robots->current();
    echo $robot->name, "\n";
    $robots->next();
}

// Count the resultset
echo count($robots);

// Alternative way to count the resultset
echo $robots->count();

// Move the internal cursor to the third robot
$robots->seek(2);
$robot = $robots->current();

// Access a robot by its position in the resultset
$robot = $robots[5];

// Check if there is a record in certain position
if (isset($robots[3])) {
   $robot = $robots[3];
}

// Get the first record in the resultset
$robot = $robots->getFirst();

// Get the last record
$robot = $robots->getLast();

Phalcon 的結(jié)果集模擬了可滾動(dòng)的游標(biāo),你可以通過位置,或者內(nèi)部指針去訪問任何一條特定的記錄。注意有一些數(shù)據(jù)庫(kù)系統(tǒng)不支持滾動(dòng)游標(biāo),這就使得查詢會(huì)被重復(fù)執(zhí)行, 以便回放光標(biāo)到最開始的位置,然后獲得相應(yīng)的記錄。類似地,如果多次遍歷結(jié)果集,那么必須執(zhí)行相同的查詢次數(shù)。

將大數(shù)據(jù)量的查詢結(jié)果存儲(chǔ)在內(nèi)存會(huì)消耗很多資源,正因?yàn)槿绱?,分成?2行一塊從數(shù)據(jù)庫(kù)中獲得結(jié)果集,以減少重復(fù)執(zhí)行查詢請(qǐng)求的次數(shù),在一些情況下也節(jié)省內(nèi)存。

注意結(jié)果集可以序列化后保存在一個(gè)后端緩存里面。 Phalcon\Cache 可以用來實(shí)現(xiàn)這個(gè)。但是,序列化數(shù)據(jù)會(huì)導(dǎo)致 Phalcon\Mvc\Model 將從數(shù)據(jù)庫(kù)檢索到的所有數(shù)據(jù)以一個(gè)數(shù)組的方式保存,因此在這樣執(zhí)行的地方會(huì)消耗更多的內(nèi)存。

<?php

// Query all records from model parts
$parts = Parts::find();

// Store the resultset into a file
file_put_contents("cache.txt", serialize($parts));

// Get parts from file
$parts = unserialize(file_get_contents("cache.txt"));

// Traverse the parts
foreach ($parts as $part) {
    echo $part->id;
}

過濾結(jié)果集(Filtering Resultsets)?

過濾數(shù)據(jù)最有效的方法是設(shè)置一些查詢條件,數(shù)據(jù)庫(kù)會(huì)利用表的索引快速返回?cái)?shù)據(jù)。Phalcon 額外的允許你通過任何數(shù)據(jù)庫(kù)不支持的方式過濾數(shù)據(jù)。

<?php

$customers = Customers::find()->filter(
    function ($customer) {

        // Return only customers with a valid e-mail
        if (filter_var($customer->email, FILTER_VALIDATE_EMAIL)) {
            return $customer;
        }
    }
);

將結(jié)果集轉(zhuǎn)為數(shù)組

<?php

$customers = Customers::find();
$arr = $customers->toArray();

綁定參數(shù)

在 Phalcon\Mvc\Model 中也支持綁定參數(shù)。即使使用綁定參數(shù)對(duì)性能有一點(diǎn)很小的影響,還是強(qiáng)烈建議您使用這種方法,以消除代碼受SQL注入攻擊的可能性。 綁定參數(shù)支持字符串和整數(shù)占位符。實(shí)現(xiàn)方法如下:

<?php

// Query robots binding parameters with string placeholders
$conditions = "name = :name: AND type = :type:";

// Parameters whose keys are the same as placeholders
$parameters = array(
    "name" => "Robotina",
    "type" => "maid"
);

// Perform the query
$robots = Robots::find(
    array(
        $conditions,
        "bind" => $parameters
    )
);

// Query robots binding parameters with integer placeholders
$conditions = "name = ?1 AND type = ?2";
$parameters = array(1 => "Robotina", 2 => "maid");
$robots     = Robots::find(
    array(
        $conditions,
        "bind" => $parameters
    )
);

// Query robots binding parameters with both string and integer placeholders
$conditions = "name = :name: AND type = ?1";

// Parameters whose keys are the same as placeholders
$parameters = array(
    "name" => "Robotina",
    1      => "maid"
);

// Perform the query
$robots = Robots::find(
    array(
        $conditions,
        "bind" => $parameters
    )
);
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)