Yii2 基础:安装,控制器、视图、数据模型

1. Yii2 的安装启动;

1.1 安装;

  • 方法1 :访问 Yii 官网,进入下载页面,下载 Yii2 的基本应用程序模板的归档文件
# 进入项目目录创建单个项目文件夹
cd /data/project/test/
mkdir yii2
cd yii2

# 下载归档文件
wget https://github.com/yiisoft/yii2/releases/download/2.0.17/yii-basic-app-2.0.17.tgz

# 解压后多出一个 basic 文件夹
tar zcvf yii-basic-app-2.0.17.tgz

# 修改配置文件
cd basic/
vim config/web.php
# 查询关键字 “cookieValidationKey”,修改如下
'cookieValidationKey' => 'asdf',

# 设置缓存文件夹可写权限
chmod -R 777 runtime
chmod -R 777 web/assets

# 检查 1:访问 http://192.168.2.214/yii2/basic/requirements.php
# 页面没有报错项目说明,则当前环境符合 Yii2 运行标准

# 检查 2:访问 http://192.168.2.214/yii2/basic/web/
# 看到 “Congratulations!” 说明框架安装成功
  • 方法2 :Composer 安装
# 进入项目目录创建单个项目文件夹
cd /data/project/test/
mkdir yii2
cd yii2

# 安装
create-project yiisoft/yii2-app-basic basic
# 文件自动下载完成后会自动配置目录权限
Generating autoload files
> yii\composer\Installer::postCreateProject
chmod('runtime', 0777)...done.
chmod('web/assets', 0777)...done.
chmod('yii', 0755)...done.
> yii\composer\Installer::postInstall
# 访问 http://192.168.2.214/yii2/basic/requirements.php
# 看到 “Congratulations!” 说明框架安装成功

1.2 请求处理流程;

参考页面: https://www.yiichina.com/doc/guide/2.0/structure-overview
当一个请求来到了入口脚本之后( basic/web/index.php),这个入口脚本的本质工作并不是去处理请求,把请求的处理交给了应用主体。应用主体在代码中就是一个对象
应用主体在正式处理请求之前,会去加载一堆应用组件、以及一些相应的模块,去帮助更好的处理请求。应用主体在正式处理请求的时候,会把请求的处理委托给一个控制器。
控制器在处理请求的时候,如果需要和数据库打交道的话,会让模型和数据库进行交流。然后控制器在处理请求完成之后,如果想要回馈给用户一些信息的话,它会使用视图去回馈内容。
视图为了更好的展现回馈的内容,会去使用一些小部件,以及一些前端资源包
在这里插入图片描述

1.3 命名空间;

// 新建文件 A.php
<?php
namespace a\b\c;

class Apple{
	function info(){
		echo 'this is Apple A';
	}
}

// 新建文件 B.php
<?php
namespace d\e\f;

class Apple{
	function info(){
		echo 'this is Apple B';
	}
}

// 新建文件 C.php
<?php
// 不存在于任何命名空间:全局类
class Apple{
	function info(){
		echo 'this is Apple C';
	}
}

// 新建文件 index.php
<?php
require_once('A.php');
require_once('B.php');
require_once('C.php');

// use 关键字:一旦使用 Apple() 类,默认使用 a\b\c 下的 Apple()
use a\b\c\Apple;
// as 关键字:重命名类名
use d\e\f\Apple as bApple;

// $a_app = new a\b\c\Apple();
$a_app = new Apple();
$a_app2 = new Apple();
$a_app->info();

$b_app = new bApple();

// 访问全局类
$c_app = new \Apple();

2. 控制器;

  • 控制器目录:basic/controllers
  • 实例:创建 basic/controllers/HelloController.php
<?php

// 控制器类必须放在命名空间中,还必须继承 controllers(yii\web\Controller) 类
namespace app\controllers;

// use 全局类 Yii
use Yii;
use yii\web\Controller;
use yii\web\cookie;

class HelloController extends controller{

    // 2.1 控制器的创建
    // 专门处理请求的方法不叫方法,叫操作
    public function actionIndex(){
        echo 'Hello World';
 
    }

