Creating EditUser Page

The EditUser page is very similar to the NewUser. The main difference is that when EditUser is initially requested, the input fields should be initialized with existing user information. Another slight difference is that EditUser can also be accessed by normal users.

To determine which user account is to be editted, we use the following policy:

  • If the current user is an administrator, he can edit any user account by specifying the account's username in a GET variable named 'username'. For example, http://hostname/blog/index.php?page=users.EditUser&username=demo.
  • If the current user is an administrator and the URl does not contain 'username', the administrator himself's data is being updated.
  • If the current user is a normal user, he can only edit his own account information, and he cannot modify his role data.

We create two files protected/pages/users/EditUser.page and protected/pages/users/EditUser.php to save the page template and page class, respectively.

Creating Page Template

As you may have guessed, the page template EditUser is largely the same as that of NewUser. Besides the difference in page title and the caption of the submit button, there are three main differences.

  • The "username" text box is replaced by a TLabel control because we do not allow modifying username;
  • The validator for the "password" input is removed. This is because if the user does not provide a password during editting, it means the user does not want to change the password.
  • The "role" input is surrounded with TControl whose visibility is toggled according to the role of the currently logged-in user. If the user is not an administrator, the "role" input will not be displayed because normal users are not allowed to modify their roles.

<%@ Title="My Blog - Edit User" %>

<com:TContent ID="Main">

<h1>Edit User</h1>

<span>Username:</span>
<com:TLabel ID="Username" />

<br/>
<span>Password:</span>
<br/>
<com:TTextBox ID="Password" TextMode="Password" />

<br/>
<span>Re-type Password:</span>
<com:TCompareValidator
    ControlToValidate="Password"
    ControlToCompare="Password2"
    ErrorMessage="Your password entries did not match."
    Display="Dynamic" />
<br/>
<com:TTextBox ID="Password2" TextMode="Password" />

<br/>
<span>Email Address:</span>
<com:TRequiredFieldValidator
    ControlToValidate="Email"
    ErrorMessage="Please provide your email address."
    Display="Dynamic" />
<com:TEmailAddressValidator
    ControlToValidate="Email"
    ErrorMessage="You entered an invalid email address."
    Display="Dynamic" />
<br/>
<com:TTextBox ID="Email" />

<com:TControl Visible="<%= $this->User->IsAdmin %>">
<br/>
<span>Role:</span>
<br/>
<com:TDropDownList ID="Role">
    <com:TListItem Text="Normal User" Value="0" />
    <com:TListItem Text="Administrator" Value="1" />
</com:TDropDownList>
</com:TControl>

<br/>
<span>First Name:</span>
<br/>
<com:TTextBox ID="FirstName" />

<br/>
<span>Last Name:</span>
<br/>
<com:TTextBox ID="LastName" />

<br/>
<com:TButton Text="Save" OnClick="saveButtonClicked" />

</com:TContent>

Creating Page Class

Based on the above description and template, we need to write a page class that initializes the inputs with the existing user information. In addition, the page class also needs to implement the saveButtonClicked() method which is attached to the "save" button's OnClick event.

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->DefaultPageUrl);
        }
    }

    /**
     * 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;
    }
}
Tip: The onInit() method is invoked by PRADO during one of the page lifecycles. Other commonly overriden lifecycle methods include onPreInit(), onLoad() and onPreRender().

Adding Permission Check

To make the EditUser page also accessible by authenticated users (users="@"), we need to adjust the page configuration file protected/pages/users/config.xml accordingly.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <authorization>
    <allow roles="admin"/>
    <allow users="@" pages="EditUser"/>
    <deny users="*"/>
  </authorization>
</configuration>

Testing

To test the EditUser page, visit the URL http://hostname/blog/index.php?page=users.EditUser&username=demo. You may be required to login first if you have not done so. Try logging in with different accounts (e.g. admin/demo, demo/demo) and see how the page displays differently.