鲁鲁槟 2016-06-03 09:45:34 9876次浏览 3条回复 22 3 0

作者:鲁鲁槟 出处:http://www.luluqi.cn/post/default/show-post?id=41 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

一、属性

1、属性的定义 一般情况下,在模型里面定义的属性是公共的并且是非静态的

class Test extends \yii\base\Model
{
    public $username;
    public $password;
}

2、属性标签 在模型里面定义属性标签很简单,只需要重写yii\base\Model::attributeLabels() 方法即可, 它返回的是name-value数组,名称为属性的名称,对应的值即为属性的标签名称。

public function attributeLabels(){
    return [
        'username'=>'用户名',
        'password'=>'密码',
    ];
}

如果想得到一个属性对应的标签可以使用yii\base\Model::attributeLabels($name)方法来得到,其中$name就是属性的名称。返回属性对应的标签。 如果某个属性没有定义对应的标签,Yii会使用yii\base\Model::generateAttributeLabel()方法自动生成对应的标签, 例如username 会生成 Username, orderNumber 生成 Order Number 3、属性的读取和赋值

public function actionIndex()
{
    $test = new Test();
    //属性的访问
    $test->username = 'lulubin';
    echo $test->username;
    //由于模型实现了ArrayAccess接口,所以也可以用数组的方式来访问:
    echo $test['username'];
    //属性批量读取和赋值
    //如果要一次获取模型的所有的属性,可用通过 attributes 属性来得到
    $test->username = 'lulubin';
    $test->password = '123456';
    var_dump($test->attributes);
    //同理,也可以用attributes来进行批量赋值
    $test->attributes=[
            'username' => 'lulubin',
            'password' => '123456',
    ];
    var_dump($test->attributes);
}
二、场景

1、场景说的通俗点,就是不同条件下环境。举个用户注册的例子,普通用户在注册的时候只要用户名、密码、电子邮箱就可以了, 而企业用户除了这些外还需要提供企业名称、法人名称、营业执照号什么的,这就是两个不同的场景。 为了让一个模型能使用在不同的场景下面,Yii里面提供了scenarios()方法,返回的也是name-value数组, name为每个不同 的场景,value是一个数组,为对应场景的所用到的属性。

public function scenarios()
{
    return [
        'login' => ['username', 'password'],
        'register' => ['username', 'email', 'password'],
    ];
}

如上所示,用户模型里面有 username,password,email三个属性,在登录的场景下只需要username和password,而在注册的场景中还需要email。 如果没有在模型中定义场景scenarios(),那么将会使用默认的场景,即所有的属性都将使用。 2、如果在定义场景的同时还要保持默认的场景可用,那么就得需要调用父类的scenarios()

public function scenarios()
{
    $scenarios = parent::scenarios();
    $scenarios['login'] = ['username', 'password'];
    $scenarios['register'] = ['username', 'email', 'password'];
    return $scenarios;
}

3、有时候我们在批量赋值的时候需要标明某些属性是不安全的,但又想让让这些属性能够正常的验证。 我们可以在场景scenarios()中的那些属性前面加上感叹号前缀,如

['username', 'password', '!secret']

username, password 和secret都能被验证,但在给属性批量赋值的时候只有username和password被认识是安全的可以赋值,而secret就不能被赋值 4、条件验证 可以在满员某些条件的情况下才验证属性,例如一个属性的验证需要另外一个属性值(确认密码等),这个时候可以用when关键字来定义

['state', 'required', 'when' => function($model) { return $model->country == Country::USA; }],
['stateOthers', 'required', 'when' => function($model) { return $model->country != Country::USA; }],
['mother', 'required', 'when' => function($model) { return $model->age < 18 && $model->married != true; }],

如果需要在客户端进行逻辑验证(enableClientValidation is true),得需要使用关键字 whenClient

['state', 'required', 'when' => $usa['server-side'], 'whenClient' => $usa['client-side']]
三、存取控制过滤器(ACF)

存取控制过滤器(ACF)是一种通过 yii\filters\AccessControl 类来实现的简单授权方法, 非常适用于仅需要简单的存取控制的应用 ACF 是一个种行动(action)过滤器 filter,可在控制器或者模块中使用 当一个用户请求一个 action 时, ACF会检查 yii\filters\AccessControl::rules 列表,判断该用户是否允许执 行所请求的action AccessControl提供基于yii\filters\AccessControl::rules规则的访问控制。 特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则 来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            //only 选项指明 ACF 应当只 对 login, logout 和 signup 方法起作用
            'only' => ['login', 'logout', 'signup'],
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['login', 'signup'],
                    'roles' => ['?'],
                ],
                // 允许认证用户
                [
                    'allow' => true,
                    'actions' => ['logout'],
                    // 是一个特殊标识, 代表”已认证用户”。
                    //? 是另一个特殊的标识,代表”访客用户”
                    'roles' => ['@'],
                ],
            ],
        ],
        //指定该规则用于匹配哪种请求方法(例如GET,POST)。 这里的匹配大小写不敏感
        'verbs' => [
            'class' => VerbFilter::className(),
            'actions' => [
                'logout' => ['post'],
            ],
        ],
    ];
}

