07第六章迭代3添加任务Task.docx

上传人:b****6 文档编号:8000835 上传时间:2023-01-27 格式:DOCX 页数:53 大小:475.45KB
下载 相关 举报
07第六章迭代3添加任务Task.docx_第1页
第1页 / 共53页
07第六章迭代3添加任务Task.docx_第2页
第2页 / 共53页
07第六章迭代3添加任务Task.docx_第3页
第3页 / 共53页
07第六章迭代3添加任务Task.docx_第4页
第4页 / 共53页
07第六章迭代3添加任务Task.docx_第5页
第5页 / 共53页
点击查看更多>>
下载资源
资源描述

07第六章迭代3添加任务Task.docx

《07第六章迭代3添加任务Task.docx》由会员分享,可在线阅读,更多相关《07第六章迭代3添加任务Task.docx(53页珍藏版)》请在冰豆网上搜索。

07第六章迭代3添加任务Task.docx

07第六章迭代3添加任务Task

第六章:

迭代3:

添加任务(Task)

在上一个迭代中,我们交付了与项目(Project)实体相关的基本功能。

项目(Project)是TrackStar应用的基础。

但是,项目(Project)本身用处并不是很大。

我们希望使用这个应用来管理问题(Issue),而项目(Project)只是问题(Issue)的基本容器。

由于管理项目(Project)中的问题(Issue)是开发这款应用的主要目的,所以我们将这个迭代主要用于添加一些基本的问题(Issue)管理功能。

迭代计划

我们已经有了创建和列出项目(Project)的功能,但是这些项目(Project)还不能包含任何东西。

在这个迭代结束后,我们希望应用程序能提供所有关于问题(Issue)或者说任务(Task)的CRUD(增删改查)操作(我们会交替使用术语问题(Issue)和任务,但是在我们的数据模型中,一个任务实际上只是问题(Issue)的一种)。

我们还需要将所有对问题(Issue)进行的CRUD操作,限制在一个特定的项目(Project)上下文中进行。

也就是说,问题(Issue)是从属于项目(Project)的。

在进行任何对问题(Issue)的CRUD操作之前,用户必须首先选定一个已经存在的项目(Project)并在该项目(Project)之下进行工作。

为了实现上述目标,我们需要识别出所有要在此迭代中完成的细化工作。

下面的列表是对这些工作的概括:

▪设计数据库结构,创建对象来支持问题(Issue)

▪创建Yii模型类,使应用能够简单地与我们创建的数据库表交互

▪创建控制器类,来容纳我们需要的功能,包括:

o创建新问题(Issue)

o从数据库中取回项目(Project)中问题(Issue)的列表

o更新、编辑问题(Issue)

o删除问题(Issue)

创建试图来为这些动作(上述的)生成用户界面

这些信息已经足够我们开始干活了。

运行完测试后,我们开始做一些必要的数据库修改。

运行测试套件

在深入到开发工作中之前,运行已经存在的测试套件,总是一个非常好的主意。

我们的测试套件在上一个迭代的时候增长了一点。

现在我们已经有了对项目(Project)进行CRUD操作和数据库链接的测试。

把它们一起再运行一次。

打开测试文件夹,/protected/tests/unit,然后运行所有单元测试:

SHELL代码或屏幕回显:

%phpunitunit/

PHPUnit3.3.17bySebastianBergmann.

.....

Time:

0secondsOK(5tests,11assertions)

都通过了。

让我们开始进行修改。

设计数据库结构

回到第3章TrackStar应用,我们提出了一些关于问题(Issue)的初始想法。

我们假设它有类型、所有人、请求人(requester)、状态和描述等自然属性。

还提到了当我们创建了表tbl_project的时候,会给每个表添加基本的审计历史信息,用于跟踪更新了表的用户、日期和时间。

在这个过程中,需求并没有发生改变,所以我们可以继续进行初始的计划。

但是,类型、所有人、请求人和状态这些属性本身就是它们自己的实体。

为了保持模型的弹性和扩展性,我们会对这些属性分别建模。

所有人和请求人都是系统的用户,将会指向tbl_user表中的一行。

