官方扩展

在本章中,我们将会讨论如下话题:

  • 身份认证客户端
  • SwitchMailer电子邮件库
  • Faker fixture数据生成器
  • Imagine库
  • MongoDB驱动
  • ElasticSearch引擎适配器
  • Gii代码生成器
  • Pjax JQuery插件
  • Redis数据库驱动

介绍

Yii2官方库为一些流行的库、数据库和搜索引擎提供了适配器。在本章中,我们将会向你展示如何在你的项目中安装和使用官方扩展。你也将会了解到如何写自己的扩展,并分享给其它开发者。

身份认证客户端

这个扩展为Yii2框架添加了OpenID、OAuth和OAuth2 consumers。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 使用如下命令安装扩展:
  1. composer require yiisoft/yii2-authclient

如何做…

  1. 打开你的Github应用页面https://github.com/settings/applications并添加自己的新应用:

官方扩展 - 图1

  1. 获取Client IDClient Secret

官方扩展 - 图2

  1. 配置你的web配置,并为authClientCollection组件设置相应的选项:
  1. 'components' => [
  2. // ...
  3. 'authClientCollection' => [
  4. 'class' => 'yii\authclient\Collection',
  5. 'clients' => [
  6. 'google' => [
  7. 'class' =>'yii\authclient\clients\GoogleOpenId'
  8. ],
  9. 'github' => [
  10. 'class' => 'yii\authclient\clients\GitHub',
  11. 'clientId' => '87f0784aae2ac48f78a',
  12. 'clientSecret' =>'fb5953a54dea4640f3a70d8abd96fbd25592ff18',
  13. ],
  14. // etc.
  15. ],
  16. ],
  17. ],
  1. 打开你的SiteController并添加auth独立动作和成功回调方法:
  1. use yii\authclient\ClientInterface;
  2. public function actions()
  3. {
  4. return [
  5. // ...
  6. 'auth' => [
  7. 'class' => 'yii\authclient\AuthAction',
  8. 'successCallback' => [$this, 'onAuthSuccess'],
  9. ],
  10. ];
  11. }
  12. public function onAuthSuccess(ClientInterface $client)
  13. {
  14. $attributes = $client->getUserAttributes();
  15. \yii\helpers\VarDumper::dump($attributes, 10, true);
  16. exit;
  17. }
  1. 打开views/site/login.php文件并插入AuthChoice小组件:
  1. <div class="site-login">
  2. <h1><?= Html::encode($this->title) ?></h1>
  3. <div class="panel panel-default">
  4. <div class="panel-body">
  5. <?= yii\authclient\widgets\AuthChoice::widget(['baseAuthUrl' => ['site/auth'], 'popupMode' => false,]) ?>
  6. </div>
  7. </div>
  8. <p>Please fill out the following fields to login:</p>
  9. ...
  10. </div>
  1. 你将会看到你配置的图标:

官方扩展 - 图3

  1. 为了使用Github provider进行验证:

官方扩展 - 图4

  1. 如果成功,你的回调将会展示验证的用户属性:
  1. [
  2. 'login' => 'Name'
  3. 'id' => 0000000
  4. 'avatar_url' =>'https://avatars.githubusercontent.com/u/0000000?v=3'
  5. 'gravatar_id' => ''
  6. 'url' => 'https://api.github.com/users/Name'
  7. 'html_url' => 'https://github.com/Name'
  8. //...
  9. 'name' => 'YourName'
  10. 'blog' =>site.com'
  11. 'email => mail@site.com'
  12. //...
  13. ]
  1. onAuthSuccess方法中创建你自己认证的代码,可参考例子https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/quick-start.md

工作原理…

这个扩展为你的应用提供了OpenID、OAuth和OAuth2认证客户端。

AuthChoice小组件在一个选择的服务网站上打开了一个身份认证页面,存储auth动作URL。身份认证以后,通过一个POST请求发送认证数据时,当前的服务将用户重定向回去。AuthAction收到这个请求,并调用相应的回调。

你可以使用任何存在的客户端或者创建自己的。

参考

SwitchMailer电子邮件库

许多web应用因为安全原因需要通过电子邮件发送通知和确认客户端动作。Yii2框架为已存在的SwitchMailer库提供了一个warpper,yiisoft/yii2-swiftmailer

准备

按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。

基础应用和高级应用都包含这个扩展。

如何做…

现在我们将会尝试从我们自己的应用中发送任何种类的电子邮件。

