文档章节

【翻译】Yii2 第2章 用Yii2创建自定义应用(第1部分)

zcgly
 zcgly
发布于 2015/09/20 23:43
字数 4615
阅读 893
收藏 2

在这一章里,我们将看到Yii2怎样帮助我们创建web应用。示例虽然很简单,但整个过程都符合软件工程思想。我们将完成应用开发的每一个步骤,并且每一步都会根据权威书籍中的最佳实践来进行:

  • 创建领域模型:这本书解释了领域驱动,Tackling Complexity in the Heart of Software, Eric Evans, Addison-Wesley Professional

  • 设置测试装置:我们遵照验收测试驱动实践,Growing Object-oriented Software, Guided by Tests, Steve Freeman and Nat Pryce, Addison-Wesley Professional

  • 设置开发流水线

    • 持续交付:Reliable Software Releases through Build, Test, and Deployment Automation, Jez Humble and David Farley, Addison-Wesley Professional

    • 持续集成:Improving Software Quality and Reducing Risk, Paul M. Duvall, Steve Matyas, and Andrew Glover, Addison-Wesley Professional

  • 红-绿-重构 开发循环:深度解释,请参考下列图书:

    • Clean Code:A Handbook of Agile Software Craftsmanship, Robert Martin, Prentice Hall

    • Test-Driven Development by Example, Kent Beck, Addison-Wesley Professional

  • 部署和手工测试:这符合持续交付,并且这些步骤也是必不可少的

保持专注。

设计阶段

贯穿整本书,在使用示例应用的时候,我们需要注意实际需求。在这个小节,我们将定义整个示例的场景。

任务

假设我们有一个小的商业应用,要对外提供一些服务。我们有一些客户,他们有一些数目巨大的账目记录在纸面上,用商业卡片管理非常不方便。因此,我们需要用自动化的方式把这些档案管理起来。

首先,我们需要一些增删查改(CRUD)界面进行记录管理,为客户展示最核心的属性。

很明显,我们的业务和客户可能会随着时间的推移而增长、变化,因此我们的应用也应该随之变化。在一开始,我们应该为可能的变化做好准备。

本着吃自己狗食的原则(译注:微软在1998年提出),既然自己开发的系统自己要使用,那这个系统最好保证是高质量的。

领域模型设计

很明显,我们将在应用中处理客户模型。在“customer”和“client”两个词中,我们觉得“customer”更为贴切。

一个客户(customer)是一个人,他至少具有姓名、地址、电子邮件,以及电话号码等属性。我们为客户提供一个服务,按小时统计,并根据合约支付这段时间产生的费用。这就是我们在第一次迭代设计中打算解决的问题。

我们假设每位客户都是单个的人,因此我们不用处理公司,有多个联系人的情况。姓名是一个复杂的结构,如果我们深入细节,有敬语、职务、昵称、中间名、姓等属性需要考虑。但在这个应用中,我们真正感兴趣的并不是客户的姓名,我们只是需要用姓名来识别一个客户。因此,我们将简单的使用一个文本行来表示,允许我们按任何格式来写入姓名。地址同样可以是一个复杂的结构,这次我们打算用一个结构来描述,而不再是一个简单的文本行。这是因为我们需要通过地址来实现以下两件事情。

  • 进行一些统计,例如在一个特定的城市,有多少个客户

  • 遵照不同的文化背景,正确地生成邮寄地址

因此,我们决定采用下面的结构:

  • 用途(例如:账单地址、购物地址、家庭地址、工作地址)

  • 国家

  • 州,国家下级的区域,比如美国

  • 城市

  • 街道

  • 建筑物

  • 部门/办公室

  • 收件人姓名

  • 邮政编码

我们应该注意到,一个地址能代表一个部门、邮箱、办公室、组织中的雇员,甚至是整个建筑。同样,一个客户也可以多个地址。

电话这个实体具有以下属性:

  • 用途(个人或工作)

  • 号码

一个客户可能有几个电话号码,通过用途字段区分。

除了姓名、地址、电话这个实体之外,我们的职员需要通过一种途径对客户进行自由的描述。这里我们简化了姓名属性。然后,我们加入生日、电子邮件属性,当然,一个客户可以有多个电子邮件。

我们先停一下。

我们现在能画出客户模型的完整聚合图了,如下图所示:

根据Eric Evans的《领域驱动设计》,客户是一个实体(Entity),也就是说,是一个状态可以改变的对象,因此我们要关心它在整个系统中的一致性。而其它部分是值对象(Value Object),意味着初始创建后,状态不会改变的对象,因此他们是可以完全互换的。

