第十章 部署

在本章中,我们将会讨论如下小节:

  • 修改Yii目录的布局
  • 修改应用的webroot
  • 修改一个高级应用模板
  • 移动配置文件到单独的文件中
  • 使用多个配置来简化部署
  • 实施和执行cron任务
  • 维护模式
  • 部署工具

介绍

在本章中,我们将会讨论多个建议,他们对应用部署特别有用;当以小组开发一个应用,或者你只是希望你的开发环境更舒适,这些建议就可以派上用场。

修改Yii目录布局

默认情况下,我们有基础和高级Yii2应用框架,他们有不同的目录结构。但是这些框架不是教条,如果有需要我们可以自定义他们。

例如,我们可以将runtime文件夹移除项目。

准备

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

如何做…

修改runtime文件夹的位置

打开config/web.phpconfig/console.php,定义runtimePath参数:

  1. $config = [
  2. 'id' => 'basic',
  3. 'basePath' => dirname(__DIR__),
  4. 'bootstrap' => ['log'],
  5. 'runtimePath' => '/tmp/runtime',
  6. 'components' => [
  7. // ...
  8. ],
  9. ]

将runtime文件夹移到新的位置。

修改vendor文件夹的位置

  1. 打开config/web.phpconsole.php,定义vendorPath参数:
  1. $config = [
  2. 'id' => 'basic',
  3. 'basePath' => dirname(__DIR__),
  4. 'bootstrap' => ['log'],
  5. 'vendorPath' => dirname(__DIR__), '/../vendor,
  6. 'components' => [
  7. // ...
  8. ],
  9. ]
  1. vendor文件夹以及composer.jsoncomposer.lock文件移到新的位置。
  2. 打开web/index.phpyii文件,找到这些行:
  1. require(__DIR__ . '/../vendor/autoload.php');
  2. require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
  1. 修改包含的路径。

修改控制器的位置

  1. 重命名commands目录为console
  2. 修改命名空间app\commands\HelloControllerapp\console\HelloController
  3. 打开config/console.php,重新定义controllerNamespace参数:
  1. $config = [
  2. 'id' => 'basic-console',
  3. 'basePath' => dirname(__DIR__),
  4. 'bootstrap' => ['log'],
  5. 'controllerNamespace' => 'app\console,
  6. 'components' => [
  7. // ...
  8. ],
  9. ]

修改视图文件夹的位置

  1. 打开config/web.php,定义viewPath参数:
  1. $config = [
  2. 'id' => 'basic',
  3. 'basePath' => dirname(__DIR__),
  4. 'bootstrap' => ['log'],
  5. 'viewPath' => '@app/myviews',
  6. 'components' => [
  7. // ...
  8. ],
  9. ]
  1. 重命名views目录。

工作原理…

yii\base\Application::preInit方法中,我们的应用定义了basePathruntimePathvendorPath参数。

默认情况下,这些值分别指向了应用目录的根,runtimevendor路径。

例如,你可以重定义vendorPath,如果你希望将vendor目录分享给同样项目的一些实例。但是注意包的版本的兼容性。

yii\base\Application类继承了yii\base\Module,它包含了controllerNamespaceviewPath参数。第一个参数允许你修改应用和模块的基命名空间。如果你希望在同一个模块目录中,提供前端和后端控制器,这会非常有帮助。只修改controllers目录到前端和后端,或者创建子目录并配置你的前端和后端应用:

  1. return [
  2. 'id' => 'app-frontend',
  3. 'basePath' => dirname(__DIR__),
  4. 'controllerNamespace' => 'frontend\controllers',
  5. 'bootstrap' => ['log'],
  6. 'modules' => [
  7. 'user' => [
  8. 'my\user\Module',
  9. 'controllerNamespace' => 'my\user\controllers\frontend',
  10. ]
  11. ],
  12. // ...
  13. ]
  14. return [
  15. 'id' => 'app-backend',
  16. 'basePath' => dirname(__DIR__),
  17. 'controllerNamespace' => 'backend\controllers',
  18. 'bootstrap' => ['log'],
  19. 'modules' => [
  20. 'user' => [
  21. 'my\user\Module',
  22. 'controllerNamespace' => 'my\user\controllers\backend',
  23. ]
  24. ],
  25. // ...
  26. ]

参考

为了了解更多关于应用结构的信息,参考http://www.yiiframework.com/doc-2.0/guide-structure-applications.html

移动一个应用webroot

默认情况下,Yii2应用使用web文件夹存放你网站的入口脚本。但是共享的托管环境通常会对配置和目录结构有限制。你不能修改你网站的工作目录。大部分服务器只提供public_html目录存放你网站的入口脚本。

准备

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

如何做…

下边我们来讨论如何修改一个应用的webroot。

在root中存放文件

  1. 上传应用文件到你的托管服务器上
  2. 重命名web目录为public_html
  3. 检查网站是否工作正常

将文件放在一个子文件夹中

一个托管服务器用户目录可能包含其它文件和文件夹。遵照下面的步骤,你可以将文件移动到子文件夹中:

  1. 创建applicationpublic_html文件夹
  2. 将应用文件移动到application文件夹中
  3. application/web文件夹中的内容移动到public_html文件夹中
  4. 打开public_html/index.php文件,并修改包含的路径:
  1. require(__DIR__ . '/../application/vendor/autoload.php');
  2. require(__DIR__ . '/../application/vendor/yiisoft/yii2/Yii.php');

工作原理…

Yii2应用基于入口脚本的位置自动设置@web@webroot alias路径。因此我们可以很容易移动或者重命名一个web目录,并且不需要修改应用的配置。

对于yii2-app-advanced,你可以移动backendweb目录中的内容到一个子文件夹中,例如admin

  1. public_html
  2. index.php
  3. ...
  4. admin
  5. index.php
  6. ...
  7. backend
  8. common
  9. console
  10. frontend
  11. ...

参考

欲了解更多关于在一个共享托管环境上安装Yii,参考http://www.yiiframework.com/doc-2.0/guide-tutorial-shared-hosting.html

修改一个高级应用模板

默认情况下,Yii2的高级模板有consolefrontendbackend应用。但是,在你的特殊情况下,你可以重命名已有的一个,创建你自己的应用。例如,如果你在为你的网站开发API,你可以添加api应用。

准备

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

如何做…

  1. 在应用的根目录下,复制backend文件夹中的内容到一个新的api文件夹中。
  2. 打开api/config/main.php文件,修改controllerNamespace的值:
  1. return [
  2. 'id' => 'app-manager',
  3. 'basePath' => dirname(__DIR__),
  4. 'controllerNamespace' => 'api\controllers',
  5. // ....
  6. ]
  1. 打开api/assets/AppAsset.phpapi/controllers/SiteController.php,将命名空间从backend修改为api
  1. namespaces api\assets;
  2. namespaces api\controllers;
  1. 打开api/views/layouts/main.php文件,找到如下行:
  1. use backend\assets\AppAsset;

