标签:yii

浏览模式: 标准 | 列表 | 图文
针对品鉴网的一些URL路由设置

针对品鉴网的一些URL路由设置

这篇文章又能当成开发文档,也能当成软文,所以,你们就将就着看吧。

yii框架中很早就支持路由功能了。所以,从那时候开始,很多人就开始将项目路由化,举例说明:
http://user.pinjian.net,访问用户中心
http://admin.pinjian.net 访问后台
http://xxxx.pinjian.net 访问Xxx
表面上这是一大堆 网站,其实很有可能是什么?只是一个控制器或者一个module罢了。
http://user.pinjian.net可能对应了什么?http://pinjian.net/user/index,很有可能就这样而已。
而对于yii来说,这个太简单了
在main.php(环境 变量设置中),针对urlManager的rules加入:

'urlManager' => array(
'urlFormat' => 'path',
'showScriptName'=>false,
'rules' => array(
'http://photo.pinjian.net/<action:\w+>'=>'image/<action>',
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
),
),

看看高亮的那一行,是不是很简单?
之前,有一篇博客介绍过的:http://www.neatstudio.com/show-1550-1.shtml,还篇比较详细

Yii的又一个BUG?

Yii的又一个BUG?

先申明一下,这个可能不是BUG。只是算起来是实现的方式不一样而已。
场景:我有一个MYSQL数据库,但是现在容量越来越大,主要是因为其中有大字段,多个大字段,所以在查询的时候会特别特别慢。所以想到用mongo来存储一些查询用的结构。单条的时候,我还是准备采用MYSQL。当然其实单条用mongo也合适。不过因为迁移数据有点麻烦,所以还是先忍忍,一步一步来。

测试阶段:因为MYSQL to MONGO有点小麻烦,没有现成的工具。官方说有mongoimport,我看过了,确实OK,但是只支持一些基础的结构,比如:json,csv等。其他的则需要第三方工具。但我自己先在测试中,所以就直接写了个脚本,先将数据用AR取出来。然后插入到mongo中。结果发现,在排序的时候。。9999比10000还大。问了一下神仙 ,他说这应该是按字符串排序的方式来做的。

于是做了一个测试,写进了一个数字,果然就对了。。难道是yii的AR的BUG?想想这不太应该啊。于是我写了一个小的Demo:

$db = mysql_connect("localhost","root","123456");
mysql_select_db("feed");
$query = mysql_query("select id from feeds_group limit 1");
while($rs = mysql_fetch_array($query)){
$result = $rs;
echo "<pre>";
var_dump($result);
echo "</pre>";
}
echo "<hr />";
$dsn = 'mysql:host=localhost;dbname=feed';
$user = 'root';
$password = '123456';
$dbh = new PDO($dsn, $user, $password);
$sth = $dbh->prepare("select id from feeds_group limit 1");
$sth->execute();
$result = $sth->fetchAll();
echo "<pre>";
var_dump($result);
echo "</pre>";

打印出来一看:

array(2) {
[0]=>
string(1) "1"
["id"]=>
string(1) "1"
}

array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
}
}

果然出来就是字符串了,最后只能自己在插到mongo的时候写了一个小函数,对于数值型字段做了转换,问题就这样解决了。

又拍云的Yii组件

这个只是基于又拍云上面的一个小小的扩展,也是作了一个封装。
因为又拍云每次操作bucket都需要为它设置用户名和密码。如果我在一个controller里多次操作不同的bucket,有点麻烦 ,于是就做了一个小封装。
使用起来很简单,在配置文件main.php的components中加入一小段:

'components'=>array(
'upyun'=>'ext.upyun.EasyUpyun',
),

当然,如果有需要额外定制的变量,也可以参考其他组件的设置方法。

附件在这里,我就不多说了,贴上组件的注释:

/**
* EasyUpyun.php
* @example:
* Yii::app()->upyun->upload($domain,$savedname,$datas,$autoCreateDir=true);
* 这个是一个demo,推荐仍然使用upyun提供的API,这样就可以几乎不用改代码
* UpyunBase的用法是$upyun->setApiDomain('abc');
* 组件用法:Yii::app()->upyun->setApiDomain('bucket的别名','abc');
*
* @category upyun
* @package upyun
* @author gouki <gouki.xiao@gmail.com>
* @version $Id$
* @created 12-7-6 PM11:07
*/

再贴上变量的注释

/**
* 别名
* 因为又拍云的bucket的名字比较长,在开发的时候,如果用很长的bucket会很痛苦,因此就做了一个别名功能用来代替bucket
* @var array
*/
public $alias = array(
'static' => 'test-public'
);
/**
* 又拍云的bucket
* key 为 bucket
* value 为 bucket对应的用户名和密码,格式为“用户名:密码”
* @var array
*/
public $bucket = array(
'test-public' => 'admin:123456'
);
/**
* 又拍云API实例
* @var UpYun
*/
public $upyun;
/**
* 是否采用upyun的debug功能,该功能为全局打开,一旦开启,所有bucket涉及的debug都开启
* @var bool
*/
public $debug = FALSE;

Over,有想试用的,可以直接尝试下载附件。

Yii : using multiple radio button

Yii : using multiple radio button

Yii在使用CHtmlRadio的时候,如果参数不正确,会隐藏一个form,导致如果radio的值有3个时,永远只能提交第一个和最后一个
太纠结了。仔细看看,确实 是有一个隐藏FORM,导致本来应该是3个radio的button,变成了6个。

找了一下资料,看了一下源码,果然。。。。有一个hidden。

/**
* Generates a radio button for a model attribute.
* If the attribute has input error, the input field's CSS class will
* be appended with {@link errorCss}.
* @param CModel $model the data model
* @param string $attribute the attribute
* @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* A special option named 'uncheckValue' is available that can be used to specify
* the value returned when the radio button is not checked. By default, this value is '0'.
* Internally, a hidden field is rendered so that when the radio button is not checked,
* we can still obtain the posted uncheck value.
* If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
* @return string the generated radio button
* @see clientChange
* @see activeInputField
*/
public static function activeRadioButton($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
if(!isset($htmlOptions['value']))
$htmlOptions['value']=1;
if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
$htmlOptions['checked']='checked';
self::clientChange('click',$htmlOptions);

if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck='0';

$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';

// add a hidden field so that if the radio button is not selected, it still submits a value
return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions);
}


太纠结了。居然用unCheckValue设置一下才OK:

echo CHtml::radioButton('btn', false, array(
'value'=>'1',
'name'=>'btnname',
'uncheckValue'=>null
));
CHtml::radioButton('btn', false, array(
'value'=>'2',
'name'=>'btnname',
'uncheckValue'=>null
));

//如果是activeForm,就得这么用
echo $form->radioButton($model, 'name', array(
'value'=>1,
'uncheckValue'=>null
));
echo $form->radioButton($model, 'name', array(
'value'=>2,
'uncheckValue'=>null
));

果然纠结。。。NND

ZendFramework

Zend 2.0的框架改动与1比实在是太大了,当然抛开Namespace不说,即使是应用和架构,都有了一部分调整。
Zend实在太庞大了。用来开发项目不一定是首选。以前都是当成类库来用的,毕竟他实现了几乎目前所需要用到的一切功能,甚至GData之类的接口都全了,你还能奢求什么?
要赶时髦?openID和oauth也有,要实用?连pdf库都有,发邮件、本地化、命令行,应有尽有,不是类库是什么?
不过2.0就不太一样。我随便看了一个DB类,和以前的操作都有点不太一样了。或许是一下子没有适应过来那种newZend_Db_TableGateway之类的调用方式吧
手册在这里:http://packages.zendframework.com/docs/latest/manual/en
下载在这里:http://packages.zendframework.com/

还有一个相对比较实用的wiki:http://framework.zend.com/wiki/display/ZFDEV2/Home
可以看看。2.0的架构和代码还是值得学习的。

Yii框架中设置时区

Yii框架中设置时区

时区这东西,在开发的时候,你说重要吧,也还好,毕竟没它也能正常运行,你说不重要吧,那就纠结了。特别是linux系统,都TMD差上几小时,你能不痛苦吗?win还好一点。
有一些常规方法,是大家目前都在采用的
1、php.ini中的设置,这个就不谈了,
2、程序中公用文件里设置,date_default_timezone_set一下时区
3、或者。。。自己写时间处理函数,在遇到时间的时候,用这个函数处理(比较偏向于使用这种方式,如果你的用户来自于五湖四海,或许就有用了)
4、yii框架中,可以直接在/protected/config/main.php中加入timeZone,即可(补充:Yii2方法也是一样,只是config文件的位置不太一样罢了)

Yii的AR效率释疑

关于yii的AR效率,其实一直以来都有很多的想法,试想,如果不做metadata的缓存,每次查询前,都必须先做一下metadata的查询,效率也不会太高到哪里吧?
所以,看到官方有人在问就关注了一下:http://www.yiiframework.com/forum/index.php/topic/16597-yii%E7%9A%84ar%E7%9C%9F%E7%9A%84%E8%83%BD%E7%94%A8%E4%B9%88%EF%BC%9F/

有人提问:

我在首页会很多个ar的请求。热门文章、最新文章、编辑推荐、最新评论的文章。。。。

我把这些通过 model()->findAll()的结果放在一个数组里。

然后把这个数组var_dump了一下,这些数据高达1.06M。这是不是太耗内存了?

页面上全是密密麻麻的数据表结构,如果关联关系复杂点的,会更多。

我光var_dump(yii::app()->db) 就有5000多行的数据。


这样的db操作这么耗内存,敢用么?谁能消除我这个担心?多谢

AcitveRecord ,只能玩一玩开拓眼界. 真要生产环境用, 就不行!

然后,Qiang就回复了:

你的结论有点想当然了。建议你仔细做profiling来验证。事实上,AR已经被成功应用在若干大流量的网站上了。

你不能用var_dump()来估计AR的内存开销。var_dump会把所有被reference到的对象都dump出来,包括application,以及所有的application component,因为它们都被AR间接reference到了。

AR额外的内存开销是存储10个左右变量的开销。如果按20字节来估算,额外的开销是200字节,这样在1000个AR对象情况下,额外的内存开销为200KB。这个对几乎所有的web应用而言应该不是问题。

如果你需要装载更多的数据,建议你使用DAO。

另外,对于任何大流量的web应用而言,cache都是必须的。cache可以帮助解决绝大多数的性能瓶颈。

cache在DB中有一些处理的,比如那个duration,在db中查询就可以做一下缓存了。然后metadata再做一下缓存,不也挺好?

Yii Behavior的简单用法

Yii Behavior的简单用法

Yii的behavior用起来是十分方便的,官方的文档也很多,我不多嘴一一解释,我只说一些简单的用法
如果你看过PHP5.4,你应该知道5.4多了个新功能traits。
那你可以对着手册看了,你就当yii的behavior就是5.4的traits。

在任何基于CComponents类扩展的类里,都可以用attachBehavior来附加一个行为,这就象5.4的在类里面 use traits类一样
附加行为后,直接可以$this->行为中的方法,嗯,这个与traits也一样。
好吧,来个简单的例子:

<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}

trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}

class MyHelloWorld extends Base {
use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

Yii的用法:

<?php
class xxx extends CBehavior
{
public function show(){
echo "show";
}
}

class test extends CComponents
{
public function hello(){
$this->attachBehavior('唯一标记符',"xxx");
$this->show();
}
}

看看,是不是用法一样?不过这样也带来一个问题。。。TMD,没法在IDE里面自动识别了。

好吧,只能这样折腾自己了。。忍忍。

yii 连接 mssql遇到的一些问题

1、yii在linux下面连接mssql时,connectString一般是dblib:xxxxx,而不是mssql,这是因为用freetds的原因
2、用gii生成mssql的数据表结构时,如果表的字段是类似"Post Time"(即,字段中间有空格),则直接会报错
3、当生成好Model时,使用xxx::model()->findAll()时,如果最初的表结构里有允许某个字段为空,即允许isnull的话,在数据库中,该字段无值时是NULL,findAll就会报错:

CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]: General error: 4004 General SQL Server error: Check messages from the SQL Server [4004] (severity 16) [(null)]. The SQL statement executed was: SELECT TOP 1 * FROM [dbo].[DatabaseLog] [t]

4、无论是mysql还是sqlserver,当在components中设置columnCase值的时候,都会报错,这是因为在 MysqlSchema中都是采用了大小写敏感的方式(如$column['IsIdenfy'])之类的,当大小写敏感后,如果在attributes 中设置了PDO的ATTR_CASE,都会报错

yii:Apache and Nginx configurations

yii的urlmanager可以让项目在访问的时候隐藏index.php,也可以以更优雅的urlrewrite方式来显示,但这一切需要一些配置,在apache上的配置上就相对比较简单,直接参考wordpress的官方配置就完了,但其实很久以来,一直都没有人写过nginx下的配置。大家都是在根据wordpress配置来更改的,比如lnmp项目中,就是:

location / {
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
}

不过,这两天在看官方guide的文档,原来这些问题,官方已经提供方案了:http://yii.neatcn.com/doc/guide/1.1/en/quickstart.apache-nginx-config#nginx

1. Apache

Yii is ready to work with a default Apache web server configuration. The .htaccess files in Yii framework and application folders restrict access to the restricted resources. To hide the bootstrap file (usually index.php) in your URLs you can add mod_rewrite instructons to the .htaccess file in your document root or to the virtual host configuration:

RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php

2. Nginx

You can use Yii with Nginx and PHP with FPM SAPI. Here is a sample host configuration. It defines the bootstrap file and makes yii catch all requests to unexisting files, which allows us to have nice-looking URLs.

server {
set $host_path "/www/mysite";
access_log /www/mysite/log/access.log main;

server_name mysite;
root $host_path/htdocs;
set $yii_bootstrap "index.php";

charset utf-8;

location / {
index index.html $yii_bootstrap;
try_files $uri $uri/ $yii_bootstrap?$args;
}

location ~ ^/(protected|framework|themes/\w+/views) {
deny all;
}

#avoid processing of calls to unexisting static files by yii
location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
try_files $uri =404;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php {
fastcgi_split_path_info ^(.+\.php)(.*)$;

#let yii catch the calls to unexising PHP files
set $fsn /$yii_bootstrap;
if (-f $document_root$fastcgi_script_name){
set $fsn $fastcgi_script_name;
}

fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fsn;

#PATH_INFO and PATH_TRANSLATED can be omitted, but RFC 3875 specifies them for CGI
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fsn;
}

location ~ /\.ht {
deny all;
}
}

Using this configuration you can set cgi.fix_pathinfo=0 in php.ini to avoid many unnesessary system stat() calls.