发送纯文本电子邮件

  1. config/console.php文件中设置mailer配置:
  1. 'components' => [
  2. // ...
  3. 'mailer' => [
  4. 'class' => 'yii\swiftmailer\Mailer',
  5. 'useFileTransport' => true,
  6. ],
  7. // ...
  8. ],
  1. 创建一个测试控制台控制器,MailController
  1. <?php
  2. namespace app\commands;
  3. use yii\console\Controller;
  4. use Yii;
  5. class MailController extends Controller
  6. {
  7. public function actionSend()
  8. {
  9. Yii::$app->mailer->compose()
  10. ->setTo('to@yii-book.app')
  11. ->setFrom(['from@yii-book.app' => Yii::$app->name])
  12. ->setSubject('My Test Message')
  13. ->setTextBody('My Text Body')
  14. ->send();
  15. }
  16. }
  1. 运行如下控制台命令:
  1. php yii main/send
  1. 检查你的runtime/mail目录。它应该包含你的邮件文件。

注意:邮件文件包含了特殊电子邮件源格式的信息,兼容任何邮件软件。你可以按纯文本文件打开。

  1. 设置useFileTransport参数为false,或者从配置中移除这个字符串:
  1. 'mailer' => [
  2. 'class' => 'yii\swiftmailer\Mailer',
  3. ],

然后将你真实的电子邮件ID放入setTo()方法:

  1. ->setTo('my@real-email.com')
  1. 再次运行控制台命令:
  1. php yii mail/send
  1. 检查你的inbox目录。

注意:默认情况下,SwiftMailer使用了一个标准的PHP函数,mail(),来发送邮件。请检查你的服务器是否正确设置,从而可以使用mail()函数发送邮件。

需要邮箱系统拒绝没有DKIM和SPF签名的邮件(例如使用mail()函数发送的邮件)或者将他们放到垃圾文件夹中。

发送HTML内容

  1. 检查你应用中的mail/layouts/html.php文件并使用如下内容添加mail/layouts/text.php文件:
  1. <?php
  2. /* @var $this \yii\web\View */
  3. /* @var $message \yii\mail\MessageInterface */
  4. /* @var $content string */
  5. ?>
  6. <?php $this->beginPage() ?>
  7. <?php $this->beginBody() ?>
  8. <?= $content ?>
  9. <?php $this->endBody() ?>
  10. <?php $this->endPage() ?>
  1. mail/message-html.php文件中创建你自己的视图:
  1. <?php
  2. use yii\helpers\Html;
  3. /* @var $this yii\web\View */
  4. /* @var $name string */
  5. ?>
  6. <p>Hello, <?= Html::encode($name) ?>!</p>
  7. Create a mail/message-text.php file with the same content, but without HTML tags:
  8. <?php
  9. use yii\helpers\Html;
  10. /* @var $this yii\web\View */
  11. /* @var $name string */
  12. ?>
  13. Hello, <?= Html::encode($name) ?>!
  1. 使用如下代码创建一个控制台控制器MailController
  1. <?php
  2. namespace app\commands;
  3. use yii\console\Controller;
  4. use Yii;
  5. class MailController extends Controller
  6. {
  7. public function actionSendHtml()
  8. {
  9. $name = 'John';
  10. Yii::$app->mailer->compose('message-html',['name' => $name])
  11. ->setTo('to@yii-book.app')
  12. ->setFrom(['from@yii-book.app' => Yii::$app->name])
  13. ->setSubject('My Test Message')
  14. ->send();
  15. }
  16. public function actionSendCombine()
  17. {
  18. $name = 'John';
  19. Yii::$app->mailer->compose(['html' => 'message-html', 'text' => 'message-text'], ['name' => $name,])
  20. ->setTo('to@yii-book.app')
  21. ->setFrom(['from@yii-book.app'
  22. => Yii::$app->name])
  23. ->setSubject('My Test Message')
  24. ->send();
  25. }
  26. }
  1. 运行如下控制台命令:
  1. php yii mail/send-html
  2. php yii mail/send-combine

使用SMTP传输

  1. mailer组件设置transport参数:
  1. 'mailer' => [
  2. 'class' => 'yii\swiftmailer\Mailer',
  3. 'transport' => [
  4. 'class' => 'Swift_SmtpTransport',
  5. 'host' => 'smtp.gmail.com',
  6. 'username' => 'username@gmail.com',
  7. 'password' => 'password',
  8. 'port' => '587',
  9. 'encryption' => 'tls',
  10. ],
  11. ],
  1. 书写并运行如下代码:
  1. Yii::$app->mailer->compose()
  2. ->setTo('to@yii-book.app')
  3. ->setFrom('username@gmail.com')
  4. ->setSubject('My Test Message')
  5. ->setTextBody('My Text Body')
  6. ->send();
  1. 检查你的Gmail收件箱。

注意:Gmail自动重写From字段为你的默认电子邮件ID,但其他电子邮件系统没有这么做。在传输配置中总是使用一个唯一电子邮件ID,并在setFrom()方法中为其它电子邮件系统中传递反垃圾邮件政策。

添加附件和图片

添加相关的方法来附加任何文件到你的邮件中:

  1. class MailController extends Controller
  2. {
  3. public function actionSendAttach()
  4. {
  5. Yii::$app->mailer->compose()
  6. ->setTo('to@yii-book.app')
  7. ->setFrom(['from@yii-book.app' => Yii::$app->name])
  8. ->setSubject('My Test Message')
  9. ->setTextBody('My Text Body')
  10. ->attach(Yii::getAlias('@app/README.md'))
  11. ->send();
  12. }
  13. }