修改为:

  1. use api\assets\AppAsset;
  1. 打开common/config/bootstrap.php,为新的应用添加@api alias:
  1. <?php
  2. Yii::setAlias('@common', dirname(__DIR__));
  3. Yii::setAlias('@frontend', dirname(dirname(__DIR__)) .'/frontend');
  4. Yii::setAlias('@backend', dirname(dirname(__DIR__)) .'/backend');
  5. Yii::setAlias('@console', dirname(dirname(__DIR__)) .'/console');
  6. Yii::setAlias('@api', dirname(dirname(__DIR__)) . '/api);
  1. 打开environments目录,在devprod子文件夹中,拷贝backend文件夹为api
  2. 打开environments/index.php文件,为api应用添加如下行:
  1. return [
  2. 'Development' => [
  3. 'path' => 'dev',
  4. 'setWritable' => [
  5. 'backend/runtime',
  6. 'backend/web/assets',
  7. 'frontend/runtime',
  8. 'frontend/web/assets',
  9. 'api/runtime',
  10. 'api/web/assets',
  11. ],
  12. 'setExecutable' => [
  13. 'yii',
  14. 'tests/codeception/bin/yii',
  15. ],
  16. 'setCookieValidationKey' => [
  17. 'backend/config/main-local.php',
  18. 'frontend/config/main-local.php',
  19. 'api/config/main-local.php',
  20. ],
  21. ],
  22. 'Production' => [
  23. 'path' => 'prod',
  24. 'setWritable' => [
  25. 'backend/runtime',
  26. 'backend/web/assets',
  27. 'frontend/runtime',
  28. 'frontend/web/assets',
  29. 'api/runtime',
  30. 'api/web/assets',
  31. ],
  32. 'setExecutable' => [
  33. 'yii',
  34. ],
  35. 'setCookieValidationKey' => [
  36. 'backend/config/main-local.php',
  37. 'frontend/config/main-local.php',
  38. 'api/config/main-local.php',
  39. ],
  40. ],
  41. ];

现在,你就有了consolefrontendbackendapi应用。

工作原理…

高级应用模板,是一组带有自定义aliases的应用集合,例如@frontend@backend@common@console,以及相对应的命名空间。而对于Basic模板只有一个简单的@app alias。

如果有需要,你可以很容易的添加、删除或者重命名这些应用(以及他们的aliases和命名空间)。

参考

欲了解更多关于应用目录结构使用的信息,参考https://github.com/yiisoft/yii2-app-advanced/tree/master/docs/guide

将配置部分移到单独的文件中

在基础应用模板中,我们分离了web和console配置文件。通常情况下,我们可以在两个配置文件中设置一些应用组件。

而且,当我们开发一个大型应用时,我们可能面临一些不方便的问题。例如,如果我们需要调整一些设置,我们很可能需要在web应用配置和console应用配置中做多次重复修改。

准备

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

如何做…

  1. 打开config/web.php文件,添加urlManager部分到组件配置中:
  1. 'components' => [
  2. // ...
  3. 'db' => require(__DIR__ . '/db.php'),
  4. 'urlManager' => [
  5. 'class' => 'yii\web\UrlManager',
  6. 'enablePrettyUrl' => true,
  7. 'showScriptName' => false,
  8. 'rules' => [
  9. '' => 'site/index',
  10. '<_c:[\w\-]+>/<id:\d+>' => '<_c>/view',
  11. '<_c:[\w\-]+/<_a:[\w\-]+>>/<id:\d+>' => '<_c>/<_a>',
  12. '<_c:[\w\-]+>' => '<_c>/index',
  13. ],
  14. ],
  15. ],
  1. 创建config/urlRules.php文件,并将规则数组移到这里边:
  1. <?php
  2. return [
  3. '' => 'site/index',
  4. '<_c:[\w\-]+>/<id:\d+>' => '<_c>/view',
  5. '<_c:[\w\-]+/<_a:[\w\-]+>>/<id:\d+>' => '<_c>/<_a>',
  6. '<_c:[\w\-]+>' => '<_c>/index',
  7. ];
  1. 使用这个文件替换这个规则数组:
  1. 'urlManager' => [
  2. 'class' => 'yii\web\UrlManager',
  3. 'enablePrettyUrl' => true,
  4. 'showScriptName' => false,
  5. 'rules' => require(__DIR__ . '/urlRules.php'),
  6. ],

工作原理…

先前的技术依赖于这样的事实,Yii配置文件是原生的PHP文件,里边有一个数组:

  1. <?php return [...];

我们看require结构:

  1. 'rules' => require(__DIR__ . '/urlRules.php'),

当我们使用这个的时候,它会读取指定的文件,并且,如果文件中有一个return语句,它会返回一个值。

因此,将主配置文件中的一部分移到一个单独的文件中,需要创建一个新的文件,将配置的一部分移到return语句的后边,并在主配置文件中使用require

它分离了应用需要的一些常用配置部分(在我们的例子中,有web应用和console应用),我们可以使用require将他们移到一个单独的文件中。

参考

欲了解更多关于requireinclude语句,参考如下URL:

使用多个配置来简化部署

高级应用模板为它的每一个应用使用不同的配置文件。

  1. common
  2. config
  3. main.php
  4. main-local.php
  5. params.php
  6. params-local.php
  7. console
  8. config
  9. main.php
  10. main-local.php
  11. params.php
  12. params-local.php
  13. backend
  14. config
  15. main.php
  16. main-local.php
  17. params.php
  18. params-local.php
  19. frontend
  20. config
  21. main.php
  22. main-local.php
  23. params.php
  24. params-local.php

每一个入口web/index.php脚本合并自己配置文件的集合:

  1. $config = yii\helpers\ArrayHelper::merge(
  2. require(__DIR__ . '/../../common/config/main.php'),
  3. require(__DIR__ . '/../../common/config/main-local.php'),
  4. require(__DIR__ . '/../config/main.php'),
  5. require(__DIR__ . '/../config/main-local.php')
  6. );
  7. $application = new yii\web\Application($config);
  8. $application->run();

每一个config/main.php文件和并参数:

  1. <?php
  2. $params = array_merge(
  3. require(__DIR__ . '/../../common/config/params.php'),
  4. require(__DIR__ . '/../../common/config/params-local.php'),
  5. require(__DIR__ . '/params.php'),
  6. require(__DIR__ . '/params-local.php')
  7. );
  8. return [
  9. // ...
  10. 'params' => $params,
  11. ];

这个系统允许你配置应用中常用和特殊应用属性和组件。并且我们可以基于版本控制系统,存储缺省配置文件,并忽略所有的*-local.php文件。

所有的本地文件模板在environments文件夹中准备,当你在控制台中运行php init,并选择一个needle环境,这个初始脚本复制相应的文件,并将它们放在目标文件夹中。

但是基础应用模板不包含敏捷配置系统,只提供如下文件:

  1. config
  2. console.php
  3. web.php
  4. db.php
  5. params.php

尝试添加一个高级配置系统到yii2-app-basic应用模板中。

准备

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

如何做…

  1. 创建config/common.php文件:
  1. <?php
  2. $params = array_merge(
  3. require(__DIR__ . '/params.php'),
  4. require(__DIR__ . '/params-local.php')
  5. );
  6. return [
  7. 'basePath' => dirname(__DIR__),
  8. 'components' => [
  9. 'cache' => [
  10. 'class' => 'yii\caching\FileCache',
  11. ],
  12. 'mailer' => [
  13. 'class' => 'yii\swiftmailer\Mailer',
  14. ],
  15. 'db' => [],
  16. ],
  17. 'params' => $params,
  18. ];
  1. 创建config/common-local文件:
  1. <?php
  2. return [
  3. 'components' => [
  4. 'db' => [
  5. 'class' => 'yii\db\Connection',
  6. 'dsn' => 'mysql:host=localhost;dbname=yii2basic',
  7. 'username' => 'root',
  8. 'password' => '',
  9. 'charset' => 'utf8',
  10. ],
  11. 'mailer' => [
  12. 'useFileTransport' => true,
  13. ],
  14. ],
  15. ];
  1. 移除config/db.php文件:
  2. config/console.php移除重复的代码:
  1. <?php
  2. Yii::setAlias('@tests', dirname(__DIR__) . '/tests');
  3. return [
  4. 'id' => 'basic-console',
  5. 'bootstrap' => ['log', 'gii'],
  6. 'controllerNamespace' => 'app\commands',
  7. 'modules' => [
  8. 'gii' => 'yii\gii\Module',
  9. ],
  10. 'components' => [
  11. 'log' => [
  12. 'targets' => [
  13. [
  14. 'class' => 'yii\log\FileTarget',
  15. 'levels' => ['error', 'warning'],
  16. ],
  17. ],
  18. ],
  19. ],
  20. ];
  1. 创建一个带有空数组的文件config/console-local.php
  1. <?php return [];
  1. 修改config/web.php文件:
  1. $config = [
  2. 'id' => 'basic',
  3. 'bootstrap' => ['log'],
  4. 'components' => [
  5. 'user' => [
  6. 'identityClass' => 'app\models\User',
  7. 'enableAutoLogin' => true,
  8. ],
  9. 'errorHandler' => [
  10. 'errorAction' => 'site/error',
  11. ],
  12. 'log' => [
  13. 'traceLevel' => YII_DEBUG ? 3 : 0,
  14. 'targets' => [
  15. [
  16. 'class' => 'yii\log\FileTarget',
  17. 'levels' => ['error', 'warning'],
  18. ],
  19. ],
  20. ],
  21. ],
  22. ];
  23. if (YII_ENV_DEV) {
  24. // configuration adjustments for 'dev' environment
  25. $config['bootstrap'][] = 'debug';
  26. $config['modules']['debug'] = 'yii\debug\Module';
  27. $config['bootstrap'][] = 'gii';
  28. $config['modules']['gii'] = 'yii\gii\Module';
  29. }
  30. return $config;
  1. request配置移动到config/web-local.php文件中:
  1. <?php
  2. return [
  3. 'components' => [
  4. 'request' => [
  5. 'cookieValidationKey' => 'TRk9G1La5kvLFwqMEQTp6PmC1NHdjtkq',
  6. ],
  7. ],
  8. ];
  1. config/params.php文件中移除电子邮件ID:
  1. <?php
  2. return [
  3. 'adminEmail' => '',
  4. ];
  1. 粘贴ID到config/params-local.php文件:
  1. <?php
  2. return [
  3. 'adminEmail' => 'admin@example.com',
  4. ];
  1. tests/codeception/config/config.php移除dsn字符串:
  1. <?php
  2. /**
  3. * Application configuration shared by all test types
  4. */
  5. return [
  6. 'controllerMap' => [
  7. // ...
  8. ],
  9. 'components' => [
  10. 'db' => [
  11. 'dsn' => '',
  12. ],
  13. 'mailer' => [
  14. 'useFileTransport' => true,
  15. ],
  16. 'urlManager' => [
  17. 'showScriptName' => true,
  18. ],
  19. ],
  20. ];
  1. 将字符串放到一个新文件中tests/codeception/config/config-local.php
  1. <?php
  2. return [
  3. 'components' => [
  4. 'db' => [
  5. 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_tests',
  6. ],
  7. ],
  8. ];
  1. 在文件web/index.php中添加配置合并:
  1. $config = yii\helpers\ArrayHelper::merge(
  2. require(__DIR__ . '/../config/common.php'),
  3. require(__DIR__ . '/../config/common-local.php'),
  4. require(__DIR__ . '/../config/web.php'),
  5. require(__DIR__ . '/../config/web-local.php')
  6. );
  1. 添加配置合并到终端入口脚本,yii
  1. $config = yii\helpers\ArrayHelper::merge(
  2. require(__DIR__ . '/config/common.php'),
  3. require(__DIR__ . '/config/common-local.php'),
  4. require(__DIR__ . '/config/console.php'),
  5. require(__DIR__ . '/config/console-local.php')
  6. );
  1. 添加配置合并到tests/codeception/config中含有单元、功能、验收测试的测试配置中:
  1. return yii\helpers\ArrayHelper::merge(
  2. require(__DIR__ . '/../../../config/common.php'),
  3. require(__DIR__ . '/../../../config/common-local.php'),
  4. require(__DIR__ . '/../../../config/web.php'),
  5. require(__DIR__ . '/../../../config/web-local.php'),
  6. require(__DIR__ . '/config.php'),
  7. require(__DIR__ . '/config-local.php'),
  8. [
  9. // ...
  10. ]
  11. );
  1. 添加配置合并到测试环境控制台的入口脚本,tests/codeception/bin/yii
  1. $config = yii\helpers\ArrayHelper::merge(
  2. require(YII_APP_BASE_PATH . '/config/common.php'),
  3. require(YII_APP_BASE_PATH . '/config/common-local.php'),
  4. require(YII_APP_BASE_PATH . '/config/console.php'),
  5. require(YII_APP_BASE_PATH . '/config/console-local.php'),
  6. require(__DIR__ . '/../config/config.php'),
  7. require(__DIR__ . '/../config/config-local.php')
  8. );
  1. 结果是,你可以在你的配置文件夹下,获得如下内容:
  1. config
  2. common.php
  3. common-local.php
  4. console.php
  5. console-local.php
  6. web.php
  7. web-local.php
  8. params.php
  9. params-local.php
  1. 最终,你可以添加一个新的.gitignore文件到你的configtests/codeception/config文件夹下,所以你可以通过版本控制系统忽略本地配置文件:
  1. /*-local.php

工作原理…

你可以在config/common.php文件中存储常见的应用组件配置,同时也可以为web和控制台应用设置指定的配置。你可以将你的临时和安全配置数据放在*-local.php文件中。

此外,你可以从yii2-app-advanced中复制初始化shell脚本。

  1. 创建一个新的environments目录,并复制你的模板到里边:
  1. environments
  2. dev
  3. config
  4. common-local.php
  5. console-local.php
  6. web-local.php
  7. params-local.php
  8. web
  9. index.php
  10. index-test.php
  11. tests
  12. codeception
  13. config
  14. config.php
  15. config-local.php
  16. yii
  17. prod
  18. config
  19. common-local.php
  20. console-local.php
  21. web-local.php
  22. params-local.php
  23. web
  24. index.php
  25. yii
  1. 创建environments/index.php文件:
  1. <?php
  2. return [
  3. 'Development' => [
  4. 'path' => 'dev',
  5. 'setWritable' => [
  6. 'runtime',
  7. 'web/assets',
  8. ],
  9. 'setExecutable' => [
  10. 'yii',
  11. 'tests/codeception/bin/yii',
  12. ],
  13. 'setCookieValidationKey' => [
  14. 'config/web-local.php',
  15. ],
  16. ],
  17. 'Production' => [
  18. 'path' => 'prod',
  19. 'setWritable' => [
  20. 'runtime',
  21. 'web/assets',
  22. ],
  23. 'setExecutable' => [
  24. 'yii',
  25. ],
  26. 'setCookieValidationKey' => [
  27. 'config/web-local.php',
  28. ],
  29. ],
  30. ];
  1. 从你的composer.json中移除默认的Installer::postCreateProject配置:
  1. "extra": {
  2. "asset-installer-paths": {
  3. "npm-asset-library": "vendor/npm",
  4. "bower-asset-library": "vendor/bower"
  5. }
  6. }
  1. 从高级模板https://github.com/yiisoft/yii2-app-advanced拷贝initinit.bat脚本,你可以使用php init运行初始化过程,从repository中克隆项目。

参考

欲了解更多关于应用配置的信息,参考http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html

实施和执行cron任务

有时,一个应用需要一些后台任务,例如重新生成一个站点地图,或者刷新统计数据。一种常见的方式是使用cron任务。当使用Yii时,有一种方法可以使用一个命令做为任务来运行。

在这个小节中,我们将会看到如何同时实现。在我们的小节中,我们将会实现写当前时间戳到受保护文件夹中的timestamp.txt文件中。

准备

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

如何做…

运行Hello命令

尝试作为shell命令运行app\commands\HelloController::actionIndex

  1. <?php
  2. namespace app\commands;
  3. use yii\console\Controller;
  4. /**
  5. * This command echoes the first argument that you have entered.
  6. */
  7. class HelloController extends Controller
  8. {
  9. /**
  10. * This command echoes what you have entered as the message.
  11. * @param string $message the message to be echoed.
  12. */
  13. public function actionIndex($message = 'hello world')
  14. {
  15. echo $message . "\n";
  16. }
  17. }
  1. 在你的应用目录中,打开shell,并执行如下命令:
  1. php yii

此外,你也可以调用如下,确保shell可以工作:

  1. ./yii
  1. 输入如下命令,展示hello
  1. ./yii help hello
  1. 这个框架可以展示一些信息:
  1. DESCRIPTION
  2. This command echoes what you have entered as the message.
  3. USAGE
  4. yii hello [message] [...options...]
  5. - message: string (defaults to 'hello world')
  6. the message to be echoed.
  1. 运行缺省命令动作:
  1. ./yii hello

或者,运行指定的index动作:

  1. ./yii hello/index
  1. 你可以看到默认提示:
  1. Hello world
  1. 运行带有任何参数的命令,将会看到响应:
  1. ./yii hello 'Bond, James Bond'

创建你自己的命令

你也可以创建你自己的控制台控制器。例如,创建一个commands/CronController.php文件:

  1. <?php
  2. namespace app\commands;
  3. use yii\console\Controller;
  4. use yii\helpers\Console;
  5. use Yii;
  6. /**
  7. * Console crontab actions
  8. */
  9. class CronController extends Controller
  10. {
  11. /**
  12. * Regenerates timestamp
  13. */
  14. public function actionTimestamp()
  15. {
  16. file_put_contents(Yii::getAlias('@app/timestamp.txt'),
  17. time());
  18. $this->stdout('Done!', Console::FG_GREEN, Console::BOLD);
  19. $this->stdout(PHP_EOL);
  20. }
  21. }

这些完成以后,在控制台中运行命令:

  1. ./yii cron/timestamp

然后,检查响应文本,以及生成的新文件timestamp.txt

设置cron任务

在你的Linux服务器上创建/etc/cron.d/myapp,并添加如下内容,让我们的脚本在每天的半夜12点整运行一次:

  1. 0 0 * * * www-data /path/to/yii cron/timestamp >/dev/null

工作原理…

一个控制台命令被定义成了一个控制器类,这个类继承了yii\console\Controller。在控制器类中,你可以定义一个或多个动作,分别对应这个控制器的多个子命令。在每一个动作中,你可以为每一个指定的子命令实现恰当的任务。

在运行一个命令时,你需要指定控制器动作的路由。例如,migrate/create调用的子命令对应于MigrateController::actionCreate()动作函数。如果在执行时,提供的路由不包含一个动作ID,默认的动作将会被执行(作为一个web控制器)。

注意你的控制台控制器被放置在指定的文件夹中,位置由web/console.php中的controllerNamespace选项定义。

参考

维护模式

有时,需要微调一些应用的设置,或者从一个备份中恢复数据库。当处理这些任务时,你不希望允许每一个人使用应用,因为它可能会导致丢失最新的用户消息,或者展示应用实现的细节。

在这个小节中,我们将会看到如何向除了开发者以外的每一个人展示一条维护消息。

准备

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

如何做…

执行如下步骤:

  1. 首先,我们需要创建protected/controllers/MaintenanceController.php。我们按如下方式做:
  1. class MaintenanceController extends Controller
  2. {
  3. public function actionIndex()
  4. {
  5. $this->renderPartial("index");
  6. }
  7. }
  1. 然后,我们创建一个名为views/maintenance/index.php的视图,如下所示:
  1. <?php
  2. use yii\helpers\Html;
  3. ?>
  4. <!doctype html>
  5. <head>
  6. <meta charset="utf-8" />
  7. <title><?php echo
  8. Html::encode(Yii::$app->name)?>is under maintenance</title>
  9. </head>
  10. <body>
  11. <h1><?php echo CHtml::encode(Yii::$app->name)?>is under
  12. maintenance</h1>
  13. <p>We'll be back soon. If we aren't back for too
  14. long,please drop a message to <?php echo
  15. Yii::$app->params['adminEmail']?>.</p>
  16. <p>Meanwhile, it's a good time to get a cup of coffee,to read a book or to check email.</p>
  17. </body>
  1. 现在,我们需要添加一行代码到config/web.php,如下所示:
  1. $config = [
  2. 'catchAll' => file_exists(dirname(__DIR__).'/.maintenance') && !(isset($_COOKIE['secret']) && $_COOKIE['secret']=="password") ? ['maintenance/index'] : null,
  3. // …
  4. ]
  1. 现在为了前往维护模式,你需要在你的网站目录下创建一个名为.maintenance的文件。做完这一步后,你将会看到这个页面。

为了回到正常模式,你只需要删除这个文件。为了查看网站的维护模式,你可以创建一个名为secret的cookie,它的值是等于password

工作原理…

一个Yii web应用提供了一种方式,可以拦截所有可能的请求,并这它们重定向到一个指定的控制器动作上。你可以通过设置yii\web\Application::catchAll为一个包含应用路由的数组来做到它:

  1. 'catchAll' => ['maintenance/index'],

这个维护控制器本身并不特别;它只是渲染一个带有文字的视图。

我们需要一种简单的方式,来打开或者关闭维护模式。因为应用配置文件是一个特殊的PHP文件,我们可以使用一个简单的检查,查看制定文件是否存在,来做到这些。如下所示:

  1. file_exists(dirname(__DIR__) . '/.maintenance')

此外,我们检查cookie值来能覆盖维护模式。如下所示:

  1. !(isset($_COOKIE['secret']) && $_COOKIE['secret']=="password")

参考

为了了解更多关于在Yii应用中如何捕获所有请求,以及为production ready solution用于维护,参考http://www.yiiframework.com/doc-2.0/yii-webapplication.html#$catchAll-detail

部署工具

如果你为你的项目代码在使用一个版本控制系统,例如Git,将发布包推到远程库,你可以使用Git中的git pull命令来部署代码到你的生产服务器上,而不用手动上传文件。此外,你可以给自己写一个shell脚本来拉取新的库提交,更新vendors,应用migration等等。

但是,有很多工具可以用来做自动化部署。在本小节中,我们来看一些名叫Deployer的工具。

准备

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

如何做…

如果你有一个共享的远程库,你可以使用它用来部署源。

第一步:准备远程host

  1. 到你的远程host,安装Composer以及asset-plugin
  1. global require 'fxp/composer-asset-plugin:~1.1.1'
  1. 使用ssh-kengen生成SSH秘钥。
  2. 添加~/.ssh/id_rsa.pub文件内容到你的库设置页面中(部署SSH秘钥页面),例如Github、Bitbucket或者其它库存储。
  3. 尝试游动克隆的库:
  1. git clone git@github.com:user/repo.git
  1. 添加Github地址,以及已知的host列表(如果你的系统问你要的话)。

第二步:准备localhost

  1. 在本地全局安装deploy.phar
  1. sudo wget http://deployer.org/deployer.phar
  2. sudo mv deployer.phar /usr/local/bin/dep
  3. sudo chmod +x /usr/local/bin/dep
  1. 使用部署配置添加deploy.php文件:
  1. <?php
  2. require 'recipe/yii2-app-basic.php';
  3. set('shared_files', [
  4. 'config/db.php',
  5. 'config/params.php',
  6. 'web/index.php',
  7. 'yii',
  8. ]);
  9. server('prod', 'site.com', 22) // SSH access to remote server
  10. ->user('user')
  11. // ->password(password) // uncomment for authentication by
  12. password
  13. // ->identityFile() // uncomment for authentication by SSH key
  14. ->stage('production')
  15. ->env('deploy_path', '/var/www/project');
  16. set('repository', 'git@github.com:user/repo.git');
  1. 尝试准备远程项目目录结构:
  1. dep deploy:prepare prod

第三步:添加远程配置

  1. 打开服务器的/var/www/project目录。初始化后它有两个子目录:
  1. project
  2. ├── releases
  3. └── shared
  1. shared文件中创建带有私有配置的原始文件:
  1. project
  2. ├── releases
  3. └── shared
  4. ├── config
  5. ├── db.php
  6. └── params.php
  7. ├── web
  8. └── index.php
  9. └── yii

Deployer工具将会在每一个发布的子目录中通过软连接的方式包含这些文件:

share/config/db.php文件中指定你的私有配置:

  1. <?php
  2. return [
  3. 'class' => 'yii\db\Connection',
  4. dsn' => 'mysql:host=localhost;dbname=catalog',
  5. 'username' => 'root',
  6. 'password' => 'root',
  7. 'charset' => 'utf8',
  8. ];

此外,在share/config/params.php中指定它:

  1. <?php
  2. return [
  3. 'adminEmail' => 'admin@example.com',
  4. ];

设置文件share/web/index.php的内容:

  1. <?php
  2. defined('YII_DEBUG') or define('YII_DEBUG', false);
  3. defined('YII_ENV') or define('YII_ENV', 'prod');
  4. $dir = dirname($_SERVER['SCRIPT_FILENAME']);
  5. require($dir . '/../vendor/autoload.php');
  6. require($dir . '/../vendor/yiisoft/yii2/Yii.php');
  7. $config = require($dir . '/../config/web.php');
  8. (new yii\web\Application($config))->run();

此外,设置share/yii文件的内容:

  1. #!/usr/bin/env php
  2. <?php
  3. defined('YII_DEBUG') or define('YII_DEBUG', false);
  4. defined('YII_ENV') or define('YII_ENV', 'prod');
  5. $dir = dirname($_SERVER['SCRIPT_FILENAME']);
  6. require($dir . '/vendor/autoload.php');
  7. require($dir . '/vendor/yiisoft/yii2/Yii.php');
  8. $config = require($dir. '/config/console.php');
  9. $application = new yii\console\Application($config);
  10. $exitCode = $application->run();
  11. exit($exitCode);

注意:我们故意使用dirname($_SERVER['SCRIPT_FILENAME']),而不是原始的__DIR__常量,因为如果这个文件时软连接的话,__DIR__将会返回不正确的值。

注意:如果你使用yii2-app-advanced模板,你可以只重定义config/main-local.phpconfig/params-local.php文件(backend、frontend、console和common),因为web/index.phpyii将会自动通过init命令生成。

第四步:尝试部署

  1. 回到本地,使用deploy.php文件,并运行部署命令:
  1. dep deploy prod

第十章 部署 - 图1

  1. 如果成功,你将会看到部署报告:
  2. Deployer在你的远程服务器上,创建一个新的发布子目录,并从你的项目到共享的items,以及从current目录到当前发布添加软连接:
  1. project
  2. ├── current -> releases/20160412140556
  3. ├── releases
  4. └── 20160412140556
  5. ├── ...
  6. ├── runtime -> /../../shared/runtime
  7. ├── web
  8. ├── vendor
  9. ├── ...
  10. └── yii -> /../../shared/yii
  11. └── shared
  12. ├── config
  13. ├── db.php
  14. └── params.php
  15. ├── runtime
  16. ├── web
  17. └── index.php
  18. └── yii
  1. 所有这些完成以后,你必须在project/current/web目录中设置你的服务器DocumentRoot
  2. 如果在部署过程中,发生了一些错误,你可以回滚到先前的发布上:
  1. dep rollback prod

current目录将会定向到你先前的发布文件上。

工作原理…

大部分的部署工具都做了同样的任务:

  • 创建一个新的发布子目录
  • 克隆库文件
  • 从项目中制作软连接到共享的目录上,以及到本地配置文件上
  • 安装Composer包
  • 应用项目migration
  • 从服务器的DocumentRoot路径上切换软链接到当前发布目录上

Deployer工具为流行的框架都做了预定义。你可以扩展任何已有的例子,或者为你的特殊的例子制作新的。

参考