php费尔康框架phalcon(费尔康)框架学习笔记

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;

即可解决。

路由规则

添加路由规则:

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。

指定参数名称

方式一,在数组中指定:

$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中,这些被命名的参数可以用如下方式这样访问:

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'

));

钩子事件

转换某个参数的值:

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

路由分组

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

或者:

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:

//Add the group to the router

$router->mount(new BlogRoutes());

路由命名

$route = $router->add("/posts/{year}/{title}", "Posts::show");

$route->setName("show-posts");

//或者这样

$router->add("/posts/{year}/{title}", "Posts::show")->setName("show-posts");

然后,我们就可以根据命名来生成符合这条路由的网址了:

// returns /posts/2012/phalcon-1-0-released

echo $url->get(array(

"for" => "show-posts",//路由名称

"year" => "2012",//参数year的值

"title" => "phalcon-1-0-released" //参数title的值

));

指定URI来源

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 定义默认值。当一个路由缺少其中任何一项时,路由器可以自动用默认值填充:

//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'

));

匿名路由

此组件提供了一个与注解服务集成的变体。使用此策略可以在控制器中直接写路由。

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;

};

可以按如下方式定义注解:

/**

* @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方法:

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');选择视图:

如果pick方法接收到一个不包含"/"的字符串则仅仅设置LEVEL_ACTION_VIEW级视图;如果包含"/"则同时还会把第一个"/"前面的部分作为LEVEL_LAYOUT级视图,比如这里会使用"视图文件目录/layouts/index.phtml"文件

如果接收到一个数字索引数组,则会将编号为0的元素作为LEVEL_ACTION_VIEW级视图,将编号为1的元素作为LEVEL_LAYOUT级视图

关闭视图

如果你的控制器不在视图里产生(或没有)任何输出,你可以禁用视图组件来避免不必要的处理:

$this->view->disable();

在模板中包含局部模板

<?php $this->partial('shared/login');?>

或者同时传递变量给局部模板,每一个索引最终会作为变量在局部模板中被赋值:

$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'//缓存索引名

));

注册缓存服务:

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服务时全局指定模板引擎:

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种不同含义的起始标签

{% ... %}包裹的标签用于赋值或执行for循环、if条件判断等语句

{{ ... }}包裹的标签用于打印表达式的结果到模板

{# ... #}包裹注释,前后标签可以处于不同行

语法详解

{{ 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 (

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

{% 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

{%- macro my_input(name, class="input-text") %}

{% return text_field(name, 'class': class) %}

{%- endmacro %}

{# Call the macro #}

{{ '

' ~ my_input('name') ~ '

' }}

{{ '

' ~ my_input('name', 'input-text') ~ '

' }}

由以上代码可见,模板中字符串间连接符为~!

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() }}`

新增模板函数

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');//第二个参数可以是函数名或匿名函数

缓存视图片段

{% cache ("article-" ~ post.id) 3600 %}

{{ post.title }}

{{ post.content }}

{% endcache %}

可以在模板中直接通过服务名访问通过DI注册的服务。

在php模板中使用"$this->服务名"来访问。

设计表单

模型

模型类的名称使用表名称且首字母大写(如果表名称含下划线"_",需要删除下划线并将原下划线位置后的一个字符大写),继承于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):

$robots = Robots::query()

->where("type = :type:")

->andWhere("year < 2000")

->bind(array("type" => "mechanical")) //绑定参数(字符串占位符)

->order("name")

->execute();

最后,还有一个 findFirstBy() 方法。这个方法扩展了前面提及的 "findFirst()" 方法。它允许您利用方法名中的属性名称,通过将要搜索的该字段的内容作为参数传给它,来快速从一个表执行检索操作。

的内容为首字母大写的数据表字段名(如果字段名称含下划线"_",需要删除下划线并将原下划线位置后的一个字符大写)。

例如,数据表字段名为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个模型,并分别设置它们的关联字段

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

验证数据

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

字段注解策略

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类的实例来查询:

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(模型管理器)来查询:

//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重定向

重定向用来在当前的处理中跳转到其它的处理流:

// 此路由重定向到其它的路由

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"处理器。

app-\>notFound(function () use (app) {

$app->response->setStatusCode(404, "Not Found")->sendHeaders();

echo 'This is crazy, but this page was not found!';

});

微应用

事件名

触发

是否可中止操作?

before

应用请求处理之前执行,常用来控制应用的访问权限

Yes

after

请求处理后执行,可以用来准备回复内容

No

finish

发送回复内容后执行, 可以用来执行清理工作

No

REST API

[https://docs.phalconphp.com/zh/latest/reference/tutorial-rest.html\](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下无法使用。

相关推荐
你的小10几秒前
JavaWeb项目-----博客系统
android
风和先行31 分钟前
adb 命令查看设备存储占用情况
android·adb
AaVictory.1 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰2 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶2 小时前
Android——网络请求
android
干一行,爱一行2 小时前
android camera data -> surface 显示
android
断墨先生3 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员4 小时前
PHP常量
android·ide·android studio
萌面小侠Plus5 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机
慢慢成长的码农5 小时前
Android Profiler 内存分析
android