0% found this document useful (0 votes)
257 views

Yii Project Blueprints Sample Chapter

Chapter No. 1 A Task-management Application From conception to production, learn how to develop real-world applications with the Yii framework

Uploaded by

Packt Publishing
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
257 views

Yii Project Blueprints Sample Chapter

Chapter No. 1 A Task-management Application From conception to production, learn how to develop real-world applications with the Yii framework

Uploaded by

Packt Publishing
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

Yii Project Blueprints

Charles R. Portwood II








Chapter No. 1
"A Task-management Application"
In this package, you will find:
The authors biography
A preview chapter from the book, Chapter no.1 "A Task-management
Application"
A synopsis of the books content
Information on where to buy this book













About the Author
Charles R. Portwood II has over 10 years of experience in developing modern web
applications and is well versed in integrating PHP with native mobile applications. An
avid proponent for the Yii framework and open source software, Charles has contributed
multiple guides, extensions, and applications to the Yii community. In addition to being a
programmer, he is also a Linux system administrator. When not in front of a computer, he
can be found writing stories, photographing nature, or spending time with his wife.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints


Yii Project Blueprints
The Yii framework is a high-performance, fast, open source, and a rapid development
PHP framework that can be used to develop modern web applications. It provides
the toolkit for developing both personal projects and enterprise applications.
This book is a step-by-step guide to develop eight reusable real-world applications using
the Yii framework. Yii Project Blueprints will guide you through several projects, from
project conception to planning your project and finally implementing it. You will explore
the key features of the Yii framework and learn how to use it efficiently and effectively
to build solid core applications that you'll be able to reuse in real-world projects. You'll
also learn how to integrate Yii with third-party libraries and services, create your own
reusable code bases, and discover many more Yii features that will expand your
knowledge and expertise of Yii.
What This Book Covers
Chapter 1, A Task-management Application, covers developing a simple task-
management application from the ground up using SQLite and basic database migrations.
This chapter will cover all the moving parts of Yii and prepare you for working with
more complex applications.
Chapter 2, Discovering What's Nearby, covers how to integrate the Yii framework with
the Google Maps API to display information about what is near a given user. You'll also
learn how to create command-line tools to handle importing and processing data.
Chapter 3, Scheduled Reminders, focuses on developing a multiuser web-based
scheduling and reminders application that can notify users via e-mail when a scheduled
event is about to occur.
Chapter 4, Developing an Issue-tracking Application, covers how to create a multiuser
issue-tracking and management system, complete with an e-mail notification system
using MySQL as a database backend. This chapter will also cover handling input from
e-mail submissions to trigger actions within the application.



For More Information:
www.packtpub.com/web-development/yii-project-blueprints


