资讯专栏INFORMATION COLUMN

Phalcon填坑手册:开发中会遇到的问题和解决方案(不断更新)

sf190404 / 762人阅读

本文将记录我在Phalcon开发过程中遇到的问题,以及如何如何解决。

本文首发在我的博客,我更新之后会更新过来;如果想查看最新的,可以到我的博客:Phalcon填坑手册:开发中会遇到的问题和解决方案(不断更新)

1. 正确地在控制器中获取参数

一般情况下,GET/POST请求获取参数:

$this->request->get(参数名);
$this->request->getPost("参数名")

路由模式下route获取参数要用dispatcher->getParam();
route下定义好了参数名称可以直接通过参数名称来获取:

this->dispatcher->getParam("参数名");

route没有定义好名称,只是规则中写了:params做匹配,可以在控制器中按顺序来获取:

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:

$router = new Router(false);

不自动解析/:controller/:action/:params这些规则, 具体的路由匹配规则自己来编写,例如:

$router->add("/login",
    [
        "module"     => "admin",
        "controller" => "login",
        "action"     => "index",
    ]
)->setName("login");

这样不会因为自动解析而导致url混乱,但是所有url都要自己来定制路由规则。

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外面一层的项目根目录也可以:


    DocumentRoot "D:phpStudyWWWzPhalpublic"
    ServerName goozp.com
    ServerAlias 
  
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
      Require all granted
  

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("ZPhalModulesAdminControllers");
    $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",
    "ZPhalModelsTerms",
    "term_id",
    [
        "alias" => "Terms",
    ]
);

不起alias别名会报错。

7. 插入数据时返回主键id

通过$model -> getWriteConnection() -> lastInsertId();来获取:

$model = new model();

if($model -> create($data)) {
    $insertId = $model -> getWriteConnection() -> lastInsertId($model -> getSource());
}

或者直接在执行之后拿id属性:

 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加密:

set(
    "cookies",
    function () {
        $cookies = new Cookies();

        $cookies->useEncryption(false);

        return $cookies;
    }
);

或者设置一个key:

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还会自动再加一遍前缀,就找不到缓存了,导致删除失败。

解决方法:

$this->cache->flush()清除所有缓存,但是会清除所有缓存,所以如果是memcache或者redis缓存可以设置一下statsKey,避免清除了所有缓存。

或者不使用前缀,就可以正常使用queryKeys()和delete()这条流程。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26324.html

相关文章

  • [填坑手册]小程序目录结构component组件使用心得

    摘要:组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。事件用于子组件向父组件传递数据,可以传递任意数据。官方文档往期回顾填坑手册小程序生成海报一拆弹时刻小程序生成海报二 showImg(https://user-gold-cdn.xitu.io/2019/6/19/16b6e94bcde767a1?w=1069&h=652&f=jpeg&s=120912); 小程序目录结构...

    myshell 评论0 收藏0
  • 【踩过坑】[web]1.生产与灰度数据缓存;2.Mysql主从不同步;

    摘要:方法,如图总结因为灰度环境在公司内网,访问量较小,相比方法,方法可以暂时解决灰度测试时的缓存问题。但是仍然存在风险。 背景:php做web开发,MVC,phalcon 1.生产与灰度数据缓存 原因: service层获取数据,有新增数据字段; controller层是通过redisCache调用service接口; redisCache采用redis-file双缓存结构,可能存在...

    sixgo 评论0 收藏0
  • [填坑手册]小程序Canvas生成海报(一)---完整流程

    摘要:海报生成示例最近智酷君在做小程序生成海报的项目中遇到一些棘手的问题,在网上查阅了各种资料,也踩扁了各种坑,智酷君希望把这些填坑经验整理一下分享出来,避免后来的兄弟重复掉坑。 showImg(https://segmentfault.com/img/bVbs5V8?w=343&h=517);海报生成示例 最近智酷君在做[小程序]canvas生成海报的项目中遇到一些棘手的问题,在网上查阅了...

    shleyZ 评论0 收藏0

发表评论

0条评论

sf190404

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<