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

在这一章里,我们将看到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了,描述我们功能需求的最佳方法,就是写一个完整的端到端测试。

时间: 2024-08-15 23:28:32

【翻译】Yii2 第2章 用Yii2创建自定义应用(第1节)的相关文章

第3章—高级装配—创建自定义的限定符

创建自定义的限定符 ? 我们可以为bean设置自己的限定符,而不是依赖于将bean ID作为限定符.在这里所需要做的就是在bean声明上添加@Qualifier注解来进行更加明确的区分.例如: Animal接口: package com.home.quar; public interface Animal { public void eat(); } Cat: package com.home.quar; import org.springframework.beans.factory.anno

在Oracle电子商务套件版本12.2中创建自定义应用程序(文档ID 1577707.1)

在本文档中 本笔记介绍了在Oracle电子商务套件版本12.2中创建自定义应用程序所需的基本步骤.如果您要创建新表单,报告等,则需要自定义应用程序.它们允许您将自定义编写的文件与Oracle电子商务套件提供的标准种子功能分离.在向您的环境应用修补程序或执行升级时可以保留自定义设置. 自定义数据和索引表空间默认为APPS_TS_TX_DATA和APPS_TS_TX_IDX. 注意:当没有活动的修补程序周期时,应在运行文件系统上执行本文档中描述的过程. 也可以按照此过程更正先前创建的不使用AD Sp

《Introduction to Tornado》中文翻译计划——第五章:异步Web服务

http://www.pythoner.com/294.html 本文为<Introduction to Tornado>中文翻译,将在https://github.com/alioth310/itt2zh上面持续更新,本文内容可能不是最新状态,请在GitHub上获得最新版本. 本文也可在http://demo.pythoner.com/itt2zh上进行格式化的预览. 第五章:异步Web服务 到目前为止,我们已经看到了许多使Tornado成为一个Web应用强有力框架的功能.它的简单性.易用性

Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

第一章 Thread导论 为何要用Thread ? 非阻塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Task) 并行算法 第二章 Thread的创建与管理 一.什么是Thread ? Thread是所在主机执行的应用程序任务(task). 只有一个线程的例子: public class Factorial { public static void main(String[] args) { int n = 5; System.ou

[翻译] DTCoreText 从HTML文档中创建富文本

DTCoreText 从HTML文档中创建富文本 https://github.com/Cocoanetics/DTCoreText 注意哦亲,DTRichTextEditor 这个组件是收费的,不贵,才650美元而已^_^. DTCoreText This project aims to duplicate the methods present on Mac OSX which allow creation of NSAttributedString from HTML code on iO

【翻译】在Ext JS和Sencha Touch中创建自定义布局

原文:Creating Custom Layouts in Ext JS and Sencha Touch 布局系统是Sencha框架中最强大和最独特的一部分.布局会处理应用程序中每个组件的大小和位置,因而,不需要手动去管理那些碎片.Ext JS与Sencha Touch的布局类有许多相似之处,最近在 Ivan Jouikov的这篇博文中对他们进行了详细的分析. 虽然是这样,但很多Ext JS和Sencha Touch开发人员可能永远都不会去了解布局系统的机制原理.Sencha框架已经提供了最常

yii2如何环境部署?yii2高级模版安装教程

使用 Composer安装: 1.设置php环境变量: 在环境变量中classpash或者用户变量中path 后面追加添加php.exe目录地址: 这样cmd中执行php即可找到php.exe 2.安装Composer : 使用安装程序 这是将 Composer 安装在你机器上的最简单的方法. 下载并且运行 Composer-Setup.exe( https://getcomposer.org/Composer-Setup.exe),它将安装最新版本的 Composer ,并设置好系统的环境变量

使用Material Design 创建App翻译系列---列表和卡片集的创建

上一篇是使用Material Design 创建App翻译系列--材料主题的使用(Using Material Theme),进入正题: 想要在应用里创建Material Design风格的复杂列表和卡片,可以使用RecyclerView 和 CardView 控件. 创建列表 RecyclerView 控件是一个比ListView更加优越和灵活的控件.这个控件是一个通过有限个数的视图来显示大型数据集并能够高效滚动的容器. 当你有数据集合是基于用户动作或者网络事件而在运行时改变数据元素的时候你可

[翻译]在objective c创建自定义collection view样式

创建自定义collection样式 苹果在ios6中新增了一个更加易于创建和管理复杂用户界面的类:collection view.在此之前ios6上面用于展示多项列表的是table view,虽然名称是表格但它展示信息的形式并不是表格形式,而是垂直列表,当然在实际设计展示垂直可滚动的文本型列表时非常有用,但是你会遇到许多垂直可滚动的列表所存在的局限性,比如不能水平滚动,每行只有一项单元格,没有复杂的样式,在ios6之前你想要做到这些事情,只能靠自定义扩展. 在ios6 平台介绍了一个新的类:co