或者在你的电子邮件视图文件中使用embed()方法来粘贴一个图片到电子邮件内容中:

  1. <img src="<?= $message->embed($imageFile); ?>">

它会自动添加图片文件附件并插入它的唯一标识。

工作原理…

wrapper实现了\yii\mail\MailerInterface。它的compose()方法返回了一个消息对象(\yii\mail\MessageInterface的一个实现)。

你可以使用setTextBody()setHtmlBody()手动设置纯文本和HTML内容,或者你可以将你的视图和视图参数传递给compose()方法。在这个例子中,mailer调用\yii\web\View::render()方法来渲染相应的内容。

useFileTransport参数在文件中存储电子邮件而不是真正的发送。它对于本地开发和应用测试非常有用。

参考

Fake fixture 数据生成器

fzaninotto/faker是一个PHP扩展,它可以生成需要种类的假数据:名称、电话、地址,以及随机字符串和数字等等。它可以帮助你生成需要随机记录,用于性能和逻辑测试。你可以通过写自己的formatters和generators来扩展你支持的类型集合。

在Yii2应用骨架中,yiisoft/yii2-faker wrapper被包含在composer.json文件的require-dev部分中,这部分用于测试代码(第十一章,测试)。这个wrapper为控制台应用和测试环境提供FixtureController控制台。

准备

按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。

如何做…

  1. 打开目录tests/codeception/templates并添加fixture模板文件users.txt
  1. <?php
  2. /**
  3. * @var $faker \Faker\Generator
  4. * @var $index integer
  5. */
  6. return [
  7. 'name' => $faker->firstName,
  8. 'phone' => $faker->phoneNumber,
  9. 'city' => $faker->city,
  10. 'about' => $faker->sentence(7, true),
  11. 'password' => Yii::$app->getSecurity()->generatePasswordHash('password_' . $index),
  12. 'auth_key' => Yii::$app->getSecurity()->generateRandomString(),
  13. ];
  1. 运行测试控制台yii命令:
  1. php tests/codeception/bin/yii fixture/generate users --count=2
  1. 确认migration生成。

  2. 检查tests/codeception/fixtures是否包含新的users.php文件,以及自动生成的数据:

  1. return [
  2. [
  3. 'name' => 'Isadore',
  4. 'phone' => '952.877.8545x190',
  5. 'city' => 'New Marvinburgh',
  6. 'about' => 'Ut quidem voluptatem itaque veniam voluptas dolores.',
  7. 'password' => '$2y$13$Fi3LOl/sKlomUH.DLgqBkOB/uCLmgCoPPL1KXiW0hffnkrdkjCzAC',
  8. 'auth_key' => '1m05hlgaAG8zfm0cyDyoRGMkbQ9W6hj1',
  9. ],
  10. [
  11. 'name' => 'Raleigh',
  12. 'phone' => '1-655-488-3585x699',
  13. 'city' => 'Reedstad',
  14. 'about' => 'Dolorem quae impedit tempore libero doloribus nobis dicta tempora facere.',
  15. 'password' => '$2y$13$U7Qte5Y1jVLrx/pnhwdwt.1uXDegGXuNVzEQyUsb65WkBtjyjUuYm',
  16. 'auth_key' => 'uWWJDgy5jNRk6KjqpxS5JuPv0OHearqE',
  17. ],
  18. ],

使用你自己的数据类型

  1. 使用你自定义生成逻辑创建你自己的provider:
  1. <?php
  2. namespace tests\codeception\faker\providers;
  3. use Faker\Provider\Base;
  4. class UserStatus extends Base
  5. {
  6. public function userStatus()
  7. {
  8. return $this->randomElement([0, 10, 20, 30]);
  9. }
  10. }
  1. /tests/codeception/config/config.php文件中添加provider到provider列表中:
  1. return [
  2. 'controllerMap' => [
  3. 'fixture' => [
  4. 'class' => 'yii\faker\FixtureController',
  5. 'fixtureDataPath' => '@tests/codeception/fixtures',
  6. 'templatePath' => '@tests/codeception/templates',
  7. 'namespace' => 'tests\codeception\fixtures',
  8. 'providers' => [
  9. 'tests\codeception\faker\providers\UserStatus',
  10. ],
  11. ],
  12. ],
  13. // ...
  14. ];
  1. 添加status字段到你的fixture模板文件中:
  1. <?php
  2. /**
  3. * @var $faker \Faker\Generator
  4. * @var $index integer
  5. */
  6. return [
  7. 'name' => $faker->firstName,
  8. 'status' => $faker->userStatus,
  9. ];
  1. 使用控制台命令生成fixture:
  1. php tests/codeception/bin/yii fixture/generate users --count=2
  1. 检查fixtures/users.php生成的代码是否包含你的自定义值:
  1. return [
  2. [
  3. 'name' => 'Christelle',
  4. 'status' => 30,
  5. ],
  6. [
  7. 'name' => 'Theo',
  8. 'status' => 10,
  9. ],
  10. ];