    // 2.2 请求处理
    public function actionRequest(){
        // 参考: https://www.yiichina.com/doc/guide/2.0/runtime-requests

        // 通过请求组件获取浏览器 URL 传来的参数
        // 通过全局类 Yii 里的 $app 静态变量(应用主体)
        // 这个应用主体在开始的时候会加载各种各样的应用组件
        // 有一个 request 的请求组件
        $request = Yii::$app->request;

        // 获取 get 数据
        echo $request->get('id', 0) . "<br>";

        // 获取 post 数据
        echo $request->post('data', 'no data') . "<br>";

        // 判断是否 get / post 过来的数据
        if($request->isGet){
            echo 'this is get method' . "<br>";
        }

        // 获取用户的 ip
        echo $request->userIP . "<br>";
    }


    // 2.3 响应处理
    public function actionResponse(){
        // 参考:https://www.yiichina.com/doc/guide/2.0/runtime-responses

        // 当浏览器发送来一个请求之后,在操作里对请求经过处理之后
        // 服务器会把请求处理结果打包成一个消息再返回给浏览器,这个消息就称之为响应
        // 在操作中可以对这些响应进行一些设置和处理
        // 要处理响应,需要通过一个响应组件,响应组件的获取和请求组件的获取非常的相似
        $response = Yii::$app->response;

        // 设置状态码
        $response->statusCode = '200';

        // 设置 HTTP 头
        $response->headers->set('pragma', 'max-age=5');
        $response->headers->remove('pragma');
        $response->headers->add('pragma2', 'no-cache');
        // 跳转
        $response->headers->add('location', 'http://www.baidu.com');
        $this->redirect('http://www.baidu.com', 302);

        // 文件下载
        $response->headers->add('content-disposition', 'attachment; filename="a.jpg"');
        $response->sendFile('./robots.txt');
    }


    // 2.4 session 处理
    public function actionSession(){
        // 参考:https://www.yiichina.com/doc/guide/2.0/runtime-sessions-cookies

        // 需要获取 session 应用组件
        $session = Yii::$app->session;
        
        // 判断 session 是否开启
        $session->open();
        if($session->isActive){
             echo 'session is active';
        }

        // 设置一个 session
        $session->set('user', 'zhangsan');  // 当做对象
        $session['user2'] = 'lisi';         // 当做数组
        // 数组式访问接口,参考:https://www.php.net/manual/zh/class.arrayaccess.php
        // 实现了这个接口的类,它所产生的对象都可以当成数组来使用
        // session 组件就是继承了 ArrayAccess

        // 获取 session
        echo $session->get('user') . "<br>";
        echo $session->get('user2') . "<br>";

        // 删除 session
        $session->remove('user');
        unset($session['user2']);
        echo $session->get('user2') . "<br>";

    }


    // 2.5 cookie 处理
    public function actionCookie(){
        // 往响应中塞入 cookie 数据
        $cookies = Yii::$app->response->cookies;

        $cookie_data = [
            'name' => 'user', 
            'value' => 'zhangsan1'
        ];

        // 添加 cookie
        $cookies->add(new Cookie($cookie_data));

        // 删除 cookie
        $cookies->remove('user');

        // 从请求中获取 cookie
        $cookies = Yii::$app->request->cookies;
        echo $cookies->getValue('user', 'nodata');

    }


}

3. 视图;

3.1 视图文件的创建、数据传递、数据安全;

  • 实例:修改 basic/controllers/HelloController.php
<?php
// 新增方法
// 视图
public function actionView1(){
    // 3.1 视图文件创建:basic/views/hello/view1.php
    return $this->renderPartial('view1');

    // 3.2 数据传递
    $data = [
        'view_hello_str' => 'Hello God!',
        'view_hello_arr' => ['hahahaha!' , 'heiheiheihei!']
    ];
    return $this->renderPartial('view1', $data);

    // 3.3 数据安全
    $data['str'] = 'Hello Jerry!<script>alert(11)</script>';
    return $this->renderPartial('view1', $data);
}
  • 创建视图文件:basic/views/hello/view1.php
<!-- 3.11 视图文件创建: -->
<h1>Hello world!</h1>

