安装
检查当前 PHP 环境是否满足 Yii 最基本需求:
通过 Composer 进行安装
1 2 3 4 5
| // 安装基础应用模板 sudo composer create-project --prefer-dist yiisoft/yii2-app-basic yii // 安装高级应用模板 sudo composer create-project --prefer-dist yiisoft/yii2-app-advanced advanced
|
如果安装的过程中提示需要 Github Token,则进入以下网址生成 Token
1
| https://github.com/settings/tokens
|
Packages
1 2 3 4 5
| // AdminLte 后台响应模板 composer require dmstr/yii2-adminlte-asset "2.*" // Yii2 RBAC 的一套管理工具,实现了漂亮的界面和完整的权限管理功能 composer require mdmsoft/yii2-admin "2.x-dev"
|
控制器
操作
控制器由操作组成,它是执行终端用户请求的最基础的单元,一个控制器可有一个或多个操作。
操作分为独立操作和内联操作
内联操作容易创建,在无需重用的情况下优先使用; 独立操作相反,主要用于多个控制器重用, 或重构为扩展
路由
终端用户通过所谓的路由寻找到操作,路由是包含以下部分的字符串:
路由两种主要的格式
1 2 3 4 5
| ControllerID/ActionID ModuleID/ControllerID/ActionID
|
部署
在应用配置文件 web.php
配置默认控制器,当请求没有指定路由,该属性值作为路由使用:
1 2 3 4 5
| <?php [ 'defaultRoute' => 'main', ]
|
在应用配置文件 web.php
强制控制器 ID 和类名对应,通常用在使用第三方不能掌控类名的控制器上
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php [ 'controllerMap' => [ 'account' => 'app\controllers\UserController', 'article' => [ 'class' => 'app\controllers\PostController', 'enableCsrfValidation' => false, ], ], ]
|
操作结果
1 2
| // 返回响应对象,进行页面跳转 $this->redirect('http://example.com');
|
操作参数
1 2 3 4 5 6 7 8 9 10 11
| namespace app\controllers; use yii\web\Controller; class PostController extends Controller { public function actionView(int $id, $version = null) { // ... } }
|
操作参数会被不同的参数填入,如下所示:
默认操作
每个控制器都有一个由 yii\base\Controller::defaultAction 属性指定的默认操作,当路由只包含控制器ID, 会使用所请求的控制器的默认操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public $defaultAction = 'home'; public function actionHome() { return $this->render('home'); } }
|
模型
属性
模型通过属性来代表业务数据,每个属性像是模型的公有可访问属性,yii\base\Model::attributes() 指定模型所拥有的属性。
1 2 3 4 5 6 7
| <?php $model = new \app\models\ContactForm; $model->name = 'example'; echo $model->name;
|
模型实现了 ArrayAccess 和 ArrayIterator 接口,可以像数组单元项一样访问属性
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $model = new \app\models\ContactForm; $model['name'] = 'example'; echo $model['name']; foreach ($model as $name => $value) { echo "$name: $value\n"; }
|
属性标签
如果你不想用自动生成的标签, 可以覆盖 yii\base\Model::attributeLabels() 方法明确指定属性标签,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php namespace app\models; use yii\base\Model; class ContactForm extends Model { public $name; public $email; public $subject; public $body; public function attributeLabels() { return [ 'name' => 'Your name', 'email' => 'Your email address', 'subject' => 'Subject', 'body' => 'Content', ]; } }
|
场景
模型可能在多个场景下使用,例如 User 模块可能会在收集用户登录输入,也可能会在用户注册时使用。在不同的场景下,模型可能会使用不同的业务规则和逻辑,例如 email 属性在注册时强制要求有,但在登陆时不需要。模型设置场景如下:
1 2 3 4 5 6 7 8
| <?php $model = new User; $model->scenario = 'login'; $model = new User(['scenario' => 'login']);
|
场景设置活动属性和验证规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php namespace app\models; use yii\db\ActiveRecord; class User extends ActiveRecord { const SCENARIO_LOGIN = 'login'; const SCENARIO_REGISTER = 'register'; public function scenarios() { $scenarios = parent::scenarios(); $scenarios[self::SCENARIO_LOGIN] = ['username', 'password']; $scenarios[self::SCENARIO_REGISTER] = ['username', 'email', 'password']; return $scenarios; } public function rules() { return [ [['username', 'email', 'password'], 'required', 'on' => 'register'], [['username', 'password'], 'required', 'on' => 'login'], ]; } }
|
块赋值
块赋值只用一行代码将用户所有输入填充到一个模型,非常方便,它直接将输入数据对应填充到 yii\base\Model::attributes 属性。以下两段代码效果是相同的,都是将终端用户输入的表单数据赋值到 ContactForm 模型的属性,明显地前一段块赋值的代码比后一段代码简洁且不易出错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php $model = new \app\models\ContactForm; $model->attributes = \Yii::$app->request->post('ContactForm'); $model = new \app\models\ContactForm; $data = \Yii::$app->request->post('ContactForm', []); $model->name = isset($data['name']) ? $data['name'] : null; $model->email = isset($data['email']) ? $data['email'] : null; $model->subject = isset($data['subject']) ? $data['subject'] : null; $model->body = isset($data['body']) ? $data['body'] : null;
|
对象转换数组
1 2 3 4
| <?php $post = \app\models\Post::findOne(100); $array = $post->attributes;
|
字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?php $array = $model->toArray([], ['prettyName', 'fullAddress']); public function fields() { return [ 'id', 'email' => 'email_address', 'name' => function () { return $this->first_name . ' ' . $this->last_name; }, ]; } public function fields() { $fields = parent::fields(); unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); return $fields; }
|
视图
控制器渲染视图的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php yii\base\Controller::render(); yii\base\Controller::renderPartial(); yii\base\Controller::renderAjax(); yii\base\Controller::renderFile(); yii\base\Controller::renderContent();
|
小部件渲染视图的方法
1 2 3 4 5 6 7
| <?php yii\base\Widget::render() yii\base\Widget::renderFile()
|
视图中访问数据
1 2 3
| $this->render('视图名',['key'=>$value]); echo $this->key;
|
视图间共享数据
yii\base\View 视图组件提供yii\base\View::params参数 属性来让不同视图共享数据。
1
| $this->params['breadcrumbs'][] = 'About Us';
|
布局
布局的渲染过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php yii\base\View::beginPage(); yii\base\View::endPage(); yii\web\View::head(); yii\web\View::beginBody(); yii\web\View::endBody()
|
布局中访问数据
在布局中可访问两个预定义变量:$this 和 $content, 前者对应和普通视图类似的 yii\base\View 视图组件 后者包含调用 yii\base\Controller::render() 方法渲染内容视图的结果。
使用布局
- yii\base\Application::layout 管理所有控制器的布局
- yii\base\Controller::layout 覆盖总布局来控制单个控制器布局
嵌套布局
布局数据块
使用视图组件
设置页面标题
1 2 3 4 5
| <?php $this->title = 'My page title'; ?> <title><?= Html::encode($this->title) ?></title>
|
1 2 3
| <?php $this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']); ?>
|
注册链接标签
1 2 3 4 5 6 7 8
| <?php $this->registerLinkTag([ 'title' => 'Live News for Yii', 'rel' => 'alternate', 'type' => 'application/rss+xml', 'href' => 'http://www.yiiframework.com/rss.xml/', ]); ?>
|
视图事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php yii\base\View::EVENT_BEFORE_RENDER: yii\base\View::EVENT_AFTER_RENDER: yii\base\View::EVENT_BEGIN_PAGE: yii\base\View::EVENT_END_PAGE: yii\web\View::EVENT_BEGIN_BODY: yii\web\View::EVENT_END_BODY:
|
过滤器(中间件)
过滤器是控制器动作执行之前或之后执行的对象。例如访问控制过滤器可在动作执行之前来控制特殊终端用户是否有权限执行动作, 内容压缩过滤器可在动作执行之后发给终端用户之前压缩响应内容。
继承 yii\base\ActionFilter 类并覆盖 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法来创建动作的过滤器,前者在动作执行之前执行,后者在动作执行之后执行。 yii\base\ActionFilter::beforeAction() 返回值决定动作是否应该执行, 如果为 false,之后的过滤器和动作不会继续执行。
核心过滤器
- yii\filters\AccessControl
- AccessControl提供基于yii\filters\AccessControl::rules规则的访问控制
- yii\filters\auth\HttpBasicAuth
- 认证方法过滤器通过HTTP Basic Auth或OAuth 2 来认证一个用户, 认证方法过滤器类在 yii\filters\auth 命名空间下
- yii\filters\ContentNegotiator
- ContentNegotiator支持响应内容格式处理和语言处理
- yii\filters\HttpCache
- HttpCache利用Last-Modified 和 Etag HTTP头实现客户端缓存
- yii\filters\PageCache
- yii\filters\RateLimiter
- RateLimiter 根据 漏桶算法 来实现速率限制。 主要用在实现RESTful APIs, 更多关于该过滤器详情请参阅 Rate Limiting 一节
- yii\filters\VerbFilter
- VerbFilter检查请求动作的HTTP请求方式是否允许执行, 如果不允许,会抛出HTTP 405异常
- yii\filters\Cors
- 跨域资源共享 CORS 机制允许一个网页的许多资源(例如字体、JavaScript等) 这些资源可以通过其他域名访问获取
请求
请求基础用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?php $request = Yii::$app->request; $get = $request->get(); $id = $request->get('id'); $id = $request->get('id', 1); $post = $request->post(); $name = $request->post('name'); $name = $request->post('name', ''); $params = $request->bodyParams; $param = $request->getBodyParam('id'); if ($request->isAjax) { } if ($request->isGet) { } if ($request->isPost) { } if ($request->isPut) { }
|
请求 URLs
- yii\web\Request::url
- 返回 /admin/index.php/product?id=100, 此URL不包括host info部分。
- yii\web\Request::absoluteUrl
- yii\web\Request::hostInfo
- yii\web\Request::pathInfo
- 返回 /product, 这个是入口脚本之后,问号之前(查询字符串)的部分。
- yii\web\Request::queryString
- yii\web\Request::baseUrl
- 返回 /admin, host info之后, 入口脚本之前的部分。
- yii\web\Request::scriptUrl
- 返回 /admin/index.php, 没有path info和查询字符串部分。
- yii\web\Request::serverName
- 返回 example.com, URL中的host name。
- yii\web\Request::serverPort
HTTP 头
可以通过 yii\web\Request::headers 属性返回的 yii\web\HeaderCollection 获取HTTP头信息
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $headers = Yii::$app->request->headers; $accept = $headers->get('Accept'); if ($headers->has('User-Agent')) { }
|
客户端信息
可以通过 yii\web\Request::userHost
和 yii\web\Request::userIP
分别获取 host-name 和客户机的 IP 地址
1 2 3 4
| <?php $userHost = Yii::$app->request->userHost; $userIP = Yii::$app->request->userIP;
|
响应
状态码
构建响应时,最先应做的是标识请求是否成功处理的状态,可通过设置 yii\web\Response::statusCode 属性,该属性使用一个有效的 HTTP 状态码
1
| Yii::$app->response->statusCode = 200;
|
当错误处理器 捕获到一个异常,会从异常中提取状态码并赋值到响应, 对于上述的 yii\web\NotFoundHttpException 对应HTTP 404状态码, 以下为Yii预定义的HTTP异常
1
| throw new \yii\web\NotFoundHttpException;
|
以下为Yii预定义的HTTP异常:
- yii\web\BadRequestHttpException
- yii\web\ConflictHttpException
- yii\web\ForbiddenHttpException
- yii\web\GoneHttpException
- yii\web\MethodNotAllowedHttpException
- yii\web\NotAcceptableHttpException
- yii\web\NotFoundHttpException
- yii\web\ServerErrorHttpException
- yii\web\TooManyRequestsHttpException
- yii\web\UnauthorizedHttpException
- yii\web\UnsupportedMediaTypeHttpException
如果想抛出的异常不在如上列表中,可创建一个yii\web\HttpException异常, 带上状态码抛出,如下:
1
| throw new \yii\web\HttpException(402);
|
HTTP 头部
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $headers = Yii::$app->response->headers; $headers->add('Pragma', 'no-cache'); $headers->set('Pragma', 'no-cache'); $values = $headers->remove('Pragma');
|
响应主体
如果在发送给终端用户之前需要格式化,应设置 yii\web\Response::format 和 yii\web\Response::data 属性,yii\web\Response::format 属性指定 yii\web\Response::data 中数据格式化后的样式,例如:
1 2 3 4 5
| <?php $response = Yii::$app->response; $response->format = \yii\web\Response::FORMAT_JSON; $response->data = ['message' => 'hello world'];
|
Yii支持以下可直接使用的格式,每个实现了 yii\web\ResponseFormatterInterface 类, 可自定义这些格式器或通过配置 yii\web\Response::formatters 属性来增加格式器。
- yii\web\Response::FORMAT_HTML
- yii\web\Response::FORMAT_XML
- yii\web\Response::FORMAT_JSON
- yii\web\Response::FORMAT_JSONP
正规格式返回 Yii 的 HTTP 响应
1 2 3 4 5 6 7 8 9 10
| <?php return \Yii::createObject([ 'class' => 'yii\web\Response', 'format' => \yii\web\Response::FORMAT_JSON, 'data' => [ 'message' => 'hello world', 'code' => 100, ], ]);
|
浏览器跳转
1 2 3 4 5 6 7 8
| <?php public function actionOld() { return $this->redirect('http://example.com/new', 301); \Yii::$app->response->redirect('http://example.com/new', 301)->send(); }
|
发送文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php public function actionDownload() { return \Yii::$app->response->sendFile('path/to/file.txt'); \Yii::$app->response->sendFile('path/to/file.txt')->send(); } yii\web\Response::sendFile() yii\web\Response::sendContentAsFile() yii\web\Response::sendStreamAsFile()
|
Session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| <?php $session = Yii::$app->session; if ($session->isActive) { } $session->open(); $session->close(); $session->destroy(); $language = $session->get('language'); $language = $session['language']; $language = isset($_SESSION['language']) ? $_SESSION['language'] : null; $session->set('language', 'en-US'); $session['language'] = 'en-US'; $_SESSION['language'] = 'en-US'; $session->remove('language'); unset($session['language']); unset($_SESSION['language']); if ($session->has('language')) ... if (isset($session['language'])) ... if (isset($_SESSION['language'])) ... foreach ($session as $name => $value) ... foreach ($_SESSION as $name => $value) ... $_SESSION['captcha']['number'] = 5; $_SESSION['captcha']['lifetime'] = 3600; $captcha = $session['captcha']; $captcha['number'] = 5; $captcha['lifetime'] = 3600; $session['captcha'] = $captcha; $session['captcha'] = new \ArrayObject; ... $session['captcha']['number'] = 5; $session['captcha']['lifetime'] = 3600; $session['captcha.number'] = 5; $session['captcha.lifetime'] = 3600;
|
自定义 Session 存储
Yii提供以下session类实现不同的session存储方式:
- yii\web\DbSession
- yii\web\CacheSession
- 存储session数据到缓存中,缓存和配置中的缓存组件相关
- yii\redis\Session
- 存储session数据到以redis 作为存储媒介中
- yii\mongodb\Session
Flash 数据
Flash数据是一种特别的session数据,它一旦在某个请求中设置后, 只会在下次请求中有效,然后该数据就会自动被删除。 常用于实现只需显示给终端用户一次的信息, 如用户提交一个表单后显示确认信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php $session = Yii::$app->session; $session->setFlash('postDeleted', 'You have successfully deleted your post.'); echo $session->getFlash('postDeleted'); $result = $session->hasFlash('postDeleted'); $session->addFlash('alerts', 'You have successfully deleted your post.'); $session->addFlash('alerts', 'You have successfully added a new friend.'); $session->addFlash('alerts', 'You are promoted.'); $alerts = $session->getFlash('alerts');
|
Cookie
Yii使用 yii\web\Cookie对象来代表每个cookie,yii\web\Request 和 yii\web\Response 通过名为’cookies’的属性维护一个cookie集合, 前者的cookie 集合代表请求提交的cookies, 后者的cookie集合表示发送给用户的cookies。
读取 Cookies
当前请求的cookie信息可通过如下代码获取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php $cookies = Yii::$app->request->cookies; $language = $cookies->getValue('language', 'en'); if (($cookie = $cookies->get('language')) !== null) { $language = $cookie->value; } if (isset($cookies['language'])) { $language = $cookies['language']->value; } if ($cookies->has('language')) ... if (isset($cookies['language'])) ...
|
发送 Cookies
可使用如下代码发送 cookie 到终端用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php $cookies = Yii::$app->response->cookies; $cookies->add(new \yii\web\Cookie([ 'name' => 'language', 'value' => 'zh-CN', ])); $cookies->remove('language'); unset($cookies['language']);
|
分页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php use yii\data\Pagination; public function actionCountry() { $query = Country::find(); $pagination = new Pagination([ 'defaultPageSize' => 5, 'totalCount' => $query->count(), ]); $countries = $query->orderBy('name') ->offset($pagination->offset) ->limit($pagination->limit) ->all(); return $this->render('country', compact('countries', 'pagination')); }
|
应用主体和应用组件
应用属性
必要属性
- id:用来区分其他应用的唯一标识ID。
- basePath :指定该应用的根目录。
重要属性
- aliases:该属性允许你用一个数组定义多个别名。 数组的 key 为别名名称,值为对应的路径。
- bootstrap :这个属性很实用,它允许你用数组指定启动阶段 yii\base\Application::bootstrap() 需要运行的组件。
- catchAll:该属性仅网页应用支持。 它指定一个要处理所有用户请求的控制器方法。
- components:允许你注册多个在其他地方使用的应用组件。
- controllerMap:该属性允许你指定一个控制器 ID 到任意控制器类。
- controllerNamespace:该属性指定控制器类默认的命名空间,默认为 app\controllers。
- language:该属性指定应用展示给终端用户的语言, 默认为 en 标识英文
- modules :该属性指定应用所包含的模块。
前端资源
资源
资源包
定义资源包
表单
ActiveForm::begin(),ActiveForm::end() 分别用来渲染表单的开始和关闭标签
查询构建器