工作原理…

yii2-faker扩展包含一个控制台生成器(它使用你的模板来生成fixture数据文件),并给了你一个准备好的原始Faker对象实例。你可以生成所有或者指定的fixtures,并且你可以在控制台参数中传递自定义数值或者语言。

注意

如果你的测试使用这些fixtures的话,小心已存在的测试文件,因为自动生成会完全覆盖旧数据。

参考

Imagine库

Imagine是用于操作图片的OOP库。它可以让你在GD、Imagic和Gmagic PHP扩展的帮助下,对多种格式的图片进行裁剪、缩放以及执行其它操作。Yii2-Imagine是队这个库的轻量静态封装。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 使用如下命令安装扩展:
  1. composer require yiisoft/yii2-imagine

如何做…

在你的项目中,你可以以两种方式使用扩展:

  • 作为工厂使用
  • 使用内部方法

作为工厂使用

你可以使用Imagine库类的一个实例:

  1. $imagine = new Imagine\Gd\Imagine();
  2. // or
  3. $imagine = new Imagine\Imagick\Imagine();
  4. // or
  5. $imagine = new Imagine\Gmagick\Imagine();

但是,这依赖于你系统中已存在的PHP扩展。你可以使用getImagine()方法:

  1. $imagine = \yii\imagine\Image::getImagine();

使用内部方法

你可以使用corp()thumbnail()watermark()text()frame()方法用于常见的高级操作:

  1. <?php
  2. use yii\imagine\Image;
  3. Image::crop('path/to/image.jpg', 100, 100, ManipulatorInterface::THUMBNAIL_OUTBOUND)
  4. ->save('path/to/destination/image.jpg', ['quality' => 90]);

\yii\imagine\BaseImage的源代码中查看所有支持的方法以及细节。

工作原理…

这个扩展准备用户数据,创建一个原始的Imagine对象,并调用对应的方法。所有的方法都会返回原始的iamge对象。你可以继续操作这个图像,或者将结果保存到你的磁盘上。

参考

MongoDB驱动

这个扩展为Yii2框架提供了MongoDB的集成,允许你通过ActiveRecord风格的模型使用MongoDB collection的记录。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. https://docs.mongodb.org/manual/installation/使用正确的安装过程为你的系统安装MongoDB。
  3. 安装php5-mongo PHP扩展
  4. 使用如下命令安装组件:
  1. composer require yiisoft/yii2-mongodb

如何做…

  1. 首先,创建新的MongoDB数据库。在mongo-clientshell中运行它,并输入数据库的名称:
  1. mongo
  2. > use mydatabase
  1. 添加连接信息到你的components配置部分:
  1. return [
  2. // ...
  3. 'components' => [
  4. // ...
  5. 'mongodb' => [
  6. 'class' => '\yii\mongodb\Connection',
  7. 'dsn' => 'mongodb://localhost:27017/mydatabase',
  8. ],
  9. ],
  10. ];
  1. 添加新的控制台控制器到你的控制台配置文件中:
  1. return [
  2. // ...
  3. 'controllerMap' => [
  4. 'mongodb-migrate' => 'yii\mongodb\console\controllers\MigrateController'
  5. ],
  6. ];
  1. 使用shell命令创建新的migration:
  1. php yii mongodb-migrate/create create_customer_collection
  1. 输入如下代码到up()down()方法中:
  1. <?php
  2. use yii\mongodb\Migration;
  3. class m160201_102003_create_customer_collection extends Migration
  4. {
  5. public function up()
  6. {
  7. $this->createCollection('customer');
  8. }
  9. public function down()
  10. {
  11. $this->dropCollection('customer');
  12. }
  13. }
  1. 应用migration:
  1. php yii mongodb-migrate/up
  1. 添加MongoDB调试板,以及模型生成器到你的配置中:
  1. <?php
  2. if (YII_ENV_DEV) {
  3. // configuration adjustments for 'dev' environment
  4. $config['bootstrap'][] = 'debug';
  5. $config['modules']['debug'] = [
  6. 'class' => 'yii\debug\Module',
  7. 'panels' => [
  8. 'mongodb' => [
  9. 'class' => 'yii\mongodb\debug\MongoDbPanel',
  10. ],
  11. ],
  12. ];
  13. $config['bootstrap'][] = 'gii';
  14. $config['modules']['gii'] = [
  15. 'class' => 'yii\gii\Module',
  16. 'generators' => [
  17. 'mongoDbModel' => [
  18. 'class' => 'yii\mongodb\gii\model\Generator'
  19. ]
  20. ],
  21. ];
  22. }
  1. 运行Gii生成器:

官方扩展 - 图5

  1. 启动新的MongoDB Model Generator来为你的collection生成新的模型:

官方扩展 - 图6

  1. 点击预览生成按钮
  2. 检查你是否有了新的模型app\models\Customer
  1. <?php
  2. namespace app\models;
  3. use Yii;
  4. use yii\mongodb\ActiveRecord;
  5. /**
  6. * This is the model class for collection "customer".
  7. *
  8. * @property \MongoId|string $_id
  9. * @property mixed $name
  10. * @property mixed $email
  11. * @property mixed $address
  12. * @property mixed $status
  13. */
  14. class Customer extends ActiveRecord
  15. {
  16. public static function collectionName()
  17. {
  18. return 'customer';
  19. }
  20. public function attributes()
  21. {
  22. return [
  23. '_id',
  24. 'name',
  25. 'email',
  26. 'address',
  27. 'status',
  28. ];
  29. }
  30. public function rules()
  31. {
  32. return [
  33. [['name', 'email', 'address', 'status'], 'safe']
  34. ];
  35. }
  36. public function attributeLabels()
  37. {
  38. return [
  39. '_id' => 'ID',
  40. 'name' => 'Name',
  41. 'email' => 'Email',
  42. 'address' => 'Address',
  43. 'status' => 'Status',
  44. ];
  45. }
  46. }
  1. 再次运行Gii,并生成CRUD:

官方扩展 - 图7

  1. 检查你已经生成了CustomerController类,并运行新的customer管理页面:

官方扩展 - 图8

  1. 你可以创建、更新和删除你的顾客数据。
  2. 在页面的底部查看调试板:

官方扩展 - 图9

  1. 你可以看到整个MongoDB查询数以及完整的执行时间。点击计数badge和查询指示:

官方扩展 - 图10

基本用法

你可以通过\yii\mongodb\Collection实例访问数据库和集合:

  1. $collection = Yii::$app->mongodb->getCollection('customer');
  2. $collection->insert(['name' => 'John Smith', 'status' => 1]);

为了执行find查询,你应该使用\yii\mongodb\Query

  1. use yii\mongodb\Query;
  2. $query = new Query;
  3. // compose the query
  4. $query->select(['name', 'status'])
  5. ->from('customer')
  6. ->limit(10);
  7. // execute the query
  8. $rows = $query->all();

注意:MongoDB文档id(“_id”字段)不是数量,是一个\MongoId类的实例。你不需要关心从整形或者字符串$id转换为\MongoId,因为查询创建会自动转换:

  1. $query = new \yii\mongodb\Query;
  2. $row = $query->from('item')
  3. ->where(['_id' => $id]) // implicit typecast to \MongoId
  4. ->one();

为了获取真实的Mongo ID字符串,你应该将\MongoId做类型转为字符串:

  1. $query = new Query;
  2. $row = $query->from('customer')->one();
  3. var_dump($row['_id']); // outputs:
  4. "object(MongoId)"var_dump((string)$row['_id']);

工作原理…

这个扩展的QueryActiveQuery以及ActiveRecord继承了yii\db\QueryInterfaceyii\db\BaseActiveRecord。因此他们和框架内置的QueryActiveQuery以及ActiveRecord是兼容的。

你可以为你的模型使用yii\mongodb\ActiveRecordyii\mongodb\ActiveQuery构建器来获取你的模型,并在你的data provider使用他们:

  1. use yii\data\ActiveDataProvider;
  2. use app\models\Customer;
  3. $provider = new ActiveDataProvider([
  4. 'query' => Customer::find(),
  5. 'pagination' => [
  6. 'pageSize' => 10,
  7. ]
  8. ]);

关于如何使用Yii ActiveRecord的一般信息,请参考第三章,ActiveRecord,模型和数据库

参考

ElasticSearch引擎适配器

这个扩展是一个类ActiveRecord的包装,将ElasticSearch全文搜索引擎集成到Yii2框架中。它允许你使用任何模型数据,并使用ActiveRecord模式在ElasticSearch数据集中获取和存储数据。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. https://www.elastic.co/downloads/elasticsearch安装ElasticSearch服务。
  3. 使用如下命令安装扩展:
  1. composer require yiisoft/yii2-elasticsearch

如何做…

在你的应用配置中设置新的ElasticSearch连接。

  1. return [
  2. //....
  3. 'components' => [
  4. 'elasticsearch' => [
  5. 'class' => 'yii\elasticsearch\Connection',
  6. 'nodes' => [
  7. ['http_address' => '127.0.0.1:9200'],
  8. // configure more hosts if you have a cluster
  9. ],
  10. ],
  11. ]
  12. ];

使用查询类

你可以使用Query类,用于在任何数据集中进行低级查询:

  1. use \yii\elasticsearch\Query;
  2. $query = new Query;
  3. $query->fields('id, name')
  4. ->from('myindex', 'users')
  5. ->limit(10);
  6. $query->search();

你也可以创建一个命令,直接运行:

  1. $command = $query->createCommand();
  2. $rows = $command->search();

使用ActiveRecord

使用ActiveRecord是一种常用的方法来访问你的数据。只需要扩展yii\elasticsearch\ActiveRecord类,并继承attributes()方法,来定义你文档的属性。

例如,你可以写Customer模型:

  1. class Buyer extends \yii\elasticsearch\ActiveRecord
  2. {
  3. public function attributes()
  4. {
  5. return ['id', 'name', 'address', 'registration_date'];
  6. }
  7. public function getOrders()
  8. {
  9. return $this->hasMany(Order::className(), ['buyer_id' => 'id'])->orderBy('id');
  10. }
  11. }

然后写Order模型:

  1. class Order extends \yii\elasticsearch\ActiveRecord
  2. {
  3. public function attributes()
  4. {
  5. return ['id', 'user_id', 'date'];
  6. }
  7. public function getBuyer()
  8. {
  9. return $this->hasOne(Customer::className(), ['id' => 'buyer_id']);
  10. }
  11. }

你可以复写index()type()来定义这个记录的index和type。

下边是一个使用例子:

  1. $buyer = new Buyer();
  2. $buyer>primaryKey = 1; // it equivalent to $customer->id = 1;
  3. $buyer>name = 'test';
  4. $buyer>save();
  5. $buyer = Buyer::get(1);
  6. $buyer = Buyer::mget([1,2,3]);
  7. $buyer = Buyer::find()->where(['name' => 'test'])->one();

你可以使用Query DSL做指定查询:

  1. $result = Article::find()->query(["match" => ["title" => "yii"]])->all();
  2. $query = Article::find()->query([
  3. "fuzzy_like_this" => [
  4. "fields" => ["title", "description"],
  5. "like_text" => "Some search text",
  6. "max_query_terms" => 12
  7. ]
  8. ]);
  9. $query->all();

你可以添加facets到你的搜索中:

  1. $query->addStatisticalFacet('click_stats', ['field' => 'visit_count']);
  2. $query->search();

使用ElasticSearch调试板

这个扩展包含了一个特殊的面板,用于yii2-debug模块。它允许你查看所有执行的查询。你可以在你的配置文件中包含这个面板:

  1. if (YII_ENV_DEV) {
  2. // configuration adjustments for 'dev' environment
  3. $config['bootstrap'][] = 'debug';
  4. $config['modules']['debug'] = [
  5. 'class' => 'yii\debug\Module',
  6. 'panels' => [
  7. 'elasticsearch' => [
  8. 'class' => 'yii\elasticsearch\DebugPanel',
  9. ],
  10. ],
  11. ];
  12. $config['bootstrap'][] = 'gii';
  13. $config['modules']['gii'] = 'yii\gii\Module';
  14. }

工作原理…

这个扩展提供了一个低级命令构建器,以及高级ActiveRecord实现,用于从ElasticSearch中查询记录。

这个扩展的ActiveRecord的用法和数据库的ActiveRecord非常类似,后者可以参考第三章,ActiveRecord,模型和数据库,此外还有join()groupBy()having()union()ActiveQuery操作。

注意ElasticSearch默认限制返回的记录数量,如果你使用via()选项来使用关系,注意这个限制。

参考

Gii代码生成器

这个扩展为Yii2应用提供了一个基于web的代码生成器,名叫Gii。你可以使用Gii来快速生成模型、表单、模块、CRUD等等。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 使用shell命令创建一个新的migration:
  1. php yii migrate/create create_customer_table
  1. 将如下代码放在up()down()两个方法中:
  1. use yii\db\Schema;
  2. use yii\db\Migration;
  3. class m160201_154207_create_customer_table extends Migration
  4. {
  5. public function up()
  6. {
  7. $tableOptions = null;
  8. if ($this->db->driverName === 'mysql') {
  9. $tableOptions =
  10. 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
  11. }
  12. $this->createTable('{{%customer}}', [
  13. 'id' => Schema::TYPE_PK,
  14. 'name' => Schema::TYPE_STRING . ' NOT NULL',
  15. 'email' => Schema::TYPE_STRING . ' NOT NULL',
  16. 'address' => Schema::TYPE_STRING,
  17. ], $tableOptions);
  18. }
  19. public function down()
  20. {
  21. $this->dropTable('{{%customer}}');
  22. }
  23. }
  1. 应用这个migration:
  1. php yii migrate/up

如何做…

在你的项目中,你可以以两种方式使用这个扩展:

  • 使用GUI
  • 使用CLI

使用GUI

  1. 检查你的web配置是否包含如下代码:
  1. if (YII_ENV_DEV) {
  2. $config['bootstrap'][] = 'gii';
  3. $config['modules']['gii'] = [
  4. 'class' => 'yii\gii\Module',
  5. ];
  6. }
  1. 你的web/index.php文件将会定义开发环境:
  1. defined('YII_ENV') or define('YII_ENV', 'dev');