ACF 自顶向下逐一检查存取规则,直到找到一个与当前 欲执行的操作相符的规则。 然后该匹配规则中的 allow 选项的值用于判定该用户是否获得授权。 如果没有找到匹配的规则, 意味着该用户没有获得授权

当 ACF 判定一个用户没有获得执行当前操作的授权时,它的默认处理是: 如果该用户是访客,将调用 yii\web\User::loginRequired() 将用户的浏览器重定向到登录页面。 如果该用户是已认证用户,将抛出一个 yii\web\ForbiddenHttpException 异常。 你可以通过配置 yii\filters\AccessControl::denyCallback 属性定制该行为

四、关联查询

Customer.php

class Customer extends \yii\db\ActiveRecord
{
    public function getOrder()
    {
        //第一个customer_id是Order表中的字段,第二个customer_id是Customer表中的字段
        //比如查询1号订单的顾客资料,1号订单的customer_id=1
        //然后在Customer表中查询customer_id=1的顾客资料
        return $this->hasMany(Order::className(),['customer_id' => 'customer_id'])->asArray()->all();
    }
}

Order.php

class Order extends \yii\db\ActiveRecord
{
    public function getCustomer()
    {
        //第一个customer_id是Customer表中的字段,第二个customer_id是Order表中的字段
        //比如查询zhangsan的订单,zhangsan的customer_id=1
        //然后在Order表中查询customer_id=1的订单
        return $this->hasOne(Customer::className(),['customer_id' => 'customer_id'])->asArray()->one();
    }
}

控制器的方法

function actionOrder()
{
/******************************* 关联查询 ****************************/
    /********** 1、根据顾客名字查询顾客订单,顾客1:n订单 ******/
    //查询zhangsan的订单
    $customer = Customer::find()->where(['name' => 'zhangsan'])->one();
    $order = $customer->getOrder();
    print_r($order);

    /********** 2、根据订单查询顾客名字,订单1:1顾客 *********/
    //查询1号订单的顾客资料
    $order = Order::find()->where(['order_id' => 1])->one();
    $customer = $order->getCustomer();
    print_r($customer);

   /**** $customer = $orders->customer;
    * 3、当访问不存在的属性时$orders->customer,php会自动调用__get()
    * 即$orders->customer相当于调用$orders->getCustomer()
    * 同时还会在末尾自动补上one()方法,即$orders->getCustomer()->one()
    * 因此,当你使用$orders->customer时,要在getCustomer()方法末尾要去掉one() *****/

    /********************* 关联查询问题1:关联查询结果会被缓存 **********************/
 /* 当你执行 $order=Order::find()->where(['order_id' => 1])->one() 时,往数据表进行了查询
  * 第二次执行 $order=Order::find()->where(['order_id' => 1])->one() 时则不会从数据表中进行查询,会直接从缓存中读取
  * 所以当你更新数据表的时候,你查询到的结果却没有更新,此时你需要先unset($order)删除缓存再从数据表中查询 */

    /********************* 关联查询问题2:关联查询的多次查询 **********************/
    $customers=Customer::find()->all(); //1次sql语句select * from customer
    foreach($customers as $customer){
        //如果Customer表中有100条记录,则会执行100次sql语句select * from order where customer_id=...
        print_r($customer->order);
    }
    /*解决方法:加上with('order')
     * select * from customer,select * from order where customer_id in(...),这时的...表示所有顾客customer_id的集合
     * 选取所有顾客的customer_id塞到各自的order属性,执行下面foreach时不会再有sql语句,这里只执行了2次sql语句*/
    /*$customers=Customer::find()->with('order')->all();
    foreach($customers as $customer){
        print_r($customer->order);
    }*/
}
五、大杂烩

1、Yii Controller 中的actions具体有什么作用 可以让controller共用相同的方法,比如: siteController和publicController里面都有actionUpdate方法并且功能一致,那么就可以用actions 验证码

public function actions()
{
    return [
        'captcha' => [
            'class' => 'yii\captcha\CaptchaAction',
        ],
    ];
}