Chapter 5, Creating a Microblogging Platform, covers how to create your own
microblogging platform similar to Twitter, complete with a robust user authentication and
registration system. You'll also learn how to integrate your application with third-party
social networks using HybridAuth, as well as how to streamline your headless
development time with Composer.
Chapter 6, Building a Content Management System, covers how to create a feature-
complete content management system and blogging platform that expands using the
knowledge built upon in the previous chapters. This chapter will also demonstrate how
to integrate with even more third-party open source libraries.
Chapter 7, Creating a Management Module for the CMS, focuses on the development of
a management module for the content management system built in the previous chapter.
In this chapter, you'll learn how to migrate data from controllers to a Yii module that can
be reused and managed independently of the content management system.
Chapter 8, Building an API for the CMS, covers how to create a JSON REST API
module for the content management system that can be used for both client-side web
applications and native development. This chapter will cover the basics of creating a
secure and authenticated JSON REST API, and will demonstrate how to adapt controller
actions for JSON responses rather than web view responses.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management
Application
One of the best ways to get started with the Yii framework is by making useful
applications. The rst application that will be covered in this book is a simple
task management application. In this chapter, we will cover the planning of the
development of this project, developing the application, and creating useful
components that we will reuse in later chapters.
Describing the project
One of the most important steps in starting a new project is planning it. By planning
the project before we begin programming, we can easily identify most (if not all)
models that our application will use, key features that we'll need to implement, as
well as any areas that may cause us problems while developing our applications.
Breaking down the project beforehand also helps us estimate how long it will take
to develop each part of our applications as well as the application as a whole. While
requirements and expectations for our application will most likely change during its
development, identifying the core components of your application will help ensure
that the core functionality of our application works as we intend.
For our task management application, there are two main components: tasks and
projects. Let's break each of these components down.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 8 ]
Tasks
The rst component of our application is tasks. A task is an item that needs to be
done by our user and usually consists of a brief, concise title, and a description of
what needs to be done to complete that task. Sometimes, a task has a due date or
time associated with it that lets us know when the task needs to be completed. Tasks
also need to indicate whether they have been completed or not. Finally, a task is
usually associated with a group or project that contains similar or related tasks.
Projects
The second component of our application is projects. Projects group related tasks
together and usually have a descriptive name associated with them. Projects may
also have a due date or time associated with them, which indicates when all tasks in
a project need to be completed. We also need to be able to indicate whether or not a
project is completed.
Users
By breaking down our project, we've also identied a third component of our
application: users. Users in our application will have the ability to create and manage
both projects and tasks as well as view the statuses and due dates of any given task.
While this component of our application may seem obvious, identifying it early
on allows us to better understand the interaction that our users will have with the
various components of our application.
The database
With the core components of our application identied, we can now begin to think
about what our database is going to look like. Let's start with the two database tables.
The tasks table
By looking at our requirements, we can identify several columns and data types for
our tasks table. As a rule, each task that we create will have a unique, incrementing
ID associated with it. Other columns that we can quickly identify are the task name,
the task description, the due date, and whether or not the task has been completed.
We also know that each task is going to be associated with a project, which means
we need to reference that project in our table.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 9 ]
There are also some columns we can identify that are not so obvious. The two
most useful columns that aren't explicitly identied are timestamps for the creation
date of the task and the date it was last updated on. By adding these two columns,
we can gain useful insights into the use of our application. It's possible that in the
future, our imaginary client may want to know how long an unresolved task has
been open for and whether or not it needs additional attention if it has not been
updated in several days.
With all the columns and data types for our table identied, our tasks table written
with generic SQL data types will look as follows:
ID INTEGER PRIMARY KEY
name TEXT
description TEXT
completed BOOLEAN
project_id INTEGER
due_date TIMESTAMP
created TIMESTAMP
updated TIMESTAMP
The projects table
By looking at our requirements for projects, we can easily pick out the major
columns for our projects table: a descriptive name, whether or not the project
has been completed, and when the project is due. We also know from our tasks
table that each project will need to have its own unique ID for the task to reference.
When the time comes to create our models in our application, we'll clearly dene
the one-to-many relationship between any given project and the many tasks
belonging to it. If we keep a created and updated column, our projects table
written in generic SQL will look as follows:
ID INTEGER PRIMARY KEY
name TEXT
completed BOOLEAN
due_date TIMESTAMP
created TIMESTAMP
updated TIMESTAMP
Downloading the example code
You can download the example code les for all Packt books you
have purchased from your account at http://www.packtpub.com.
If you purchased this book elsewhere, you can visit http://www.
packtpub.com/support and register to have the les e-mailed
directly to you.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 10 ]
Users
Our application requirements also show us that we need to store users somewhere.
For this application, we're going to store our users in a at le database. In Chapter 3,
Scheduled Reminders, we will expand upon this and store users in their own
database table.
Choosing a database technology
Now that we have decided what our database is going to look like, it's time to start
thinking about where we're going to store this information. To help familiarize
yourself with the different database adapters Yii natively supports, for this project,
we will be using SQLite. Since we now know where we're going to store our data,
we can identify all the correct data types for database tables.
The tasks table
Since SQLite only supports ve basic data types (NULL, INTEGER, REAL, TEXT, and
BLOB), we need to convert a few of the data types we initially identied for this table
into ones that SQLite supports. Since SQLite does not support Boolean or timestamps
natively, we need to nd another way of representing this data using a data type
that SQLite supports. We can represent a Boolean value as an integer either as 0
(false) or 1 (true). We can also represent all of our timestamp columns as integers by
converting the current date to a Unix timestamp.
With our nal data types gured out, our tasks table now will look like this:
ID INTEGER PRIMARY KEY
name TEXT
description TEXT
completed INTEGER
project_id INTEGER
due_date INTEGER
created INTEGER
updated INTEGER
The projects table
By applying the same logic to our projects table, we can derive the following
structure for this table:
ID INTEGER PRIMARY KEY
name TEXT
completed INTEGER
due_date INTEGER


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 11 ]
created INTEGER
updated INTEGER
The database overview
By spending a few minutes thinking about our application beforehand, we've
successfully identied all the tables for our application, how they interact with one
another, and all the column names and data types that our application will be using.
We've done a lot of work on our application already without even writing a single
line of code. By doing this work upfront, we have also reduced some of the work
we'll need to do later on when creating our models.
Initializing the project
With our nal database structure gured out, we can now start writing code. Using
the instructions in the ofcial guide (http://www.yiiframework.com/doc/guide/),
download and install the Yii framework. Once Yii is installed, navigate to your
webroot directory, and create a new folder called tasks. Next, navigate inside
the tasks folder, and create the following folder structure to serve as our
application's skeleton:
tasks/
assets/
protected/
commands/
components/
config/
controllers/
data/
migrations/
models/
runtime/
views/
layouts/
projects/
tasks/
site/
Yii has a built-in tool called yiic, which can automatically generate
a skeleton project. Refer to the quick start guide (http://www.
yiiframework.com/doc/guide/1.1/en/quickstart.
first-app) for more details.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 12 ]
Depending upon the web server you are using, you may also need to create a
.htaccess le in the root directory of your tasks folder. Information about how to
set up your application for the web server you are using can be found in the quick
start guide (http://www.yiiframework.com/doc/guide/1.1/en/quickstart.
apache-nginx-config).
After setting up our skeleton structure, we can rst create our conguration le located
at protected/config/main.php. Our conguration le is one of the most important
les of our application as it provides Yii with all the critical information necessary to
load and congure our application. The conguration le informs Yii about the les to
be preloaded by Yii's built-in autoloader, the modules to be loaded, the component to
be registered, and any other conguration options we want to pass to our application.
For this application, we will be enabling the Gii module, which will allow us
to create models based upon our database structure. We will also enable two
components, urlManager and db, which will allow us to set up custom routes
and access our SQLite database. Have a look at the following code snippet:
<?php
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'Task Application',
'import'=>array(
'application.models.*',
'application.components.*',
),
'modules'=>array(
// Include the Gii Module so that we can
//generate models and controllers for our application
'gii'=>array(
'class'=>'system.gii.GiiModule',
'password'=>false,
'ipFilters'=>false
),
),
'components'=>array(
'urlManager'=>array(
'urlFormat'=>'path',
'showScriptName'=>false,
'rules'=>array(
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>
'<controller>/<action>',


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 13 ]
'<controller:\w+>/<action:\w+>'=>
'<controller>/<action>',
),
),
// Define where our SQLite database is going to be
// stored, relative to our config file
'db'=>array(
'connectionString' =>
'sqlite:'.dirname(__FILE__).'/../data/tasks.db',
)
)
);
Next, we can create our index.php le as follows, which will serve as our bootstrap
endpoint for our web application:
<?php
// change the following paths if necessary
$yii='/opt/frameworks/php/yii/framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
// remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
// specify how many levels of call stack should be shown in each log
message
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
require_once($yii);
Yii::createWebApplication($config)->run();
Finally, we can create our applications yiic le in protected/yiic.php as follows,
which will allow us to run console commands native to Yii from our application:
<?php
// change the following paths if necessary
$config=dirname(__FILE__).'/config/main.php';
$config = require($config);
require_once('/opt/frameworks/php/yii/framework/yiic.php');


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 14 ]
Creating the database with migrations
Now that our application can be bootstrapped, we can create our database. To do
this, we are going to create a migration. Migrations are a feature of Yii that allow the
creation and modication of your database to be a part of your application. Rather
than creating schema modications in pure SQL, we can use migrations to grow
our database as a part of our application. In addition to acting as a revision system
for our database schema, migrations also have the added benet of allowing us to
transmit our database with our application without having to worry about sharing
data that would be stored in our database.
To create our database, open up your command-line interface of choice, navigate
to your tasks directory, and run the following command:
$ php protected/yiic.php migrate create tasks
The yiic command will then prompt you to conrm the creation of the
new migration:
Yii Migration Tool v1.0 (based on Yii v1.1.14)
Create new migration '/var/www/tasks/protected/migrations/m131213_013354_
tasks.php'? (yes|no) [no]:yes
New migration created successfully.
To prevent naming conicts with migrations, yiic will create the
migration with the following naming structure: m<timestamp>_<name>.
This has the added benet of allowing us to sequentially apply or remove
specic migrations based upon the order in which they were added. The
exact name of your migration will be slightly different than the one listed
in the preceding command.
After conrming the creation of the migration, a new le will be created in the
protected/migrations folder of our application. Open up the le, and add the
following to the up method:
$this->createTable('tasks', array(
'id' => 'INTEGER PRIMARY KEY',
'title' => 'TEXT',
'data' => 'TEXT',
'project_id' => 'INTEGER',
'completed' => 'INTEGER',
'due_date' => 'INTEGER',
'created' => 'INTEGER',


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 15 ]
'updated' => 'INTEGER'
));
$this->createTable('projects', array(
'id' => 'INTEGER PRIMARY KEY',
'name' => 'TEXT',
'completed' => 'INTEGER',
'due_date' => 'INTEGER',
'created' => 'INTEGER',
'updated' => 'INTEGER'
));
Notice that our database structure matches the schema that we identied earlier in
the chapter.
Next, replace the contents of the down method with instructions to drop the
database table if we call migrate down from the yiic command. Have a look at
the following code:
$this->dropTable('projects');
$this->dropTable('tasks');
Now that the migration has been created, run migrate up from the command line to
create the database and apply our migration. Run the following commands:
$ php protected/yiic.php migrate up
Yii Migration Tool v1.0 (based on Yii v1.1.14)
Total 1 new migration to be applied:
m131213_013354_tasks
Apply the above migration? (yes|no) [no]:yes
*** applying m131213_013354_tasks
*** applied m131213_013354_tasks (time: 0.009s)
Migrated up successfully.
Now, if you navigate to protected/data/, you will see a new le called tasks.db,
the SQLite database that was created by our migrations.
Migration commands can be run non-interactively by appending
--interactive=0 to the migrate command. This can be useful if you
want to automate deployments of your code to remote systems or if you
run your code through an automated testing service.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 16 ]
Creating models with Gii
Now that our database has been created, we can create models for our database
table. To create our models, we are going to use Gii, Yii's built-in code generator.
Open up your web browser and navigate to http://localhost/gii (in this book,
we will always use localhost as our working hostname for our working project. If
you are using a different hostname, replace localhost with your own). Once loaded,
you should see the Yii Code Generator, as shown in the following screenshot:
If you aren't able to access Gii, verify that your web server has rewriting
enabled. Information about how to properly congure your web server
for Yii can be found at (http://www.yiiframework.com/doc/
guide/1.1/en/quickstart.apache-nginx-config).
Click on the link titled Model Generator, and then ll in the form on the page
that appears. The table name should be set to tasks. The model name should
prepopulate. If it doesn't, set the model name to Tasks, and then click on preview.
Once the page has reloaded, you can preview what the model will look like before
clicking on the Generate button to write your new model to your protected/
models/ directory. Once you have generated your model for tasks, repeat the
process for projects.
Enhancing the models
Now that our models have been created, there are several sections that should
be modied.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 17 ]
Updating the default validation rules
The rst part of our model that needs to be modied is the validation rules.
Validation rules in Yii are stored in the model's rules() method and are
executed when the model's validate() method is called. Starting with our tasks
model, we can see that Gii has already prepopulated our validation rules for us
based upon our database.
There are several elds of this model that we would like to always have set, namely,
project_id, title, the task itself, and whether or not it has been completed. We can
make these elds required in our model by adding a new array to our rules section,
as follows:
array('project_id, title, data, completed', 'required')
By making these elds required in our model, we can make client- and server-side
validation easier when we start making forms. Our nal method for this model will
look as follows:
public function rules()
{
return array(
array('project_id, completed, due_date, created, updated',
'numerical', 'integerOnly'=>true),
array('project_id, title, data, completed', 'required'),
array('title, data', 'safe'),
array('id, title, data, project_id, completed, due_date,
created, updated', 'safe', 'on'=>'search'),
);
}
Our project's models should also be changed so that the project name and its
completed status are required. We can accomplish this by adding the following
to our validation rules array:
array('name, completed', 'required')
Additional validation rules can be found in the Yii wiki at http://
www.yiiframework.com/wiki/56/


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 18 ]
Dened relations
Another component of our model that we should change is the relations()
method. By declaring model relations in Yii, we can take advantage of the ability
of ActiveRecords to automatically join several related models together and retrieve
data from them without having to explicitly call that model for its data.
For example, once our model relations are set up, we will be able to retrieve the
project name from the Tasks model, as follows:
Tasks::model()->findByPk($id)->project->name;
Before we can declare our relations though, we need to determine what the
relations actually are. Since SQLite does not support foreign key relations,
Gii was unable to automatically determine the relations for us.
In Yii, there are four types of relations: BELONGS_TO, HAS_MANY, HAS_ONE, and
MANY_MANY. Determining the relation type can be done by looking at the foreign
key for a table and asking which relational type ts best based upon the data that
the table will store. For this application, this question can be answered as follows:
Tasks belong to a single project
A project has one or many tasks
Now that we have determined our relationship types between our two tables,
we can write the relations. Starting with the tasks table, replace the relations()
method with the following:
public function relations()
{
return array(
'tasks' => array(self::HAS_MANY, 'Task', 'project_id')
);
}
The syntax for the relations array is as follows:
'var_name'=>array('relationship_type', 'foreign_model', 'foreign_key',
[... other options ..])
For our projects model, our relations() method looks like this:
public function relations()
{
return array(
'tasks' => array(self::HAS_MANY, 'Tasks', 'project_id')
);
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 19 ]
Removing tasks when a project is deleted
In our model's current state, whenever a project is deleted, all the tasks associated
with it become orphaned. One way of dealing with this edge case is to simply delete
any tasks associated with the project. Rather than writing code to handle this in the
controller, we can have the model take care of it for us by referencing the project's
model's beforeDelete() method as follows:
public function beforeDelete()
{
Tasks::model()->deleteAllByAttributes(array('project_id' => $this-
>id));
return parent::beforeDelete();
}
Retrieving the project metadata
There is also metadata about a project that we cannot obtain directly from the
projects database table. This data includes the number of tasks a project has, as
well as the number of completed tasks a project has. We can obtain this from our
model by creating two new methods in the project's model, as follows:
public function getNumberOfTasks()
{
return Tasks::model()->countByAttributes(array('project_id' =>
$this->id));
}
public function getNumberOfCompletedTasks()
{
return Tasks::model()->countByAttributes(array('project_id' =>
$this->id, 'completed' => 1));
}
Additionally, we can determine the progress of a project by getting a percentage of
completed tasks versus the total number of tasks, as follows:
public function getPercentComplete()
{
$numberOfTasks = $this->getNumberOfTasks();
$numberOfCompletedTasks = $this->getNumberOfCompletedTasks();
if ($numberOfTasks == 0)
return 100;
return ($numberOfCompletedTasks / $numberOfTasks) * 100;
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 20 ]
Automatically setting the created and updated time
The last change needed to be made to the models is to enable them to automatically
set the created and updated timestamp in the database every time the model is
saved. By moving this logic into the models, we can avoid having to manage it
either in the forms that submit the data or in the controllers that will process this
data. This change can be made by adding the following to both models:
public function beforeSave()
{
if ($this->isNewRecord)
$this->created = time();
$this->updated = time();
return parent::beforeSave();
}
In the beforeSave() method, the updated property is always set every time the
model is saved, and the created property is only set if ActiveRecord considers this
to be a new record. This is accomplished by checking the isNewRecord property of
the model. Additionally, both properties are set to time(), the PHP function used
to get the current Unix timestamp.
The last piece of code that is important in this method is return
parent::beforeSave();. When Yii's save() method is called, it checks that
beforeSave() returns true before saving the data to the database. While we could
have this method return true, it's easier to have it return whatever the parent model
(in this case CActiveRecord) returns. It also ensures that any changes made to the
parent model will get carried to the model.
Since the beforeSave() method is identical for both models, we
could also create a new model that only extended CActiveRecord and
only implemented this method. The tasks and projects model will then
extend that model rather than CActiveRecord and will inherit this
functionality. Moving shared functionality to a shared location reduces
the number of places where code needs to be written and, consequently,
the number of places a bug can show up in.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 21 ]
Creating the presentation layer
Up until this point, all the code that has been written is backend code that the end
user won't be able to see. In this section, we will be creating the presentation layer
of our application. The presentation layer of our application is composed of three
components: controllers, layouts, and views. For this next section, we'll be creating
all the three components.
As a developer, we have several options to create the presentation layer. One way we
can create the presentation layer is using Gii. Gii has several built-in tools that can
assist you in creating new controllers, forms for our views, and even full create, read,
update, and delete (CRUD) skeletons for our application. Alternatively, we can write
everything by hand.
Managing projects
The rst part of the presentation layer we are going to work on is the projects
section. To begin with, create a new le in protected/controllers/ called
ProjectControllerProjectController.php that has the following class signature:
<?php
class ProjectControllerProjectController extends CController {}
For our controllers, we will be extending Yii's base class called CController. In future
chapters, we will create our own controllers and extend the controllers from them.
Before we can start displaying content from our new action, we'll need to create
a layout for our content to be rendered in. To specify our layout, create a public
property called $layout, and set the value to 'main':
public $layout = 'main';
Next, let's create our rst action to make sure everything is working:
public function actionIndex()
{
echo "Hello!";
}
Now, we should be able to visit http://localhost/projects/index from our web
browser and see the text Hello printed on the screen. Before we continue dening
our actions, let's create a layout that will help our application look a little better.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 22 ]
Creating the layout
The layout that we specied references the le located in protected/views/
layouts/main.php. Create this le and open it for editing. Then, add the following
basic HTML5 markup:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
Then add a title within the <head> tag that will display the application name we
dened in protected/config/main.php:
<title><?php echo Yii::app()->name; ?></title>
Next, let's add a few meta tags, CSS, and scripts. To reduce the number of les we
need to download, we'll be including styles and scripts from a publicly available
Content Distribution Network (CDN). Rather than writing markup for these
elements, we're going to use CClientScript, a class made to manage JavaScript,
CSS, and meta tags for views.
For this application, we'll be using a frontend framework called Twitter Bootstrap.
This framework will style many of the common HTML tags that our application will
use, providing it with a cleaner overall look.
When you're ready to go live with your application, you should consider
moving the static assets you are using to a CDN, referencing popular
libraries such as Twitter Bootstrap and jQuery from a publicly available
CDN. CDNs can help to reduce hosting costs by reducing the amount of
bandwidth your server needs to use to send les. Using a CDN can also
speed up your site since they usually have servers geographically closer
to your users than your main server.
First, we're going to call CClientScript, as follows:
<?php $cs = Yii::app()->clientScript; ?>
Secondly, we're going to set the Content-Type to text/html with a UTF-8 character
set, as follows:
<?php $cs->registerMetaTag('text/html; charset=UTF-8', 'Content-
Type'); ?>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 23 ]
Next, we're going to register the CSS from Twitter Bootstrap 3 from a popular CDN,
as follows:
<?php $cs->registerCssFile( '//netdna.bootstrapcdn.com/
bootstrap/3.0.3/css/bootstrap.min.css' ); ?>
Then we'll register the JavaScript library for Twitter Bootstrap:
<?php $cs->registerScriptFile( '//netdna.bootstrapcdn.com/
bootstrap/3.0.3/js/bootstrap.min.js' ); ?>
Finally, we're going to register jQuery 2.0 and have Yii placed at the end of the
<body> tag, as follows:
<?php $cs->registerScriptFile( '//code.jquery.com/jquery.js',
CClientScript::POS_END ); ?>
CClientScript also supports method chaining, so you could also change the
preceding code to the following:
<?php Yii::app()->clientScript
->registerMetaTag('text/html; charset=UTF-8', 'Content-
Type')
->registerCssFile( '//netdna.bootstrapcdn.com/
bootstrap/3.0.3/css/bootstrap.min.css'
->registerScriptFile( '//netdna.bootstrapcdn.com/
bootstrap/3.0.3/js/bootstrap.min.js' )
->registerScriptFile( 'https://code.jquery.com/jquery.js' ,
CClientScript::POS_END); ?>
For the last part of our layout, let's add a basic header within our <body> tag that will
help with navigation, as follows:
<div class="row">
<div class="container">
<nav class="navbar navbar-default navbar-fixed-top"
role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="/"><?php echo
CHtml::encode(Yii::app()->name); ?></a>
</div>
</nav>
</div>
</div>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 24 ]
After the closing </div> tag, add the following:
<div class="row" style="margin-top: 100px;">
<div class="container">
<?php echo $content; ?>
</div>
</div>
The $content variable that we've added to our layout is a special variable that
contains all the rendered HTML markup from our view les and is dened by the
CController class in the render() method. Yii will automatically populate this
variable for us whenever we call the render() method from within our controllers.
Creating the project index action
With our layout dened, we can get back to creating actions. Let's start by modifying
our actionIndex() method so that it renders a view.
First, create a variable to store a searchable copy of our model. Have a look at the
following code:
$model = new Projects('search');
Next, render a view called index, which references protected/views/projects/
index.php, and pass the model we created to this view, as follows:
$this->render('index', array('model' => $model));
Now, create the view le in protected/views/projects/index.php and open it
for editing. Begin by adding a button in the view as follows, which will reference
the save action that we will create later on:
<?php echo CHtml::link('Create New Project', $this->createUrl('/
projects/save'), array('class' => 'btn btn-primary pull-right')); ?>
<div class="clearfix"></div>
Then add a descriptive title so that we know what page we are on. Have a look at
the following line of code:
<h1>Projects</h1>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 25 ]
Finally, create a new widget that uses CListView, a built-in Yii widget designed
for displaying data from CActiveDataProvider. In Yii, widgets are frontend
components that help us to quickly generate commonly used code, typically for
presentation purposes. This widget will automatically generate pagination for us
as necessary and will allow each of our items to look the same. Have a look at the
following code:
<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$model->search(),
'itemView'=>'_project',
)); ?>
The new widget that we created consists of two parts. The rst is the dataProvider,
which provides data to the widget. This data comes from our project's model's
search() method, a piece of code automatically generated by Gii.
The second part of the widget is the itemView, which references the specic view
le that our items will be rendered out of. In this case, the view references a le in
the same directory of protected/views/projects called _project.php. Create
this le and then add the following code to it:
<div>
<div class="pull-left">
<p><strong><?php echo CHtml::link(CHtml::encode($data->name),
$this->createUrl('/projects/tasks', array('id' => $data->id))); ?></
strong></p>
<p>Due on <?php echo date('m/d/Y', $data->due_date); ?></p>
<?php if ($data->completed): ?>
Completed
<?php else: ?>
<?php if ($data->numberOfTasks == 0): ?>
<p>No Tasks</p>
<?php else: ?>
<p><?php echo $data->getPercentComplete(); ?>%
Completed</p>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="pull-right">
<?php echo CHtml::link(NULL, $this->createUrl('/projects/
save', array('id' => $data->id)), array('title' => 'edit', 'class' =>
'glyphicon glyphicon-pencil')); ?>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 26 ]
<?php echo CHtml::link(NULL, $this->createUrl('/projects/
complete', array('id' => $data->id)), array('title' => $data-
>completed == 1 ? 'uncomplete' : 'complete', 'class' => 'glyphicon
glyphicon-check')); ?>
<?php echo CHtml::link(NULL, $this->createUrl('/projects/
delete', array('id' => $data->id)), array('title' => 'delete', 'class'
=> 'glyphicon glyphicon-remove')); ?>
</div>
<div class="clearfix"></div>
</div>
<hr/>
If we refresh our browser page now, our view will show us that no results were
found. Before we can see data, we need to create an action and view to create and
update it. Before we start creating new records, let's create two other actions that we
outlined in our item's view: complete and delete.
Changing a project's completion state
First, let's create an action to mark a project as completed or uncompleted. This
action will only be responsible for changing the completed eld of the projects table
to 0 or 1, depending on its current state. For simplicity, we can just XOR the eld by
1 and save the model. Have a look at the following code:
public function actionComplete($id)
{
$model = $this->loadModel($id);
$model->completed ^= 1;
$model->save();
$this->redirect($this->createUrl('/projects'));
}
Additionally, we'll create another private method called loadModel(), which will
load our appropriate model for us and throw an error if it cannot be found. For this
method, we'll use CHttpException, which will create an HTTP exception with the
error message we provide if a model with the specied ID cannot be found. Have a
look at the following code:
private function loadModel($id)
{
$model = Projects::model()->findByPk($id);
if ($model == NULL)
throw new CHttpException('404', 'No model with that ID could
be found.');
return $model;
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 27 ]
Deleting projects
Next, we'll create a method to delete the project. This method will use the
loadModel() method we dened earlier. Additionally, if we encounter an error
deleting the model, we'll throw an HTTP exception so that the user knows something
went wrong. Here's how we go about it:
public function actionDelete($id)
{
$model = $this->loadModel($id);
if ($model->delete())
$this->redirect($this->createUrl('/projects'));
throw new CHttpException('500', 'There was an error deleting the
model.');
}
Creating and updating projects
With the two other methods dened, we can now work on creating and updating a
project. Rather than creating two actions to handle both these tasks, we're going to
create one action that knows how to handle both by checking the ID that we'll pass
as a GET parameter. We can do that by dening a new action that looks as follows:
public function actionSave($id=NULL) {
We can then either create a new project or update a project based upon whether or
not we were provided with an ID by the user. By taking advantage of loadModel(),
we also take care of any errors that would occur if an ID was provided but a project
with that ID didn't exist. Have a look at the following code:
if ($id == NULL)
$model = new Projects;
else
$model = $this->loadModel($id);
Next, we can detect whether the user submitted data by checking the $_POST
variable for an array called Projects. If that array is dened, we'll assign it to
our $model->attributes object. Before saving the model, however, we'll want
to convert whatever the user entered into a Unix timestamp. Have a look at the
following code:
if (isset($_POST['Projects']))
{
$model->attributes = $_POST['Projects'];


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 28 ]
$model->due_date = strtotime($_POST['Projects']['due_date']);
$model->save();
}
Finally, we'll render the view and pass the model down to it, as follows:
$this->render('save', array('model' => $model));
Create a new le in protected/views/projects/ called save.php and open it to
edit. Begin by adding a header that will let us know whether we are editing a project
or creating a new one, as follows:
<h1><?php echo $model->isNewRecord ? 'Create New' : 'Update'; ?>
Project</h1>
Next, we'll create a new widget with CActiveForm, which will take care of the hard
tasks of creating and inserting form elds into our view le (such as what the names
and IDs of form elds should be):
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'project-form',
'htmlOptions' => array(
'class' => 'form-horizontal',
'role' => 'form'
)
)); ?>
<?php $this->endWidget(); ?>
Between the beginWidget and endWidget call, add an error summary if the
user encounters an error:
<?php echo $form->errorSummary($model); ?>
Then, after the error summary, add the form elds and their associated styles,
as follows:
<div class="form-group">
<?php echo $form->labelEx($model,'name', array('class' => 'col-
sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->textField($model,'name', array('class' =>
'form-control')); ?>
</div>
</div>
<div class="form-group">


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 29 ]
<?php echo $form->labelEx($model,'completed', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->dropDownList($model,'completed', array('0'
=> 'No','1' => 'Yes'), array('class' => 'form-control')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model,'due_date', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<div class="input-append date">
MM/DD/YYYY
<?php $this->widget('zii.widgets.jui.CJuiDatePicker',
array(
'model' => $model,
'attribute' => 'due_date',
'htmlOptions' => array(
'size' => '10',
'maxlength' => '10',
'class' => 'form-control',
'value' => $model->due_date == "" ? "" :
date("m/d/Y", $model->due_date)
),
)); ?>
</div>
</div>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' :
'Save', array('class' => 'btn btn-primary pull-right')); ?>
</div>
Did you notice how we're taking advantage of the Yii widget called
CJuiDatePicker? This widget will provide us with a clean interface for
selecting dates from a calendar view, rather than requiring our end user
to type in the date manually and in the specied format we've requested.
Now we can create, update, view, and delete projects. Additionally, we've created
an easy action to mark them as completed. Before we're done with this controller,
we need to add an action that allows us to view tasks in our project.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 30 ]
Viewing tasks
Our tasks action for this controller will function in the same manner as our index
action but will instead use a view called tasks:
public function actionTasks($id=NULL)
{
if ($id == NULL)
throw new CHttpException(400, 'Missing ID');
$project = $this->loadModel($id);
if ($project === NULL)
throw new CHttpException(400, 'No project with that ID
exists');
$model = new Tasks('search');
$model->attributes = array('project_id' => $id);
$this->render('tasks', array('model' => $model, 'project' =>
$project));
}
The tasks.php view in protected/views/projects/tasks.php will look
as follows:
<?php echo CHtml::link('Create New Task', $this->createUrl('/tasks/
save?Tasks[project_id]=' . $project->id), array('class' => 'btn btn-
primary pull-right')); ?>
<div class="clearfix"></div>
<h1>View Tasks for Project: <?php echo $project->name; ?></h1>
<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$model->search(),
'itemView'=>'_tasks',
));
?>
The _tasks.php item view in protected/views/projects/tasks.php will look
as follows:
<div>
<div class="pull-left">
<p><strong><?php echo CHtml::link(CHtml::encode($data->title),
$this->createUrl('/tasks/save', array('id' => $data->id))); ?></
strong></p>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 31 ]
<p>Due on <?php echo date('m/d/Y', $data->due_date); ?></p>
</div>
<div class="pull-right">
<?php echo CHtml::link(NULL, $this->createUrl('/tasks/save',
array('id' => $data->id)), array('class' => 'glyphicon glyphicon-
pencil')); ?>
<?php echo CHtml::link(NULL, $this->createUrl('/tasks/
complete', array('id' => $data->id)), array('title' => $data-
>completed == 1 ? 'uncomplete' : 'complete', 'class' => 'glyphicon
glyphicon-check')); ?>
<?php echo CHtml::link(NULL, $this->createUrl('/tasks/delete',
array('id' => $data->id)), array('class' => 'glyphicon glyphicon-
remove')); ?>
</div>
<div class="clearfix"></div>
</div>
<hr/>
Managing tasks
Now that we can manage projects, let's work on managing tasks. Our
TasksController is going to be nearly identical to our project's controller with
only a few differences. Start by creating a new le in protected/controllers
called TasksController.php that has the following signature:
<?php class TasksController extends CController {}
By only making a small change to our loadModel() method, we can reuse the
delete and complete action from our projects controller, as follows:
private function loadModel($id)
{
$model = Tasks::model()->findByPk($id);
if ($model == NULL)
throw new CHttpException('404', 'No model with that ID could
be found.');
return $model;
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 32 ]
Our save action is almost identical to our project's save action. Have a look at the
following code:
public function actionSave($id=NULL)
{
if ($id == NULL)
$model = new Tasks;
else
$model = $this->loadModel($id);
if (isset($_GET['Tasks']))
$model->attributes = $_GET['Tasks'];
if (isset($_POST['Tasks']))
{
$model->attributes = $_POST['Tasks'];
$model->due_date = strtotime($_POST['Tasks']['due_date']);
$model->save();
}
$this->render('save', array('model' => $model));
}
The view le for this action is almost the same as well. If you haven't already, create
a le called save.php in protected/views/tasks/, and then add the following
lines of code to nish the view:
<ol class="breadcrumb">
<li><?php echo CHtml::link('Project', $this->createUrl('/
projects')); ?></li>
<li class="active"><?php echo $model->isNewRecord ? 'Create New' :
'Update'; ?> Task</li>
</ol>
<hr />
<h1><?php echo $model->isNewRecord ? 'Create New' : 'Update'; ?>
Task</h1>
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'project-form',
'htmlOptions' => array(
'class' => 'form-horizontal',
'role' => 'form'
)
)); ?>
<?php echo $form->errorSummary($model); ?>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 33 ]
<div class="form-group">
<?php echo $form->labelEx($model,'title', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->textField($model,'title', array('class'
=> 'form-control')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model,'data', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->textArea($model,'data', array('class' =>
'form-control')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model,'project_id', array('class'
=> 'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->dropDownList($model,'project_id',
CHtml::listData(Projects::model()->findAll(), 'id', 'name'),
array('empty'=>'Select Project', 'class' => 'form-control')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model,'completed', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<?php echo $form->dropDownList($model,'completed',
array('0' => 'No','1' => 'Yes'), array('class' => 'form-control')); ?>
</div>
</div>
<div class="form-group">
<?php echo $form->labelEx($model,'due_date', array('class' =>
'col-sm-2 control-label')); ?>
<div class="col-sm-10">
<div class="input-append date">
<?php $this->widget('zii.widgets.jui.CJuiDatePicker',
array(
'model' => $model,
'attribute' => 'due_date',
'htmlOptions' => array(


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 34 ]
'size' => '10',
'maxlength' => '10',
'class' => 'form-control',
'value' => $model->due_date == "" ? "" :
date("m/d/Y", $model->due_date)
),
)); ?> </div>
</div>
</div>

<div class="row buttons">
<?php echo CHtml::submitButton($model->isNewRecord ? 'Create'
: 'Save', array('class' => 'btn btn-primary pull-right')); ?>
</div>
<?php $this->endWidget(); ?>
Preventing unauthorized access to our
application
Our tasks application can now do everything we dened in our requirements.
However, it is open to the world. Anyone who wants to edit our tasks could simply
visit our website and change anything without our knowledge. Before nishing up,
let's create a simple authentication system to protect our data.
Requiring authentication with lters and
access rules
The rst part in protecting our application is making sure that only authorized
people can visit our application. We can do this by adding a lter to our controller
called accessControl and dening access rules to access our content.
A lter is a piece of code that gets executed before (and/or after) a controller
action runs, which means that the user will be required to be authenticated before
accessing our content. To add the accessControl lter, add the following to both
TasksController and ProjectsController:
public function filters()
{
return array(
'accessControl',
);
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 35 ]
Next, create a new method called accessRules(), which will dene what users can
access our application. For our application, we want to deny access to anyone who
isn't authenticated. Have a look at the following code snippet:
public function accessRules()
{
return array(
array('allow',
'users'=>array('@'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
In the preceding array, @ is a shorthand reference to an authenticated user. Now if
we try to visit our web page, we'll be redirected to /site/login, the default login
action in Yii.
Creating a controller for the authentication
Create a le called SiteController.php in protected/controllers, and then
create login and logout actions as follows:
<?php
class SiteController extends CController
{
public $layout = 'signin';

public function actionLogin()
{
$model = new LoginForm;
if (isset($_POST['LoginForm']))
{
$model->attributes = $_POST['LoginForm'];
if ($model->login())
$this->redirect($this->createUrl('/projects'));
}
$this->render('login', array('model' => $model));
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 36 ]
public function actionLogout()
{
Yii::app()->user->logout();
$this->redirect($this->createUrl('/site/login'));
}
}
Creating a login layout
For this controller, we're going to create a new layout called login.php in
protected/views/layouts. Copy the markup from protected/views/
layouts/main.php to our new layout, and replace the contents of the <body>
tag with the following:
<div class="row">
<div class="container">
<?php echo $content; ?>
</div>
</div>
To make our login page look more like a login page, add the following CSS to
the layout either as an inline style or as a separate le in /css/signup.css:
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
}
.form-signin .checkbox {
font-weight: normal;
}
.form-signin .form-control {
position: relative;


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 37 ]
font-size: 16px;
height: auto;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="text"] {
margin-bottom: -1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
Creating a login view
Create a new form in protected/views/site/login.php that will hold our login
model, as follows:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableClientValidation'=>true,
'htmlOptions' => array(
'class' => 'form-signin',
'role' => 'form'
),
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<?php if (!Yii::app()->user->isGuest): ?>
<h2 class="form-signin-heading">You are already signed in!
Please <?php echo CHtml::link('logout', $this->createUrl('/site/
logout')); ?> first.</h2>
<?php else: ?>


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 38 ]
<h2 class="form-signin-heading">Please sign in</h2>
<?php echo $form->errorSummary($model); ?>
<?php echo $form->textField($model,'username', array('class'
=> 'form-control', 'placeholder' => 'Username')); ?>
<?php echo $form->passwordField($model,'password',
array('class' => 'form-control', 'placeholder' => 'Password')); ?>
<?php echo CHtml::tag('button', array('class' => 'btn btn-lg
btn-primary btn-block'), 'Submit'); ?>
<?php endif; ?>
<?php $this->endWidget(); ?>
Identifying our users with the UserIdentity
CUserIdentity class
Before we create our login model, we need to create a way to identify our users.
Fortunately, Yii has a built-in class to handle this called CUserIdentity. By easily
extending CUserIdentity, we can create a key-value login pair that will ensure
that only authenticated users can log in to our application.
Create a new le called UserIdentity.php in /components, and add the following:
<?php
class UserIdentity extends CUserIdentity
{
public function authenticate()
{
$users=array(
'demo'=>'demo',
'admin'=>'admin',
);
if(!isset($users[$this->username]))
$this->errorCode=self::ERROR_USERNAME_INVALID;
elseif($users[$this->username]!==$this->password)
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
$this->errorCode=self::ERROR_NONE;
return !$this->errorCode;
}
}
The authenticate() method of UserIdentity is what we'll use in our login model
to ensure that we have valid credentials. In this class, we are simply checking
whether the username that will be sent to this class by our login model matches the
key associated with it. If a user's password does not match the key in our $users
array, or if the user is not dened in our $users array, we return an error code.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 39 ]
Creating the login model
The last component we need to authenticate our users is to create a generic model
to authenticate the user against. Begin by creating a new le called LoginForm.php
in protected/models. This class will extend CFormModel, a generic model in Yii for
forms, as follows:
<?php class LoginForm extends CFormModel {
Since CFormModel doesn't connect to a database, we dened attributes as public
properties, as follows:
public $username;
public $password;
private $_identity;
Our model also needs validation rules to verify that we have a valid user. In addition
to making sure username and password are provided, we're going to provide an
additional validation rule called authenticate, which will validate that we have a
valid username and password. Have a look at the following lines of code:
public function rules()
{
return array(
array('username, password', 'required'),
array('password', 'authenticate'),
);
}
Because our authenticate() method is a custom validator, its method signature
has two parameters, $attribute and $params, which have information about the
attribute and parameters that may have been passed from the validator. This method
will determine whether our credentials are valid. Have a look at the following code:
public function authenticate($attribute,$params)
{
if(!$this->hasErrors())
{
$this->_identity=new UserIdentity($this->username,$this-
>password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect username or
password.');
}
}


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 40 ]
Finally, we'll create the login() method that our SiteController calls. In addition
to validating our credentials, it will do the heavy lifting of creating a session for the
user. Have a look at the following code:
public function login()
{
if (!$this->validate())
return false;
if ($this->_identity===null)
{
$this->_identity=new UserIdentity($this->username,$this-
>password);
$this->_identity->authenticate();
}
if ($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration = 3600*24*30;
Yii::app()->user->login($this->_identity,$duration);
return true;
}
else
return false;
}
Now you can visit our site and log in with the credentials provided in our
UserIdentity.php le.
Finishing touches
Before completing our project, there are a few things we need to take care of in our
protected/config/main.php le to enhance the security of our application and to
make our application easier to use.
It would be nice to also add some pictures of the nal application.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

Chapter 1
[ 41 ]
Disabling Gii
At the beginning of our project, we enabled the Gii module to assist us in creating
models for our application. Since Gii has the ability to write new les to our project,
we should remove the following section from our config le:
'gii'=>array(
'class'=>'system.gii.GiiModule',
'password'=>false,
'ipFilters' => false
),
Dening a default route
Presently, if we try to visit the root URL of our application, we are presented with
an error. To avoid this, we can add a route in to the routes array of our URL Manager
component. With this addition, whenever we visit the root URL of our application,
we will be presented with the index action of the project's controller. Have a look
at the following code:
'components'=>array(
[...]
'urlManager'=>array(
[...]
'rules'=>array(
[...]
'/' => 'projects/index'
),
)
)
Adding extra routes
Finally, add two more routes to our URL Manager routes array. These routes will
help us more easily access the login and logout actions for our site. Have a look
at the following code:
'login' => 'site/login',
'logout' => 'site/logout'


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

A Task-management Application
[ 42 ]
Summary
In this chapter, we covered quite a lot of information. We created an automated
way of creating and distributing our database, models to represent the tables in
the database, and a few controllers to manage and interact with our data. We also
created a simple key-value authentication system to protect our data. Many of
the methods we used in this chapter, and the code we wrote, can be reused and
expanded upon in later chapters. Before continuing, be sure to take a look at all
the classes we referenced in the chapter, in the ofcial Yii documentation, so that
you can better understand them.


For More Information:
www.packtpub.com/web-development/yii-project-blueprints


Where to buy this book
You can buy Yii Project Blueprints from the Packt Publishing website:
.
Free shipping to the US, UK, Europe and selected Asian countries. For more information, please
read our shipping policy.
Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and
most internet book retailers.




















www.PacktPub.com


For More Information:
www.packtpub.com/web-development/yii-project-blueprints

You might also like