07第六章迭代3添加任务Task.docx
- 文档编号:8000835
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:53
- 大小:475.45KB
07第六章迭代3添加任务Task.docx
《07第六章迭代3添加任务Task.docx》由会员分享,可在线阅读,更多相关《07第六章迭代3添加任务Task.docx(53页珍藏版)》请在冰豆网上搜索。
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 07 第六 章迭代 添加 任务 Task