在表tbl_project中,我们已经引入了用户的概念,我们添加了create_user_id和update_user_id两列,来跟踪创建了这个项目(Project)和对这个项目(Project)细节最后一次更新负责的用户的标识符。

尽管还没有正式引入用户表,这些域已经被设定成数据库中另一个存储用户的表的外键。

在表tbl_issue中,owner_id和requestor_id也是指向表tbl_user的外键。

我们可以用同样的方式来为类型和状态属性建模。

不过,在需求要求模型具备这些额外的复杂度之前,我们让事情简单一些。

表tbl_issue中的type和status列仍将是整数值类型,映射到命名的类型和状态。

我们把这些属性建模成问题(Issue)实体的AR模型类的常量值,而不是使用分开的表来完善我们的模型。

如果所有的这一切看起来有一点迷惑,请不要担心,在接下来的章节中,这些都会变清楚的。

定义一些关系

因为要引入表tbl_user,我们回过头来定义一下用户和项目(Project)之间的关系。

第三章引入TrackStar应用的时候,我们设定用户(项目成员)可以和一个或者多个项目关联。

还提到项目可以有许多(0个或多个)用户。

因为项目可以有多个用户,而且用户可以被关联到多个项目,我们称之为项目和用户之间的多对多关系。

在关系型数据库中,对一个多对多关系建模的最简单方法是,使用关联或者赋值表(assignmenttable)。

所以,我们也需要将这个表添加到我们的模型中。

下图勾勒出一个基本的实体关系,这个关系就是我们需要在用户,项目(Project),问题(Issue)之间建立的模型关系。

项目可以有0个或者多个用户参与,一个用户至少要被关联到一个项目,但是也可以被关联到多个项目。

问题(Issue)属于且仅属于一个项目,同时项目可以包含0个或者多个问题(Issue)。

最后,一个问题(Issue)只能被分配给一个用户(或者由一个用户提出)。

建立数据库和关系

那么,我们需要创建三张新表:

tbl_issue,tbl_user和我们的关联表tbl_project_user_assignment。

为了让您方便一点,我们提供了基本的数据定义语言(DDL)语句用于创建表和它们之间的关系。

由于基本的用户管理不是这个迭代的一部分,我们还提供了一点种子数据填充到用户表中,以使我们可以立即使用它们。

请像前几个迭代你做的那样,创建下列的表和关系。

下列的语法假设你使用的是MySQL数据库:

SQL代码:

DROPTABLEIFEXISTS`tbl_project`;

CREATETABLE`tbl_project`

`id`INTEGERNOTNULLPRIMARYKEYAUTO_INCREMENT,

`name`VARCHAR(128),

`description`TEXT,

`create_time`DATETIME,

`create_user_id`INTEGER,

`update_time`DATETIME,

`update_user_id`INTEGER

)ENGINE=InnoDB;

CREATETABLEIFNOTEXISTS`tbl_issue`

`id`INTEGERNOTNULLPRIMARYKEYAUTO_INCREMENT,

`name`VARCHAR(256)NOTNULL,

`description`VARCHAR(2000),

`project_id`INTEGER,

`type_id`INTEGER,

`status_id`INTEGER,

`owner_id`INTEGER,

`requester_id`INTEGER,

`create_time`DATETIME,

`create_user_id`INTEGER,

`update_time`DATETIME,

`update_user_id`INTEGER,

INDEX(`project_id`)

)ENGINE=InnoDB;

CREATETABLEIFNOTEXISTS`tbl_user`

`id`INTEGERNOTNULLPRIMARYKEYAUTO_INCREMENT,

`email`VARCHAR(256)NOTNULL,

`username`VARCHAR(256),

`password`VARCHAR(256),

`last_login_time`DATETIME,

`create_time`DATETIME,

`create_user_id`INTEGER,

`update_time`DATETIME,

`update_user_id`INTEGER

)ENGINE=InnoDB;

CREATETABLEIFNOTEXISTS`tbl_project_user_assignment`

`project_id`INT(11)NOTNULL,

`user_id`INT(11)NOTNULL,

`create_time`DATETIME,

`create_user_id`INTEGER,

`update_time`DATETIME,

`update_user_id`INTEGER,

PRIMARYKEY(`project_id`,`user_id`)

)ENGINE=InnoDB;

--TheRelationships

ALTERTABLE`tbl_issue`ADDCONSTRAINT`FK_issue_project`

FOREIGNKEY(`project_id`)REFERENCES`tbl_project`(`id`)

ONDELETECASCADEONUPDATERESTRICT;

ALTERTABLE`tbl_issue`ADDCONSTRAINT`FK_issue_owner`

FOREIGNKEY(`owner_id`)REFERENCES`tbl_user`(`id`)

ONDELETECASCADEONUPDATERESTRICT;

ALTERTABLE`tbl_issue`ADDCONSTRAINT`FK_issue_requester`

FOREIGNKEY(`requester_id`)REFERENCES`tbl_user`(`id`)

ONDELETECASCADEONUPDATERESTRICT;

ALTERTABLE`tbl_project_user_assignment`

ADDCONSTRAINT`FK_project_user`FOREIGNKEY(`project_id`)

REFERENCES`tbl_project`(`id`)

ONDELETECASCADEONUPDATERESTRICT;

ALTERTABLE`tbl_project_user_assignment`

ADDCONSTRAINT`FK_user_project`FOREIGNKEY(`user_id`)

REFERENCES`tbl_user`(`id`)

ONDELETECASCADEONUPDATERESTRICT;

--Insertsomeseeddatasowecanjustbeginusingthedatabase

INSERTINTO`tbl_user`

(`email`,`username`,`password`)

VALUES

('test1@','Test_User_One',MD5('test1')),

('test2@','Test_User_Two',MD5('test2'));

创建ActiveRecord模型类

建立好了这些表后,为了能与它们简单地交互,我们需要创建Yii的AR模型类。

在第5章迭代2:

项目CRUD中,使用Gii代码生成工具创建过Project.php模型类时,我们就做过这件事。

在这里,我们会把步骤再提醒你一次,但是省略了截屏。

用Gii工具的更多细节请参考第5章。

创建问题(Issue)模型类

访问http:

//localhost/trackstar/index.php?

r=gii打开Gii工具页面,选择模型生成器链接。

表前缀保留tbl_。

表名(TableName)填写tbl_issue,模型类(ModelClass)格会自动填上Issue。

填写后,点击预览按钮,会得到一个链接,那个链接会打开一个弹出框,里面将展示所有将要生成的代码。

然后点击生成按钮来真正创建Issue.php模型类文件到/protected/model文件夹。

生成代码的完整列表如下:

PHP代码:

/**

*Thisisthemodelclassfortable"tbl_issue".

*

*Thefollowingsaretheavailablecolumnsintable'tbl_issue':

*@propertyinteger$id

*@propertystring$name

*@propertystring$description

*@propertyinteger$project_id

*@propertyinteger$type_id

*@propertyinteger$status_id

*@propertyinteger$owner_id

*@propertyinteger$requester_id

*@propertystring$create_time

*@propertyinteger$create_user_id

*@propertystring$update_time

*@propertyinteger$update_user_id

*

*Thefollowingsaretheavailablemodelrelations:

*@propertyUser$requester

*@propertyUser$owner

*@propertyProject$project

*/