<!-- 3.12 数据传递 -->
<h1><?=$view_hello_str;?></h1>
<h1><?=$view_hello_arr[1];?></h1>

<!-- 3.13 数据安全 -->
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<!-- script代码原样输出 -->
<h1><?=Html::encode($str);?></h1>
<!-- 过滤 script 代码 -->
<h1><?=HtmlPurifier::process($str);?></h1>
  • 访问 http://192.168.2.214/yii2/basic/web/index.php?r=hello/view1
    在这里插入图片描述

3.2 布局文件;

  • 创建视图布局文件:basic/views/layouts/common.php
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <h1>hello common</h1>
    
    <?=$content;?>

    <!-- 数据块 -->
    <h1>      
        <?php if(isset($this->blocks['block1'])): ?>
            <?=$this->blocks['block1'];?>
        <?php else: ?>
            <h1>hello common2</h1>
        <?php endif; ?>
    </h1>
</head>
</html>
  • 创建视图文件:basic/views/hello/about.php
<h2>about 页面:hello about</h2>

<!-- render() 方法传递参数 -->
<h3>参数传递:<?=$v_hello_str;?></h3>

<!-- 呈现 about2.php 的内容 -->
<?php echo '导入 about2 内容:' . $this->render('about2');?>

<!-- 数据块 -->
<?php $this->beginBlock('block1'); ?>
<h1>replace common2</h1>
<?php $this->endBlock(); ?>

  • 创建视图文件:basic/views/hello/about2.php
<h2>hello about2</h2>
  • 修改 basic/controllers/HelloController.php
<?php
// 添加如下方法

public $layout = 'common';

public function actionIndex(){
    // 3.21 布局文件
    // 1. 会把视图文件里面的内容放到一个 $content 的变量中
    // 2. 会把布局文件显示出来:common.php
    return $this->render('about', ['v_hello_str' => 'hello world']); // 显示 common + about
    return $this->renderPartial('about');   // 显示 about

}

4. 数据模型(活动记录);

4.1 数据模型之单表增删改查;

  • 修改数据库配置文件:basic/config/db.php
  • 创建活动记录:basic/models/Test.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

// 创建数据模型,对数据库 Test 进行操作
class Test extends ActiveRecord{

    // 设定表名(如果表名和类名不一致)
    public static function tableName(){
        return 'test';
    }


    public function rules(){
        // 验证器参考:https://www.yiichina.com/doc/guide/2.0/tutorial-core-validators
        return [
            ['id', 'integer'],
            ['title', 'string', 'length' => [0, 10]]
        ];
    }

}
  • 创建 basic/controllers/TestController.php
<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\Test;    // 加载 model

class TestController extends controller{

    public function actionIndex(){
        // 1. 单表查询
        // 查询数据,同时防止 SQL 注入
        $id = '1 or 1=1';
        $sql = "SELECT * FROM test WHERE id = :id";
        $results = Test::findBySql($sql, [':id' => $id])->all();
        // 返回一个数组,数组里面是 id = 1 的对象

        // id = 1;
        $results = Test::find()->where(['id' => 1])->all();

        // id > 0;
        $results = Test::find()->where(['>', 'id', 0])->all();

        // id >= 1 AND id <= 2
        $results = Test::find()->where(['between', 'id', 1, 2])->all();

        // title like "%title1%"
        $results = Test::find()->where(['like', 'title', 'title1'])->all();

        // 更多 where 方法参考:https://www.yiichina.com/doc/api/2.0/yii-db-queryinterface#where()-detail

        // 对象在内存里的占用量比数组高,所以要优化
        // 查询结果转化为数组
        $results = Test::find()->where(['like', 'title', 'title1'])->asArray()->all();

        // 批量查询
        foreach(Test::find()->asArray()->batch(1) as $tests){
            print_R($tests);
        }

		// 另: createCommand() 查询
		// $sql = "SELECT * FROM test WHERE id = " . $id;
       	// $results = Yii::$app->db->createCommand($sql)->queryAll();

        // 2. 单表删除:调用对象 delete() 方法
        $results = Test::find()->where(['id' => 1])->all();
        $results[0]->delete();

        // 删除条件
        Test::deleteAll('id>:id', [':id' => 0]);
        echo '<pre>';print_R($results);

        // 3. 单表添加数据
        $test = new Test;
        $test->title = 'title4';
        // 调用 model 设置的验证器
        $test->validate();
        if($test->hasErrors()){
            echo $test->getErrors();
            exit;
        }
        // $test->save();

        // 4. 单表数据修改
        $test = Test::find()->where(['id'=> 3])->one();
        //print_r($test);
        $test->title = 'title33';
        $test->save();

    }
}