先前的配置表明,如果是在开发环境中,这个应用将会包含一个名叫gii的模块,它的类是yii\gii\Module

默认情况下,这个模块允许IP地址为127.0.0.1访问。如果你在其它地方访问,将你的IP地址添加到allowedIPs属性中:

  1. $config['modules']['gii'] = [
  2. 'class' => 'yii\gii\Module',
  3. allowedIPs = ['127.0.0.1', '::1', '192.168.0.*'],
  4. ];
  1. 访问http://localhost/index.php?r=gii

官方扩展 - 图11

  1. 点击模型生成器按钮,在表单中填写你的标明和模型名:

官方扩展 - 图12

  1. 点击预览按钮。你能看到文件列表:

官方扩展 - 图13

  1. 如果想重新生成已经存在的文件,Gii将会用黄色标记:

官方扩展 - 图14

  1. 在这种情况下,你可以查看存在的文件和新文件之间的区别,如果需要就覆盖目标。
  2. 做完这些以后,点击生成按钮:

官方扩展 - 图15

  1. 检查新的类,\app\models\Customer
  2. CRUD是一个缩写,代表四种常用的任务:创建、读取、更新和删除。为了使用Gii创建CRUD,选择CRUD生成器部分。指定你的模型类,并输出其它字段:

官方扩展 - 图16

  1. 生成新的条目:

官方扩展 - 图17

  1. 然后,尝试打开新的控制器:

官方扩展 - 图18

  1. 你将会看到一个数据grid,展示了数据表中的消费者数据。尝试创建一个新的条目,你可以对这个表格进行排序或者在列头上输入过滤条件进行过滤。

使用CLI

Gii为代码生成提供了一个控制台控制器:

  1. 检查你的控制台配置是否包含Gii模块设置:
  1. return [
  2. // ...
  3. 'modules' => [
  4. 'gii' => 'yii\gii\Module',
  5. ],
  6. // ...
  7. ];
  1. 运行任何shell命令获取帮助:
  1. php yii help gii
  2. php yii help gii/model
  1. 输出如下命令启动一个模型生成过程:
  1. php yii gii/model --tableName=customer --modelClass=Customer --useTablePrefix=1
  1. 检查新的类\app\models\Customer
  2. 为你的模型生成CRUD:
  1. php yii gii/crud --modelClass=app\\models\\Customer \
  2. --searchModelClass=app\\models\\CustomerSearch \
  3. --controllerClass=app\\controllers\\CustomerController

工作原理…

Gii允许你生成一些标准代码元素,而不是手动输入。它提供了基于web的和控制台接口来使用每一个生成器。

参考

Pjax JQuery插件

Pjax是一个小组件,它集成了pjax jQuery插件。所有被这个小组件包括的内容,可以通过AJAX加载,而不需要刷新当前页面,这个小组件在你浏览器的地址栏中也使用HTML5 History API来修改当前URL。

准备

按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。

如何做…

在下面的例子中,你可以看到如何通过yii\grid\GridView小组件来使用Pjax:

  1. <?php
  2. use yii\widgets\Pjax;
  3. ?>
  4. <?php Pjax::begin(); ?>
  5. <?= GridView::widget([...]); ?>
  6. <?php Pjax::end(); ?>

只需要在Pjax::begin()Pjax::end()包裹任何代码片段。

这将会渲染出如下HTML代码:

  1. <div id="w1">
  2. <div id="w2" class="grid-view">...</div>
  3. </div>
  4. <script type="text/javascript">jQuery(document).ready(function () {
  5. jQuery(document).pjax("#w1 a", "#w1", {...});
  6. });</script>

所有被包裹的内容,包括翻页和排序链接,都会通过AJAX重新加载。

指定一个自定义ID

Pjax从AJAX请求获取页面内容,然后使用相同的ID释放它自己的DOM元素。你可以通过渲染没有布局的内容加速页面渲染性能,尤其是对于Pjax请求:

  1. public function actionIndex()
  2. {
  3. $dataProvider = ...;
  4. if (Yii::$app->request->isPjax) {
  5. return $this->renderPartial('_items', [
  6. 'dataProvider' => $dataProvider,
  7. ]);
  8. } else {
  9. return $this->render('index', [
  10. 'dataProvider' => $dataProvider,
  11. ]);
  12. }
  13. }

默认情况下,yii\base\Widget::getId方法会自增标识符,因此小组件在任何页面上,都会有一个自增的属性:

  1. <nav id="w0">...</nav> // Main navigation
  2. <ul id="w1">...</ul> // Breadcrumbs widget
  3. <div id="w2">...</div> // Pjax widget

使用renderPartial()或者renderAjax()方法进行渲染,不需要渲染布局,你自己的页面将会有一个带有数字0的小组件:

  1. <div id="w0">...</div> // Pjax widget

在这个结果中,你自己的小组件将不会在下次请求中通过w2选择器找到自己的block。

