Phalcon route路由只能访问根路径的问题
问题现象
我用Phalcon-dev-tools创建了一个空的项目,然后比着文档一步一步往下做。刚开始还行,修改IndexController中的indexAction方法啥的都没有问题,可是,一旦自己写一个Controller或者在原有的Controller上添加其他Action
方法,还是返回根路径/
下的内容。
这tm是咋回事儿?
反复寻找答案,看文档的每一个细节,是否漏了某些代码?
环境没问题吧?这都跑起来了,肯定是代码问题吧?
问题原因以及解决
还真就是环境问题,不是php版本、Phalcon版本bug,是nginx配置问题!
坑!
Phalcon默认的URI信息是从$_GET['_url']
获得,也可以设置为$_SERER['REQUEST_URI']
获取。
使用这两种不同方法获取,还得要不同的nginx配置!!(详情请看Phalcon文档 Phalcon nginx配置)
这特么也得配置!
使用$_GET['_url']
(默认):
location / {
try_files $uri $uri/ /index.php?_url=$uri&$args;
}
使用$_SERVER['REQUEST_URI']
,nginx配置:
location / {
try_files $uri $uri/ /index.php;
}
想要正常使用$_SERVER['REQUEST_URI']
的方式,nginx配置完了还不要紧,还得在php代码里修改:
use Phalcon\Mvc\Router;
$router->setUriSource(Router::URI_SOURCE_SERVER_REQUEST_URI);
Phalcon3.1版本无法结合mongodb的问题
问题现象
我在php5.6、Phalcon2.0的环境下按照如下方式把mongodb
服务注入到Phalcon中是没问题的:
1 | $di->set( |
但是在php7.1、Phalcon3.1的环境下,却报错了。说找不到mongo类…
问题原因以及解决
左思右想,谷歌百度,刷新调试。原来,MongoClient这个类用到了php5.6的mongo
这个扩展,PHP官方文档提示mongo
扩展将由mongodb
所替代,而mongo
这个扩展在php7中已经不支持。php7中只支持mongodb
这个扩展。
但是Phalcon3.1封装的类库MongoClient却引用了mongo
这个库,所以报了错…
Phalcon研发组发现了这个问题,所以提供了一个php类库:"phalcon/incubator"
只需要在composer包中加入此类库,用类库的类替代原来的类就可以了:
- 在composer中加入(Phalcon2.x版本对应2.x版本,Phalcon3.x版本对应3.x版本)
1
"phalcon/incubator": "^3.1"
- 代码中引入
use Phalcon\Db\Adapter\MongoDB\Client
,然后代码中这样注入:1
2
3
4
5$di->setShared("mongo", function(){
$mongoConfig = $this->getConfig()->mongo;
return (new Client("mongodb://{$mongoConfig->host}:{$mongoConfig->port}/?replicaSet={$mongoConfig->replicaSet}"))
->selectDatabase($mongoConfig->database);
}); - 如果想使用Phalcon中的
ODM
,原来是引用use Phalcon\Mvc\Collection;
并继承。现在是引用以下:并继承它。1
use Phalcon\Mvc\MongoCollection;
其他问题,出现 A dependency injector container is required to obtain the services related to the ODM
这是由于加的包"phalcon/incubator": "^3.1"
对于PHP 7.1.0版本以上支持的不好,每次对实体保存的时候都会在mongo中保存一下一些脏数据
1 | "_dependencyInjector" : {}, |
然后再次存数据的时候,就报错了。
解决办法就是重写save()
方法:
1 | public function save() |
Phalcon无法使用redis
或者memcached
作为Phalcon的缓存服务
问题现象
使用Phalcon封装好的缓存类,只需要如下操作就可以了。
1 | use Phalcon\Cache\Frontend\Data as FrontData; |
但是有时候报错,找不到redis类…
问题原因以及解决
这是因为Phalcon扩展在封装缓存类的时候,引用了PHP的redis
扩展,而redis
扩展并不是php的标准扩展包,so…
只需要安装好redis
扩展就好。
同理,假如报memcache
找不到,只需要安装相应扩展就好。
Phalcon ORM使用Join
语句出现The column 'XXX' is ambiguous
或者 Model 'XXX' could not be loaded
的问题
问题现象以及解决
在使用Phalcon的ORM进行Join
语句的时候,需要如下操作
1 | $infos = User::query()->inWhere("tkey", $uids) |
报 Model 'XXX' could not be loaded
的错误,看看leftJoin
方法:
1 |
|
感觉没毛病,细细想来,发现Model
参数应该是该写的是namespace
吧,于是:
1 | $user = User::class; |
但是又出现了新问题:The column 'tkey' is ambiguous,
,将SQL解析后发现:SQL语句中是不允许先”where 然后 join”的,但是Phalcon帮我们封装的时候,帮我们避开了这个问题:where 语句可以在Join之前写,但是最终解析的sql还是在join之后,既然在join之后,那么tkey
当然就不明确咯,改成:
1 | $user = User::class; |
问题就解决了
Phalcon 设置model之间的Realaction 通过一个model的实体找不到另一实体
model之间的对应关系,通常是在model的initialize
方法中实现,但是在实现的时候,要特别注意:Phalcon中参数都为定义的Model类,而不是MySQL中的table名字,这就带来一个问题:类名必须加namespace,生成的model的property名字奇怪或者引用不了。解决方法就是加上一个别名alias
,代码如下:
1 | $this->hasMany("order_no", OrderDetail::class, "order_no", |
Phalcon 请求处理中getPost(“”)找不到数据和处理json数据的问题
在Phalcon中,发送post请求的时候,如果post请求中的Content-Type
是以application/json
的json形式发送请求数据,那么,使用$this->request->getPost("xxx")
是拿不到任何数据的,必须使用$this->request->getJsonRawBody()
这个方法。
- $this->request->getJsonRawBody(true) 拿到的是一个请求数组
- $this->request->getJsonRawBody() 拿到的是一个object
Phalcon 中使用where查询
连续几个where条件,不能和laravel等其他框架一样,好几个where并排,只能有一个 where
,剩下的都是andWhere
可能习惯了其他框架(例如:laravel 的查询,喜欢连续的where
),如下:
1 | $members = Member::query() |
感觉没毛病,但是一运行就报错:SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
,通过打印出来(语句为$this->di->get('profiler')->getLastProfile()->getSQLStatement()
)的SQL可以看出来,上条语句转义的SQL语句中连续写了两个where
,并不是 where ... AND ...
这就和预期不太一致。改为如下代码,就正常了:
1 | $members = Member::query() |
有inWhere
的情况下,bind
要写在where
或者andWhere
语句之后,不能和inWhere
掺和在一起
如下语句:
1 | $members = Member::query() |
运行后报错:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
原因是:bind
没有和连续的where语句“绑”在一起。
应该写成:
1
2
3
4
5
6
7
8
9$members = Member::query()
->where("id = :uid:")
->andWhere("member_id = :memberId:")
->bind([
"uid" => 1,
"memberId" => 1
])
->inWhere("country", [86])
->execute();
where语句中有时间的比较的时候,时间单位若为Y-m-d H:i:s
格式,一定要把在时间上加上引号
1 | $orderPayment = OrderPayment::query() |
以上代码报错:Syntax error, unexpected token INTEGER(15), near to ':51:53)'
因为Y-m-d H:i:s
格式的时间,中间有个空格,导致Phalcon无法正确的解析加上引号就好了。
1 | $orderPayment = OrderPayment::query() |
Phalcon update更新语句问题
Phalcon一般的update方式为:先查询,拿到实体model
;然后实体model
的字段赋值$model->xxxx = xxxx
,最后运行$model->update()
,并判断update
方法的返回值是true还是false,来判断更新是否成功。
但是,在高并发条件下,最好是update table set columnA = xxx where colum = AND ...
这种形式。
代码为:
1 | //项目启动的时候先注入 |
可是这却存在一个问题:
假如说where
语句得到的是一个空行,不存在的数据,那么以上语句执行之后,还是会返回true。
也就是说其实Phalcon仅仅是判断的是否SQL返回正确,并没有判断改变了多少行,所以在用的时候要特别小心。尽量加上redis制作一个分布式锁。
Phalcon model 查询方法find()
和findFirst()
的使用
find
的使用
1 | $member = Member::find( |
或者:
1 | $member = Member::find( |
或者
1 | $member = Member::find( |
findFirst()
的使用
find()
能使用的,findFirst()
都可以使用,而且,findFirst()
还多了一种:
1 | $member = Member::findFirst(4) |
特别注意:Phalcon中ODM
和ORM
对find
及findFirst
的操作是不相同的
ODM中可以这么用:
1 | $action = UserAction::findFirst( |
conditions
是一个数组,包含查询条件,但是,ORM不可以这么用!我想,可能是因为SQL语句中不仅包含AND
还包含OR
,直接用数组的话… (^__^)
ODM中还可以直接这么用:
1 | $action = UserAction::findFirst( |
Mac本地环境下不缺少类,但是一发布到测试环境,就报错xx class cannot be loaded
可能存在这样的原因:
你的包名为小写,而你的包下的namespace
为大写,而你在引用了包的时候,仅仅引入了某个父包的namespace,而没有引入父包下每个子包的包名,在Mac下,不区分大小写,可以正常跑,但是到了Linux环境中,区分大小写,系统只会通过namespace
的大写来找目录,而包名又都是小写,因而会找不到~
所以,应该避免如下简写:
1 | $loader = new \Phalcon\Loader(); |
而是将各个父目录下的子目录都给它引上
1 | $loader = new \Phalcon\Loader(); |
cli程序必须跑到指定的目录下
假如你想使用phalcon的 task功能,然后使用crontab
来作定时脚本任务,会经常出现“路径找不到的问题”…
细究其原因,是因为 run
文件中的诸多文件都是以 run
文件所在的位置作为“中心”来查找其他文件的,假如运行的当前目录中没有 run
文件,那么就会报找不到某某某文件的错误。解决这个问题的途径也很简单,只需要让当前目录移动到run
文件所在的目录就好了。
哪怕使用PHQL ,重写 model的update方法也会有问题
假如你重写了model
的update
方法,而你又想用偏原生SQL的方式去避开model
的update
方法带来的修改,例如你选择Phalcon自带的PHQL来躲避update方法的修改。那么,你就大错特错了,使用PHQL最终会调用excute
方法,实际上就是拼出了model name,然后find相关的model;之后的操作,都是针对model的,也就是说,最终还会调用你重写的model的update
方法…