classIssueextendsCActiveRecord{

/**

*ReturnsthestaticmodelofthespecifiedARclass.

*@returnIssuethestaticmodelclass

*/

publicstaticfunctionmodel($className=__CLASS__){

returnparent:

:

model($className);

}

/**

*@returnstringtheassociateddatabasetablename

*/

publicfunctiontableName(){

return'tbl_issue';

}

/**

*@returnarrayvalidationrulesformodelattributes.

*/

publicfunctionrules(){

//NOTE:

youshouldonlydefinerulesforthoseattributesthat

//willreceiveuserinputs.

returnarray(

array('name','required'),

array('project_id,type_id,status_id,owner_id,requester_id,create_user_id,

update_user_id','numerical','integerOnly'=>true),

array('name','length','max'=>256),

array('description','length','max'=>2000),

array('create_time,update_time','safe'),

//Thefollowingruleisusedbysearch().

//Pleaseremovethoseattributesthatshouldnotbesearched.

array('id,name,description,project_id,type_id,status_id,owner_id,

requester_id,create_time,create_user_id,update_time,update_user_id',

'safe','on'=>'search'),

);

}

/**

*@returnarrayrelationalrules.

*/

publicfunctionrelations(){

//NOTE:

youmayneedtoadjusttherelationnameandtherelated

//classnamefortherelationsautomaticallygeneratedbelow.

returnarray(

'requester'=>array(self:

:

BELONGS_TO,'User','requester_id'),

'owner'=>array(self:

:

BELONGS_TO,'User','owner_id'),

'project'=>array(self:

:

BELONGS_TO,'Project','project_id'),

);

}

/**

*@returnarraycustomizedattributelabels(name=>label)

*/

publicfunctionattributeLabels(){

returnarray(

'id'=>'ID',

'name'=>'Name',

'description'=>'Description',

'project_id'=>'Project',

'type_id'=>'Type',

'status_id'=>'Status',

'owner_id'=>'Owner',

'requester_id'=>'Requester',

'create_time'=>'CreateTime',

'create_user_id'=>'CreateUser',

'update_time'=>'UpdateTime',

'update_user_id'=>'UpdateUser',

);

}

/**

*Retrievesalistofmodelsbasedonthecurrentsearch/filterconditions.

*@returnCActiveDataProviderthedataproviderthatcanreturnthemodelsbasedon

thesearch/filterconditions.

*/

publicfunctionsearch(){

//Warning:

Pleasemodifythefollowingcodetoremoveattributesthat

//shouldnotbesearched.

$criteria=newCDbCriteria;

$criteria->compare('id',$this->id);

$criteria->compare('name',$this->name,true);

$criteria->compare('description',$this->description,true);

$criteria->compare('project_id',$this->project_id);

$criteria->compare('type_id',$this->type_id);

$criteria->compare('status_id',$this->status_id);

$criteria->compare('owner_id',$this->owner_id);

$criteria->compare('requester_id',$this->requester_id);

$criteria->compare('create_time',$this->create_time,true);

$criteria->compare('create_user_id',$this->create_user_id);

$criteria->compare('update_time',$this->update_time,true);

$criteria->compare('update_user_id',$this->update_user_id);

returnnewCActiveDataProvider(get_class($this),array(

'criteria'=>$criteria,

));

}

}

创建用户模型类

这对您来说可能已经像是老生常谈了,所以我们把创建用户AR模型类的工作留作练习。

下一章中,讨论用户权限和认证的时候,这个类会变得非常重要。

表tbl_project_user_assignment对应的AR类什么时候创建呢?

虽然可以为这个表创建一个AR类,但是这并没有必要。

AR模型为我们的应用提供了一个对象关系映射(ORM)层,来帮助我们方便地操作我们的领域对象。

然而,ProjectUserAssignment不是一个应用中的领域对象。

它只是在关系型数据库中,构建出来,帮助我们建模和管理项目(Project)和用户之间的多对多关系。

维护一个专门的AR类来管理这个表,增加了额外的复杂性,我们可以避免在这时候做这样的事。

我们可以通过使用Yii的DAO来直接管理这个表的插入、更新和删除来避免额外的维护工作和性能负载。

创建问题(Issue)CRUD操作

现在,AR类已经准备就绪了,我们可以开始创建管理我们项目问题(Issue)必须的功能了。

由于项目问题(Issue)的CRUD操作是我们这个迭代要实现的主要目标,我们还是要依赖Gii代码生成工具来帮助我们这些基本的功能。

这方面的细节,我们在第5章创建项目的时候已经做过了。

在这里,为问题(Issue)创建相关代码的时候,我们会再提醒你一些基本的步骤。

在http:

//localhost/trackstar/index.php?

r=gii打开Gii代码生成器的菜单,选择CrudGenerator链接。

在ModelClass表单域中填写I

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 历史学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1