但是,Pjax将会在Ajax响应中通过w2选择器找到相同的block。在这个结果中,你自己的小组件将不会在下次请求中通过w2选择器找到这个block。

因此,你必须为你的Pjax小组件手动指定一个唯一标识符,来避免冲突:

  1. <?php Pjax::begin(['id' => 'countries']) ?>
  2. <?= GridView::widget([...]); ?>
  3. <?php Pjax::end() ?>

使用ActiveForm

默认情况下,Pjax只和被包裹的快交互。如果你想和ActiveForm小组件一起使用它,你必须使用表单的data-pjax选项:

  1. <?php
  2. use \yii\widgets\Pjax
  3. use \yii\widgets\ActiveForm;
  4. <?php yii\widgets\Pjax::begin(['id' => 'my-block']) ?>
  5. <?php $form = ActiveForm::begin(['options' => [
  6. 'data-pjax' => true,
  7. ]]); ?>
  8. <?= $form->field($model, 'name') ?>
  9. <?php ActiveForm::end(); ?>
  10. <?php Pjax::end(); ?>

它会为表单的提交事件添加相应的监听器。

你也可以使用Pjax小组件的$formSelector选项,来指定什么表单提交将会出发pjax

使用客户端脚本

你可以订阅容器事件:

  1. <?php $this->registerJs('
  2. $("#my-block").on("pjax:complete", function() {
  3. alert('Pjax is completed');
  4. });
  5. '); ?>

或者,你可以通过使用它的选择器,手动重新加载容器:

  1. <?php $this->registerJs('
  2. $("#my-button").on("click", function() {
  3. $.pjax.reload({container:"#my-block"});
  4. });
  5. '); ?>

工作原理…

Pjax是任何代表片段的一个容器。它订阅片段中所有链接的点击事件,并替换整个页面,使用Ajax调用重新加载它。我们可以使用data-pjax属性用于被包裹的表单,以及任何表单提交将会触发一个Ajax请求。

这个小组件将会加载和更新on-the-fly小组件内容,而不需要再加布局资源(JS,CSS)。

你可以配置小组件的$linkSelector来指定什么链接将会触发Pjax,以及配置$formSelector来指定什么样的表单提交将会触发Pjax。

你可以为容器中一个指定的链接禁用Pjax,方法是给这个链接添加一个data-pjax="0"属性。

参考

Redis数据库驱动

这个扩展允许你在基于Yii2框架的任何项目中使用Redis键值对存储。它包含了CacheSession两个存储句柄,以及这个扩展,它实现了ActiveRecord模式,用于访问Redis数据库记录。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 安装存储http://redis.io
  3. 使用如下命令安装migration:
  1. composer require yiisoft/yii2-redis

如何做…

首先,在你的配置文件中配置Connection类:

  1. return [
  2. //....
  3. 'components' => [
  4. 'redis' => [
  5. 'class' => 'yii\redis\Connection',
  6. 'hostname' => 'localhost',
  7. 'port' => 6379,
  8. 'database' => 0,
  9. ],
  10. ]
  11. ];

直接使用方法

对于Redis命令的低级使用,你可以使用这个连接组件的executeCommand()方法:

  1. Yii::$app->redis->executeCommand('hmset', ['test_collection', 'key1', 'val1', 'key2', 'val2']);

你也可以使用简化的快捷方式,而不是调用executeCommand

  1. Yii::$app->redis->hmset('test_collection', 'key1', 'val1', 'key2', 'val2')

使用ActiveRecord

欲通过ActiveRecord模式访问Redis记录,你的记录类需要从yii\redis\ActiveRecord基类扩展,并实现attributes()方法:

  1. class Customer extends \yii\redis\ActiveRecord
  2. {
  3. public function attributes()
  4. {
  5. return ['id', 'name', 'address', 'registration_date'];
  6. }
  7. public function getOrders()
  8. {
  9. return $this->hasMany(Order::className(), ['customer_id' => 'id']);
  10. }
  11. }

任何模型的主键可以通过primaryKey()方法定义,如果没有指定,它的缺省值是id。如果你没有通过primaryKey()手动执行这个主键的话,它需要被放置在属性列表中。

下面是一个使用例子:

  1. $customer = new Customer();
  2. $customer->name = 'test';
  3. $customer->save();
  4. echo $customer->id; // id will automatically be incremented if not set explicitly
  5. // find by query
  6. $customer = Customer::find()->where(['name' => 'test'])->one();

工作原理…

这个扩展提供了一个Connection组件,用于对Redis存储记录的低级访问。

你也可以使用一个类ActiveRecord的模型,它带有一些方法的集合(where()limit()offset()indexBy())。其它方法不存在,因为Redis不支持SQL查询。

在Redis中没有表,所以你不能定义via relation via a junction table name。你只需要通过hasMany关系定义一个多对多的关系。

关于Yii的ActiveRecord的一般信息,参考第三章,ActiveRecord,模型和数据库

参考