1、07第六章迭代3添加任务Task第六章:迭代3:添加任务(Task)在上一个迭代中,我们交付了与项目(Project)实体相关的基本功能。项目(Project)是TrackStar应用的基础。但是,项目(Project)本身用处并不是很大。我们希望使用这个应用来管理问题(Issue),而项目(Project)只是问题(Issue)的基本容器。由于管理项目(Project)中的问题(Issue)是开发这款应用的主要目的,所以我们将这个迭代主要用于添加一些基本的问题(Issue)管理功能。迭代计划我们已经有了创建和列出项目(Project)的功能,但是这些项目(Project)还不能包含任何东西。
2、在这个迭代结束后,我们希望应用程序能提供所有关于问题(Issue)或者说任务(Task)的CRUD(增删改查)操作(我们会交替使用术语问题(Issue)和任务,但是在我们的数据模型中,一个任务实际上只是问题(Issue)的一种)。我们还需要将所有对问题(Issue)进行的CRUD操作,限制在一个特定的项目(Project)上下文中进行。也就是说,问题(Issue)是从属于项目(Project)的。在进行任何对问题(Issue)的CRUD操作之前,用户必须首先选定一个已经存在的项目(Project)并在该项目(Project)之下进行工作。为了实现上述目标,我们需要识别出所有要在此迭代中完成的细
3、化工作。下面的列表是对这些工作的概括: 设计数据库结构,创建对象来支持问题(Issue) 创建Yii模型类,使应用能够简单地与我们创建的数据库表交互 创建控制器类,来容纳我们需要的功能,包括:o 创建新问题(Issue)o 从数据库中取回项目(Project)中问题(Issue)的列表o 更新、编辑问题(Issue)o 删除问题(Issue) 创建试图来为这些动作(上述的)生成用户界面这些信息已经足够我们开始干活了。运行完测试后,我们开始做一些必要的数据库修改。运行测试套件在深入到开发工作中之前,运行已经存在的测试套件,总是一个非常好的主意。我们的测试套件在上一个迭代的时候增长了一点。现在我们
4、已经有了对项目(Project)进行CRUD操作和数据库链接的测试。把它们一起再运行一次。打开测试文件夹,/protected/tests/unit,然后运行所有单元测试:SHELL代码或屏幕回显:%phpunit unit/PHPUnit 3.3.17 by Sebastian Bergmann. . Time: 0 seconds OK (5 tests, 11 assertions)都通过了。让我们开始进行修改。设计数据库结构回到第3章TrackStar应用,我们提出了一些关于问题(Issue)的初始想法。我们假设它有类型、所有人、请求人(requester)、状态和描述等自然属性。还提
5、到了当我们创建了表tbl_project的时候,会给每个表添加基本的审计历史信息,用于跟踪更新了表的用户、日期和时间。在这个过程中,需求并没有发生改变,所以我们可以继续进行初始的计划。但是,类型、所有人、请求人和状态这些属性本身就是它们自己的实体。为了保持模型的弹性和扩展性,我们会对这些属性分别建模。所有人和请求人都是系统的用户,将会指向tbl_user表中的一行。在表tbl_project中,我们已经引入了用户的概念,我们添加了create_user_id和update_user_id两列,来跟踪创建了这个项目(Project)和对这个项目(Project)细节最后一次更新负责的用户的标识符
6、。尽管还没有正式引入用户表,这些域已经被设定成数据库中另一个存储用户的表的外键。在表tbl_issue中,owner_id和requestor_id也是指向表tbl_user的外键。我们可以用同样的方式来为类型和状态属性建模。不过,在需求要求模型具备这些额外的复杂度之前,我们让事情简单一些。表tbl_issue中的type和status列仍将是整数值类型,映射到命名的类型和状态。我们把这些属性建模成问题(Issue)实体的AR模型类的常量值,而不是使用分开的表来完善我们的模型。如果所有的这一切看起来有一点迷惑,请不要担心,在接下来的章节中,这些都会变清楚的。定义一些关系因为要引入表tbl_us
7、er,我们回过头来定义一下用户和项目(Project)之间的关系。第三章引入TrackStar应用的时候,我们设定用户(项目成员)可以和一个或者多个项目关联。还提到项目可以有许多(0个或多个)用户。因为项目可以有多个用户,而且用户可以被关联到多个项目,我们称之为项目和用户之间的多对多关系。在关系型数据库中,对一个多对多关系建模的最简单方法是,使用关联或者赋值表(assignment table)。所以,我们也需要将这个表添加到我们的模型中。下图勾勒出一个基本的实体关系,这个关系就是我们需要在用户,项目(Project),问题(Issue)之间建立的模型关系。项目可以有0个或者多个用户参与,一个
8、用户至少要被关联到一个项目,但是也可以被关联到多个项目。问题(Issue)属于且仅属于一个项目,同时项目可以包含0个或者多个问题(Issue)。最后,一个问题(Issue)只能被分配给一个用户(或者由一个用户提出)。建立数据库和关系那么,我们需要创建三张新表:tbl_issue,tbl_user和我们的关联表tbl_project_user_assignment。为了让您方便一点,我们提供了基本的数据定义语言(DDL)语句用于创建表和它们之间的关系。由于基本的用户管理不是这个迭代的一部分,我们还提供了一点种子数据填充到用户表中,以使我们可以立即使用它们。请像前几个迭代你做的那样,创建下列的表和
9、关系。下列的语法假设你使用的是MySQL数据库:SQL代码:DROP TABLE IF EXISTS tbl_project;CREATE TABLE tbl_project( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(128), description TEXT, create_time DATETIME, create_user_id INTEGER, update_time DATETIME, update_user_id INTEGER) ENGINE = InnoDB; CREATE TABLE IF N
10、OT EXISTS tbl_issue( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(256) NOT NULL, 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_
11、id INTEGER, INDEX (project_id) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS tbl_user( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, email VARCHAR(256) NOT NULL, username VARCHAR(256), password VARCHAR(256), last_login_time DATETIME, create_time DATETIME, create_user_id INTEGER, update_time DATETIME
12、, update_user_id INTEGER) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS tbl_project_user_assignment( project_id INT(11) NOT NULL, user_id INT(11) NOT NULL, create_time DATETIME, create_user_id INTEGER, update_time DATETIME, update_user_id INTEGER, PRIMARY KEY (project_id,user_id) ENGINE = InnoDB; - Th
13、e RelationshipsALTER TABLE tbl_issue ADD CONSTRAINT FK_issue_projectFOREIGN KEY (project_id) REFERENCES tbl_project (id)ON DELETE CASCADE ON UPDATE RESTRICT; ALTER TABLE tbl_issue ADD CONSTRAINT FK_issue_ownerFOREIGN KEY (owner_id) REFERENCES tbl_user (id)ON DELETE CASCADE ON UPDATE RESTRICT; ALTER
14、TABLE tbl_issue ADD CONSTRAINT FK_issue_requesterFOREIGN KEY (requester_id) REFERENCES tbl_user (id)ON DELETE CASCADE ON UPDATE RESTRICT; ALTER TABLE tbl_project_user_assignmentADD CONSTRAINT FK_project_user FOREIGN KEY (project_id)REFERENCES tbl_project (id)ON DELETE CASCADE ON UPDATE RESTRICT; ALT
15、ER TABLE tbl_project_user_assignmentADD CONSTRAINT FK_user_project FOREIGN KEY (user_id)REFERENCES tbl_user (id)ON DELETE CASCADE ON UPDATE RESTRICT; - Insert some seed data so we can just begin using the database INSERT INTO tbl_user(email, username, password)VALUES(test1,Test_User_One, MD5(test1),
16、(test2,Test_User_Two, MD5(test2);创建Active Record模型类建立好了这些表后,为了能与它们简单地交互,我们需要创建Yii的AR模型类。在第5章 迭代2:项目CRUD中,使用Gii代码生成工具创建过Project.php模型类时,我们就做过这件事。在这里,我们会把步骤再提醒你一次,但是省略了截屏。用Gii工具的更多细节请参考第5章。创建问题(Issue)模型类访问http:/localhost/trackstar/index.php?r=gii打开Gii工具页面,选择模型生成器链接。表前缀保留tbl_。表名(Table Name)填写tbl_issue,
17、模型类(Model Class)格会自动填上Issue。填写后,点击预览按钮,会得到一个链接,那个链接会打开一个弹出框,里面将展示所有将要生成的代码。然后点击生成按钮来真正创建Issue.php模型类文件到/protected/model文件夹。生成代码的完整列表如下:PHP代码:/* * This is the model class for table tbl_issue. * * The followings are the available columns in table tbl_issue: * property integer $id * property string $na
18、me * property string $description * property integer $project_id * property integer $type_id * property integer $status_id * property integer $owner_id * property integer $requester_id * property string $create_time * property integer $create_user_id * property string $update_time * property integer
19、 $update_user_id * * The followings are the available model relations: * property User $requester * property User $owner * property Project $project */class Issue extends CActiveRecord /* * Returns the static model of the specified AR class. * return Issue the static model class */ public static fun
20、ction model($className=_CLASS_) return parent:model($className); /* * return string the associated database table name */ public function tableName() return tbl_issue; /* * return array validation rules for model attributes. */ public function rules() / NOTE: you should only define rules for those a
21、ttributes that / will receive user inputs. return array( 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, upd
22、ate_time, safe), / The following rule is used by search(). / Please remove those attributes that should not be searched. 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), ); /* * return a
23、rray relational rules. */ public function relations() / NOTE: you may need to adjust the relation name and the related / class name for the relations automatically generated below. return array( requester = array(self:BELONGS_TO, User, requester_id), owner = array(self:BELONGS_TO, User, owner_id), p
24、roject = array(self:BELONGS_TO, Project, project_id), ); /* * return array customized attribute labels (name=label) */ public function attributeLabels() return array( id = ID, name = Name, description = Description, project_id = Project, type_id = Type, status_id = Status, owner_id = Owner, requeste
25、r_id = Requester, create_time = Create Time, create_user_id = Create User, update_time = Update Time, update_user_id = Update User, ); /* * Retrieves a list of models based on the current search/filter conditions. * return CActiveDataProvider the data provider that can return the models based on the
26、 search/filter conditions. */ public function search() / Warning: Please modify the following code to remove attributes that / should not be searched. $criteria = new CDbCriteria; $criteria-compare(id, $this-id); $criteria-compare(name, $this-name, true); $criteria-compare(description, $this-descrip
27、tion, 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,
28、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); return new CActiveDataProvider(get_class($this), array( criteria = $criteria, ); 创建用户模型类这对您来说可能已经像是老生常谈了,所以我们把创建用户AR模型类的工作
29、留作练习。下一章中,讨论用户权限和认证的时候,这个类会变得非常重要。表tbl_project_user_assignment对应的AR类什么时候创建呢?虽然可以为这个表创建一个AR类,但是这并没有必要。AR模型为我们的应用提供了一个对象关系映射(ORM)层,来帮助我们方便地操作我们的领域对象。然而,ProjectUserAssignment不是一个应用中的领域对象。它只是在关系型数据库中,构建出来,帮助我们建模和管理项目(Project)和用户之间的多对多关系。维护一个专门的AR类来管理这个表,增加了额外的复杂性,我们可以避免在这时候做这样的事。我们可以通过使用Yii的DAO来直接管理这个表的
30、插入、更新和删除来避免额外的维护工作和性能负载。创建问题(Issue)CRUD操作现在,AR类已经准备就绪了,我们可以开始创建管理我们项目问题(Issue)必须的功能了。由于项目问题(Issue)的CRUD操作是我们这个迭代要实现的主要目标,我们还是要依赖Gii代码生成工具来帮助我们这些基本的功能。这方面的细节,我们在第5章创建项目的时候已经做过了。在这里,为问题(Issue)创建相关代码的时候,我们会再提醒你一些基本的步骤。在http:/localhost/trackstar/index.php?r=gii打开Gii代码生成器的菜单,选择Crud Generator链接。在Model Class表单域中填写I
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1