帮助你开始使用 phalcon 的简易指南。php
Phalcon 2将于2015年4月17日发布,这个版本大约85%的代码是基于 Zephir 语言重写的。Zephir是开源的,使用相似PHP语法的语言,生成C语言代码,并编译成PHP扩展。这提升了PHP扩展的开发效率,并下降了框架的后期维护成本。html
安装 https://github.com/phalcon/phalcon-devtools 以后能够帮助自动生成目录结构和代码。同时把ide目录下的相应版本加入IDE的External libraries以后,能够帮助IDE自动完成代码。node
配置nginx的时候,建议用$_SERVER[‘REQUEST_URI’]方式,这样能够防止自动加入$_GET[‘_url’]的隐规则,在参数签名时,若是你忘记这个隐规则会导至签名验证失败。mysql
参考配置:nginx
server { listen 80; server_name www.example.com; index index.html index.htm index.php; root $root_path/example/public; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
这样设置后,代码也要参考URI Sources调整git
$router->setUriSource(Router::URI_SOURCE_SERVER_REQUEST_URI);
phalcon框架对代码结构并无约定,你能够按本身的实际须要自行组织代码结构,这里有一个供参考的例子:https://github.com/phalcon/mvc。github
实际项目中,代码分层至少要分三层,controller/view -> services -> modelssql
services和models为了重用,能够参考composer的组织方式,放到vendor。数据库
使用PSR-4规范的namespace自动加载。api
404要处理3个场景
没有匹配route
dispatch时没找到controller文件
dispatch时没找到action方法
当没有匹配route时,会使用用默认的namespace,默认的module,默认的controller,默认的action,默认的params。此时你或许会困惑为什么一个请求会显示默认首页。
参考not found paths,配置route
// Not Found Paths $router->notFound([ 'controller' => 'errors', 'action' => 'route404' ]);
参考handling not found exceptions在注入dispatcher服务时初始化代码以下
$di->setShared('dispatcher', function () { $eventsManager = new EventsManager(); $eventsManager->attach("dispatch:beforeException", function ($event, $dispatcher, $exception) { if ($exception instanceof DispatcherException) { switch ($exception->getCode()) { case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND: case Dispatcher::EXCEPTION_ACTION_NOT_FOUND: $dispatcher->forward([ 'controller' => 'errors', 'action' => 'show404', 'params' => array('message' => $exception->getMessage()) ]); return false; } } $dispatcher->forward([ 'controller' => 'errors', 'action' => 'show500' ]); return false; }); $dispatcher = new MvcDispatcher(); $dispatcher->setDefaultNamespace('\namespace\Controllers'); $dispatcher->setEventsManager($eventsManager); return $dispatcher; });
以代码因为还拦截了其它异常,且没有throw $exception,会中断异常调用链,能够考虑把异常$exception->getMessage(), $exception->getFile(),$exception->getLine(),$exception->getCode()信息传给view,判断是开发模式就显示,生产模式就不显示。
原则上是不容许使用原生的SQL的,某些场景必定要用的状况下,建议把全部的sql放到config内,在service层读取使用。
$sql = "SELECT id, name FROM robots ORDER BY name"; $connection = \Phalcon\DI::getDefault()->get('db'); $result = $connection->query($sql); $result->setFetchMode(Db::FETCH_ASSOC); echo $connection->getSQLStatement(); // sql $data = $result->fetchAll(); print_r($data);
// A raw SQL statement $sql = "SELECT * FROM robots WHERE id > 0"; $robot = new Robots(); $result = $robot->getReadConnection()->query($sql); $result->setFetchMode(Db::FETCH_ASSOC); $data = $result->fetchAll(); print_r($data); echo $robot->getReadConnection()->getSQLStatement();
参考Phalcon Query Language (PHQL)
简单粗暴的理解是把models下的namespaceclass对应成数据库的表,类属性对应表字段。
理解了PHQL以后就能够读下Working with Models
model类的事件调用顺序以下:参考官方文档http://docs.phalconphp.com/en/latest/reference/models.html#events-and-events-manager
用命名空间区分不一样的数据库实例,对应代码结构上是不一样的目录区分,在同一目录下基类负责初始化链接。链接来自初始化时注入的多个db服务
隐规则:
initialize()在每一个请求期间只会调用一次
为每一个 new 建立的实例执行初始化任务使用onConstruct()
namespace Company\Models\Notification; /** * Class BaseModel * * beforeSave()和afterFetch()成对使用,用于读写数据时自动转化数据。 * 例如自动执行serialize unSerialize * * save()发生时事件调用顺序是 * initialize, * onConstruct, * beforeValidation, * beforeValidationOnCreate, * afterValidationOnCreate, * afterValidation, * beforeSave, * beforeCreate, * afterCreate, * afterSave, * * @package Company\Models\Notification */ class BaseModel extends \Phalcon\Mvc\Model { /** * - initialize()在每一个请求期间只会调用一次 * - 子类必需调用父类方法 * - 为每一个 new 建立的实例执行初始化任务使用onConstruct() */ public function initialize() { $this->setConnectionService('db_notification'); //$this->setConnectionService('node1'); //$this->setConnectionService('node2'); // //真实场景可能使用mysqlnd_ms扩展或者haproxy //仅演示读负载均衡一种思路 //$dbSlave = ['node1', 'node2', 'node3']; //$key = array_rand($dbSlave); //$db = $dbSlave[$key]; //$this->setReadConnectionService($db); // // //$this->setReadConnectionService('dbRead'); //$this->setWriteConnectionService('dbWrite'); } }
model中提供的getSource()方法,合理运用便可。
class BaseModel extends \Phalcon\Mvc\Model { public function getSource() { return 'v1'.str_tolower(get_class($this)); } } class User extends BaseModel { ... } class Robots extends Phalcon\Mvc\Model { public function getSource() { return "robots_" . date("Ym"); } }
2.0.9以前的版本先set('key'),而后再正常的set('key','value')。也就是set两次绕过bug。
2.0.x分支已经修复这个bug,查看github源码
下面的单元测试能够重现这个bug。若是使用2.0.9以前的版本,建议采用两次set
public function testCookies() { // di factory $di = new \Phalcon\Di\FactoryDefault(); $di->setShared('crypt', function () { $crypt = new \Phalcon\Crypt(); // don't use PADDING_DEFAULT, Affect the cookie result $crypt->setPadding(\Phalcon\Crypt::PADDING_ZERO); $crypt->setKey('secret_key@123456789'); // Use your own key! return $crypt; }); // http cookies $di->setShared('cookies', function () { $cookies = new \Phalcon\Http\Response\Cookies(); $cookies->useEncryption(false); return $cookies; }); /** @var \Phalcon\Http\Response\CookiesInterface $cookies */ $cookies = \Phalcon\DI::getDefault()->get('cookies'); $_COOKIE['key'] = '1234567890'; $_COOKIE['key2'] = '0987654321'; //$cookies->set('key'); // ver <= 2.0.9 uncomment will test passed //$cookies->set('key2'); // ver <= 2.0.9 uncomment will test passed $this->assertEquals('1234567890', $cookies->get('key')->getValue()); $cookies->set('key', 'value', time() + 3600, '/', false, 'kinhom.com', true); $cookies->set('key2', 'value2', time() + 3600, '/', false, 'kinhom.com', true); $this->assertInstanceOf('\Phalcon\Http\Cookie', $cookies->get('key')); /* * phalcon ver <= 2.0.9 * Failed asserting that two strings are equal. * Expected :'value' * Actual :'1234567890' */ $this->assertEquals('value', $cookies->get('key')->getValue()); $this->assertEquals('value2', $cookies->get('key2')->getValue()); }
volt模板文件内 {{ content() }} 是联接各个模板的桥梁,完整的顺序是setMainView() -> setTemplateAfter() -> setLayout() -> setTemplateBefore -> pick()
即Main Layout -> Layout -> Action View
controller中若echo字符串,Action view内要写上{{ content() }}才会输出。
不管你是否使用phalcon框架,作为PHP开发者,有些背景知识是必须要了解的。