4.2 关联查询;

  • 创建活动记录:basic/models/Customer.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Customer extends ActiveRecord{
}
  • 创建活动记录:basic/models/Order.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Order extends ActiveRecord{
}
  • 修改 basic/controllers/TestController.php
<?php
// 顾客表 customer:id,name
// 订单表 order:id,customer_id,price

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\Customer;
use app\models\Order;

class TestController extends controller{

    public function actionIndex(){
		
		// 1. 根据顾客查询订单信息
		// 返回的 $customer 为 Customer 类的实例,是一个对象
		$customer = Customer::find()->where(['name' => 'zhangsan'])->one();
		// customer_id 属于 order 表,id 属于 customer 表
		// hasMany() 方法:一个顾客有对个订单(一对多)
		$orders = $customer->hasMany('app\models\Order', ['customer_id' => 'id'])->asArray()->all();
		print_R($orders);
		
		// 总结:
		// 改进写法 1:hasMany(Order::className(), []);
		// 改进写法 2:
		// basic/models/Customer.php 追加方法:帮助顾客获取订单信息
	    // public function getOrders(){
	    //     return $this->hasMany(Order::className(), ['customer_id' => 'id'])->asArray();
	    // }
	    // 控制器修改:
	    $orders = $customer->getOrders();
	    // 或者以属性的方式获取订单数据,
	    // 但是没有在 customer 的活动记录中定义过 orders 属性
	    // 原因是在访问对象里不存在属性的时候,会调用 __get() 方法,
	    // 然后去调用 get+属性的名字() 方法,就是 getOrders() 方法,
	    // 然后在后面会再补上一个 all() 方法
	    $orders = $customer->orders; 


		// 2. 根据订单查询顾客的信息(类似上面代码)
		// basic/models/Order.php 追加方法:
	    // public function getCustomer(){
	    	// hasOne() 方法:因为一个订单只属于一个顾客(一对一)
	    //    return $this->hasOne(Customer::className(), ['id' => 'customer_id'])->asArray();
	    // }
	    // 控制器写如下代码
	    $order = Order::find()->where(['id' => 1])->one();
	    // 调用 getCustomer() 方法后,补上 one() 方法(因为之前调用 hasOne())
	    $customer = $order->customer;
	    print_R($customer);
    }
}
  • 关于关联查询的性能
<?php
// 1. 关联查询的结果会被缓存
$customer = Customer::find()->where(['name' => 'zhangsan'])->one();
$orders = $customer->orders; 	// 相当于执行了 SELECT * FROM order WHERE customer_id = 1;
// 如果第二次执行 $orders2 = $customer->orders; 的时候, 就不会去执行上面的 SELECT 语句
// 因为第一次执行的时候,已经去访问过数据库,把数据塞到 orders 里面
// 第二次执行,直接去 orders 里拿数据
// 避免缓存的方法:
// unset($customer->orders);

// 2. 关联查询的多次查询
$customers = Customer::find()->all();
foreach($customers as $customer){
	// 每次查询订单都会执行 SELECT 语句
	// 假设顾客有 100 个,就会执行 1+100 次 SELECT 语句,影响效率
	// 优化方法如下:
	// $customers = Customer::find()->with('orders')->all();
	// 相当于执行
	// SELECT * FROM customer 和 SELECT * FROM order WHERE customer_id in (...)
	// 查询出来的结果塞入每一个顾客的 orders 里
	// 之后 foreach() 的时候就不会执行 SELECT 语句了
	// 原来需要执行 1+100 次 SQL 语句,现在只要执行 1+1 次
	$orders = $customer->orders;
}
发布了119 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hualaoshuan/article/details/100921702