# phalcon(費爾康)框架學習筆記 #
以實例程序invo為例(invo程序放在網站根目錄下的invo文件夾里,推薦php版本>=5.4)
## 環境不支持偽靜態網址時的配置 ##
第一步:
在`app\config\config.ini`文件中的`[application]`節點內修改`baseUri`參數值為`/invo/index.php/`或`/invo/index.php?_url=/`,并增加一個參數`staticBaseUri`,值設為`/invo/`。
例如:
;支持非偽靜態網址
baseUri = "/invo/index.php?_url=/"
;靜態資源文件網址
staticBaseUri = /invo/
如果將baseUri設置為`/invo/index.php/`的話,需要在router服務中作如下設置,才能正常工作:
$di -> set('router', function () {
$router = new Router();
$router->setUriSource(Router::URI_SOURCE_SERVER_REQUEST_URI);//重要
return $router;
});
第二步:
在文件`app\config\services.php`中找到`$di->set('url',`所在位置,在其中的匿名函數內return語句前增加一行,輸入`$url->setStaticBaseUri($config->application->staticBaseUri);`
>
> 這里使用的是phalcon v2.0.2,此版本在使用非偽靜態網址的過程中,發現存在一個bug:當在模板中使用`$this->tag->linkTo('products/search?page=1')`函數生成網址時,由于第一個參數中包含了問號,再加上配置文件中的`baseUri`中也包含問號,這樣生成的網址中就包含兩處問號,只能通過自己擴展Url類來修復了,下面是修復步驟。
>
> 在文件`app\config\services.php`中添加以下代碼:
>
> /**
> * 重寫Url,修復動態網址中關于問號的bug
> *
> * @author:S.W.H
> * @E-mail:swh@admpub.com
> * @update:2015/6/9
> */
>
> class MyUrl extends UrlProvider{
> static public $hasDynamicUrl=null;
> public function get($uri=null, $args=null, $local=null){
> if(self::$hasDynamicUrl && strpos($uri,'?')!==false){
> $uri=str_replace('?','&',$uri);
> }
> return parent::get($uri, $args, $local);
> }
> }
>
> 并將代碼:
>
> $url = new UrlProvider();
>
> 替換為:
>
> $url = new \MyUrl();
> \MyUrl::$hasDynamicUrl=strpos($config->application->baseUri,'?')!==false;
>
> 即可解決。
## 路由規則 ##
添加路由規則:
<?php
use Phalcon\Mvc\Router;
// Create the router
$router = new Router();
//Define a route
$router->add(
"/admin/:controller/a/:action/:params",
array(
"controller" => 1, //匹配第一個占位符(/:controller)
"action" => 2, //匹配第二個占位符(/:action)
"params" => 3, //匹配第三個占位符(/:params)
)
);
支持的占位符有:
<table border="1" class="docutils">
<colgroup>
<col width="10%">
<col width="15%">
<col width="75%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">占位符</th>
<th class="head">正則表達式</th>
<th class="head">Usage</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>/:module</td>
<td>/([a-zA-Z0-9_-]+)</td>
<td>Matches a valid module name with alpha-numeric characters only</td>
</tr>
<tr class="row-odd"><td>/:controller</td>
<td>/([a-zA-Z0-9_-]+)</td>
<td>Matches a valid controller name with alpha-numeric characters only</td>
</tr>
<tr class="row-even"><td>/:action</td>
<td>/([a-zA-Z0-9_]+)</td>
<td>Matches a valid action name with alpha-numeric characters only</td>
</tr>
<tr class="row-odd"><td>/:params</td>
<td>(/.*)*</td>
<td>Matches a list of optional words separated by slashes. Use only this placeholder at the end of a route</td>
</tr>
<tr class="row-even"><td>/:namespace</td>
<td>/([a-zA-Z0-9_-]+)</td>
<td>Matches a single level namespace name</td>
</tr>
<tr class="row-odd"><td>/:int</td>
<td>/([0-9]+)</td>
<td>Matches an integer parameter</td>
</tr>
</tbody>
</table>
Controller名稱是采用駝峰命名法(camel),這意味著“-”和“_”將會被刪除并將其后的一個字符大寫。
例如,some\_controller 會被轉換為 SomeController。
### 指定參數名稱 ###
- 方式一,在數組中指定:
<?php
$router->add(
"/news/([0-9]{4})/([0-9]{2})/([0-9]{2})/:params",
array(
"controller" => "posts",
"action" => "show",
"year" => 1, // ([0-9]{4})
"month" => 2, // ([0-9]{2})
"day"=> 3, // ([0-9]{2})
"params" => 4, // :params
)
);
在上面的例子中,路由沒有定義“controller”和“action”部分,而是被指定為“posts”和“show”,這樣,用戶將不知道控制器的真實請求路徑。
在controller中,這些被命名的參數可以用如下方式這樣訪問:
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller{
public function indexAction(){
}
public function showAction(){
// Return "year" parameter
$year = $this->dispatcher->getParam("year");
// Return "month" parameter
$month = $this->dispatcher->getParam("month");
// Return "day" parameter
$day = $this->dispatcher->getParam("day");
}
}
- 方式二,在路由中指定:
$router->add(
"/documentation/{chapter}/{name}.{type:[a-z]+}",
array(
"controller" => "documentation",
"action" => "show"
)
);
看見了嗎?花括號中的chaper、name和type就是相對應的名稱了。
總結:路由中的匹配項,可以使用
- 占位符
- 正則表達式
- 帶命名的正則表達式(命名與正則表達式間用冒號“:”隔開,并整個用花括號括起來)
- {命名}
指定名稱空間的例子:
$router->add("/login", array(
'namespace' => 'Backend\Controllers',
'controller' => 'login',
'action' => 'index'
));
### 鉤子事件 ###
轉換某個參數的值:
<?php
//The action name allows dashes, an action can be: /products/new-ipod-nano-4-generation
$router->add('/products/{slug:[a-z\-]+}', array(
'controller' => 'products',
'action' => 'show'
))->convert('slug', function($slug) {
//Transform the slug removing the dashes
return str_replace('-', '', $slug);
});
除了convert方法之外,還支持:
- 匹配回調函數
->beforeMatch(function($uri, $route) {
//Check if the request was made with Ajax
if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'xmlhttprequest') {
return false;
}
return true;
});//參數可以是匿名函數,也可以采用數組的方式指定某個對象的方法:array(new AjaxFilter(), 'check')
- 限制主機名
->setHostName('([a-z+]).company.com');
### 路由分組 ###
<?php
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Router\Group as RouterGroup;
$router = new Router();
//Create a group with a common module and controller
$blog = new RouterGroup(array(
'module' => 'blog',
'controller' => 'index'
));
//All the routes start with /blog
$blog->setPrefix('/blog');
//Add another route to the group
$blog->add('/edit/{id}', array(
'action' => 'edit'
));
//Add the group to the router
$router->mount($blog);
或者:
<?php
use Phalcon\Mvc\Router\Group as RouterGroup;
class BlogRoutes extends RouterGroup{
public function initialize(){
//Default paths
$this->setPaths(array(
'module' => 'blog',
'namespace' => 'Blog\Controllers'
));
//All the routes start with /blog
$this->setPrefix('/blog');
//Add another route to the group
$this->add('/edit/{id}', array(
'action' => 'edit'
));
}
}
Then mount the group in the router:
<?php
//Add the group to the router
$router->mount(new BlogRoutes());
### 路由命名 ###
<?php
$route = $router->add("/posts/{year}/{title}", "Posts::show");
$route->setName("show-posts");
//或者這樣
$router->add("/posts/{year}/{title}", "Posts::show")->setName("show-posts");
然后,我們就可以根據命名來生成符合這條路由的網址了:
<?php
// returns /posts/2012/phalcon-1-0-released
echo $url->get(array(
"for" => "show-posts", //路由名稱
"year" => "2012", //參數year的值
"title" => "phalcon-1-0-released" //參數title的值
));
### 指定URI來源 ###
<?php
use Phalcon\Mvc\Router;
...
$router->setUriSource(Router::URI_SOURCE_GET_URL); // use $_GET['_url'] (default)
$router->setUriSource(Router::URI_SOURCE_SERVER_REQUEST_URI); // use $_SERVER['REQUEST_URI'] (default)
### 限制HTTP請求方式
當您使用路由的add方法時,意味著不限制HTTP請求方式。
有時我們可以限制一個路由使用一個特定的方式來訪問,這在創建RESTful應用程序時將非常有用:
// This route only will be matched if the HTTP method is GET
$router->addGet("/products/edit/{id}", "Products::edit");
// This route only will be matched if the HTTP method is POST
$router->addPost("/products/save", "Products::save");
// This route will be matched if the HTTP method is POST or PUT
$router->add("/products/update")->via(array("POST", "PUT"));
限制http請求方式:$router->addGet()、$router->addPut()、$router->addPost()……
### 設置默認
可以為通用路徑中的 module, controller, action 定義默認值。當一個路由缺少其中任何一項時,路由器可以自動用默認值填充:
<?php
//Setting a specific default
$router->setDefaultModule('backend');
$router->setDefaultNamespace('Backend\Controllers');
$router->setDefaultController('index');
$router->setDefaultAction('index');
//Using an array
$router->setDefaults(array(
'controller' => 'index',
'action' => 'index'
));
### 匿名路由
此組件提供了一個與注解服務集成的變體。使用此策略可以在控制器中直接寫路由。
<?php
use Phalcon\Mvc\Router\Annotations as RouterAnnotations;
$di['router'] = function() {
//Use the annotations router
$router = new RouterAnnotations(false);
//Read the annotations from ProductsController if the uri starts with /api/products
$router->addResource('Products', '/api/products');
return $router;
};
可以按如下方式定義注解:
<?php
/**
* @RoutePrefix("/api/products")
*/
class ProductsController
{
/**
* @Get("/")
*/
public function indexAction() {}
/**
* @Get("/edit/{id:[0-9]+}", name="edit-robot")
*/
public function editAction($id) {}
/**
* @Route("/save", methods={"POST", "PUT"}, name="save-robot")
*/
public function saveAction() {}
/**
* @Route("/delete/{id:[0-9]+}", methods="DELETE",
* conversors={id="MyConversors::checkId"})
*/
public function deleteAction($id) {}
public function infoAction($id) {}
}
支持的注解有:
<table border="1" class="docutils">
<colgroup>
<col width="8%">
<col width="55%">
<col width="38%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Name</th>
<th class="head">Description</th>
<th class="head">Usage</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>RoutePrefix</td>
<td>A prefix to be prepended to each route uri. This annotation must be placed at the class’ docblock</td>
<td>@RoutePrefix(“/api/products”)</td>
</tr>
<tr class="row-odd"><td>Route</td>
<td>This annotation marks a method as a route. This annotation must be placed in a method docblock</td>
<td>@Route(“/api/products/show”)</td>
</tr>
<tr class="row-even"><td>Get</td>
<td>This annotation marks a method as a route restricting the HTTP method to GET</td>
<td>@Get(“/api/products/search”)</td>
</tr>
<tr class="row-odd"><td>Post</td>
<td>This annotation marks a method as a route restricting the HTTP method to POST</td>
<td>@Post(“/api/products/save”)</td>
</tr>
<tr class="row-even"><td>Put</td>
<td>This annotation marks a method as a route restricting the HTTP method to PUT</td>
<td>@Put(“/api/products/save”)</td>
</tr>
<tr class="row-odd"><td>Delete</td>
<td>This annotation marks a method as a route restricting the HTTP method to DELETE</td>
<td>@Delete(“/api/products/delete/{id}”)</td>
</tr>
<tr class="row-even"><td>Options</td>
<td>This annotation marks a method as a route restricting the HTTP method to OPTIONS</td>
<td>@Option(“/api/products/info”)</td>
</tr>
</tbody>
</table>
用注解添加路由時,支持以下參數:
<table border="1" class="docutils">
<colgroup>
<col width="8%">
<col width="55%">
<col width="38%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Name</th>
<th class="head">Description</th>
<th class="head">Usage</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>methods</td>
<td>Define one or more HTTP method that route must meet with</td>
<td>@Route(“/api/products”, methods={“GET”, “POST”})</td>
</tr>
<tr class="row-odd"><td>name</td>
<td>Define a name for the route</td>
<td>@Route(“/api/products”, name=”get-products”)</td>
</tr>
<tr class="row-even"><td>paths</td>
<td>An array of paths like the one passed to Phalcon\Mvc\Router::add</td>
<td>@Route(“/posts/{id}/{slug}”, paths={module=”backend”})</td>
</tr>
<tr class="row-odd"><td>conversors</td>
<td>A hash of conversors to be applied to the parameters</td>
<td>@Route(“/posts/{id}/{slug}”, conversors={id=”MyConversor::getId”})</td>
</tr>
</tbody>
</table>
如果要將路由映射到模塊中的控制器,可以使用addModuleResource方法:
<?php
use Phalcon\Mvc\Router\Annotations as RouterAnnotations;
$di['router'] = function() {
//Use the annotations router
$router = new RouterAnnotations(false);
//Read the annotations from Backend\Controllers\ProductsController if the uri starts with /api/products
$router->addModuleResource('backend', 'Products', '/api/products');
return $router;
};
###路由執行事件
依次按以下順序執行:
dispatch:beforeDispatchLoop
開始循環匹配路由
dispatch:beforeDispatch
dispatch:beforeNotFoundAction
dispatch:beforeExecuteRoute
beforeExecuteRoute($dispatcher)
initialize() -> dispatch:afterInitialize
執行路由到的方法
dispatch:afterExecuteRoute
dispatch:afterDispatch
afterExecuteRoute($dispatcher)
結束循環匹配路由
dispatch:afterDispatchLoop
> 其中,以“dispatch:”開頭的均為eventManager中定義的事件名稱。“xxx(...)”這種格式的均為控制器中的方法。
## 控制器命名 ##
默認調用IndexController控制器中的indexAction方法。
控制器名稱需要加`Controller`后綴,動作名稱需要加`Action`后綴。
控制器的首字母要大寫且繼承自`Phalcon\Mvc\Controller`。
控制器的文件名稱與控制器全名完全相同并加擴展名“.php”。
## 視圖渲染 ##
`Phalcon\Mvc\View` 默認采用PHP本身作為模板引擎,此時應該以`.phtml`作為視圖文件擴展名。
可以在控制器方法中使用`$this->view->setVar("postId", $postId);`來傳遞變量到視圖,然后在視圖中用php來使用此變量,比如:`<?php echo $postId;?>`,setVar方法也可以通過接收關鍵字索引數組來一次傳遞多個值(類似于smarty中assign的批量賦值)。
`Phalcon\Mvc\View` 支持視圖分層。
### 分層渲染 ###
第一步、渲染模板:
`視圖文件目錄`/`小寫的控制器名(不含后綴)`/`方法名(不含后綴)`.phtml
并保存結果。級別代號`LEVEL_ACTION_VIEW`。
> 可在此模板中通過調用`<?php echo $this->getContent() ?>`輸出控制器中的輸出內容(比如在控制器中使用echo輸出一些內容)。
第二步、渲染模板(如果有):
`視圖文件目錄`/layouts/`小寫的控制器名(不含后綴)`.phtml
并保存結果。級別代號`LEVEL_LAYOUT`。
> 可在此模板中通過調用`<?php echo $this->getContent() ?>`輸出第一步的模板結果。
第三步、渲染模板(如果有):
`視圖文件目錄`/index.phtml
并保存結果。級別代號`LEVEL_MAIN_LAYOUT`。
> 同樣的,可在此模板中通過調用`<?php echo $this->getContent() ?>`輸出第二步的模板結果。
最后保存的結果就是視圖的最終結果。
可以在控制器方法中使用`$this->view->setTemplateAfter('common');`來在第三步之前插入一個渲染操作,比如這里渲染模板:`視圖文件目錄`/layouts/common.phtml
### 渲染級別控制 ###
可以在控制器方法中使用`$this->view->setRenderLevel(View::LEVEL_NO_RENDER);`來關閉渲染,或者僅僅渲染某個級別`$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);`
也可以使用`$this->view->disableLevel(View::LEVEL_MAIN_LAYOUT);`來禁止某個級別的渲染。
可以用`$this->view->pick('index/pick');`選擇視圖:
1. 如果pick方法接收到一個不包含“/”的字符串則僅僅設置`LEVEL_ACTION_VIEW`級視圖;如果包含“/”則同時還會把第一個“/”前面的部分作為`LEVEL_LAYOUT`級視圖,比如這里會使用“`視圖文件目錄`/layouts/index.phtml”文件
2. 如果接收到一個數字索引數組,則會將編號為0的元素作為`LEVEL_ACTION_VIEW`級視圖,將編號為1的元素作為`LEVEL_LAYOUT`級視圖
### 關閉視圖 ###
如果你的控制器不在視圖里產生(或沒有)任何輸出,你可以禁用視圖組件來避免不必要的處理:
$this->view->disable();
### 在模板中包含局部模板 ###
<?php $this->partial('shared/login');?>
或者同時傳遞變量給局部模板,每一個索引最終會作為變量在局部模板中被賦值:
<?php
$this->partial('shared/login',array(
'var1'=>'val1',
'var2'=>'val2'
));
?>
## 緩存視圖 ##
在控制器方法中的代碼例子:
//Check whether the cache with key "downloads" exists or has expired
if ($this->view->getCache()->exists('downloads')) {
//Query the latest downloads
$latest = Downloads::find(array(
'order' => 'created_at DESC'
));
$this->view->latest = $latest;
}
//Enable the cache with the same key "downloads"
$this->view->cache(array(
'service' => 'myCache',//使用自己的緩存服務,不設置時默認為viewCache
'lifetime' => 86400, //緩存時間
'key' => 'downloads' //緩存索引名
));
注冊緩存服務:
<?php
use Phalcon\Cache\Frontend\Output as OutputFrontend;
use Phalcon\Cache\Backend\Memcache as MemcacheBackend;
//Set the views cache service
$di->set('viewCache', function() {
//Cache data for one day by default
$frontCache = new OutputFrontend(array(
'lifetime' => 86400
));
//Memcached connection settings
$cache = new MemcacheBackend($frontCache, array(
'host' => 'localhost',
'port' => '11211'
));
return $cache;
});
其中“Phalcon\Cache\Frontend”中包含了對前臺數據的處理操作(比如數據格式編碼等);
“Phalcon\Cache\Backend”中包含了對各種后臺緩存引擎的操作。
## 使用模板引擎
- 在控制器方法中指定模板引擎:
// Using more than one template engine
$this->view->registerEngines(
array(
'.my-html' => 'MyTemplateAdapter',
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
)
);
方法`Phalcon\Mvc\View::registerEngines()`接受一個包含定義模板引擎數據的數組。每個引擎的鍵名是一個區別于其他引擎的拓展名。模板文件和特定的引擎關聯必須有這些擴展名。
`Phalcon\Mvc\View::registerEngines()`會按照相關模板引擎定義的順序來執行。如果`Phalcon\Mvc\View`發現視圖文件具有相同名稱但擴展名不同,它只會使用第一個。
- 在注冊`view`服務時全局指定模板引擎:
<?php
use Phalcon\Mvc\View;
//Setting up the view component
$di->set('view', function() {
$view = new View();
//A trailing directory separator is required
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
'.my-html' ='MyTemplateAdapter' //元素值可以是類名、服務名或返回模板引擎對象的匿名函數
));
return $view;
}, true);
Volt 視圖最終會被編譯成純PHP代碼
### Volt模板引擎語法
#### 3種不同含義的起始標簽
1. ` {% ... %} `包裹的標簽用于賦值或執行for循環、if條件判斷等語句
2. ` {{ ... }} `包裹的標簽用于打印表達式的結果到模板
3. ` {# ... #} `包裹注釋,前后標簽可以處于不同行
#### 語法詳解
- `{{ post.title }}`相當于`$post->title`;
`{{ post.getTypes().name }}`相當于`$post->getTypes()->name`;
- `{{ post['title'] }}`相當于`$post['title']`;
- `{{ post.title|e }}`使用過濾器,豎線左邊表達式的值將會作為過濾器的第一個參數;
`{{ '%.2f'|format(post.price) }}`相當于執行`sprintf('%.2f', $post->price)`;
默認過濾器列表:
<table class="docutils" border="1">
<colgroup>
<col width="22%">
<col width="78%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Filter</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>e</td>
<td>Applies Phalcon\Escaper->escapeHtml to the value</td>
</tr>
<tr class="row-odd"><td>escape</td>
<td>Applies Phalcon\Escaper->escapeHtml to the value</td>
</tr>
<tr class="row-even"><td>escape_css</td>
<td>Applies Phalcon\Escaper->escapeCss to the value</td>
</tr>
<tr class="row-odd"><td>escape_js</td>
<td>Applies Phalcon\Escaper->escapeJs to the value</td>
</tr>
<tr class="row-even"><td>escape_attr</td>
<td>Applies Phalcon\Escaper->escapeHtmlAttr to the value</td>
</tr>
<tr class="row-odd"><td>trim</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.trim.php">trim</a> PHP function to the value. Removing extra spaces</td>
</tr>
<tr class="row-even"><td>left_trim</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.ltrim.php">ltrim</a> PHP function to the value. Removing extra spaces</td>
</tr>
<tr class="row-odd"><td>right_trim</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.rtrim.php">rtrim</a> PHP function to the value. Removing extra spaces</td>
</tr>
<tr class="row-even"><td>striptags</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.striptags.php">striptags</a> PHP function to the value. Removing HTML tags</td>
</tr>
<tr class="row-odd"><td>slashes</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.slashes.php">slashes</a> PHP function to the value. Escaping values</td>
</tr>
<tr class="row-even"><td>stripslashes</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.stripslashes.php">stripslashes</a> PHP function to the value. Removing escaped quotes</td>
</tr>
<tr class="row-odd"><td>capitalize</td>
<td>Capitalizes a string by applying the <a class="reference external" href="http://php.net/manual/en/function.ucwords.php">ucwords</a> PHP function to the value</td>
</tr>
<tr class="row-even"><td>lower</td>
<td>Change the case of a string to lowercase</td>
</tr>
<tr class="row-odd"><td>upper</td>
<td>Change the case of a string to uppercase</td>
</tr>
<tr class="row-even"><td>length</td>
<td>Counts the string length or how many items are in an array or object</td>
</tr>
<tr class="row-odd"><td>nl2br</td>
<td>Changes newlines \n by line breaks (<br />). Uses the PHP function <a class="reference external" href="http://php.net/manual/en/function.nl2br.php">nl2br</a></td>
</tr>
<tr class="row-even"><td>sort</td>
<td>Sorts an array using the PHP function <a class="reference external" href="http://php.net/manual/en/function.asort.php">asort</a></td>
</tr>
<tr class="row-odd"><td>keys</td>
<td>Returns the array keys using <a class="reference external" href="http://php.net/manual/en/function.array-keys.php">array_keys</a></td>
</tr>
<tr class="row-even"><td>join</td>
<td>Joins the array parts using a separator <a class="reference external" href="http://php.net/manual/en/function.join.php">join</a></td>
</tr>
<tr class="row-odd"><td>format</td>
<td>Formats a string using <a class="reference external" href="http://php.net/manual/en/function.sprintf.php">sprintf</a>.</td>
</tr>
<tr class="row-even"><td>json_encode</td>
<td>Converts a value into its <a class="reference external" href="http://php.net/manual/en/function.json-encode.php">JSON</a> representation</td>
</tr>
<tr class="row-odd"><td>json_decode</td>
<td>Converts a value from its <a class="reference external" href="http://php.net/manual/en/function.json-encode.php">JSON</a> representation to a PHP representation</td>
</tr>
<tr class="row-even"><td>abs</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.abs.php">abs</a> PHP function to a value.</td>
</tr>
<tr class="row-odd"><td>url_encode</td>
<td>Applies the <a class="reference external" href="http://php.net/manual/en/function.urlencode.php">urlencode</a> PHP function to the value</td>
</tr>
<tr class="row-even"><td>default</td>
<td>Sets a default value in case that the evaluated expression is empty
(is not set or evaluates to a falsy value)</td>
</tr>
<tr class="row-odd"><td>convert_encoding</td>
<td>Converts a string from one charset to another</td>
</tr>
</tbody>
</table>
- for循環用法
基礎用法:
{% for robot in robots %}
{{ robot.name|e }}
{% endfor %}
嵌套循環:
{% for robot in robots %}
{% for part in robot.parts %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }}
{% endfor %}
{% endfor %}
獲取索引值
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for name, value in numbers %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
用if進行篩選
{% for value in numbers if value < 2 %}
Value: {{ value }}
{% endfor %}
{% for name, value in numbers if name != 'two' %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
else、elsefor
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br/>
{% else %}{# else也可以寫成elsefor #}
There are no robots to show
{% endfor %}
可以在for結構中使用`{% break %}`和`{% continue %}`來跳出和執行下一次循環
- if條件判斷
基本用法
{% if robot.type == "cyborg" %}
{{ robot.name|e }}
{% endif %}
{% if robot.type == "cyborg" %}
{{ robot.name|e }}
{% else %}
{{ robot.name|e }} (not a cyborg)
{% endif %}
{% if robot.type == "cyborg" %}
Robot is a cyborg
{% elseif robot.type == "virtual" %}
Robot is virtual
{% elseif robot.type == "mechanical" %}
Robot is mechanical
{% endif %}
if中可以使用的內置變量:
<table class="docutils" border="1">
<colgroup>
<col width="22%">
<col width="78%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Variable</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>loop.index</td>
<td>The current iteration of the loop. (1 indexed)</td>
</tr>
<tr class="row-odd"><td>loop.index0</td>
<td>The current iteration of the loop. (0 indexed)</td>
</tr>
<tr class="row-even"><td>loop.revindex</td>
<td>The number of iterations from the end of the loop (1 indexed)</td>
</tr>
<tr class="row-odd"><td>loop.revindex0</td>
<td>The number of iterations from the end of the loop (0 indexed)</td>
</tr>
<tr class="row-even"><td>loop.first</td>
<td>True if in the first iteration.</td>
</tr>
<tr class="row-odd"><td>loop.last</td>
<td>True if in the last iteration.</td>
</tr>
<tr class="row-even"><td>loop.length</td>
<td>The number of items to iterate</td>
</tr>
</tbody>
</table>
- 賦值
- 單個變量賦值:
{% set fruits = ['Apple', 'Banana', 'Orange'] %}
{% set name = robot.name %}
- 多個變量賦值:
{% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %}
- 支持的字面值:
<table border="1" class="docutils">
<colgroup>
<col width="22%">
<col width="78%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">字面值</th>
<th class="head">說明</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>“this is a string”</td>
<td>被單引號或雙引號括起來的內容作為字符串</td>
</tr>
<tr class="row-odd"><td>100.25</td>
<td>帶小數部分的數字作為(double/float)</td>
</tr>
<tr class="row-even"><td>100</td>
<td>不帶小數的數字作為整數(integer)</td>
</tr>
<tr class="row-odd"><td>false</td>
<td>靜態內容“false”作為布爾值中false</td>
</tr>
<tr class="row-even"><td>true</td>
<td>Constant “true” is the boolean true value</td>
</tr>
<tr class="row-odd"><td>null</td>
<td>Constant “null” is the Null value</td>
</tr>
</tbody>
</table>
數組可以用中括號或花括號定義
{# Other simple array #}
{{ ['Apple', 1, 2.5, false, null] }}
{# Multi-Dimensional array #}
{{ [[1, 2], [3, 4], [5, 6]] }}
{# Hash-style array #}
{{ ['first': 1, 'second': 4/2, 'third': '3'] }}
{% set myArray = {'Apple', 'Banana', 'Orange'} %}
{% set myHash = {'first': 1, 'second': 4/2, 'third': '3'} %}
算術運算符和比較符與PHP語法中的一致,邏輯運算符為:`or`,`and`,`not`
- if中的is測試操作
內置支持的測試:
<table border="1" class="docutils">
<colgroup>
<col width="19%">
<col width="81%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Test</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>defined</td>
<td>Checks if a variable is defined (isset)</td>
</tr>
<tr class="row-odd"><td>empty</td>
<td>Checks if a variable is empty</td>
</tr>
<tr class="row-even"><td>even</td>
<td>Checks if a numeric value is even</td>
</tr>
<tr class="row-odd"><td>odd</td>
<td>Checks if a numeric value is odd</td>
</tr>
<tr class="row-even"><td>numeric</td>
<td>Checks if value is numeric</td>
</tr>
<tr class="row-odd"><td>scalar</td>
<td>Checks if value is scalar (not an array or object)</td>
</tr>
<tr class="row-even"><td>iterable</td>
<td>Checks if a value is iterable. Can be traversed by a “for” statement</td>
</tr>
<tr class="row-odd"><td>divisibleby</td>
<td>Checks if a value is divisible by other value</td>
</tr>
<tr class="row-even"><td>sameas</td>
<td>Checks if a value is identical to other value</td>
</tr>
<tr class="row-odd"><td>type</td>
<td>Checks if a value is of the specified type</td>
</tr>
</tbody>
</table>
- 宏定義:https://docs.phalconphp.com/zh/latest/reference/volt.html#macros
{%- macro my_input(name, class="input-text") %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name') ~ '</p>' }}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
由以上代碼可見,模板中字符串間連接符為`~`!
- 使用標簽助手:https://docs.phalconphp.com/zh/latest/reference/volt.html#using-tag-helpers
<table border="1" class="docutils">
<colgroup>
<col width="61%">
<col width="39%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Method</th>
<th class="head">Volt function</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Phalcon\Tag::linkTo</td>
<td>link_to</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::textField</td>
<td>text_field</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::passwordField</td>
<td>password_field</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::hiddenField</td>
<td>hidden_field</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::fileField</td>
<td>file_field</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::checkField</td>
<td>check_field</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::radioField</td>
<td>radio_field</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::dateField</td>
<td>date_field</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::emailField</td>
<td>email_field</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::numberField</td>
<td>number_field</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::submitButton</td>
<td>submit_button</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::selectStatic</td>
<td>select_static</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::select</td>
<td>select</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::textArea</td>
<td>text_area</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::form</td>
<td>form</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::endForm</td>
<td>end_form</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::getTitle</td>
<td>get_title</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::stylesheetLink</td>
<td>stylesheet_link</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::javascriptInclude</td>
<td>javascript_include</td>
</tr>
<tr class="row-odd"><td>Phalcon\Tag::image</td>
<td>image</td>
</tr>
<tr class="row-even"><td>Phalcon\Tag::friendlyTitle</td>
<td>friendly_title</td>
</tr>
</tbody>
</table>
- 函數
<table border="1" class="docutils">
<colgroup>
<col width="22%">
<col width="78%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Name</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>content</td>
<td>Includes the content produced in a previous rendering stage</td>
</tr>
<tr class="row-odd"><td>get_content</td>
<td>Same as ‘content’</td>
</tr>
<tr class="row-even"><td>partial</td>
<td>Dynamically loads a partial view in the current template</td>
</tr>
<tr class="row-odd"><td>super</td>
<td>Render the contents of the parent block</td>
</tr>
<tr class="row-even"><td>time</td>
<td>Calls the PHP function with the same name</td>
</tr>
<tr class="row-odd"><td>date</td>
<td>Calls the PHP function with the same name</td>
</tr>
<tr class="row-even"><td>dump</td>
<td>Calls the PHP function ‘var_dump’</td>
</tr>
<tr class="row-odd"><td>version</td>
<td>Returns the current version of the framework</td>
</tr>
<tr class="row-even"><td>constant</td>
<td>Reads a PHP constant</td>
</tr>
<tr class="row-odd"><td>url</td>
<td>Generate a URL using the ‘url’ service</td>
</tr>
</tbody>
</table>
- 模板的繼承
- 父模板(templates/base.volt)
`{% block title %}默認標題{% endblock %}`
- 子模板
{% extends "templates/base.volt" %}
{% block title %}重新定義的標題{% endblock %}
父模板中塊(block)內的內容會被子模板中的同名塊中的內容替換,除非在子模板中不存在該塊的定義。
如果想要保留或引用父模板中某block的內容,可以在子模板的同名塊中使用`{{ super() }}`
- 新增模板函數
<?php
use Phalcon\Mvc\View\Engine\Volt;
$volt = new Volt($view, $di);
$compiler = $volt->getCompiler();
//This binds the function name 'shuffle' in Volt to the PHP function 'str_shuffle'
$compiler->addFunction('shuffle', 'str_shuffle');//第二個參數可以是函數名或匿名函數
- 新增過濾器
//This creates a filter 'hash' that uses the PHP function 'md5'
$compiler->addFilter('hash', 'md5');//第二個參數可以是函數名或匿名函數
- 編寫擴展:https://docs.phalconphp.com/zh/latest/reference/volt.html#extensions
- 緩存視圖片段
{% cache ("article-" ~ post.id) 3600 %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endcache %}
- 可以在模板中直接通過服務名訪問通過DI注冊的服務。
在php模板中使用“$this->`服務名`”來訪問。
## 設計表單
[https://docs.phalconphp.com/zh/latest/reference/tags.html](https://docs.phalconphp.com/zh/latest/reference/tags.html)
## 模型
[https://docs.phalconphp.com/zh/latest/reference/models.html](https://docs.phalconphp.com/zh/latest/reference/models.html)
模型類的名稱使用表名稱且首字母大寫(如果表名稱含下劃線“_”,需要刪除下劃線并將原下劃線位置后的一個字符大寫),繼承于`Phalcon\Mvc\Model`。
例如,我們有數據表`member_account`,那么我們需要創建一個模型類`MemberAccount`。
模型類的文件名稱與模型類名稱一致。
### 數據庫操作方法
#### 查找: find() findFirst()
$robots = Robots::find(array(
"type = 'virtual'",
"order" => "name",
"limit" => 100
));
foreach ($robots as $robot) {
echo $robot->name, "\n";
}
$robots = Robots::find(array(
"conditions" => "type = ?1",
"bind" => array(1 => "virtual") //綁定參數(數字占位符)
));
$robot = Robots::findFirst(array("type = 'virtual'", "order" => "name"));
echo "The first virtual robot name is ", $robot->name, "\n";
可用的查詢選項如下:
<table border="1" class="docutils">
<colgroup>
<col width="5%">
<col width="70%">
<col width="26%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">參數</th>
<th class="head">描述</th>
<th class="head">舉例</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>conditions</td>
<td>查詢操作的搜索條件。用于提取只有那些滿足指定條件的記錄。默認情況下 Phalcon\Mvc\Model 假定第一個參數就是查詢條件。</td>
<td>"conditions" => "name LIKE 'steve%'"</td>
</tr>
<tr class="row-odd"><td>columns</td>
<td>只返回指定的字段,而不是模型所有的字段。 當用這個選項時,返回的是一個不完整的對象。</td>
<td>"columns" => "id, name"</td>
</tr>
<tr class="row-even"><td>bind</td>
<td>綁定與選項一起使用,通過替換占位符以及轉義字段值從而增加安全性。</td>
<td>"bind" => array("status" => "A", "type" => "some-time")</td>
</tr>
<tr class="row-odd"><td>bindTypes</td>
<td>當綁定參數時,可以使用這個參數為綁定參數定義額外的類型限制從而更加增強安全性。</td>
<td>"bindTypes" => array(Column::BIND_TYPE_STR, Column::BIND_TYPE_INT)</td>
</tr>
<tr class="row-even"><td>order</td>
<td>用于結果排序。使用一個或者多個字段,逗號分隔。</td>
<td>"order" => "name DESC, status"</td>
</tr>
<tr class="row-odd"><td>limit</td>
<td>限制查詢結果的數量在一定范圍內。</td>
<td>"limit" => 10 / "limit" => array("number" => 10, "offset" => 5)</td>
</tr>
<tr class="row-even"><td>group</td>
<td>從多條記錄中獲取數據并且根據一個或多個字段對結果進行分組。</td>
<td>"group" => "name, status"</td>
</tr>
<tr class="row-odd"><td>for_update</td>
<td>通過這個選項, <a href="../api/Phalcon_Mvc_Model.html" class="reference internal"><em>Phalcon\Mvc\Model</em></a> 讀取最新的可用數據,并且為讀到的每條記錄設置獨占鎖。</td>
<td>"for_update" => true</td>
</tr>
<tr class="row-even"><td>shared_lock</td>
<td>通過這個選項, <a href="../api/Phalcon_Mvc_Model.html" class="reference internal"><em>Phalcon\Mvc\Model</em></a> 讀取最新的可用數據,并且為讀到的每條記錄設置共享鎖。</td>
<td>"shared_lock" => true</td>
</tr>
<tr class="row-odd"><td>cache</td>
<td>緩存結果集,減少了連續訪問數據庫。</td>
<td>"cache" => array("lifetime" => 3600, "key" => "my-find-key")</td>
</tr>
<tr class="row-even"><td>hydration</td>
<td>Sets the hydration strategy to represent each returned record in the result</td>
<td>"hydration" => Resultset::HYDRATE_OBJECTS</td>
</tr>
</tbody>
</table>
如果你愿意,除了使用數組作為查詢參數外,還可以通過一種面向對象的方式來創建查詢(更多可用類方法詳見源碼phalcon/mvc/model/criteria.zep):
<?php
$robots = Robots::query()
->where("type = :type:")
->andWhere("year < 2000")
->bind(array("type" => "mechanical")) //綁定參數(字符串占位符)
->order("name")
->execute();
最后,還有一個 findFirstBy<property-name>() 方法。這個方法擴展了前面提及的 “findFirst()” 方法。它允許您利用方法名中的屬性名稱,通過將要搜索的該字段的內容作為參數傳給它,來快速從一個表執行檢索操作。
<property-name>的內容為首字母大寫的數據表字段名(如果字段名稱含下劃線“_”,需要刪除下劃線并將原下劃線位置后的一個字符大寫)。
例如,數據表字段名為`user_name`,可以采用`findFirstByUserName('admpub')`方法查詢。
#### 添加: create() 或 save()
//Creating a new robot
$robot = new Robots();
$robot->type = 'mechanical';
$robot->name = 'Astro Boy';
$robot->year = 1952;
$robot->create();
//Passing an array to create
$robot = new Robots();
$robot->create(array(
'type' => 'mechanical',
'name' => 'Astroy Boy',
'year' => 1952
));
#### 更新: update() 或 save()
//Updating a robot name
$robot = Robots::findFirst("id=100");
$robot->name = "Biomass";
$robot->update();
//Passing an array to update
$robot->create(array(
'name' => 'Biomass'
),array('name'));//第二個參數用于指定允許設置的字段的名稱,不指定的話則表示允許數據表內全部字段名稱的鍵。
> 如果傳入的數組的鍵與數據表字段名不一致,可以使用`$robot->assign(<數組>, <鍵值分別為數組鍵名與數據表字段名組成的數組>, <允許的字段>)`來賦值。例如:
>
> $robot = new Robots();
> $robot->assign(
> array(
> 'name' ='Biomass'
> ),
> array('name'=>'user_name'),
> array('user_name')
> );
> $robot->create();
>
#### 刪除: delete()
$robot = Robots::findFirst("id=100");
$robot->delete();
foreach (Robots::find("type = 'mechanical'") as $robot) {
$robot->delete();
}
#### 運算:
- count()
//How many robots are there?
$number = Robots::count();
echo "There are ", $number, "\n";
//How many mechanical robots are there?
$number = Robots::count("type='mechanical'");
echo "There are ", $number, " mechanical robots\n"
- sum()
//How much are all robots?
$sum = Robots::sum(array('column' => 'price'));
echo "The total price of robots is ", $sum, "\n";
//How much are mechanical robots?
$sum = Robots::sum(array("type='mechanical'", 'column' => 'price'));
echo "The total price of mechanical robots is ", $sum, "\n";
- average()
用法與sum類似
- maximum()
用法與sum類似
- minimum()
用法與sum類似
#### 保存: save()
$robot = new Robots();
$robot->type = 'mechanical';
$robot->name = 'Astro Boy';
$robot->year = 1952;
if ($robot->save() == false) {
echo "Umh, We can't store robots right now ";
foreach ($robot->getMessages() as $message) {
echo $message;
}
} else {
echo "Great, a new robot was saved successfully!";
}
$robot = new Robots();
$robot->save(array('type'=>'mechanical'),array('type'));//參數分別為array data,array whiteList
### 指定數據返回類型
`$findResult->setHydrateMode(Resultset::HYDRATE_ARRAYS);`
可選的值有:`Resultset::HYDRATE_ARRAYS`、`Resultset::HYDRATE_OBJECTS`、`Resultset::HYDRATE_RECORDS`。
也可以這樣指定:
$robots = Robots::find(array(
'hydration' => Resultset::HYDRATE_ARRAYS
));
### 綁定參數
#### 占位符
- 數字占位符在sql中的格式為“**?`數字`**”;
- 字符串占位符在sql中的格式為“**:`字符串`:**”。
#### 參數類型
默認的參數類型為`\Phalcon\Db\Column::BIND_PARAM_STR`。
支持的參數類型:
- `Column::BIND_PARAM_NULL` 綁定null類型
- `Column::BIND_PARAM_INT` 綁定整數類型
- `Column::BIND_PARAM_STR` 綁定字符串類型
- `Column::BIND_PARAM_BOOL` 綁定bool值類型
- `Column::BIND_PARAM_DECIMAL` 綁定小數類型
$robots = Robots::find(array(
"conditions" => "name = :name: AND type = ?1",
"bind" => array('name'=>'admpub',1 => 'virtual'),
"bindTypes" => array(Column::BIND_TYPE_STR, Column::BIND_TYPE_STR)
));
### 模型關聯
有四種關聯類型:1對1,1對多,多對1,多對多。關聯可以是單向或者雙向的,每個關聯可以是簡單的(一個1對1的模型)也可以是復雜的(1組模型)。
在Phalcon中,關聯必須定義在某個模型的initialize()方法。通過方法belongsTo(),hasOne(),hasMany()和hasManyToMany()來定義當前模型中字段到另一個模型中字段之間的關聯。上述每種方法都需要三個參數:本地字段,引用的模型,引用的字段。
方法的具體含義:
<table border="1" class="docutils">
<colgroup>
<col width="35%">
<col width="65%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Method</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>hasMany</td>
<td>Defines a 1-n relationship</td>
</tr>
<tr class="row-odd"><td>hasOne</td>
<td>Defines a 1-1 relationship</td>
</tr>
<tr class="row-even"><td>belongsTo</td>
<td>Defines a n-1 relationship</td>
</tr>
<tr class="row-odd"><td>hasManyToMany</td>
<td>Defines a n-n relationship</td>
</tr>
</tbody>
</table>
多對多必須關聯3個模型,并分別設置它們的關聯字段
<?php
use Phalcon\Mvc\Model;
class Robots extends Model
{
public $id;
public $name;
public function initialize()
{
$this->hasManyToMany(
"id", //當前模型中的字段
"RobotsParts", //關聯到的中間表模型
"robots_id", "parts_id", //分別為當前模型id與中間表相關聯的字段和中間表與第三張表關聯的字段,這兩個字段都在中間表內
"Parts", //第三張表模型名
"id" //第三張表中與中間表關聯的字段
);
}
}
對于使用名稱空間的情況下,可以設置別名,或在model類中使用以下方法,但是對于多對多的情況,對于第三張表由于無法設置別名,只能使用以下方法:
$this->getRelated('Robots\Parts');
### 驗證信息
`Phalcon\Mvc\Model`可以生成如下驗證類型信息:
<table border="1" class="docutils">
<colgroup>
<col width="14%">
<col width="86%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Type</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>PresenceOf</td>
<td>Generated when a field with a non-null attribute on the database is trying to insert/update a null value</td>
</tr>
<tr class="row-odd"><td>ConstraintViolation</td>
<td>Generated when a field part of a virtual foreign key is trying to insert/update a value that doesn’t exist in the referenced model</td>
</tr>
<tr class="row-even"><td>InvalidValue</td>
<td>Generated when a validator failed because of an invalid value</td>
</tr>
<tr class="row-odd"><td>InvalidCreateAttempt</td>
<td>Produced when a record is attempted to be created but it already exists</td>
</tr>
<tr class="row-even"><td>InvalidUpdateAttempt</td>
<td>Produced when a record is attempted to be updated but it doesn’t exist</td>
</tr>
</tbody>
</table>
###事件
`Phalcon\Mvc\Model`會根據各個操作依序各自執行如下事件:
<table border="1" class="docutils">
<colgroup>
<col width="10%">
<col width="13%">
<col width="12%">
<col width="66%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">操作</th>
<th class="head">事件名</th>
<th class="head">是否能終止執行?</th>
<th class="head">說明</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Inserting/Updating</td>
<td>beforeValidation</td>
<td>YES</td>
<td>Is executed before the fields are validated for not nulls/empty strings or foreign keys</td>
</tr>
<tr class="row-odd"><td>Inserting</td>
<td>beforeValidationOnCreate</td>
<td>YES</td>
<td>Is executed before the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made</td>
</tr>
<tr class="row-even"><td>Updating</td>
<td>beforeValidationOnUpdate</td>
<td>YES</td>
<td>Is executed before the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made</td>
</tr>
<tr class="row-odd"><td>Inserting/Updating</td>
<td>onValidationFails</td>
<td>YES (already stopped)</td>
<td>Is executed after an integrity validator fails</td>
</tr>
<tr class="row-even"><td>Inserting</td>
<td>afterValidationOnCreate</td>
<td>YES</td>
<td>Is executed after the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made</td>
</tr>
<tr class="row-odd"><td>Updating</td>
<td>afterValidationOnUpdate</td>
<td>YES</td>
<td>Is executed after the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made</td>
</tr>
<tr class="row-even"><td>Inserting/Updating</td>
<td>afterValidation</td>
<td>YES</td>
<td>Is executed after the fields are validated for not nulls/empty strings or foreign keys</td>
</tr>
<tr class="row-odd"><td>Inserting/Updating</td>
<td>beforeSave</td>
<td>YES</td>
<td>Runs before the required operation over the database system</td>
</tr>
<tr class="row-even"><td>Updating</td>
<td>beforeUpdate</td>
<td>YES</td>
<td>Runs before the required operation over the database system only when an updating operation is being made</td>
</tr>
<tr class="row-odd"><td>Inserting</td>
<td>beforeCreate</td>
<td>YES</td>
<td>Runs before the required operation over the database system only when an inserting operation is being made</td>
</tr>
<tr class="row-even"><td>Updating</td>
<td>afterUpdate</td>
<td>NO</td>
<td>Runs after the required operation over the database system only when an updating operation is being made</td>
</tr>
<tr class="row-odd"><td>Inserting</td>
<td>afterCreate</td>
<td>NO</td>
<td>Runs after the required operation over the database system only when an inserting operation is being made</td>
</tr>
<tr class="row-even"><td>Inserting/Updating</td>
<td>afterSave</td>
<td>NO</td>
<td>Runs after the required operation over the database system</td>
</tr>
</tbody>
</table>
### 驗證數據
<?php
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Validator\Uniqueness;
use Phalcon\Mvc\Model\Validator\InclusionIn;
class Robots extends \Phalcon\Mvc\Model
{
public function validation()
{
$this->validate(new InclusionIn(
array(
"field" => "type",
"domain" => array("Mechanical", "Virtual")
)
));
$this->validate(new Uniqueness(
array(
"field" => "name",
"message" => "The robot name must be unique"
)
));
return $this->validationHasFailed() != true;
}
}
`Phalcon\Mvc\Model\Validator`包含以下驗證:
Email
Exclusionin
Inclusionin
Numericality
PresenceOf
Regex
StringLength
Uniqueness
Url
### 字段注解策略
<?php
use Phalcon\Mvc\Model;
class Robots extends Model
{
/**
* @Primary
* @Identity
* @Column(type="integer", nullable=false)
*/
public $id;
/**
* @Column(type="string", length=70, nullable=false)
*/
public $name;
/**
* @Column(type="string", length=32, nullable=false)
*/
public $type;
/**
* @Column(type="integer", nullable=false)
*/
public $year;
}
支持如下注解:
<table border="1" class="docutils">
<colgroup>
<col width="15%">
<col width="85%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Name</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Primary</td>
<td>Mark the field as part of the table’s primary key</td>
</tr>
<tr class="row-odd"><td>Identity</td>
<td>The field is an auto_increment/serial column</td>
</tr>
<tr class="row-even"><td>Column</td>
<td>This marks an attribute as a mapped column</td>
</tr>
</tbody>
</table>
注解@Column支持如下參數:
<table border="1" class="docutils">
<colgroup>
<col width="15%">
<col width="85%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Name</th>
<th class="head">Description</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>type</td>
<td>The column’s type (string, integer, decimal, boolean)</td>
</tr>
<tr class="row-odd"><td>length</td>
<td>The column’s length if any</td>
</tr>
<tr class="row-even"><td>nullable</td>
<td>Set whether the column accepts null values or not</td>
</tr>
</tbody>
</table>
## PHQL
在執行操作之前必須要有相應的model文件存在。
### 創建 PHQL 查詢
- 方式一、直接通過創建`Phalcon\Mvc\Model\Query`類的實例來查詢:
<?php
use Phalcon\Mvc\Model\Query;
// Instantiate the Query
$query = new Query("SELECT * FROM Cars", $this->getDI());
// Execute the query returning a result if any
$cars = $query->execute();
- 方式二、在控制器或視圖中,通過modelsManager(模型管理器)來查詢:
<?php
//Executing a simple query
$query = $this->modelsManager->createQuery("SELECT * FROM Cars");
$cars = $query->execute();
//With bound parameters
$query = $this->modelsManager->createQuery("SELECT * FROM Cars WHERE name = :name:");
$cars = $query->execute(array('name' => 'Audi'));
也可以簡化的寫為:
//Executing a simple query
$cars = $this->modelsManager->executeQuery("SELECT * FROM Cars");
//Executing with bound parameters
$cars = $this->modelsManager->executeQuery("SELECT * FROM Cars WHERE name = :name:", array('name' => 'Audi'));
注意:FROM后面的那個不是表名稱而是模型類名稱,這與真正的SQL語句是不同的。由于是模型類名稱,所以也可以帶名稱空間。
- executeQuery($phql)與Cars::find()的查詢結果是一樣的;
- executeQuery($phql)->getFirst()與Cars::findFirst()結果一樣。
### 插入數據:
// Inserting using placeholders
$phql = "INSERT INTO Cars (name, brand_id, year, style) "
. "VALUES (:name:, :brand_id:, :year:, :style:)";
$status=$manager->executeQuery($sql,
array(
'name' => 'Lamborghini Espada',
'brand_id' => 7,
'year' => 1969,
'style' => 'Grand Tourer',
)
);
//Create a response
#$response = new Response();
//Check if the insertion was successful
if ($status->success() == true) {
//Change the HTTP status
#$response->setStatusCode(201, "Created");
#$robot->id = $status->getModel()->id;
#$response->setJsonContent(array('status' => 'OK', 'data' => $robot));
} else {
//Change the HTTP status
#$response->setStatusCode(409, "Conflict");
//Send errors to the client
$errors = array();
foreach ($status->getMessages() as $message) {
$errors[] = $message->getMessage();
}
#$response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));
}
更新、刪除數據與插入數據類似。
### 使用查詢構建器創建查詢
//Getting a whole set
$robots = $this->modelsManager->createBuilder()
->from('Robots')
->join('RobotsParts')
->orderBy('Robots.name')
->getQuery()
->execute();
//Getting the first row
$robots = $this->modelsManager->createBuilder()
->from('Robots')
->join('RobotsParts')
->orderBy('Robots.name')
->getQuery()
->getSingleResult();
### 綁定參數
//Passing parameters in the query construction
$robots = $this->modelsManager->createBuilder()
->from('Robots')
->where('name = :name:', array('name' => $name))
->andWhere('type = :type:', array('type' => $type))
->getQuery()
->execute();
//Passing parameters in query execution
$robots = $this->modelsManager->createBuilder()
->from('Robots')
->where('name = :name:')
->andWhere('type = :type:')
->getQuery()
->execute(array('name' => $name, 'type' => $type));
### 轉義保留字
將保留字用中括號括起來。例如:
$phql = "SELECT * FROM [Update]";
$result = $manager->executeQuery($phql);
$phql = "SELECT id, [Like] FROM Posts";
$result = $manager->executeQuery($phql);
## 其它
### URL重定向
重定向用來在當前的處理中跳轉到其它的處理流:
<?php
// 此路由重定向到其它的路由
$app->post('/old/welcome', function () use ($app) {
$app->response->redirect("new/welcome")->sendHeaders();
});
$app->post('/new/welcome', function () use ($app) {
echo 'This is the new Welcome';
});
有以下跳轉方式:
//設置一個內部跳轉
$this->response->redirect( 'posts/index' );
// 外部跳轉url
$this->response->redirect( 'http://www.admpub.com/blog', true );
// 設置跳轉 http狀態
$this->resopnse->redirect( 'http://www.admpub.com/blog' , true , 301 );
重定向不會禁用視圖組件。因此,如果你想從一個controller/action重定向到另一個controller/acton上,視圖將正常顯示。當然,你也可以使用 $this->view->disable() 禁用視圖輸出。
### 存儲/獲取 Session數據
$this->session->set("session_name", "session_value");
$this->session->has("session-name");
$this->session->get("session-name");
$this->session->remove("session-name");
$this->session->destroy();
### From 表單接收
//獲取$_POST['name'],第二個參數是過濾器,還可以傳遞第三個參數作為默認值,第四個參數為是否允許為空。
//如果第一個參數為null或不傳遞任何參數的話,返回$_POST,以下getXXX()方法類似。
$name= $this->request->getPost("name", "string");
//獲取$_GET['email']
$email=$this->request->getQuery("email", "email");
//獲取$_REQUEST['email']
$email=$this->request->get("email", "email");
還有 $this->request->getPut、$this->request->getServer等等。
要判斷某個鍵的元素是否存在只需要將這里的get換成has即可。
比如:hasQuery('email')、has('email')、hasPost('email')、hasPut('email')、hasServer('HTTP_REFERER')。
支持的過濾器有:
- email
- absint
- int
- int!
使用intval函數處理
- string
- float
- float!
使用doubleval函數處理
- alphanum
- trim
- striptags
- lower
- upper
request的更多方法請參考phalcon源代碼:`phalcon/http/request.zep`
從容器中獲取的服務的最簡單方式就是只用get方法,它將從容器中返回一個新的實例:
<?php $request = $di->get('request'); ?>
或者通過下面這種魔術方法的形式調用:
<?php $request = $di->getRequest(); ?>
### 處理Not-Found
當用戶訪問未定義的路由時, 微應用會試著執行 "Not-Found"處理器。
<?php
$app->notFound(function () use ($app) {
$app->response->setStatusCode(404, "Not Found")->sendHeaders();
echo 'This is crazy, but this page was not found!';
});
### 微應用
[https://docs.phalconphp.com/zh/latest/reference/micro.html](https://docs.phalconphp.com/zh/latest/reference/micro.html)
支持如下的中間件事件:
<table border="1" class="docutils">
<colgroup>
<col width="22%">
<col width="55%">
<col width="23%">
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">事件名</th>
<th class="head">觸發</th>
<th class="head">是否可中止操作?</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>before</td>
<td>應用請求處理之前執行,常用來控制應用的訪問權限</td>
<td>Yes</td>
</tr>
<tr class="row-odd"><td>after</td>
<td>請求處理后執行,可以用來準備回復內容</td>
<td>No</td>
</tr>
<tr class="row-even"><td>finish</td>
<td>發送回復內容后執行, 可以用來執行清理工作</td>
<td>No</td>
</tr>
</tbody>
</table>
### REST API
[https://docs.phalconphp.com/zh/latest/reference/tutorial-rest.html](https://docs.phalconphp.com/zh/latest/reference/tutorial-rest.html)
#End