phalcon(費爾康)框架學習筆記


phalcon(費爾康)框架學習筆記

http://www.qixing318.com/article/phalcon-framework-to-study-notes.html

 

目錄結構
 

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) ) );

支持的占位符有:

占位符 正則表達式 Usage
/:module /([a-zA-Z0-9_-]+) Matches a valid module name with alpha-numeric characters only
/:controller /([a-zA-Z0-9_-]+) Matches a valid controller name with alpha-numeric characters only
/:action /([a-zA-Z0-9_]+) Matches a valid action name with alpha-numeric characters only
/:params (/.*)* Matches a list of optional words separated by slashes. Use only this placeholder at the end of a route
/:namespace /([a-zA-Z0-9_-]+) Matches a single level namespace name
/:int /([0-9]+) Matches an integer parameter

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) {} }

支持的注解有:

Name Description Usage
RoutePrefix A prefix to be prepended to each route uri. This annotation must be placed at the class’ docblock @RoutePrefix(“/api/products”)
Route This annotation marks a method as a route. This annotation must be placed in a method docblock @Route(“/api/products/show”)
Get This annotation marks a method as a route restricting the HTTP method to GET @Get(“/api/products/search”)
Post This annotation marks a method as a route restricting the HTTP method to POST @Post(“/api/products/save”)
Put This annotation marks a method as a route restricting the HTTP method to PUT @Put(“/api/products/save”)
Delete This annotation marks a method as a route restricting the HTTP method to DELETE @Delete(“/api/products/delete/{id}”)
Options This annotation marks a method as a route restricting the HTTP method to OPTIONS @Option(“/api/products/info”)

用注解添加路由時,支持以下參數:

Name Description Usage
methods Define one or more HTTP method that route must meet with @Route(“/api/products”, methods={“GET”, “POST”})
name Define a name for the route @Route(“/api/products”, name=”get-products”)
paths An array of paths like the one passed to Phalcon\Mvc\Router::add @Route(“/posts/{id}/{slug}”, paths={module=”backend”})
conversors A hash of conversors to be applied to the parameters @Route(“/posts/{id}/{slug}”, conversors={id=”MyConversor::getId”})

如果要將路由映射到模塊中的控制器,可以使用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);

    默認過濾器列表:

    Filter Description
    e Applies Phalcon\Escaper->escapeHtml to the value
    escape Applies Phalcon\Escaper->escapeHtml to the value
    escape_css Applies Phalcon\Escaper->escapeCss to the value
    escape_js Applies Phalcon\Escaper->escapeJs to the value
    escape_attr Applies Phalcon\Escaper->escapeHtmlAttr to the value
    trim Applies the trim PHP function to the value. Removing extra spaces
    left_trim Applies the ltrim PHP function to the value. Removing extra spaces
    right_trim Applies the rtrim PHP function to the value. Removing extra spaces
    striptags Applies the striptags PHP function to the value. Removing HTML tags
    slashes Applies the slashes PHP function to the value. Escaping values
    stripslashes Applies the stripslashes PHP function to the value. Removing escaped quotes
    capitalize Capitalizes a string by applying the ucwords PHP function to the value
    lower Change the case of a string to lowercase
    upper Change the case of a string to uppercase
    length Counts the string length or how many items are in an array or object
    nl2br Changes newlines \n by line breaks (<br />). Uses the PHP function nl2br
    sort Sorts an array using the PHP function asort
    keys Returns the array keys using array_keys
    join Joins the array parts using a separator join
    format Formats a string using sprintf.
    json_encode Converts a value into its JSON representation
    json_decode Converts a value from its JSON representation to a PHP representation
    abs Applies the abs PHP function to a value.
    url_encode Applies the urlencode PHP function to the value
    default Sets a default value in case that the evaluated expression is empty (is not set or evaluates to a falsy value)
    convert_encoding Converts a string from one charset to another
  • 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中可以使用的內置變量:

Variable Description
loop.index The current iteration of the loop. (1 indexed)
loop.index0 The current iteration of the loop. (0 indexed)
loop.revindex The number of iterations from the end of the loop (1 indexed)
loop.revindex0 The number of iterations from the end of the loop (0 indexed)
loop.first True if in the first iteration.
loop.last True if in the last iteration.
loop.length The number of items to iterate
  • 賦值

    • 單個變量賦值:

      {% set fruits = ['Apple', 'Banana', 'Orange'] %} {% set name = robot.name %}
    • 多個變量賦值:

      {% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %}
    • 支持的字面值:

      字面值 說明
      “this is a string” 被單引號或雙引號括起來的內容作為字符串
      100.25 帶小數部分的數字作為(double/float)
      100 不帶小數的數字作為整數(integer)
      false 靜態內容“false”作為布爾值中false
      true Constant “true” is the boolean true value
      null Constant “null” is the Null value

    數組可以用中括號或花括號定義

    {# 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測試操作
    內置支持的測試:

    Test Description
    defined Checks if a variable is defined (isset)
    empty Checks if a variable is empty
    even Checks if a numeric value is even
    odd Checks if a numeric value is odd
    numeric Checks if value is numeric
    scalar Checks if value is scalar (not an array or object)
    iterable Checks if a value is iterable. Can be traversed by a “for” statement
    divisibleby Checks if a value is divisible by other value
    sameas Checks if a value is identical to other value
    type Checks if a value is of the specified type
  • 宏定義: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

    Method Volt function
    Phalcon\Tag::linkTo link_to
    Phalcon\Tag::textField text_field
    Phalcon\Tag::passwordField password_field
    Phalcon\Tag::hiddenField hidden_field
    Phalcon\Tag::fileField file_field
    Phalcon\Tag::checkField check_field
    Phalcon\Tag::radioField radio_field
    Phalcon\Tag::dateField date_field
    Phalcon\Tag::emailField email_field
    Phalcon\Tag::numberField number_field
    Phalcon\Tag::submitButton submit_button
    Phalcon\Tag::selectStatic select_static
    Phalcon\Tag::select select
    Phalcon\Tag::textArea text_area
    Phalcon\Tag::form form
    Phalcon\Tag::endForm end_form
    Phalcon\Tag::getTitle get_title
    Phalcon\Tag::stylesheetLink stylesheet_link
    Phalcon\Tag::javascriptInclude javascript_include
    Phalcon\Tag::image image
    Phalcon\Tag::friendlyTitle friendly_title
  • 函數

    Name Description
    content Includes the content produced in a previous rendering stage
    get_content Same as ‘content’
    partial Dynamically loads a partial view in the current template
    super Render the contents of the parent block
    time Calls the PHP function with the same name
    date Calls the PHP function with the same name
    dump Calls the PHP function ‘var_dump’
    version Returns the current version of the framework
    constant Reads a PHP constant
    url Generate a URL using the ‘url’ service
  • 模板的繼承

    • 父模板(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/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";

可用的查詢選項如下:

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

如果你願意,除了使用數組作為查詢參數外,還可以通過一種面向對象的方式來創建查詢(更多可用類方法詳見源碼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()來定義當前模型中字段到另一個模型中字段之間的關聯。上述每種方法都需要三個參數:本地字段,引用的模型,引用的字段。

方法的具體含義:

Method Description
hasMany Defines a 1-n relationship
hasOne Defines a 1-1 relationship
belongsTo Defines a n-1 relationship
hasManyToMany Defines a n-n relationship

多對多必須關聯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可以生成如下驗證類型信息:

Type Description
PresenceOf Generated when a field with a non-null attribute on the database is trying to insert/update a null value
ConstraintViolation 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
InvalidValue Generated when a validator failed because of an invalid value
InvalidCreateAttempt Produced when a record is attempted to be created but it already exists
InvalidUpdateAttempt Produced when a record is attempted to be updated but it doesn’t exist

事件

Phalcon\Mvc\Model會根據各個操作依序各自執行如下事件:

操作 事件名 是否能終止執行? 說明
Inserting/Updating beforeValidation YES Is executed before the fields are validated for not nulls/empty strings or foreign keys
Inserting beforeValidationOnCreate YES Is executed before the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made
Updating beforeValidationOnUpdate YES Is executed before the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made
Inserting/Updating onValidationFails YES (already stopped) Is executed after an integrity validator fails
Inserting afterValidationOnCreate YES Is executed after the fields are validated for not nulls/empty strings or foreign keys when an insertion operation is being made
Updating afterValidationOnUpdate YES Is executed after the fields are validated for not nulls/empty strings or foreign keys when an updating operation is being made
Inserting/Updating afterValidation YES Is executed after the fields are validated for not nulls/empty strings or foreign keys
Inserting/Updating beforeSave YES Runs before the required operation over the database system
Updating beforeUpdate YES Runs before the required operation over the database system only when an updating operation is being made
Inserting beforeCreate YES Runs before the required operation over the database system only when an inserting operation is being made
Updating afterUpdate NO Runs after the required operation over the database system only when an updating operation is being made
Inserting afterCreate NO Runs after the required operation over the database system only when an inserting operation is being made
Inserting/Updating afterSave NO Runs after the required operation over the database system

驗證數據

<?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; }

支持如下注解:

Name Description
Primary Mark the field as part of the table’s primary key
Identity The field is an auto_increment/serial column
Column This marks an attribute as a mapped column

注解@Column支持如下參數:

Name Description
type The column’s type (string, integer, decimal, boolean)
length The column’s length if any
nullable Set whether the column accepts null values or not

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
支持如下的中間件事件:

事件名 觸發 是否可中止操作?
before 應用請求處理之前執行,常用來控制應用的訪問權限 Yes
after 請求處理后執行,可以用來准備回復內容 No
finish 發送回復內容后執行, 可以用來執行清理工作 No

REST API

https://docs.phalconphp.com/zh/latest/reference/tutorial-rest.html

使用 phalcon devtools

如果提醒無法找到類這樣的錯誤提示,需要在phalcon.php文件中添加以下代碼:

spl_autoload_register(function($className){ $classDir = __DIR__.'/scripts/'; $classFile = $classDir . str_replace('\\', '/', $className) . '.php'; if (file_exists($classFile)) require_once($classFile); });

把所有文件復制到現有phalcon項目下新建的“devtools”文件夾中,並將其中的webtools.php復制到public文件夾下,並在public文件夾內新建文件webtools.config.php,內容為:

define('PTOOLSPATH',__DIR__.'/../devtools/'); define('PTOOLS_IP','127.0.0.1'); spl_autoload_register(function($className){ $classDir = PTOOLSPATH.'/scripts/'; $classFile = $classDir . str_replace('\\', '/', $className) . '.php'; if (file_exists($classFile)) require_once($classFile); });

修改public文件夾下的webtools.php文件,將其中的require 'webtools.config.php';剪切到文件最開頭的<?php下一行。

經過測試,該工具對PHP版本要求較高,我在PHP5.4下無法使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM