学习所用版本:yii2.0,基本应用程序模板。
所用视频教程:【Yii2不得不说的 - xx篇】 http://pan.baidu.com/s/1bpC0tx9 密码: 2333
文档:http://www.yiichina.com/doc
此处使用HelloController控制器和hello视图目录
../basic/controllers/HelloController.php
../basic/views/hello
浏览器访问:http://127.0.0.1/../basic/web/index.php?r=hello/index
../index.php?r=视图目录/视图文件 视图目录要对应控制器(HelloController控制器-->hello视图目录/xxxx)
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller{
public function actionIndex(){
//如无特殊说明,以下代码都默认放在此处
}
}
Request
echo 'HELLO WORLD!<br>';
$request = \Yii::$app->request;
echo $request->get('id',0); //第二个参数表示如果没有get到这个参数
echo '<br>';
echo $request->post('name','no name');//第二个参数表示如果没有post到这个参数
echo '<br>';
if($request->isGet){// isPost...
echo '这是Get方式';
}
echo '<br>';
echo $request->userIP.'<br>'.$request->userAgent;
Response
$response = \Yii::$app->response;
$response->statusCode = '404';//设置状态码为404
//添加头信息,设置为不把消息缓存在浏览器里
$response->headers->add('pragma','no-cache');
//设置为缓存5秒钟
$response->headers->set('pragma','max-age=5');
//删除
$response->headers->remove('pragma');
}
//跳转
//跳转到别的页面
$response->headers->add('location','http://laji.blog');
//yii框架直接包装了个跳转页面的函数,第二个参数是返回的状态码
$this->redirect('http://laji.blog',302);
//文件下载
$response->headers->add('content-disposition','attachment;filename="1T.bt"');
//同样包装了个函数,如果文件不存在会报错
$response->sendFile('./robots.txt');
Session
$session = \Yii::$app->session;
$session->open();
if($session->isActive){//判断session是否已开启
echo 'session已开启';
}
//把session当成【对象】来使用
$session->set('user','张三');
//session被保存在哪?查看php.ini配置文件,搜索session.save_path即可找到session文件保存的路径
//取出session数据
echo $session->get('user');
//删除
$session->remove('user');
//把session当成【数组】来使用
$session['user'] = '张三';
echo $session['user'];
//删除
unset($session['user']);
ArrayAccess接口(interface)所产生的类都可以把它当成数组来使用
$session['user'] = '张三';
echo $session['user'];
//在chrome浏览器生成了的session,到其他浏览器是获取不到的,
//因为会自动记录识别并返回给相应的浏览器,根据浏览器cookies里的PHPSESSID来识别。
Cookies
记得在代码顶部添加use yiiwebCookie;
//response
$cookies_res = \Yii::$app->response->cookies;
$cookies_data = array('name'=>'username','value'=>'zhangsan');
//记得选web下的那个cookie,最上面要引用yiiwebCookie
$cookies_res->add(new Cookie($cookies_data));
//cookie的值会经过加密
//如果name一样,值会被覆盖掉。
//删除
$cookies_res->remove('username');
//request
$cookies_req = \Yii::$app->request->cookies;
echo $cookies_req->getValue('username','木有');//如果没有对应的cookie,将返回第二个参数,不填默认返回空
Views
要先在HelloController下定义$layout
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller{
///////
public $layout = 'common';//选择使用的layout布局
///////
public function actionIndex(){
xxxxxxxx
}
}
然后hello视图目录下新建index.php
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;//或者在下边直接写成yii\helpers\HtmlPurifier::process(****)
?>
<h1>HELLO <?=$view_username;?>!</h1>
<h1><?=$view_arr1['id'];?></h1>
<h1><?=$view_arr1['email'];?></h1>
<h1><?=$view_arr2[0];?> <?=$view_arr2[1];?></h1>
<!--<h1><?=$view_post_str;?></h1>-->
<h1>转义text输出:<?=Html::encode($view_post_str);?></h1>
<h1>直接过滤掉:<?=HtmlPurifier::process($view_post_str);?></h1>
<?php include('test1.php'); ?>
<?php echo $this->render('test2',array('view_test2'=>$view_test2)); ?><!--HelloController传来的view_test2-->
<?php echo $this->render('test3',array('view_test3'=>'test3')); ?>
<?php $this->beginBlock('block1'); ?>
<h1>此处的布局文件的原内容被视图文件里的block1覆盖(重写)掉了!</h1>
<?php $this->endBlock('block1'); ?>
新建test1.php
<h2><?=$view_test1;?></h2>
新建test2.php
<h3><?=$view_test2;?></h3>
新建test3.php
<h4><?=$view_test3;?></h4>
//actionIndex()内
$username = '张三';
$arr1 = array('id'=>233,'email'=>'[email protected]');
$arr2 = array(1,2,3);
$post_str = '666666666<script>alert("用户传来了script脚本攻击")</script>';
$test1 = 'test1';
$test2 = 'test2';
//yii会把字符串里的js脚本真的当做js来执行了,所以避免这个情况,在视图文件里用Html::encode()来转义一下。
//也可以使用HtmlPurifier::process()来把脚本代码过滤掉
//把变量传递给视图
//创建一个数组
$data = array();
//把需要传递给视图的数据放到数组当中
$data['view_username'] = $username;
$data['view_arr1'] = $arr1;
$data['view_arr2'] = $arr2;
$data['view_post_str'] = $post_str;
$data['view_test1'] = $test1;
$data['view_test2'] = $test2;
return $this->renderPartial('index',$data);//不用加.php后缀,第二个参数传递数据给视图
//注意:yii的视图文件规定放到views目录下对应的控制器的目录里
//如:HelloController对应views目录下的hello目录
//布局文件,即把重复的内容放到layouts目录当中
return $this->render('index',$data);//视图文件会保存到布局文件的$content这个变量当中
SQL
首先在config目录下的db.php里配置好数据库
然后在models目录下新建Test.php 文件名要对应表名
<?php
namespace app\models;
use \yii\db\ActiveRecord;
class Test extends ActiveRecord{
public function rules(){//传入数据库的规则
return [
['id','integer'], //是否整型
['title','string','length'=>[1,15]]
];
}
}
最后要在HelloController最上面添加use appmodelsTest;
查询数据
//直接使用sql语句
$sql = 'select * from test where id=:id';//使用了占位符,用户传来的id会被当做一个整体,避免sql注入。
$results = Test::findBySql($sql,array(':id'=>1))->all();
print_r($results);
//使用yii框架封装好的
$results = Test::find()->where(['id'=>1])->all(); //等于
$results = Test::find()->where(['>','id',0])->all(); //大于
$results = Test::find()->where(['between','id',0,2])->all(); //之间 1 <= X <= 2
$results = Test::find()->where(['like','title','标题'])->all(); //模糊查询
//把查询结果由对象转化成为数组,降低内存使用
$results = Test::find()->where(['between','id',0,2])->asArray()->all(); //之间 1 <= X <= 2
//批量查询
$i = 0;
foreach(Test::find()->batch(2) as $tests){//存放到$test里
//因为批量查询是分批去读取数据的,不会只读取一次,耗资源,所以用batch来指定每次读取的条数
//如果数据表里只有2条数据,就只读取一次就结束了。
$i++;
}
echo '读取了'.$i.'次数据库<br>';
print_r($tests);
删除数据
$results = Test::find()->where(['id'=>3])->all();
//一次只能删一条....
$results[0]->delete();
//批量删除
Test::deleteAll('id>:id',array(':id'=>1));//删除id>1的数据
增加数据
$test = new Test();
$test->id = 123;
$test->title = 'title';
//首先得去验证数据的合法性(models/Test.php rules)
$test->validate();
if($test->hasErrors()){//如果有数据校验发生了错误
echo 'data is error!';
die;
}
$test->save();
修改数据
$test = Test::find()->where(['id'=>666])->one();
$test->title = '我是666';
$test->validate();
if($test->hasErrors()){//如果有数据校验发生了错误
echo 'data is error!';
die;
}
$test->save();
关联查询
先在models里新建Customer.php和Order.php,因为文件名是对应表名的所以在数据库新建相对应的表和添加数据
并在HelloController顶部添加:
use app\models\Customer;
use app\models\Order;
//Customer.php
<?php
namespace app\models;
use \yii\db\ActiveRecord;
class Customer extends ActiveRecord{
//获取顾客订单信息
public function getOrders(){
$orders = $this->hasMany(Order::className(),['customer_id'=>'user_id'])->asArray();
//因为控制器调用未定义的XXXX方法,系统会去调用_get(),并转向getXXXX()方法,并在最后自动补上all(),所以这里删掉->all()
return $orders;
}
}
//Order.php
<?php
namespace app\models;
use \yii\db\ActiveRecord;
class Order extends ActiveRecord{
//根据订单查询顾客
public function getCustomer(){
return $this->hasOne(Customer::className(),['user_id'=>'customer_id'])->asArray();
//因为控制器调用未定义的XXXX方法,系统会去调用_get(),并转向getXXXX()方法,并在最后自动补上one(),所以这里删掉->one()
}
}
//根据顾客查询他的订单的信息
$customer = Customer::find()->where(['username'=>'zhangsan'])->one();
//Order::className()会自动获取app\models\Order
$orders = $customer->hasMany(Order::className(),['customer_id'=>'user_id'])->asArray()->all();
//customer_id是属于订单表里面的,user_id是属于顾客表的,注意先后顺序,根据第一个参数对应的表
//最好把上面这句代码封装起来-->models/Customer.php getOrders()
//$orders = $customer->getOrders();
//上面这句代码可以写成下面这条
$orders = $customer->orders;
//我们并没有在Customes里定义orders方法,为什么还会获取到数据呢?
//因为yii检测到没有XXXxx方法时,会去调用_get(),
//_get()于是会去调用getXXXX()方法,并在最后补上一个all()方法
//获取到数据后返回到调用的变量当中
print_r($orders);
//根据订单查询顾客
$order = Order::find()->where(['order_id'=>1])->one();
$customer = $order->customer;
print_r($customer);
//关联查询结果缓存
$customer = Customer::find()->where(['username'=>'zhangsan'])->one();
$orders = $customer->orders;//首先会select * from order where customer_id = ...
//如果再执行一次的话会直接调用$orders而不去先执行select * from...了,导致更新了数据却使用了之前的缓存
//所以可以先unset掉再执行
unset($customer->orders);
$orders = $customer->orders;
//关联查询的多次查询
$customers = Customer::find()->all();//select * from customer
foreach($customers as $customer){
$orders = $customer->orders;//select * from order where customer_id = ....
//假如有100个客户那么,就会执行100次
}
//那么一共执行101次sql语句了,所以~
//使用with()方法
$customers = Customer::find()->with('orders')->all();
foreach($customers as $customer){
$orders = $customer->orders;
}
类的映射表机制
\yii::$classMap['app\models\Order'] = '../models/Order.php';
$order = new Order();//系统会根据所给的路径去找
组件的延迟加载
$session = \yii::$app->session;
// \yii::$app会在使用的时候去调用到__get()这个方法,需要用到的时候再去加载组件
数据缓存的增删改查
//获取缓存组件
$cache = \yii::$app->cache;
//往缓存当中写入数据
$cache->add('key1','helle world~111111');
//如果前面已经有的key,后面继续add给这个key是会不起作用的,也不会报错~
$cache->add('key1','helle world~yoooooooo');
$cache->add('key2','helle world~222222');
//修改数据
$cache->set('key1','helle world~niconiconi');
//删除数据
$cache->delete('key1');
//清空数据
$cache->flush();
//读取缓存
$data = $cache->get('key1');
var_dump($data);
//缓存的有效期设置
$cache->add('key3','helle world~333333',15);//第三个参数是缓存的有效期,单位为秒。
$cache->set('key3','helle world~123456',5);//第三个参数是缓存的有效期,单位为秒。
$data = $cache->get('key3');
var_dump($data);
数据缓存依赖关系
文件依赖
首先在web目录下新建一个hw.txt,随便填点什么。
$cache = \yii::$app->cache;
$dependency = new \yii\caching\FileDependency(['fileName'=>'hw.txt']);
$cache->add('file_key','hello world~FileDependency',6666,$dependency);
//当hw.txt这个文件遭到修改(发生了变化)时,该缓存会自动失效
//而且把文件改回原来的样子也获取不到原来的缓存了
$data = $cache->get('file_key');
var_dump($data);
hw.txt文件被修改后:
表达式依赖
$cache = \yii::$app->cache;
$dependency = new \yii\caching\ExpressionDependency(
['expression'=>'\yii::$app->request->get("name")']
//这个表达式是在浏览器的地址栏传递过来的name参数
//如:http://127.0.0.1/xxxxxx/index&name=zhangsan
//我们添加了这个缓存,传递的是zhangsan的name(添加完记得注释掉add语句)
//如果我们把zhangsan改成其它,会获取不到原来的缓存,
//但把name的值改回zhangsan又获取到原来的缓存了~
);
$cache->add('expression_key','hello world~ExpressionDependency',6666,$dependency);
$data = $cache->get('expression_key');
var_dump($data);
name参数被修改后:
DB依赖
$cache = \yii::$app->cache;
$dependency = new \yii\caching\DbDependency(
['sql'=>'SELECT count(*) FROM yii.order']
//当order表发生变化时,会获取不到原来的缓存,
//但如果把order表恢复成原来的,又获取到原来的缓存了
);
$cache->add('db_key','hello world~DbDependency',6666,$dependency);
$data = $cache->get('db_key');
var_dump($data);
当sql查出来的结果和第一次的不一样后:
片段缓存
//跳转到cache1.php(开启片段缓存)
return $this->renderPartial('cache1');
../hello/cache1.php
<?php
if($this->beginCache('cache_div')) { //
?>
<div id="cache_div">
<h2>这里待会会被缓存,缓存后,修改此处代码依旧显示原来的代码,不会实时更新</h2>
</div>
<?php
$this->endCache();
} ?>
<div id="no_cache_div">
<h2>这里不会被缓存,修改此处代码会实时更新</h2>
</div>
//跳转到cache2.php(设置缓存时间)
return $this->renderPartial('cache2');
../hello/cache2.php
<?php
//缓存时间
$duration = 15;
echo '<h3>缓存时间:'.$duration.'秒</h3>'
?>
<?php
if($this->beginCache('cache_div',['duration'=>$duration])) { //
?>
<div id="cache_div">
<h2>这里待会会被缓存,缓存后,在缓存时间内修改此处代码依旧显示原来的代码,不会实时更新123</h2>
</div>
<?php
$this->endCache();
} ?>
<div id="no_cache_div">
<h2>这里不会被缓存,修改此处代码会实时更新123</h2>
</div>
//跳转到cache3.php(缓存依赖)
return $this->renderPartial('cache3');
../hello/cache3.php
<?php
//缓存依赖
echo '<h3>缓存依赖</h3>';
echo '<h3>此处使用文件依赖</h3>';
$dependency = [
'class'=>'yii\caching\FileDependency',
'fileName'=>'hw.txt'
];
echo '<h3>依赖文件:'.$dependency['fileName'].'</h3>';
?>
<?php
if($this->beginCache('cache_div',['dependency'=>$dependency])) { //
?>
<div id="cache_div">
<h2>这里待会会被缓存,缓存后,在依赖文件被修改前修改此处代码依旧显示原来的代码,不会实时更新</h2>
</div>
<?php
$this->endCache();
} ?>
<div id="no_cache_div">
<h2>这里不会被缓存,修改此处代码会实时更新</h2>
</div>
//跳转到cache4.php(缓存开关)
return $this->renderPartial('cache4');
../hello/cache4.php
<?php
//缓存开关
$enabled = true;
echo '<p>缓存开关:</p>';
var_dump($enabled);
?>
<?php
if($this->beginCache('cache_div',['enabled'=>$enabled])) { //
?>
<div id="cache_div">
<h2>缓存开关为true,这里待会会被缓存,缓存后,修改此处代码依旧显示原来的代码,不会实时更新</h2>
</div>
<?php
$this->endCache();
} ?>
<div id="no_cache_div">
<h2>这里不会被缓存,修改此处代码会实时更新</h2>
</div>
//跳转到cache5.php(嵌套缓存)
return $this->renderPartial('cache5');
../hello/cache5.php
<?php
if($this->beginCache('cache_div',['duration'=>20])) { //
?>
<div id="cache_outer_div">
<h2>这里是外层,待会会被缓存</h2>
<?php
if($this->beginCache('cache_inner_div',['duration'=>1])) { //
?>
<div id="cache_inner_div">
<h3>这里是内层,待会会被缓存</h3>
</div>
<?php
$this->endCache();
} ?>
</div>
<?php
$this->endCache();
} ?>
<h1>得出结论:</h1>
<h4>缓存后,在外层的缓存时间未结束前,内部缓存时间会被无视。</h4>
<h4>因为,当外层缓的存换层时间未结束前,系统会直接把已经缓存好的整个外层所包含的代码直接读取出来,</h4>
<h4>当外层的缓存时间结束后,再考虑内层的缓存时间,若内层的缓存时间已经过期,则缓存结束,反之,继续缓存着。</h4>
<div id="no_cache_div">
<h2>这里不会被缓存,修改此处代码会实时更新</h2>
</div>
(整个)页面缓存
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller{
public function actionIndex(){
echo '请修改此处测试是否会被缓存actionIndex';
}
public function behaviors(){//这个函数会先于其它函数执行
//(整个)页面缓存
//当有一个请求到actionIndex方法时,会先到behaviors,behaviors会告诉yii框,
//架要使用PageCache缓存,yii得知后,到Cache缓存里查看,如果有值得话会直接使用缓存里的值,
//actionIndex里的代码/操作就不会被执行了。
return [
[
'class'=>'yii\filters\PageCache', //使用PageCache缓存
'duration'=>30, //缓存时间
//不使用only时,默认所有页面都缓存
'only'=>['index'],//此处写进数组的页面才会被缓存
//例如test没被写进去,actionTest不会被缓存
'dependency'=>[ //依赖缓存
//此处使用文件依赖的类(表达式依赖、DB依赖以此类推。
'class'=>'yii\caching\FileDependency',//依赖的类
'fileName'=>'hw.txt'
]
]
];
}
public function actionTest(){//(整个)页面缓存
echo '请修改此处测试是否会被缓存actionTest';
}
}
http缓存
<?php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller{
public function actionIndex(){
//浏览器首次访问网页时,会发送请求到服务器,
//服务器会将已生成的last-modified(最后修改时间)和etag(特征?!)随着数据/内容响应给浏览器,
//并告诉浏览器接收到数据后要将内容缓存起来,那么浏览器是如何知道服务器要它将内容缓存起来的呢?
//具体是在响应的头部信息(Response Headers)里的Cache-Control,
//浏览器刷新/下次访问时,再次发送请求到服务器,同时会把If-Modified-Since(Last-Modified)和
//If-None-Match(Etag)发送给服务器,服务器将浏览器发来的数据与服务器的进行对比,
//如果相同,表示服务器内容没有变化,为避免浪费资源,让浏览器使用之前的浏览器缓存,
//如果不同,表示服务器内容发生了变化,则进行上面第2~5行的步骤。
$content = file_get_contents('hw.txt');
return $this->renderPartial('cache6',['new'=>$content]);
}
public function behaviors(){//这个函数会先于其它函数执行
//http缓存(见actionIndex函数的http缓存部分)
return [
[
'class'=>'yii\filters\HttpCache',
'lastModified'=>function(){
return filemtime('hw.txt'); //最后修改时间,返回时间戳给浏览器
//(浏览器会自动转换为格林时间,统一标准格林时间
},//比如return 1432817566(2015-05-28 【20】:52:46)--转换-->2015-05-28 【12】:52:46
'etagSeed'=>function(){
$fp = fopen('hw.txt','r');
$file_one_line = fgets($fp);
fclose($fp);
$file_size = filesize('hw.txt');
$md5 = md5('hw.txt');
$etag = $file_one_line.'|filesize:'.(string)$file_size.'|md5:'.$md5;
//return一些该文件的特征,比如文件的内容、文件大小、md5之类的,此处代码还不严谨。
return $etag;
}
]
];
}
}
../hello/cache6.php
<div>
<div><?=$new;?></div>
</div>
gii模型生成器 http://../basic/web/index.php?r=gii
可以直接配置并生成各种模型
Comments | NOTHING