摘要:查詢語言查詢語言,簡稱或,是一種面向對象的高級語言,允許用標準化的編寫。該對象的每個成員都是一個包含所查詢字段的標準對象。
Phalcon查詢語言(Phalcon Query Language)
Phalcon查詢語言,簡稱PhalconQL或PHQL,是一種面向對象的高級SQL語言,允許用標準化的SQL編寫。PHQL實現了把操作語句解析為RDBMS目標語言的解析器(C語言編寫)。
為了達到最佳性能,Phalcon提供了與SQLite相同的解析器,其線程安全,內存占用極低。
解析器先檢查傳遞的PHQL語句的語法,然后構建中間語句,最后將其轉換為RDBMS對應的SQL語句。
PHQL實現了一系列功能,可以更安全的操作數據庫。
參數綁定是PHQL功能之一,使代碼更安全
PHQL每次只允許執行一條SQL語句,以防SQL注入
PHQL會忽略所有SQL注入中常用的SQL注釋
PHQL只允許數據操作語句,避免錯誤的或未經授權的更改、刪除數據庫和表
PHQL實現了高級抽象接口,允許以模型方式操作表,以類屬性方式操作表字段
使用示例(Usage Example)為了更好的解釋PHQL工作原理,請參考下例。有Cars和Brands兩個模型:
belongsTo("brand_id", "Brands", "id"); } }
每輛車都屬于一個品牌,每個品牌有多輛車:
hasMany("id", "Cars", "brand_id"); } }創建PHQL查詢(Creating PHQL Queries)
實例化PhalconMvcModelQuery類即可創建PHQL查詢:
getDI() ); // 執行查詢,返回結果(如果有的話) $cars = $query->execute();
控制器或視圖中,使用PhalconMvcModelManager可以很容易的創建、執行PHQL查詢:
modelsManager->createQuery("SELECT * FROM Cars"); $cars = $query->execute(); // 使用參數綁定 $query = $this->modelsManager->createQuery("SELECT * FROM Cars WHERE name = :name:"); $cars = $query->execute( [ "name" => "Audi", ] );
或者直接執行查詢:
modelsManager->executeQuery( "SELECT * FROM Cars" ); // 使用參數綁定 $cars = $this->modelsManager->executeQuery( "SELECT * FROM Cars WHERE name = :name:", [ "name" => "Audi", ] );查詢記錄(Selecting Records)
PHQL允許使用我們熟知的SELECT語句查詢記錄,使用模型名字代替表名:
createQuery( "SELECT * FROM Cars ORDER BY Cars.name" ); $query = $manager->createQuery( "SELECT Cars.name FROM Cars ORDER BY Cars.name" );
允許帶命名空間的模型名:
createQuery($phql); $phql = "SELECT FormulaCars.name FROM FormulaCars ORDER BY FormulaCars.name"; $query = $manager->createQuery($phql); $phql = "SELECT c.name FROM FormulaCars c ORDER BY c.name"; $query = $manager->createQuery($phql);
PHQL支持大部分標準SQL語法,非標準的SQL語法也同樣支持,如LIMIT:
createQuery($phql);結果集類型(Result Types)
結果集類型根據我們查詢字段的不同而不同,如果檢索單個完整對象,則返回PhalconMvcModelResultsetSimple對象。這種結果集是一組完整的模型對象:
executeQuery($phql); foreach ($cars as $car) { echo "Name: ", $car->name, " "; }
下面這種方式也一樣:
"name", ] ); foreach ($cars as $car) { echo "Name: ", $car->name, " "; }
完整模型對象中的數據能夠被修改,并重新保存到數據庫中,因為它們代表關聯表的完整記錄。下面這種查詢方式不會返回完整模型對象:
executeQuery($phql); foreach ($cars as $car) { echo "Name: ", $car->name, " "; }
我們僅僅查詢了表中的某些字段,雖然返回的結果集仍然是PhalconMvcModelResultsetSimple對象,但不能當成完整模型對象。該對象的每個成員都是一個包含所查詢字段的標準對象。
這些不表示完整對象的值就是我們所說的標量,PHQL允許查詢所有類型的標量:字段,函數,字面兩,表達式等:
execute($phql); foreach ($cars as $car) { echo $car->id_name, " "; }
我們可以查詢完整對象或標量,也可以同時查詢它們:
executeQuery($phql);
這種情況下的結果集是一個PhalconMvcModelResultsetComplex對象,可以同時訪問完整對象和標量:
cars->name, " "; echo "Price: ", $row->cars->price, " "; echo "Taxes: ", $row->taxes, " "; }連接(Joins)
使用PHQL可以很容易的從多個模型請求記錄,支持大部分的JOIN方式。我們在模型中定義關系之后,PHQL會自動添加這些條件:
executeQuery($phql); foreach ($rows as $row) { echo $row->car_name, " "; echo $row->brand_name, " "; }
默認使用INNER JOIN,可以指定JOIN類型:
executeQuery($phql); $phql = "SELECT Cars.*, Brands.* FROM Cars LEFT JOIN Brands"; $rows = $manager->executeQuery($phql); $phql = "SELECT Cars.*, Brands.* FROM Cars LEFT OUTER JOIN Brands"; $rows = $manager->executeQuery($phql); $phql = "SELECT Cars.*, Brands.* FROM Cars CROSS JOIN Brands"; $rows = $manager->executeQuery($phql);
也可以手動設置JOIN條件:
executeQuery($phql);
如果查詢中為模型定義別名,則將使用別名為結果集中的每一條記錄命名:
executeQuery($phql); foreach ($rows as $row) { echo "Car: ", $row->c->name, " "; echo "Brand: ", $row->b->name, " "; }
如果連接模型與from之后的模型具有多對多關系時,中間模型將隱式的添加到查詢中:
modelsManager->executeQuery($phql);
上述代碼在MySQL中執行下列SQL:
SELECT `artists`.`name`, `songs`.`name` FROM `artists` INNER JOIN `albums` ON `albums`.`artists_id` = `artists`.`id` INNER JOIN "songs" ON `albums`.`songs_id` = `songs`.`id` WHERE `artists`.`genre` = "Trip-Hop"聚合(Aggregations)
下面例子展示了PHQL中如何使用聚合:
executeQuery($phql)->getFirst(); echo $row["summatory"]; // 每個品牌下的汽車總數 $phql = "SELECT Cars.brand_id, COUNT(*) FROM Cars GROUP BY Cars.brand_id"; $rows = $manager->executeQuery($phql); foreach ($rows as $row) { echo $row->brand_id, " ", $row["1"], " "; } // 每個品牌下的汽車總數 $phql = "SELECT Brands.name, COUNT(*) FROM Cars JOIN Brands GROUP BY 1"; $rows = $manager->executeQuery($phql); foreach ($rows as $row) { echo $row->name, " ", $row["1"], " "; } $phql = "SELECT MAX(price) AS maximum, MIN(price) AS minimum FROM Cars"; $rows = $manager->executeQuery($phql); foreach ($rows as $row) { echo $row["maximum"], " ", $row["minimum"], " "; } // 統計品牌數量 $phql = "SELECT COUNT(DISTINCT brand_id) AS brandId FROM Cars"; $rows = $manager->executeQuery($phql); foreach ($rows as $row) { echo $row->brandId, " "; }條件(Conditions)
條件能讓我們過濾想要查詢的記錄,WHERE子句允許這樣:
executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.price > 10000"; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE TRIM(Cars.name) = "Audi R8""; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.name LIKE "Ferrari%""; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.name NOT LIKE "Ferrari%""; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.price IS NULL"; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.id IN (120, 121, 122)"; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.id NOT IN(430, 431)"; $cars = $manager->executeQuery($phql); $phql = "SELECT * FROM Cars WHERE Cars.id BETWEEN 1 AND 100"; $cars = $manager->executeQuery($phql);
此外,作為PHQL的一部分,參數綁定會自動轉義輸入數據,安全性更高:
executeQuery( $phql, [ "name" => "Lamborghini Espada", ] ); $phql = "SELECT * FROM Cars WHERE Cars.name = ?0"; $cars = $manager->executeQuery( $phql, [ 0 => "Lamborghini Espada", ] );插入數據(Inserting Data)
通過PHQL,可以使用我們非常熟悉的INSERT語句插入數據:
executeQuery($phql); // 插入數據,指定字段 $phql = "INSERT INTO Cars (name, brand_id, year, style) VALUES ("Lamborghini Espada", 7, 1969, "Grand Tourer")"; $manager->executeQuery($phql); // 插入數據,使用占位符 $phql = "INSERT INTO Cars (name, brand_id, year, style) VALUES (:name:, :brand_id:, :year:, :style:)"; $manager->executeQuery( $phql, [ "name" => "Lamborghini Espada", "brand_id" => 7, "year" => 1969, "style" => "Grand Tourer", ] );
Phalcon不只是單純的將PHQL語句轉化成SQL,模型中定義的所有事件和業務規則都會執行,就像我們手動創建對象那樣。我們為模型Cars創建一條規則,車的價格不能低于$ 10,000:
price < 10000) { $this->appendMessage( new Message("A car cannot cost less than $ 10,000") ); return false; } } }
如果我們在模型Cars中執行下面的INSERT語句,操作將會失敗,因為price不滿足我們制定的規則。通過檢查插入狀態,我們可以打印任何內部生成的驗證消息:
executeQuery($phql); if ($result->success() === false) { foreach ($result->getMessages() as $message) { echo $message->getMessage(); } }更新數據(Updating Data)
更新記錄與插入記錄非常相似,更新記錄使用UPDATE命令。更新記錄時,將為每條記錄執行與更新操作相關的事件。
executeQuery($phql); // 更新多個字段 $phql = "UPDATE Cars SET price = 15000.00, type = "Sedan" WHERE id = 101"; $manager->executeQuery($phql); // 更新多條記錄 $phql = "UPDATE Cars SET price = 7000.00, type = "Sedan" WHERE brands_id > 5"; $manager->executeQuery($phql); // 使用占位符 $phql = "UPDATE Cars SET price = ?0, type = ?1 WHERE brands_id > ?2"; $manager->executeQuery( $phql, [ 0 => 7000.00, 1 => "Sedan", 2 => 5, ] );
UPDATE語句執行更新分兩步進行:
首先,如果UPDATE包含WHERE子句,將檢索符合條件的所有對象
其次,基于查詢對象更新字段并保存
這種操作方式允許事件、虛擬外鍵和驗證參與更新過程。
101"; $result = $manager->executeQuery($phql); if ($result->success() === false) { $messages = $result->getMessages(); foreach ($messages as $message) { echo $message->getMessage(); } }
上面代碼相當于:
101"); foreach ($cars as $car) { $car->price = 15000; if ($car->save() === false) { $messages = $car->getMessages(); return false; } } return true; }; $success = $process();刪除數據(Deleting Data)
刪除記錄時,與刪除操作相關的事件將逐一執行:
executeQuery($phql); // 刪除多條記錄 $phql = "DELETE FROM Cars WHERE id > 100"; $manager->executeQuery($phql); // 使用占位符 $phql = "DELETE FROM Cars WHERE id BETWEEN :initial: AND :final:"; $manager->executeQuery( $phql, [ "initial" => 1, "final" => 100, ] );
和UPDATE一樣,DELETE操作也分兩步執行,要檢查刪除操作是否產生驗證消息,你可以檢查返回的狀態:
100"; $result = $manager->executeQuery($phql); if ($result->success() === false) { $messages = $result->getMessages(); foreach ($messages as $message) { echo $message->getMessage(); } }使用查詢構造器創建查詢(Creating queries using the Query Builder)
查詢構造器可用于創建PHQL查詢,無需編寫PHQL語句:
modelsManager->createBuilder() ->from("Robots") ->join("RobotsParts") ->orderBy("Robots.name") ->getQuery() ->execute(); // 獲取第一條記錄 $robots = $this->modelsManager->createBuilder() ->from("Robots") ->join("RobotsParts") ->orderBy("Robots.name") ->getQuery() ->getSingleResult();
同下列操作:
executeQuery($phql);
查詢構造器更多示例:
from("Robots"); // "SELECT Robots.*, RobotsParts.* FROM Robots, RobotsParts"; $builder->from( [ "Robots", "RobotsParts", ] ); // "SELECT * FROM Robots"; $phql = $builder->columns("*") ->from("Robots"); // "SELECT id FROM Robots"; $builder->columns("id") ->from("Robots"); // "SELECT id, name FROM Robots"; $builder->columns(["id", "name"]) ->from("Robots"); // "SELECT Robots.* FROM Robots WHERE Robots.name = "Voltron""; $builder->from("Robots") ->where("Robots.name = "Voltron""); // "SELECT Robots.* FROM Robots WHERE Robots.id = 100"; $builder->from("Robots") ->where(100); // "SELECT Robots.* FROM Robots WHERE Robots.type = "virtual" AND Robots.id > 50"; $builder->from("Robots") ->where("type = "virtual"") ->andWhere("id > 50"); // "SELECT Robots.* FROM Robots WHERE Robots.type = "virtual" OR Robots.id > 50"; $builder->from("Robots") ->where("type = "virtual"") ->orWhere("id > 50"); // "SELECT Robots.* FROM Robots GROUP BY Robots.name"; $builder->from("Robots") ->groupBy("Robots.name"); // "SELECT Robots.* FROM Robots GROUP BY Robots.name, Robots.id"; $builder->from("Robots") ->groupBy(["Robots.name", "Robots.id"]); // "SELECT Robots.name SUM(Robots.price) FROM Robots GROUP BY Robots.name"; $builder->columns(["Robots.name", "SUM(Robots.price)"]) ->from("Robots") ->groupBy("Robots.name"); // "SELECT Robots.name, SUM(Robots.price) FROM Robots GROUP BY Robots.name HAVING SUM(Robots.price) > 1000"; $builder->columns(["Robots.name", "SUM(Robots.price)"]) ->from("Robots") ->groupBy("Robots.name") ->having("SUM(Robots.price) > 1000"); // "SELECT Robots.* FROM Robots JOIN RobotsParts"; $builder->from("Robots") ->join("RobotsParts"); // "SELECT Robots.* FROM Robots JOIN RobotsParts AS p"; $builder->from("Robots") ->join("RobotsParts", null, "p"); // "SELECT Robots.* FROM Robots JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p"; $builder->from("Robots") ->join("RobotsParts", "Robots.id = RobotsParts.robots_id", "p"); // "SELECT Robots.* FROM robots JOIN RobotsParts ON Robots.id = RobotsParts.robots_id AS p JOIN Parts ON Parts.id = RobotsParts.parts_id AS t"; $builder->from("Robots") ->join("RobotsParts", "Robots.id = RobotsParts.robots_id", "p") ->join("RobotsParts", "Parts.id = RobotsParts.parts_id", "t"); // "SELECT r.* FROM Robots AS r"; $builder->addFrom("Robots", "r"); // "SELECT Robots.*, p.* FROM Robots, Parts AS p"; $builder->from("Robots") ->addFrom("Parts", "p"); // "SELECT r.*, p.* FROM Robots AS r, Parts AS p"; $builder->from(["r" => "Robots"]) ->addFrom("Parts", "p"); // "SELECT r.*, p.* FROM Robots AS r, Parts AS p"; $builder->from(["r" => "Robots", "p" => "Parts"]); // "SELECT Robots.* FROM Robots LIMIT 10"; $builder->from("Robots") ->limit(10); // "SELECT Robots.* FROM Robots LIMIT 10 OFFSET 5"; $builder->from("Robots") ->limit(10, 5); // "SELECT Robots.* FROM Robots WHERE id BETWEEN 1 AND 100"; $builder->from("Robots") ->betweenWhere("id", 1, 10); // "SELECT Robots.* FROM Robots WHERE id IN (1, 2, 3)"; $builder->from("Robots") ->inWhere("id", [1, 2, 3]); // "SELECT Robots.* FROM Robots WHERE id NOT IN (1, 2, 3)"; $builder->from("Robots") ->notInWhere("id", [1, 2, 3]); // "SELECT Robots.* FROM Robots WHERE name LIKE "%Art%""; $builder->from("Robots") ->where("name LIKE :name:", ["name" => "%" . $name . "%"]); // "SELECT r.* FROM StoreRobots WHERE r.name LIKE "%Art%""; $builder->from(["r" => "StoreRobots"]) ->where("r.name LIKE :name:", ["name" => "%" . $name . "%"]);參數綁定(Bound Parameters)
查詢構造器中的參數綁定可以在查詢構建時設置,也可以在查詢執行時設置:
modelsManager->createBuilder() ->from("Robots") ->where("name = :name:", ["name" => $name]) ->andWhere("type = :type:", ["type" => $type]) ->getQuery() ->execute(); // 執行查詢時傳遞參數 $robots = $this->modelsManager->createBuilder() ->from("Robots") ->where("name = :name:") ->andWhere("type = :type:") ->getQuery() ->execute(["name" => $name, "type" => $type]);禁用字面量(Disallow literals in PHQL)
PHQL中可以禁用字面量,這意味著如果禁用開啟,則不能在PHQL語句中直接使用PHP字符串、數字和布爾值。如果在PHQL語句中嵌入外部數據,可能導致潛在的注入攻擊:
executeQuery($phql);
如果$login的值為" OR " " = " ,將產生如下PHQL語句:
SELECT * FROM ModelsUsers WHERE login = "" OR "" = "";
無論存儲在數據庫中的login是何值,條件總是true。
如果字面量被禁用,在PHQL中使用PHP字面量會拋出異常,以強制開發者使用參數綁定。上面的查詢這樣寫更安全:
executeQuery( $phql, [ "type" => $type, ] );
可以通過以下方式禁用字面量:
false] );
無論字面量是否禁用,參數綁定都可以正常使用。禁用只是開發人員能夠在web應用中采取的一項安全策略。
轉義保留字(Escaping Reserved Words)PHQL有一些保留字,如果想將保留字作為模型名或字段名使用,則需要使用轉義分隔符[和]來轉義關鍵字:
executeQuery($phql); $phql = "SELECT id, [Like] FROM Posts"; $result = $manager->executeQuery($phql);PHQL生命周期(PHQL Lifecycle)
作為高級語言,PHQL賦予了開發者個性化定制的能力,以滿足不同的需求。以下是PHQL語句的生命周期:
PHQL被解析并轉換為獨立于數據庫SQL之外的中間表示(IR)
根據模型對應的數據庫系統,IR被轉換為有效的SQL
PHQL語句被解析并保存在內存中,再次執行相同語句時速度會更快
使用原生SQL(Using Raw SQL)某些數據庫系統可能會提供PHQL不支持的特殊SQL擴展,這種情況適合使用原生SQL:
0"; // 模型 $robot = new Robots(); // 執行查詢 return new Resultset( null, $robot, $robot->getReadConnection()->query($sql) ); } }
如果原生SQL查詢在應用中很普遍,可以在模型中添加通用方法:
getReadConnection()->query($sql), ); } }
上述findByRawSQL可以如下使用:
?", [ 10, ] );注意事項(Troubleshooting)
PHQL中的一些注意事項:
類名稱區分大小寫,如果定義類時名稱和創建時的名稱不一致,在大小寫敏感的操作系統(如linux)中將導致不可預知行為
為保證參數綁定成功,連接數據庫時必須指定正確的字符集
指定別名的類不能用完整命名空間替換,因為這項操作發生在PHP代碼中,而非PHQL語句里
如果字段使用別名,應避免別名和字段名相同,不然查詢解析器容易混淆。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28527.html
摘要:本文描述了框架中數據庫操作方法,主要討論框架的組件中的操作方法。屬性方法在框架中支持屬性的擴展查詢,在上例中,可以把條件語句改為同時省略查詢條件結果不變。 本文描述了PHP-Phalcon框架中數據庫操作方法,主要討論Phalcon框架的Model組件中的操作方法。更詳細的Model介紹請參考:官方文檔 1. 連接數據庫 在Phalcon框架中,通過在DI中注入db參數來實現數據庫的...
摘要:初次認識是在剛學的時候最近終于有機會用上了故此說說使用上的一些感受個人是很喜歡這套框架的方式使用依賴注入讓代碼組織很靈活耦合也很低但是也許是框架東西太多了遇到幾個坑上一年以上的也還沒解決不過有一定開發經驗的話還是可以自己修復的被這幾個坑浪費 初次認識phalcon是在剛學php的時候,最近終于有機會用上了.故此說說使用上的一些感受 個人是很喜歡phalcon這套框架的方式,使用...
摘要:幫助你開始使用的簡易指南。第一種方式參考第二種方式參考使用參考簡單粗暴的理解是把下的對應成數據庫的表,類屬性對應表字段。 幫助你開始使用 phalcon 的簡易指南。 簡介 Phalcon 2將于2015年4月17日發布,這個版本大約85%的代碼是基于 Zephir 語言重寫的。Zephir是開源的,使用類似PHP語法的語言,生成C語言代碼,并編譯成PHP擴展。這提高了PHP擴展的開發...
摘要:是什么是開源全功能棧使用擴展編寫針對高性能優化的框架。也是松耦合的,可以根據項目的需要任意使用其他對象。安裝支持版本的不支持普通方式的編譯安裝,只能通過安裝。因此安裝之前,請先安裝。 Phalcon 是什么? Phalcon 是開源、全功能棧、使用 C 擴展編寫、針對高性能優化的 PHP 5 框架。 開發者不需要學習和使用 C 語言的功能, 因為所有的功能都以 PHP 類的方式暴露出來...
摘要:先引入類確定查詢表關聯表需要查詢的字段,這里兩個表的字段都可以當數據很大時,統計數據時用條件你好執行搜索執行模糊搜索設置條件,什么的都可以往后加注意這里的條件和原始語句中的語句剛好相反獲取查詢對象執行并返回結果 先引入Builder類 use PhalconMvcModelQueryBuilder as QueryBuilder; public function mytestActio...
閱讀 1858·2021-09-22 15:45
閱讀 1640·2019-08-30 15:55
閱讀 1829·2019-08-29 11:16
閱讀 3302·2019-08-26 11:44
閱讀 702·2019-08-23 17:58
閱讀 2698·2019-08-23 12:25
閱讀 1624·2019-08-22 17:15
閱讀 3597·2019-08-22 16:09