2、设置返回的是JSON数据类型

public function actionResponse()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    $items = ['some', 'array', 'of', 'data' => ['associative', 'array']];
    return $items;
}

3、View::params

public function actionAbout()
{
    //设置View::params属性的值
    \Yii::$app->view->params=['testData'=>'hello'];
    return $this->render('about');
}
<!-- 访问View::params的值 -->
<?php echo $this->params['testData'];?>

4、View::context 由于about是TestController指定显示的方法,所以about的上文是TestController 此时View::context获取到的是TestController中所有的属性和方法

$context=$this->context;
echo $context->testData;
echo $context->actionTest();

5、$this->register

$this->registerMetaTag(['name'=>'author','content'=>'discuss'],'meta-description'); //添加<meta>标签
$this->registerMetaTag(['name'=>'author1','content'=>'discuss'],'meta-description'); //添加<meta>标签
如果对同一个类型(这个例子里面为meta-description)的registerMetaTag调用多次,后面的值将会覆盖前面的值,最终只有最后的一个标签会渲染出来
$this->registerLinkTag(['rel'=>'arce','title'=>'yii2','href'=>'www.yii.com']); //添加<link>标签
$this->registerCss('body{margin:0px;padding:0px;}'); //注册css代码
$this->registerJs('alert(4)'); //注册js代码
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [BootstrapAsset::className()], ['media' => 'print'], 'css-print-theme');
第一个参数指定要添加的css文件
第二个参数指定这个css文件依赖的BootstrapAsset。意思是说在BootstrapAsset里面的css文件加载完成之后才加载刚才指定的css文件。如果没有指定依赖项那么这个css文件和BootstrapAsset里面的css文件的将没有先后顺序。
第三个参数设置<link>标签的其它属性的值。
最后一个参数用来唯一标识这个css文件。如果没有指定的话将会用这个css的URL连接。 */
**在注册外部css文件的时候,我们推荐你使用asset bundles 而不是使用registerCssFile()。使用asset bundles的话可以合并和压缩多个css文件,以减少网络流量的传输。**
注册asset bundles(重要)
如先前所提到的,在页面中最好使用asset bundles,而不是直接在页面中使用css和javascript。关于asset bundles的相关信息可以查看asset manager。
使用已经定义的asset bundles代码如下
\frontend\assets\AppAsset::register($this);

depends保证加载JS文件的先后顺序 asset bundles资源包 此时先加载yii\web\YiiAsset,再加载assets/e05e437e/yii.js

$this->registerJsFile('assets/e05e437e/yii.js',
    ['depends'=>'yii\web\YiiAsset','position'=>\yii\web\View::POS_HEAD]); //注册js文件

6、\Yii::$app->cache

public function actionCache()
{
    $cache = \Yii::$app->cache;
    $data = $cache->get('cache_data_key');
    if ($data === false) {
        //这里我们可以操作数据库获取数据,然后通过$cache->set方法进行缓存
        $cacheData = User::findOne(['id'=>\Yii::$app->user->id]);
        //set方法的第一个参数是我们的数据对应的key值,方便我们获取到
        //第二个参数即是我们要缓存的数据
        //第三个参数是缓存时间,如果是0,意味着永久缓存。默认是0
        $cache->set('cache_data_key', $cacheData, 60*60);
    }
    var_dump($data['username']);
}

7、静态页面 如果需要渲染一个静态页面可以使用ViewAction类。它会根据用户的设置调用这个action来显示相应的视图文件。 首先在控制器里面的actions里面

<?php
class SiteController extends Controller
{
    public function actions()
    {
        return [
            'static' => [
                'class' => '\yii\web\ViewAction',
            ],
        ];
    }
}
?>

在@app/views/site/pages/目录中创建index.php //index.php

<h1>Hello, I am a static page!</h1>

现在可以通过/index.php?r=site/static来访问 默认情况下是通过GET参数中的view变量来显示相应的静态文件的。如果URL为/index.php?r=site/static?&view=about那么将会显示@app/views/site/pages/about.php静态文件。 静态文件默认按照如下顺序来显示 获取GET参数:view 如果没有指定view参数,将使用默认的index.php静态文件。 在静态文件的目录中查找相应的文件(viewPrefix):pages为目录 使用相应的布局文件。 更多相关信息可以查看yii\web\ViewAction。 8、php匿名函数

$message = 'hello';
//从父作用域继承变量
$example = function () use ($message){
    var_dump($message);
};
$example();

$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("hello");
觉得很赞
您需要登录后才可以回复。登录 | 立即注册