Adding one more issue changes the display of issues to have links that allow us to go from page to page within our Project Issues listing, as depicted in the following screenshot: Makin
Trang 1<b><?php echo CHtml::encode($data->getAttributeLabel('description')); ?>:</b>
<?php echo CHtml::encode($data->description); ?>
<br />
<b><?php echo CHtml::encode($data->getAttributeLabel('type_id')); ?>:</b>
<?php echo CHtml::encode($data->type_id); ?>
<br />
<b><?php echo CHtml::encode($data->getAttributeLabel('status_id')); ?:</b>
Trang 2As we set the pagination property of our data provider very low (remember
we set it to just 1), we can add one more issue to demonstrate the built-in paging functionality Adding one more issue changes the display of issues to have links that
allow us to go from page to page within our Project Issues listing, as depicted in the
following screenshot:
Making some final tweaks
We now have a list of our issues associated with a project that are displayed from within the project details page We also have the ability to view the details of an issue "R"ead, as well as links to "U"pdate and "D"elete issues So, for the most part our CRUD operations are in place
However, there are still a few items that need to be addressed before we can close out this iteration One thing we notice is that the issues display list is showing
numeric ID numbers for the Type, Status, Owner and Requester fields We should
change this so that the text values for those are displayed instead Also, as issues are under a specific project already, it is a bit redundant to have the project ID displayed
as part of the issue list data So, we can remove that Finally, we need to address some of the navigational links that are displayed on the various other issue related forms to ensure we are always returning to this project details page as the starting place for all of our issue management
We'll tackle these one at a time
Getting the status and type text to display
Previously we added public methods to the Issue AR class to retrieve the Status and Type options to populate our dropdowns on the issue creation form We need
to add similar methods on this AR class to return the text for the specific identifier for display on our issues listing
Trang 3As these will be public methods on the issue AR class, we should implement it using our TDD approach To speed things up a bit, we'll do both of these at the same time Also, as we get a hang of TDD a little bit, we'll start to take bigger steps
We can always return to a more granular approach
First we need to add some fixture data to ensure we have a couple of issues
associated with a project We also need to make sure our issue tests are using the project fixture data as well as issues belong to projects
First, add a new fixtures data file for issues, /protected/tests/fixtures/tbl_issue.php and add to it the following content:
<?php
return array(
'issueBug'=>array(
'name' => 'Test Bug 1',
'description' => 'This is test bug for project 1',
'name' => 'Test Bug 2',
'description' => 'This is test bug for project 2',
Trang 4Now we need to configure our IssueTest class to use some fixture data Add the following fixtures array at the top of the issue test class:
And also this test:
public function testGetTypeText()
Time: 2 seconds, Memory: 12.25Mb
There were 2 errors:
Trang 5So, we've got our failing test, let's add the necessary code to our /protected/
models/Issue.php file to get them to pass Add the following two new public
methods to the Issue class to retrieve the status and type text for the current issue: /**
* @return string the status text display for the current issue */
public function getStatusText()
return isset(>type_id]) ?
$typeOptions[$this->type_id] : "unknown type ({$this->type_id})";
Trang 6Adding the text display to the form
Now we have our two new public methods that will return the valid status and type text for our listing to display, we need to make use of them Alter the following lines of code in /protected/views/issue/_view.php:
Change the following command:
It now looks like what is displayed in the following screenshot:
As we are using the sameviewfile to display our Issues listing on our project detail pages, these changes are reflected there as well
Trang 7Changing the issue detail view
We also need to make these and a few other changes to the detailed view
of the Issue Currently, if we view the Issue details, it should look like the
Trang 8Here we are setting the data model of theCDetailViewwidget to be the Issue
modelclass and then setting a list of attributes of the model to be displayed in the rendered detail view An attribute can be specified as a string in the format
of Name:Type:Label, of which both Type and Label are optional, or as an array itself Here, just the name of the attributes are specified
If we specify an attribute as an array, we can customize the display further by declaring avalueelement We will take this approach in order to specify the model class methodsgetTypeText()and getStatusText()be used as the values for the Type and Status fields respectively
Let's change this use ofCDetailViewto use the following configuration:
Here we have removed a few attributes from displaying at all The project_id,
create_time, update_time, create_user_id, and update_user_id We will handle the population and display of some of these later, but for now we can just remove them from the detail display
Trang 9We also changed the declaration of the type_id and status_id attributes to use an array specification so that we could use the value element We have specified that the corresponding Issue::getTypeText() and Issue::getStatusText() methods
be used for getting the values of these attributes With these changes in place, the
Issue details page looks like the following:
Okay, we are getting much closer to what we want, but there are still a couple of changes we need to make
Getting the owner and requester names to display
Things are looking better, but we still see integer identifiers displaying for the owner and requester, rather than the actual user names We'll take a similar approach to what we did for the type and status text displays We'll add two newpublicmethods on the Issue model class to return the names of these
two properties
Using relational AR
As the issues and users are represented as separate database tables and related
through a foreign key relationship, we an actually access the owner and requester username directly from $model in the view file Utilizing the power of Yii's relational
AR model features, displaying the username attribute of the related User model class instance is a snap
Trang 10As we have mentioned, the model class Issue::relations() method is where the relationships are defined If we take a peek at this method, we see the following:/**
* @return array relational rules.
'owner' => array(self::BELONGS_TO, 'User', 'owner_id'),
'project' => array(self::BELONGS_TO, 'Project', 'project_ id'),
'requester' => array(self::BELONGS_TO, 'User', 'requester_ id'),
);
}
The highlighted code is what is most relevant for our needs There are both owner
and requester attributes defined as relations to the Usermodel class These
definitions specify that the values of these attributes are Usermodel class instances The owner_id and the requester_id specify the unique Primary key of their
respective User class instances So, we can access these just as we do for other
attributes of the Issue model class
So, to display the username of the owner and requester User class instances, we once again change our CDetailView configuration to be:
Trang 11Making some final navigation tweaks
We are very close to completing the functionality we set out to implement within this iteration The only thing left is to clean up our navigation just a little You may have noticed that there are still some options available that allow the user to navigate to
an entire listing of issues, or to create a new issue, outside of a project context For the purposes of the TrackStar application, everything we do with issues should be within the context of a specific project Earlier, we enforced this project context for creating a new issue (which is a good start), but we still need to make a few changes
One thing that we notice is that the application still allows the user to navigate
to a listing of all issues, across all projects For example, on an Issue detail page, likehttp://localhost/trackstar/index.php?r=issue/view&id=1, we see in the right column menu navigation there are the links List Issue and Manage Issue, corresponding to http://localhost/trackstar/index.php?r=issue/indexand http://localhost/trackstar/index.php?r=issue/admin respectively
(remember that to access the admin page, you have to be logged in as admin/
admin) These still display all issues, across all projects So, we need to limit this list to a specific project
Trang 12As these links originate from the Issue details page, and that specific issue has
an associated project, we can first alter the links to pass in a specific project ID, and thehe uof that project ID as both theIssueController::actionIndex, and
IssueController::actionAdmin() methods
First let's alter the links Open up /protected/views/issue/view.phpfile
and locate the array of menu items at the top of the file Change the menu
array('label'=>'Manage Issue', 'url'=>array('admin',
'pid'=>$model->project->id)),
);
The changes made are highlighted We have added a new querystring parameter to
the new Create Issue link, as well as to the Issue listing page and the issue admin
listing page We already knew we had to make this change for the Create link, as we have previously implemented a filter to enforce a valid project conssue We won't
have to make any further changes relative to this link But for the index and admin
links, we will need to alter their corresponding action methods to make use of this new querystring variable
As we have already configured a filter to load the associated project using the
querysting variable, let's take advantage of this We'll need to change the filter configuration so that our filter method is called prior to execution of both the
IssueController::actionIndex() and IssueController::actionAdmin()
methods Change the filters method as shown:
public function filters()
Trang 13With this in place, the associated project will be loaded and available for use Let's use it in our IssueController::actionIndex() method Alter that method to be: public function actionIndex()
We need to make the same change to the admin listing page However, this view
file, /protected/views/issue/admin.php is using the results of the model class
Issue::search() method to provide the listing of issues So, we actually need to make two changes to enforce the project context with this listing
First, we need to alter the IssueController::actionAdmin() method to set the correct project_id attribute on the model instance it is sending to the view The following highlighted code shows this change:
public function actionAdmin()
Trang 14Then we need to add to our criteria in the Issue::search() model class method The following highlighted code identifies the change we need to make to this method:public function search()
$criteria->compare('update_user_id',$this->update_user_id);
With these changes in place, the issues listed on the admin page are now restricted to
be only those associated with the specific project
Trang 15There are several places throughout the view files under /protected/views/issues/ that contain links that require a pid querystring
to be added in order to work properly We leave it as an exercise to the
reader to make the appropriate changes following the same approach
as provided in these examples As we proceed with our application's
development, we'll assume all links to create a new issue or to display
a list of issues are properly formatted to contain the appropriate pid
querystring parameter
Summary
We were able to cover a lot of different topics in this iteration Based on the
relationship between issues, projects, and users within our application, the
implementation of our issue management functionality was significantly more complicated than our project entity management we worked on in the previous iteration Fortunately, Yii was able to come to our rescue many times to alleviate the pain of having to write all of the code needed to address this complexity
Specifically, we covered:
• Using the Gii code generator tool for Active Record model creation as well
as for the initial implementation of all basic CRUD operations against the
Issue entity
• Designing and building database tables with explicit relationships
• Using relational Active Record
• Adding drop-down menu input type form elements
• Controller filters
We have made a lot of progress on our basic application thus far, and have done so without having to write a lot of code The Yii Framework itself has done most of the heavy lifting We now have a working application that allows us to manage projects and also manage issues within those projects This is the heart of what our application
is trying to achieve We should feel proud of the accomplishments thus far
However, we still have a long way to go before this application is truly ready for production use A major missing piece is all of the needed functionality around user management This is going to be the focus of the next two iterations
Trang 17Iteration 4: User Management
Back in Chapter 3, when we were introducing this application, we described it as
a user-based application that allows for the creation of user accounts, and grants access to the application features once a user has been authenticated and authorized
In order for this application to be useful to more than one person we need to add the ability to manage users within projects This is going to be the focus of the next two iterations
Iteration planning
When we used the yiic command line tool to initially create our TrackStar
application, we noticed that basic login functionality was automatically created for us The login page allows for two username/password credential combinations,
demo/demo and admin/admin You may recall that we had to log in to the
application in order to perform some of our CRUD operations on our project
and issue entities
This basic authentication skeleton code does provide a good start, but we need
to make a few changes in order to support any number of users We also need
to add user CRUD functionality to the application to allow us to manage these
multiple users This iteration is going to focus on extending the authentication
model to use the User table and add the needed functionality to allow for basic user data management
Trang 18In order to achieve the above outlined goals, we should identify all the more
granular items we will work on within this iteration The following list identifies these items:
• Create the controller classes that will house the functionality to allow us to:
° Delete existing users
• Create the view files and presentation tier logic that will:
Running the test suite
It's always best to run our test suite before we start adding new functionality With each iteration, as we add to our application functionality, we add to our test suite
As our test suite grows, so does our application's ability to provide us feedback on its general health Making sure everything is still working as expected will boost our confidence as we begin making changes From the tests folder, /protected/tests/, run all unit tests as once: