Phalcon填坑手冊:開發中會遇到的問題和解決方案(不斷更新)

本文將記錄我在Phalcon開發過程當中遇到的問題,以及如何如何解決。php

本文首發在個人博客,我更新以後會更新過來;若是想查看最新的,能夠到個人博客:Phalcon填坑手冊:開發中會遇到的問題和解決方案(不斷更新)css

1. 正確地在控制器中獲取參數

通常狀況下,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;
    }
}

2. 爲 url 定製路由

默認自動解析/: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

3. flash提示重寫後輸出不正確 (未解決)

重寫後輸出的html標籤是字符串,外面帶""

4. Config 中 baseURI 的正確設置

由於有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配置:

  • Apache:

.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>
  • Nginx

大概的配置以下,配置到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;
    }
}

5. 事件管理器,fire寫法無論用

被手冊誤導,理解錯誤了。

下面是 錯誤 的寫法,在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;
});

6.使用模型關聯不起做用

扔進去的對象報錯;須要給關聯的對象定義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別名會報錯。

7. 插入數據時返回主鍵id

經過$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;
}

8. model事件 beforeCreate 和字段檢查

在 beforeCreate 事件中定義數據表字段的數據檢查和數據賦值,不生效。

beforeCreate 在執行以前就會檢查字段是否符合要求(validation),因此在beforecreate時再插入不行,會報錯,須要在執行create前就傳值,或者設置默認值。

能夠在 beforeValidation 時進行賦值檢查的操做。

9. 操做model保存時,save或update無效

表現爲save或者update失敗,且不報錯的問題。
狀況:主鍵設置爲兩個字段,更新時更新了其中一個字段。
解決:不該該修改主鍵。
參考:https://stackoverflow.com/questions/3838414/can-we-update-primary-key-values-of-a-table

10. find()與findFirst()

  • find()與findFirst()返回值數據格式是不一樣的。
  • 加了 column 參數時的返回值object裏時不完整的,因此沒法使用save等方法,沒法使用model關係。
  • 沒有數據時,find()返回空數組,findfrist()返回false

11. PhalconCacheBackendRedis 的 queryKeys()出現如下錯誤:

Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCR')!

Redis的默認配置有一個參數爲‘_PHCR’前綴,因此queryKeys()時須要帶上查詢前綴。

12 dispatcher->forward() 分發後原腳本仍然繼續執行

能夠加上return阻斷:

$this->dispatcher->forward([
    "controller" => "error",
    "action"    => "route404"
]);
return;

在分發後後面的代碼將再也不執行。

13. 錯誤:Encryption key cannot be empty

使用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;
    }
);

14. cache刪除失敗:queryKeys()以後foreach遍歷循環delete()刪除失敗

正常刪除時:

$this->cache->delete($key)

若是設置了前綴,會在$key自動加上前綴。

queryKeys列出來的已經帶上了前綴,因此這樣刪除:

$keys = $this->cache->queryKeys();
    foreach($keys as $key) {
        $this->cache->delete($key)
    }

傳進去的key還會自動再加一遍前綴,就找不到緩存了,致使刪除失敗。

解決方法:

  1. $this->cache->flush()清除全部緩存,可是會清除全部緩存,因此若是是memcache或者redis緩存能夠設置一下statsKey,避免清除了全部緩存。
  2. 或者不使用前綴,就能夠正常使用queryKeys()和delete()這條流程。
相關文章
相關標籤/搜索