本文將記錄我在Phalcon開發過程當中遇到的問題,以及如何如何解決。php
本文首發在個人博客,我更新以後會更新過來;若是想查看最新的,能夠到個人博客:Phalcon填坑手冊:開發中會遇到的問題和解決方案(不斷更新)css
通常狀況下,GET/POST請求獲取參數:html
$this->request->get(參數名); $this->request->getPost("參數名")
路由模式下route獲取參數要用dispatcher->getParam();
route下定義好了參數名稱能夠直接經過參數名稱來獲取:nginx
this->dispatcher->getParam("參數名");
route沒有定義好名稱,只是規則中寫了:params作匹配,能夠在控制器中按順序來獲取:redis
class NewsController extends Controller { public function showAction($id, $testParam) { echo $id, '|' , $testParam; } }
默認自動解析/:controller/:action/:params
模式:
在實例化時,不加false參數:數組
$router = new Router();
url將會自動進行/:controller/:action/:params
參數的解析, 好比https://www.goozp.com/login
將會解析成Login controller下的默認action。緩存
當使用路由時,保留默認解析模式有時候會致使解析混亂,比較建議採用徹底自定義路由模式。
徹底自定義路由,在new時加上false:cookie
$router = new Router(false);
不自動解析/:controller/:action/:params
這些規則, 具體的路由匹配規則本身來編寫,例如:php7
$router->add('/login', [ 'module' => 'admin', 'controller' => 'login', 'action' => 'index', ] )->setName('login');
這樣不會由於自動解析而致使url混亂,可是全部url都要本身來定製路由規則。app
重寫後輸出的html標籤是字符串,外面帶""
由於有Apache+.htaccess文件重寫規則 或者 nginx配置到public/index.php的重寫規則,咱們不須要項目中的url帶有/publc/index.php。
可是默認是指到了/public/index.php中(好比$_SERVER["PHP_SELF"]獲取從根目錄到當前頁面自己的路徑); 因此,若是有Apache重寫規則或者nginx配置到public/index.php的重寫配置,咱們須要把url設置爲不帶public/index.php的,因而就有了官方的這個設置:
使用 $_SERVER["PHP_SELF"],而且正則去除/public/index.php
'baseUri' => preg_replace('/public([\/\\\\])index.php$/', '', $_SERVER["PHP_SELF"]),
這是動態寫法,這種寫法的問題在於 $_SERVER["PHP_SELF"] 的不肯定性,返回的值將根據 Apache 或 nginx 配置的 root,是否配置host或者域名,$_SERVER["PHP_SELF"]會有不一樣的返回值。這樣的話上面寫法前面的正則並非所有兼容的,因此這樣寫調試起來就稍麻煩。
簡單一點,用靜態寫法:
設置host或者配置域名
'baseUri' => '/',
若是是想在localhost下直接打開,則須要加上項目外層目錄名,例如:
'baseUri' => '/zphal/',
這樣的話,咱們在定義url服務的時候只須要把這個定義的配置傳進去:
$di->setShared('url', function () { $config = $this->getConfig(); $url = new UrlResolver(); $url->setBaseUri($config->application->baseUri); // baseUri return $url; });
以上寫法的WebServer配置:
.hatccess按照官方配置就能夠;配置host時配置到public下或者public外面一層的項目根目錄也能夠:
<VirtualHost *:80> DocumentRoot "D:\phpStudy\WWW\zPhal\public" ServerName goozp.com ServerAlias <Directory "D:\phpStudy\WWW\zPhal\public"> Options FollowSymLinks ExecCGI AllowOverride All Order allow,deny Allow from all Require all granted </Directory> </VirtualHost>
大概的配置以下,配置到public下,並定義rewrite規則:
server { listen 80; server_name www.goozp.com goozp.com; root /data/www/zPhal/public; index index.php index.html index.htm; charset utf-8; client_max_body_size 100M; fastcgi_read_timeout 1800; location / { # Matches URLS `$_GET['_url']` try_files $uri $uri/ /index.php?_url=$uri&$args; } location ~ \.php$ { try_files $uri =404; #fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_pass php-fpm:9000; fastcgi_index /index.php; include fastcgi_params; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED /data/www/zPhal/public/$fastcgi_path_info; fastcgi_param SCRIPT_FILENAME /data/www/zPhal/public/$fastcgi_script_name; } location ~ /\.ht { deny all; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; access_log off; } }
被手冊誤導,理解錯誤了。
下面是 錯誤 的寫法,在dispatcher中去定義了監聽事件:
$di->set('dispatcher', function () { // 建立一個事件管理器 $eventsManager = new EventsManager(); $media = new Media(); $media->setEventsManager($eventsManager); // 監聽分發器中使用插件產生的事件 $eventsManager->attach( "media", new AliYunOss() ); $dispatcher = new Dispatcher(); $dispatcher->setDefaultNamespace('ZPhal\Modules\Admin\Controllers\\'); $dispatcher->setEventsManager($eventsManager); // 分配事件管理器到分發器 return $dispatcher; });
然而我想封裝的是文件上傳功能,跟 dispatcher分發器 沒有任何關係,因此起不了做用還報錯;應該註冊一個返回DI容器的文件上傳服務:
$di->set('mediaUpload',function (){ // 建立一個事件管理器 $eventsManager = new EventsManager(); $media = new Media(); $eventsManager->attach( "media", new AliYunOss() ); $media->setEventsManager($eventsManager); return $media; });
扔進去的對象報錯;須要給關聯的對象定義alias,經過alias來獲取。
若是是這樣:
$terms = new Terms(); $terms->name = $name; $terms->slug = $slug; $termTaxonomy = new TermTaxonomy(); $termTaxonomy->Terms = $terms; // 這裏 $termTaxonomy->taxonomy = $type; $termTaxonomy->save();
在$termTaxonomy->Terms = $terms;這裏,Terms是TermTaxonomy Model中定義的關係的別名(alias);
定義方式以下,在model中:
$this->belongsTo( "term_id", "ZPhal\\Models\\Terms", "term_id", [ "alias" => "Terms", ] );
不起alias別名會報錯。
經過$model -> getWriteConnection() -> lastInsertId();
來獲取:
$model = new model(); if($model -> create($data)) { $insertId = $model -> getWriteConnection() -> lastInsertId($model -> getSource()); }
或者直接在執行以後拿id屬性:
<?php $model = new model(); if($model -> create($data)) { $insertId = $model -> id; }
在 beforeCreate 事件中定義數據表字段的數據檢查和數據賦值,不生效。
beforeCreate 在執行以前就會檢查字段是否符合要求(validation),因此在beforecreate時再插入不行,會報錯,須要在執行create前就傳值,或者設置默認值。
能夠在 beforeValidation 時進行賦值檢查的操做。
表現爲save或者update失敗,且不報錯的問題。
狀況:主鍵設置爲兩個字段,更新時更新了其中一個字段。
解決:不該該修改主鍵。
參考:https://stackoverflow.com/questions/3838414/can-we-update-primary-key-values-of-a-table
Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCR')!
Redis的默認配置有一個參數爲‘_PHCR’前綴,因此queryKeys()時須要帶上查詢前綴。
能夠加上return阻斷:
$this->dispatcher->forward([ "controller" => "error", "action" => "route404" ]); return;
在分發後後面的代碼將再也不執行。
使用cookie時,默認會使用Crypt加密,而使用Crypt加密須要定義一個全局加密key。
能夠禁用cookie加密:
<?php use Phalcon\Http\Response\Cookies; $di->set( "cookies", function () { $cookies = new Cookies(); $cookies->useEncryption(false); return $cookies; } );
或者設置一個key:
<?php use Phalcon\Crypt; $di->set( "crypt", function () { $crypt = new Crypt(); $crypt->setKey('#1dj8$=dp?.ak//j1V$'); // 使用你本身的key! return $crypt; } );
正常刪除時:
$this->cache->delete($key)
若是設置了前綴,會在$key自動加上前綴。
queryKeys列出來的已經帶上了前綴,因此這樣刪除:
$keys = $this->cache->queryKeys(); foreach($keys as $key) { $this->cache->delete($key) }
傳進去的key還會自動再加一遍前綴,就找不到緩存了,致使刪除失敗。
解決方法:
$this->cache->flush()
清除全部緩存,可是會清除全部緩存,因此若是是memcache或者redis緩存能夠設置一下statsKey,避免清除了全部緩存。