From e2cb0b52aaa02a3f3f41d0df377d189529713738 Mon Sep 17 00:00:00 2001
From: wei <>
Date: Thu, 10 May 2007 23:00:04 +0000
Subject: Update blog tutorial
---
buildscripts/chmbuilder/chm_style.css | 6 +
.../protected/pages/Day1/CreateContact.page | 83 +++++-----
.../blog-tutorial/protected/pages/Day1/Setup.page | 2 +-
.../protected/pages/Day1/ShareLayout.page | 14 +-
.../protected/pages/Day2/CreateAR.page | 105 +++++++++---
.../protected/pages/Day2/CreateDB.page | 11 +-
demos/blog-tutorial/protected/pages/Day2/ER.gif | Bin 5172 -> 4444 bytes
demos/blog-tutorial/protected/pages/Day2/ER.vsd | Bin 73216 -> 73216 bytes
demos/blog-tutorial/protected/pages/Day3/Auth.page | 84 +++++-----
.../protected/pages/Day3/CreateAdminUser.page | 58 +++----
.../protected/pages/Day3/CreateEditUser.page | 177 +++++++++++----------
.../protected/pages/Day3/CreateLoginUser.page | 106 ++++++------
.../protected/pages/Day3/CreateNewUser.page | 120 +++++++-------
.../samples/day2/blog/protected/data/blog.db | Bin 4096 -> 4096 bytes
.../day2/blog/protected/database/PostRecord.php | 23 +--
.../day2/blog/protected/database/UserRecord.php | 23 +--
.../samples/day2/blog/protected/schema.sql | 7 +-
.../samples/day3/blog/protected/data/blog.db | Bin 5120 -> 4096 bytes
.../day3/blog/protected/database/PostRecord.php | 23 +--
.../day3/blog/protected/database/UserRecord.php | 23 +--
.../samples/day3/blog/protected/schema.sql | 7 +-
demos/blog-tutorial/themes/PradoSoft/style.css | 6 +
.../pages/GettingStarted/CommandLine.page | 12 +-
demos/quickstart/themes/PradoSoft/style.css | 6 +
24 files changed, 494 insertions(+), 402 deletions(-)
diff --git a/buildscripts/chmbuilder/chm_style.css b/buildscripts/chmbuilder/chm_style.css
index 6b2ae955..f512e1ab 100644
--- a/buildscripts/chmbuilder/chm_style.css
+++ b/buildscripts/chmbuilder/chm_style.css
@@ -108,6 +108,12 @@ a
margin: 0;
}
+.cli
+{
+ color: white;
+ background-color: #555;
+}
+
.runbar
{
margin: 1em 0 1em 0;
diff --git a/demos/blog-tutorial/protected/pages/Day1/CreateContact.page b/demos/blog-tutorial/protected/pages/Day1/CreateContact.page
index 4daf43e3..28ad4b21 100644
--- a/demos/blog-tutorial/protected/pages/Day1/CreateContact.page
+++ b/demos/blog-tutorial/protected/pages/Day1/CreateContact.page
@@ -47,37 +47,34 @@ We use template to organize the presentational layout of the feedback form. In t
<com:TForm>
-
Contact
-Please fill out the following form to let me know your feedback on my blog. Thanks!
-
Your Name:
<com:TRequiredFieldValidator ControlToValidate="Name"
- ErrorMessage="Please provide your name."
- Display="Dynamic" />
+ ErrorMessage="Please provide your name."
+ Display="Dynamic" />
<com:TTextBox ID="Name" />
Your Email:
<com:TRequiredFieldValidator ControlToValidate="Email"
- ErrorMessage="Please provide your email address."
- Display="Dynamic" />
+ ErrorMessage="Please provide your email address."
+ Display="Dynamic" />
<com:TEmailAddressValidator ControlToValidate="Email"
- ErrorMessage="You entered an invalid email address."
- Display="Dynamic" />
+ ErrorMessage="You entered an invalid email address."
+ Display="Dynamic" />
<com:TTextBox ID="Email" />
Feedback:
<com:TRequiredFieldValidator ControlToValidate="Feedback"
- ErrorMessage="Please provide your feedback."
- Display="Dynamic" />
+ ErrorMessage="Please provide your feedback."
+ Display="Dynamic" />
<com:TTextBox ID="Feedback"
- TextMode="MultiLine"
- Rows="10"
- Columns="40" />
+ TextMode="MultiLine"
+ Rows="10"
+ Columns="40" />
<com:TButton Text="Submit" OnClick="submitButtonClicked" />
@@ -103,13 +100,13 @@ Besides TTextBox controls, the template also uses many validator contro
Your Email:
<com:TRequiredFieldValidator
- ControlToValidate="Email"
- ErrorMessage="Please provide your email address."
- Display="Dynamic" />
+ ControlToValidate="Email"
+ ErrorMessage="Please provide your email address."
+ Display="Dynamic" />
<com:TEmailAddressValidator
- ControlToValidate="Email"
- ErrorMessage="You entered an invalid email address."
- Display="Dynamic" />
+ ControlToValidate="Email"
+ ErrorMessage="You entered an invalid email address."
+ Display="Dynamic" />
<com:TTextBox ID="Email" />
@@ -152,29 +149,29 @@ We thus write down the page class as follows:
IsValid) // check if input validation is successful
- {
- // obtain the user name, email, feedback from the textboxes
- $name = $this->Name->Text;
- $email = $this->Email->Text;
- $feedback = $this->Feedback->Text;
-
- // send an email to administrator with the above information
- $this->mailFeedback($name, $email, $feedback);
- }
- }
-
- protected function mailFeedback($name, $email, $feedback)
- {
- // implementation of sending the feedback email
- }
+ /**
+ * Event handler for the OnClick event of the submit button.
+ * @param TButton the button triggering the event
+ * @param TEventParameter event parameter (null here)
+ */
+ public function submitButtonClicked($sender, $param)
+ {
+ if ($this->IsValid) // check if input validation is successful
+ {
+ // obtain the user name, email, feedback from the textboxes
+ $name = $this->Name->Text;
+ $email = $this->Email->Text;
+ $feedback = $this->Feedback->Text;
+
+ // send an email to administrator with the above information
+ $this->mailFeedback($name, $email, $feedback);
+ }
+ }
+
+ protected function mailFeedback($name, $email, $feedback)
+ {
+ // implementation of sending the feedback email
+ }
}
?>
diff --git a/demos/blog-tutorial/protected/pages/Day1/Setup.page b/demos/blog-tutorial/protected/pages/Day1/Setup.page
index 0fe877bf..e8316253 100644
--- a/demos/blog-tutorial/protected/pages/Day1/Setup.page
+++ b/demos/blog-tutorial/protected/pages/Day1/Setup.page
@@ -13,7 +13,7 @@ Assume blog is the name of the directory to hold the whole blog system,
Under the blog directory, we run the PRADO command line tool with the following command (replace path/to with the actual path to the PRADO framework installation):
-
+
php path/to/prado-cli.php -c .
diff --git a/demos/blog-tutorial/protected/pages/Day1/ShareLayout.page b/demos/blog-tutorial/protected/pages/Day1/ShareLayout.page
index d3d1f553..d6c4d29f 100644
--- a/demos/blog-tutorial/protected/pages/Day1/ShareLayout.page
+++ b/demos/blog-tutorial/protected/pages/Day1/ShareLayout.page
@@ -135,13 +135,13 @@ We can specify master in code like the following to enable dynamic change of lay
MasterClass='Path.To.NewLayout';
- }
-
- // ...
+ public function onPreInit($param)
+ {
+ parent::onPreInit($param);
+ $this->MasterClass='Path.To.NewLayout';
+ }
+
+ // ...
}
?>
diff --git a/demos/blog-tutorial/protected/pages/Day2/CreateAR.page b/demos/blog-tutorial/protected/pages/Day2/CreateAR.page
index 00ac1166..c8684ee0 100644
--- a/demos/blog-tutorial/protected/pages/Day2/CreateAR.page
+++ b/demos/blog-tutorial/protected/pages/Day2/CreateAR.page
@@ -3,7 +3,7 @@
Creating Active Record Classes
-We need to create two Active Record classes, UserRecord and PostRecord, to represent data records in the users and posts tables, respectively. Active Record classes must extend from the base class ActiveRecord, and their properties must match exactly to the fields of the corresponding tables.
+We need to create two Active Record classes, UserRecord and PostRecord, to represent data records in the users and posts tables, respectively. Active Record classes must extend from the base class ActiveRecord, and must define property names that matches with the field names of the corresponding table.
@@ -11,9 +11,9 @@ To better organize our directories, we create a new directory protected/data
-
-
-
+
+
+
@@ -24,7 +24,7 @@ Instead of writing the classes manually, we will use the
+
php path/to/prado-cli.php shell .
@@ -32,7 +32,7 @@ php path/to/prado-cli.php shell .
We should see
-
+
Command line tools for Prado 3.1.0.
** Loaded PRADO appplication in directory "protected".
PHP-Shell - Version 0.3.1
@@ -47,7 +47,7 @@ PHP-Shell - Version 0.3.1
At the prompt, enter the following two commands to create UserRecord and PostRecord classes:
-
+
>> generate users Application.database.UserRecord
>> generate posts Application.database.PostRecord
@@ -70,17 +70,18 @@ If we check the PostRecord class file, we should see the following cont
class PostRecord extends TActiveRecord
{
- const TABLE='posts';
- public $post_id;
- public $author;
- public $create_time;
- public $title;
- public $content;
-
- public static function finder($className=__CLASS__)
- {
- return parent::finder($className);
- }
+ const TABLE='posts';
+ public $post_id;
+ public $author_id;
+ public $create_time;
+ public $title;
+ public $content;
+ public $status;
+
+ public static function finder($className=__CLASS__)
+ {
+ return parent::finder($className);
+ }
}
@@ -92,17 +93,18 @@ As we see, for each field in the posts table, the class has a correspon
We can use the command line tool to do some testing with our newly created Active Record classes. Still in the interactive mode of the command line tool, we enter a PHP statement and should see the following. Interested readers may try some other PHP statements, such as UserRecord::finder()->findAll().
-
+
>> PostRecord::finder()->findAll()
array
(
[0] => PostRecord#1
(
[post_id] => '1'
- [author] => 'admin'
+ [author_id] => 'admin'
[create_time] => '1175708482'
[title] => 'first post'
[content] => 'this is my first post'
+ [status] => '0'
[TActiveRecord:_readOnly] => false
[TActiveRecord:_connection] => null
[TComponent:_e] => array()
@@ -110,4 +112,67 @@ array
)
+Relationship Between Posts and Users
+
+Recall that there was a foreign key relationship between the users and posts table. The entity-relationship diagram is shown below for convienence.
+
+
+
+
+
+From the entity-relationship diagram above, we see that the posts table contains a field named author_id. This author_id field is a foreign key to the reference table users. In particular, the values in the author_id field should be of that from the users table's username field. One of the consequence of this relationship, thinking in terms of objects, is that each "post" belongs to an "author" and one "author" may have many "posts".
+
+
+
+We can model the relationship between posts and users table in Active Record by modifying the PostRecord and UserRecord classes as follows.
+
+
+
+class PostRecord extends TActiveRecord
+{
+ //... properties and methods as before
+
+ public $author; //holds an UserRecord
+
+ protected static $RELATIONS=array
+ (
+ 'author' => array(self::BELONGS_TO, 'UserRecord'),
+ );
+}
+
+
+
+The static $RELATIONS property of PostRecord defines that the property $author belongs to an UserRecord. In array(self::BELONGS_TO, 'UserRecord'), the first element defines the relationship type, in this case self::BELONGS_TO. The second element is the name of related record, in this case an UserRecord. The UserRecord is defined similarly below, the difference is that, the user record has many PostRecords.
+
+
+
+class UserRecord extends TActiveRecord
+{
+ //... properties and methods as before
+
+ public $posts=array(); //holds an array of PostRecord
+
+ protected static $RELATIONS=array
+ (
+ 'posts' => array(self::HAS_MANY, 'PostRecord'),
+ );
+}
+
+
+
+An array of UserRecord with and its corresponding posts may be fetched as follows.
+
+
+
+$users = UserRecord::finder()->withPosts()->findAll();
+
+
+
+The method withXXX() (where XXX is the relationship property name, in this case, Posts) fetches the corresponding PostRecords using a second query (not by using a join). The withXXX() method accepts the same arguments as other finder methods of TActiveRecord, e.g. withPosts('status = ?', 0).
+
+
+
+Further detailed documentation can be found in the quickstart Active Record docs.
+
+
\ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day2/CreateDB.page b/demos/blog-tutorial/protected/pages/Day2/CreateDB.page
index eebda4c1..de4e2436 100644
--- a/demos/blog-tutorial/protected/pages/Day2/CreateDB.page
+++ b/demos/blog-tutorial/protected/pages/Day2/CreateDB.page
@@ -30,9 +30,11 @@ CREATE TABLE users (
/* create posts table */
CREATE TABLE posts (
post_id INTEGER NOT NULL PRIMARY KEY,
- author VARCHAR(128) NOT NULL, /* references users.username */
+ author_id VARCHAR(128) NOT NULL
+ CONSTRAINT fk_author REFERENCES users(username),
create_time INTEGER NOT NULL, /* UNIX timestamp */
title VARCHAR(256) NOT NULL, /* title of the post */
+ content TEXT, /* post body */
status INTEGER NOT NULL /* 0: published; 1: draft; 2: pending; 2: denied */
);
@@ -43,14 +45,17 @@ INSERT INTO posts VALUES (NULL, 'admin', 1175708482, 'first post', 'this is my f
-SQLite does not support foreign key constraint. Therefore, we will write PHP code to ensure that the posts.author field contains valid data. Also, we are exploiting the fact that the posts.post_id field is auto-incremental if we assign NULL to it.
+SQLite does not support foreign key constraint such that
+the constraints can still be defined but will be ignored by SQLite.
+Therefore, we will write PHP code to ensure that the posts.author_id field contains valid data.
+Also, we are exploiting the fact that the posts.post_id field is auto-incremental if we assign NULL to it.
We then use the SQLite command line tool to create the SQLite database. We create a directory protected/data to hold the SQLite database file. We now execute the following command under the directory protected/data:
-
+
sqlite3 blog.db < ../schema.sql
diff --git a/demos/blog-tutorial/protected/pages/Day2/ER.gif b/demos/blog-tutorial/protected/pages/Day2/ER.gif
index 90e4c1ea..7a5397b3 100644
Binary files a/demos/blog-tutorial/protected/pages/Day2/ER.gif and b/demos/blog-tutorial/protected/pages/Day2/ER.gif differ
diff --git a/demos/blog-tutorial/protected/pages/Day2/ER.vsd b/demos/blog-tutorial/protected/pages/Day2/ER.vsd
index 95cf7f32..474833fd 100644
Binary files a/demos/blog-tutorial/protected/pages/Day2/ER.vsd and b/demos/blog-tutorial/protected/pages/Day2/ER.vsd differ
diff --git a/demos/blog-tutorial/protected/pages/Day3/Auth.page b/demos/blog-tutorial/protected/pages/Day3/Auth.page
index 82c667d7..8d066b24 100644
--- a/demos/blog-tutorial/protected/pages/Day3/Auth.page
+++ b/demos/blog-tutorial/protected/pages/Day3/Auth.page
@@ -52,50 +52,50 @@ Prado::using('System.Security.TDbUserManager');
*/
class BlogUser extends TDbUser
{
- /**
- * Creates a BlogUser object based on the specified username.
- * This method is required by TDbUser. It checks the database
- * to see if the specified username is there. If so, a BlogUser
- * object is created and initialized.
- * @param string the specified username
- * @return BlogUser the user object, null if username is invalid.
- */
- public function createUser($username)
- {
- // use UserRecord Active Record to look for the specified username
- $userRecord=UserRecord::finder()->findByPk($username);
- if($userRecord instanceof UserRecord) // if found
- {
- $user=new BlogUser($this->Manager);
- $user->Name=$username; // set username
- $user->Roles=($userRecord->role==1?'admin':'user'); // set role
- $user->IsGuest=false; // the user is not a guest
- return $user;
- }
- else
- return null;
- }
+ /**
+ * Creates a BlogUser object based on the specified username.
+ * This method is required by TDbUser. It checks the database
+ * to see if the specified username is there. If so, a BlogUser
+ * object is created and initialized.
+ * @param string the specified username
+ * @return BlogUser the user object, null if username is invalid.
+ */
+ public function createUser($username)
+ {
+ // use UserRecord Active Record to look for the specified username
+ $userRecord=UserRecord::finder()->findByPk($username);
+ if($userRecord instanceof UserRecord) // if found
+ {
+ $user=new BlogUser($this->Manager);
+ $user->Name=$username; // set username
+ $user->Roles=($userRecord->role==1?'admin':'user'); // set role
+ $user->IsGuest=false; // the user is not a guest
+ return $user;
+ }
+ else
+ return null;
+ }
- /**
- * Checks if the specified (username, password) is valid.
- * This method is required by TDbUser.
- * @param string username
- * @param string password
- * @return boolean whether the username and password are valid.
- */
- public function validateUser($username,$password)
- {
- // use UserRecord Active Record to look for the (username, password) pair.
- return UserRecord::finder()->findBy_username_AND_password($username,$password)!==null;
- }
+ /**
+ * Checks if the specified (username, password) is valid.
+ * This method is required by TDbUser.
+ * @param string username
+ * @param string password
+ * @return boolean whether the username and password are valid.
+ */
+ public function validateUser($username,$password)
+ {
+ // use UserRecord Active Record to look for the (username, password) pair.
+ return UserRecord::finder()->findBy_username_AND_password($username,$password)!==null;
+ }
- /**
- * @return boolean whether this user is an administrator.
- */
- public function getIsAdmin()
- {
- return $this->isInRole('admin');
- }
+ /**
+ * @return boolean whether this user is an administrator.
+ */
+ public function getIsAdmin()
+ {
+ return $this->isInRole('admin');
+ }
}
diff --git a/demos/blog-tutorial/protected/pages/Day3/CreateAdminUser.page b/demos/blog-tutorial/protected/pages/Day3/CreateAdminUser.page
index 36b43014..95d7dac5 100644
--- a/demos/blog-tutorial/protected/pages/Day3/CreateAdminUser.page
+++ b/demos/blog-tutorial/protected/pages/Day3/CreateAdminUser.page
@@ -83,35 +83,35 @@ In the above page template, the datagrid's OnDeleteCommand event is tta
class AdminUser extends TPage
{
- /**
- * Populates the datagrid with user lists.
- * This method is invoked by the framework when initializing the page
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- // fetches all data account information
- $this->UserGrid->DataSource=UserRecord::finder()->findAll();
- // binds the data to interface components
- $this->UserGrid->dataBind();
- }
-
- /**
- * Deletes a specified user record.
- * This method responds to the datagrid's OnDeleteCommand event.
- * @param TDataGrid the event sender
- * @param TDataGridCommandEventParameter the event parameter
- */
- public function deleteButtonClicked($sender,$param)
- {
- // obtains the datagrid item that contains the clicked delete button
- $item=$param->Item;
- // obtains the primary key corresponding to the datagrid item
- $username=$this->UserGrid->DataKeys[$item->ItemIndex];
- // deletes the user record with the specified username primary key
- UserRecord::finder()->deleteByPk($username);
- }
+ /**
+ * Populates the datagrid with user lists.
+ * This method is invoked by the framework when initializing the page
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ // fetches all data account information
+ $this->UserGrid->DataSource=UserRecord::finder()->findAll();
+ // binds the data to interface components
+ $this->UserGrid->dataBind();
+ }
+
+ /**
+ * Deletes a specified user record.
+ * This method responds to the datagrid's OnDeleteCommand event.
+ * @param TDataGrid the event sender
+ * @param TDataGridCommandEventParameter the event parameter
+ */
+ public function deleteButtonClicked($sender,$param)
+ {
+ // obtains the datagrid item that contains the clicked delete button
+ $item=$param->Item;
+ // obtains the primary key corresponding to the datagrid item
+ $username=$this->UserGrid->DataKeys[$item->ItemIndex];
+ // deletes the user record with the specified username primary key
+ UserRecord::finder()->deleteByPk($username);
+ }
}
diff --git a/demos/blog-tutorial/protected/pages/Day3/CreateEditUser.page b/demos/blog-tutorial/protected/pages/Day3/CreateEditUser.page
index 64ac6798..055ea62b 100644
--- a/demos/blog-tutorial/protected/pages/Day3/CreateEditUser.page
+++ b/demos/blog-tutorial/protected/pages/Day3/CreateEditUser.page
@@ -44,23 +44,23 @@ As you may have guessed, the page template EditUser is largely the same
Re-type Password:
<com:TCompareValidator
- ControlToValidate="Password"
- ControlToCompare="Password2"
- ErrorMessage="Your password entries did not match."
- Display="Dynamic" />
+ ControlToValidate="Password"
+ ControlToCompare="Password2"
+ ErrorMessage="Your password entries did not match."
+ Display="Dynamic" />
<com:TTextBox ID="Password2" TextMode="Password" />
Email Address:
<com:TRequiredFieldValidator
- ControlToValidate="Email"
- ErrorMessage="Please provide your email address."
- Display="Dynamic" />
+ ControlToValidate="Email"
+ ErrorMessage="Please provide your email address."
+ Display="Dynamic" />
<com:TEmailAddressValidator
- ControlToValidate="Email"
- ErrorMessage="You entered an invalid email address."
- Display="Dynamic" />
+ ControlToValidate="Email"
+ ErrorMessage="You entered an invalid email address."
+ Display="Dynamic" />
<com:TTextBox ID="Email" />
@@ -69,8 +69,8 @@ As you may have guessed, the page template EditUser is largely the same
Role:
<com:TDropDownList ID="Role">
- <com:TListItem Text="Normal User" Value="0" />
- <com:TListItem Text="Administrator" Value="1" />
+ <com:TListItem Text="Normal User" Value="0" />
+ <com:TListItem Text="Administrator" Value="1" />
</com:TDropDownList>
</com:TControl>
@@ -100,82 +100,83 @@ Based on the above description and template, we need to write a page class that
class EditUser extends TPage
{
- /**
- * Initializes the inputs with existing user data.
- * This method is invoked by the framework when the page is being initialized.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- if(!$this->IsPostBack) // if the page is initially requested
- {
- // Retrieves the existing user data. This is equivalent to:
- // $userRecord=$this->getUserRecord();
- $userRecord=$this->UserRecord;
-
- // Populates the input controls with the existing user data
- $this->Username->Text=$userRecord->username;
- $this->Email->Text=$userRecord->email;
- $this->Role->SelectedValue=$userRecord->role;
- $this->FirstName->Text=$userRecord->first_name;
- $this->LastName->Text=$userRecord->last_name;
- }
- }
-
- /**
- * Saves the user account if all inputs are valid.
- * This method responds to the OnClick event of the "save" button.
- * @param mixed event sender
- * @param mixed event parameter
- */
- public function saveButtonClicked($sender,$param)
- {
- if($this->IsValid) // when all validations succeed
- {
- // Retrieves the existing user data. This is equivalent to:
- $userRecord=$this->UserRecord;
-
- // Fetches the input data
- $userRecord->username=$this->Username->Text;
- // update password when the input is not empty
- if(!empty($this->Password->Text))
- $userRecord->password=$this->Password->Text;
- $userRecord->email=$this->Email->Text;
- // update the role if the current user is an administrator
- if($this->User->IsAdmin)
- $userRecord->role=(int)$this->Role->SelectedValue;
- $userRecord->first_name=$this->FirstName->Text;
- $userRecord->last_name=$this->LastName->Text;
-
- // saves to the database via Active Record mechanism
- $userRecord->save();
-
- // redirects the browser to the homepage
- $this->Response->redirect($this->Service->constructUrl($this->Service->DefaultPage));
- }
- }
-
- /**
- * Returns the user data to be editted.
- * @return UserRecord the user data to be editted.
- * @throws THttpException if the user data is not found.
- */
- protected function getUserRecord()
- {
- // the user to be editted is the currently logged-in user
- $username=$this->User->Name;
- // if the 'username' GET var is not empty and the current user
- // is an administrator, we use the GET var value instead.
- if($this->User->IsAdmin && $this->Request['username']!==null)
- $username=$this->Request['username'];
-
- // use Active Record to look for the specified username
- $userRecord=UserRecord::finder()->findByPk($username);
- if(!($userRecord instanceof UserRecord))
- throw new THttpException(500,'Username is invalid.');
- return $userRecord;
- }
+ /**
+ * Initializes the inputs with existing user data.
+ * This method is invoked by the framework when the page is being initialized.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ if(!$this->IsPostBack) // if the page is initially requested
+ {
+ // Retrieves the existing user data. This is equivalent to:
+ // $userRecord=$this->getUserRecord();
+ $userRecord=$this->UserRecord;
+
+ // Populates the input controls with the existing user data
+ $this->Username->Text=$userRecord->username;
+ $this->Email->Text=$userRecord->email;
+ $this->Role->SelectedValue=$userRecord->role;
+ $this->FirstName->Text=$userRecord->first_name;
+ $this->LastName->Text=$userRecord->last_name;
+ }
+ }
+
+ /**
+ * Saves the user account if all inputs are valid.
+ * This method responds to the OnClick event of the "save" button.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function saveButtonClicked($sender,$param)
+ {
+ if($this->IsValid) // when all validations succeed
+ {
+ // Retrieves the existing user data. This is equivalent to:
+ $userRecord=$this->UserRecord;
+
+ // Fetches the input data
+ $userRecord->username=$this->Username->Text;
+ // update password when the input is not empty
+ if(!empty($this->Password->Text))
+ $userRecord->password=$this->Password->Text;
+ $userRecord->email=$this->Email->Text;
+ // update the role if the current user is an administrator
+ if($this->User->IsAdmin)
+ $userRecord->role=(int)$this->Role->SelectedValue;
+ $userRecord->first_name=$this->FirstName->Text;
+ $userRecord->last_name=$this->LastName->Text;
+
+ // saves to the database via Active Record mechanism
+ $userRecord->save();
+
+ // redirects the browser to the homepage
+ $url=$this->Service->constructUrl($this->Service->DefaultPage);
+ $this->Response->redirect($url);
+ }
+ }
+
+ /**
+ * Returns the user data to be editted.
+ * @return UserRecord the user data to be editted.
+ * @throws THttpException if the user data is not found.
+ */
+ protected function getUserRecord()
+ {
+ // the user to be editted is the currently logged-in user
+ $username=$this->User->Name;
+ // if the 'username' GET var is not empty and the current user
+ // is an administrator, we use the GET var value instead.
+ if($this->User->IsAdmin && $this->Request['username']!==null)
+ $username=$this->Request['username'];
+
+ // use Active Record to look for the specified username
+ $userRecord=UserRecord::finder()->findByPk($username);
+ if(!($userRecord instanceof UserRecord))
+ throw new THttpException(500,'Username is invalid.');
+ return $userRecord;
+ }
}
diff --git a/demos/blog-tutorial/protected/pages/Day3/CreateLoginUser.page b/demos/blog-tutorial/protected/pages/Day3/CreateLoginUser.page
index 61ce27b7..d54fc967 100644
--- a/demos/blog-tutorial/protected/pages/Day3/CreateLoginUser.page
+++ b/demos/blog-tutorial/protected/pages/Day3/CreateLoginUser.page
@@ -31,19 +31,19 @@ Below we show the template for LoginPage. As we see, the page mainly co
Username:
<com:TRequiredFieldValidator
- ControlToValidate="Username"
- ErrorMessage="Please provide your username."
- Display="Dynamic" />
+ ControlToValidate="Username"
+ ErrorMessage="Please provide your username."
+ Display="Dynamic" />
<com:TTextBox ID="Username" />
Password:
<com:TCustomValidator
- ControlToValidate="Password"
- ErrorMessage="Your entered an invalid password."
- Display="Dynamic"
- OnServerValidate="validateUser" />
+ ControlToValidate="Password"
+ ErrorMessage="Your entered an invalid password."
+ Display="Dynamic"
+ OnServerValidate="validateUser" />
<com:TTextBox ID="Password" TextMode="Password" />
@@ -62,36 +62,36 @@ Like the Contact page, the LoginUser<
class LoginUser extends TPage
{
- /**
- * Validates whether the username and password are correct.
- * This method responds to the TCustomValidator's OnServerValidate event.
- * @param mixed event sender
- * @param mixed event parameter
- */
- public function validateUser($sender,$param)
- {
- $authManager=$this->Application->getModule('auth');
- if(!$authManager->login($this->Username->Text,$this->Password->Text))
- $param->IsValid=false; // tell the validator that validation fails
- }
-
- /**
- * Redirects the user's browser to appropriate URL if login succeeds.
- * This method responds to the login button's OnClick event.
- * @param mixed event sender
- * @param mixed event parameter
- */
- public function loginButtonClicked($sender,$param)
- {
- if($this->Page->IsValid) // all validations succeed
- {
- // obtain the URL of the privileged page that the user wanted to visit originally
- $url=$this->Application->getModule('auth')->ReturnUrl;
- if(empty($url)) // the user accesses the login page directly
- $url=$this->Service->constructUrl($this->Service->DefaultPage);
- $this->Response->redirect($url);
- }
- }
+ /**
+ * Validates whether the username and password are correct.
+ * This method responds to the TCustomValidator's OnServerValidate event.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function validateUser($sender,$param)
+ {
+ $authManager=$this->Application->getModule('auth');
+ if(!$authManager->login($this->Username->Text,$this->Password->Text))
+ $param->IsValid=false; // tell the validator that validation fails
+ }
+
+ /**
+ * Redirects the user's browser to appropriate URL if login succeeds.
+ * This method responds to the login button's OnClick event.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function loginButtonClicked($sender,$param)
+ {
+ if($this->Page->IsValid) // all validations succeed
+ {
+ // obtain the URL of the privileged page that the user wanted to visit originally
+ $url=$this->Application->getModule('auth')->ReturnUrl;
+ if(empty($url)) // the user accesses the login page directly
+ $url=$this->Service->constructUrl($this->Service->DefaultPage);
+ $this->Response->redirect($url);
+ }
+ }
}
@@ -117,12 +117,12 @@ We modify the footer section of the MainLayout's template as follows. T