为了简化处理,我们不再详细描述商业上是如何处理客户的,我们不打算在这本书中涵盖它。无论如何,让我们把注意力回到我们为客户提供的一系列服务中来,维护这些记录将会很有用。我们将在后面的章节用到这个模型

目标特性

让我们来执行一个特定的任务。考虑到有的人给我们打电话(假如我们已经识别出号码),我们想获取呼入者的所有详细信息。在应用中,如果这个号码没有找到关联的人,那我们就知道他并不是我们的客户。如果找到关联人,我们至少可以直接用他的姓名跟他打招呼,这是很好的客户服务。

我们应该理解数据库查询,我们需要一个途径可以插入数据,有可能还需要编辑和删除它。因此,我们第一次开发迭代的特性包含以下内容:

  • 将客户信息插入数据库

  • 在数据库中编辑客户信息

  • 从数据库中删除客户信息

  • 根据电话号码从数据库中查询客户信息

构造通用的数据库查询并不是我们的目标,我们仅仅需要根据一个电话号码进行查询。

让我们开始吧。

初始准备

一直到本书结束,我们将在接下来的章节中讨论同一个应用,因此准备工作只需要做这一次。

下载示例代码:Packt的网站上可以下载你购买过图书的示例代码,地址是http://www.packtpub.com,如果你已经购买了这本书,请访问http://www.packtpub.com/support,注册后会直接将文件通过电子邮件发送给你。

配置项目管理

我们要开发的应用,从本质上说,是一个客户关系管理系统(CRM)。因此,我们首先创建一个名为 crmapp 的目录。

请注意,正本书中,通过命令行调用的示例,都假定你当前目录为crmapp目录。

Yii2推荐使用包管理器Composer进行安装,因此我们就来使用这个工具。你可以去阅读Composer的完整文档了解详细的细节,我们这里准备了一个简短的说明:

  • 所有通过Composer安装的包,都会存放在项目路径下,一个名为vendor的子目录中。

  • 与Composer相关的数据,所有依赖和其它信息,都保存在名为composer.json的清单文件中,位于项目根目录下。只要你在这个文件中申明了依赖,你就能在任何时候安全的删除vendor目录,并在调用php composer.phar install 或 php composer.phar update时完全重建。

Composer的文档描述了一个获取composer.phar的方法:

curl -sS https://getcomposer.org/installer | php

当然,如果你的PATH路径中如果没有CURL,你也可以直接去Composer的官方网站 https://getcomposer.org/  直接下载PHAR文件。(译注:如果是windows环境,推荐直接下载一个Composer的安装包,安装完成后,添加到PATH目录,以后就可以直接使用composer <command>进行调用,而不使用php composer.phar <command>,更为方便)。

我们准备好后,就可以按下面的格式执行命令了:

php composer.phar <command>

假定你会使用版本控制系统来管理代码,本书的代码使用Git(http://git-scm.com/)进行管理。

准备阶段快速指引:

mkdir crmapp
cd crmapp
curl -sS  | php
git init
配置测试工具

正如我们在本章的开始部分所说,我们将遵从测试优先的开发实践来进行验收测试。这样做的原因如下:

  • 我们想检查应用是否能正常工作,又不想使用乏味的人工测试

  • 我们还没有深度的单元测试需求,因为我们目前主要的工作只是把已经存在的组件装配在一起,因此,通过对UI进行端对端的验收测试最为简单可行

如果我们关心用户特性请求的实现情况,我们需要一些形式的验收测试。

Yii2内置支持Codeception测试框架,官方站点是 http://codeception.com/。我们不会在本身中直接使用它,但是 yii2-codeception(https://github.com/yiisoft/yii2-codeception)提供了一些辅助类,来集成到Yii框架中。

让我们来申明,我们需要在项目中使用 Codeception,执行下面的命令:

php composer.phar require "codeception/codeception:*"

稍等片刻,直到Composer执行完成。

目前,composer.json文件的内容是:

{
    "require": {
        "codeception/codeception": "*",
    }
}

命令 php composer.phar require <包名:版本> 只是一个辅助方法,将require块插入到清单文件中,并调用update命令。

当然,我也需要将Yii2同样作为依赖加入,但在这之前,让我们先干一件事情。

正如我们看到的,Codeception已经存在于 ./vendor/bin/codecept 目录中了。这个路径敲起来比较长,在POSIX兼容的shell中,比如bash,允许我们使用下面的方式来进行简化:

alias cept="./vender/bin/codecept"

这样做更好。在本章余下的部分,我们都假定你已经执行了上面这条命令。

Codeception是一个复杂的系统,所以我们需要依赖它自己内建的命令。没必要深入Codeception的内部细节,我们只是简单实用就可以了。执行下面的命令:

cept bootstrap

这将为Codeception生成一个tests目录,并进行配置。

现在,让我们创建一个傻瓜型的验收测试,用以检查我们的测试工具。

cept generate:cept acceptance SmokeTest

这个命令将生成 SmokeTestCept.php,位于 tests/acceptance 目录下。当我们打开这个文件,我们将看到如下代码(根据Codeception版本,代码可能略有不同):

$I = new AcceptanceTester($scenario);
$I->wantTo('perform actions and see result');

AcceptanceTester是一个可以模仿浏览器后的真实用户,对应用进行测试的类。Codeception同时也提供 CodeGuy 用以进行单元测试,提供 TestGuy 进行功能测试,在后面我们才会用到。

当我们调用 AcceptanceTester.wantTo("do something")时,我们只是为下面的测试行为创建了一个标题(用双引号括起来的)。

让我们修改一下代码,加入冒烟测试的功能,对我们的首页进行测试:

$I = new AcceptanceTester($scenario);
$I->wantTo('See that landing page is up');
$I->amOnPage('/');
$I->see('Our CRM');

当我们访问应用首页的时候,我们希望看到有 Our CRM 这一行。假设我们应用中已经有那么一个标题存在了。

现在运行测试:

cept run

我们会看到失败的信息,因为我们还没有设置web服务器,处理 / 请求。这样,到了该我们写一些生产代码来通过这个测试的时候了。然而,到目前而言,我们需要的还不是生产代码,我们的基础服务都还没有建立起来。我们需要先建立发布机制。

配置发布流水线

我们已经说过,编写的web验收测试会模拟真实用户,在浏览器中打开应用,通过可视的UI进行交互。因此,我们现在需要做的是将应用整个部署到我们能运行验收测试的机器。

提示:最常见的情况是,你决定开发和测试使用同一台机器,这是错误的!别这么干。

很可能你的工作平台和应用最终要运行的机器不是一样的。参照已有数十年历史的工业生产,这已经是一个持续不断的问题了。当应用的生命周期预计是数年时,在不同环境的生产服务器上测试你的应用,你会面临相似的集成问题。当然,这不是将打包好的软件卖给用户,这还是要简便一些。在我们的案例中,我们假定一个单一的发布点只有一个固定web应用,因此,简便性不是问题,可重复性测试才是问题。

最终,你的验收测试将会包含以下几个步骤:

  • 将应用发布到测试服务器

  • 在你的机器上运行验收测试

当然,你可以在测试服务器上运行验收测试。要这样做,你只需要用localhost这个本地回路网络接口来配置测试就可以了。然而,还是需要你安装一些与测试服务器不相干的软件。例如,如果你想全栈运行,使用Selenium进行浏览器内测试,你可能需要安装一个web浏览器,Java运行时,虚拟帧缓冲软件,并且这又需要安装它们各自相关的软件,这样做非常费劲。最有效的做法是使用你自己的桌面环境,来运行web验收测试。

提示:这当然不是在谈论单元测试和功能测试。单元测试由于只与本身有关,应在有原始代码的地方执行,完全不需要部署。功能测试,应在部署后的应用上测试,因为需要测试经过配置后的最终应用以及交互的正确性。

在任何案例中,理想化的方案是,你只需一个就像deploy这样的简单命令,就能完成以下功能:

  1. 访问并启动目标机器(特别是,当它是一个虚拟机实例的时候)

  2. 确保除应用外,环境是有效的

  3. 将当前代码拷贝到目标机器

  4. 在目标机器上,配置刚拷贝过去的代码的环境

  5. 启动应用

你应该能在命令行中输入deploy,并敲击Enter键,完成上述的所有步骤。正如Martin Fowler在他的《持续集成》(http://martinfowler.com/articles/continuousIntegration.html)中所说,这对你来说小菜一碟。理想情况下,部署行为应该在你启动验收测试工具时自动完成。

在本书中,我们只关心最后两步。因为我们开发的是PHP应用,只要目标机器上的web服务器在运行,”启动应用“这一步就算已经完成了。

本书仅关注web应用开发,并不涉及系统管理,那是系统管理员的事。然而,在附录A,”使用Vagrant进行部署设置“,我们准备介绍一个基于虚拟机的部署,同样也很容易在任何桌面工作站上实现。你可以不必需要另外一台物理机,就仍然能模拟现实世界的部署过程。如果你别无选择,强烈推荐你读读。实际上,采用那里的描述,本身所有的代码都准备好了。让我们假设你有一个准备好的环境和deploy命令,为了简化,我们同时假定每次运行验收测试前,部署都会自动运行。部署的结果可以从你的机器通过一个简单的URL进行访问,验收测试工具会将它作为应用的入口点。

现在,让我们到Codeception的跟验收测试相关的配置部分,打开文件 tests/acceptance.suite.yml,把入口URL加入到 modules.config.PhpBrowser.url 词条中。假定你没修改过这个文件,文件内容看起来应该像这样:

class_name: AcceptanceTester
modules:
    enabled:
        - PhpBrowser
        - WebHelper
    config:
        PhpBrowser:
            url: 'http://YOUR.APPLICATION.URL'

(译注:本机acceptance.suite.yml文件格式跟上面不同,不存在config项,url直接放在enabled的PhpBrowser下)

举例来说,如果你用Apache的基于IP的虚拟主机技术来配置目标机器(https://httpd.apache.org/docs/2.2/vhosts/ip-based.html),modules.config.PhpBrowser.url 的值就应该像这样:http://127.0.0.01:8000。

当我们改变配置,我们需要重建Codeception,执行下面的命令:

cept build

不要忘记 cept 这个别名是我们自己创建的。实际运行的是 ./vendor/bin/codecept 文件。

如果你现在运行测试:

cept run

你应该可以看到如下输出:

你会看到Codeception在 / 路由上显示了一些东西,但还不是我们期望的。根据使用的Apache版本不同,可以是404错误或者403错误。如果你使用的其它Web服务器,可能显示的另外的错误信息。无论如何,问题的根源很简单,这就是我们需要在外界可访问的web目录中,加入index.php文件。

创建一个可见的web应用入口

我们先做一个约定,可以被外部访问到的目录只有一个,命名为web,放在项目的根目录下。例如,如果你的web服务器是Apache,应该把DocumentRoot指向web目录。

因此,将下面的内容放在web目录的index.php文件中:

Our CRM

是的,就是7个字符的文本文件。毕竟,这就是我们的验收测试期望的所有内容了,正确吗?

让我们来运行测试:

cept run

我们得到了如下输出:

现在,我们需要在项目中使用Yii2了,描述我们功能需求的最佳方法,就是写一个完整的端到端测试。

下一节        上一节














































© 著作权归作者所有

zcgly

zcgly

粉丝 7
博文 6
码字总数 13340
作品 0
成都
技术主管
私信 提问
加载中

评论(1)

zcgly
zcgly 博主
由于整个第2章会超出OSC的博客字数限制,因此将其拆分成节,这是第1节
【翻译】Yii2 第1章 开始

让我们看看,怎样以最小的代价使用Yii2创建一个站点。目的是学习使用Yii2应用模版的安装过程,并开始体验模版里提供的一系列特性。 一个基本应用 开始使用Yii2最基本和直接的方式,是使用Yii...

zcgly
2015/09/15
967
7
【翻译】Yii2 第2章 用Yii2创建自定义应用(第2部分)

将Yii框架引入我们的应用 现在,我们拥有了可以工作的全套基础设施,让我们回到在设计阶段时定义的第一个特性,让我们先为它写一个验收测试。 第一个端到端测试 端到端验收测试的要点就是,我...

zcgly
2015/09/29
454
1
Yii 2.0开发一个仿京东商城平台

第1章 课程简介 介绍了课程内容、背景和案例展示。 第2章 项目的准备工作 介绍了如何使用PHP依赖管理工具Composer安装Yii2框架,模拟配置真实企业开发项目运行环境和编辑器。 第3章 项目前台...

15543595340
2018/05/19
0
0
yii2源码分析之执行基本流程

用yii2框架用了将近2年,一直都没有去看过它底层源码, 马上快不用了,最近对其源码研究一番,哈哈 废话少说,上代码, 入口文件是web/index.php

china_lx1
2018/04/22
0
0
reids之YII常见使用问题

首先YII的框架包中并不含redis部分,需要自己配置和安装。 第一部分:Mac下YII框架的redis安装与配置 1.安装redis 方法一: 在没有安装YII的时候,可以通过修改composer的json文件实现修改安...

0_0Loong
2017/10/19
80
0

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
5
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
43
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部