diff options
| author | xue <> | 2007-06-26 15:59:16 +0000 | 
|---|---|---|
| committer | xue <> | 2007-06-26 15:59:16 +0000 | 
| commit | f92ca63a225d43e7ecca4ebe528c2a1e206a40f1 (patch) | |
| tree | 0fb92aafab5fedc866c6cafd49433d72bf719114 /demos/blog-tutorial/samples | |
| parent | c31e5ab3ebd4ae1561cbdaeaa504d1095dcbbb0a (diff) | |
Completed day 4 for blog tutorial.
Diffstat (limited to 'demos/blog-tutorial/samples')
36 files changed, 1123 insertions, 3 deletions
diff --git a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/EditUser.php b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/EditUser.php index cb69b9d5..81538c33 100644 --- a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/EditUser.php +++ b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/EditUser.php @@ -54,7 +54,7 @@ class EditUser extends TPage  			$userRecord->save();
  			// redirects the browser to the homepage
 -			$this->Response->redirect($this->Service->constructUrl($this->Service->DefaultPage));
 +			$this->Response->redirect($this->Service->DefaultPageUrl);
  		}
  	}
 diff --git a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/LoginUser.php b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/LoginUser.php index dff8f2f0..a0955490 100644 --- a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/LoginUser.php +++ b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/LoginUser.php @@ -28,7 +28,7 @@ class LoginUser extends TPage  			// 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);
 +				$url=$this->Service->DefaultPageUrl;
  			$this->Response->redirect($url);
  		}
  	}
 diff --git a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/NewUser.php b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/NewUser.php index 005fb7d2..76e8cb88 100644 --- a/demos/blog-tutorial/samples/day3/blog/protected/pages/users/NewUser.php +++ b/demos/blog-tutorial/samples/day3/blog/protected/pages/users/NewUser.php @@ -37,7 +37,7 @@ class NewUser extends TPage  			$userRecord->save();
  			// redirects the browser to the homepage
 -			$this->Response->redirect($this->Service->constructUrl($this->Service->DefaultPage));
 +			$this->Response->redirect($this->Service->DefaultPageUrl);
  		}
  	}
  }
 diff --git a/demos/blog-tutorial/samples/day4/blog/index.php b/demos/blog-tutorial/samples/day4/blog/index.php new file mode 100644 index 00000000..7ccffe49 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/index.php @@ -0,0 +1,22 @@ +<?php
 +
 +// The following directory checks may be removed if performance is required
 +$basePath=dirname(__FILE__);
 +$frameworkPath=$basePath.'/../../../../../framework/prado.php';
 +$assetsPath=$basePath.'/assets';
 +$runtimePath=$basePath.'/protected/runtime';
 +
 +if(!is_file($frameworkPath))
 +	die("Unable to find prado framework path $frameworkPath.");
 +if(!is_writable($assetsPath))
 +	die("Please make sure that the directory $assetsPath is writable by Web server process.");
 +if(!is_writable($runtimePath))
 +	die("Please make sure that the directory $runtimePath is writable by Web server process.");
 +
 +
 +require_once($frameworkPath);
 +
 +$application=new TApplication;
 +$application->run();
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/.htaccess b/demos/blog-tutorial/samples/day4/blog/protected/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/.htaccess @@ -0,0 +1 @@ +deny from all
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/BlogUser.php b/demos/blog-tutorial/samples/day4/blog/protected/BlogUser.php new file mode 100644 index 00000000..6b9e0a23 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/BlogUser.php @@ -0,0 +1,59 @@ +<?php
 +
 +// Include TDbUserManager.php file which defines TDbUser
 +Prado::using('System.Security.TDbUserManager');
 +
 +/**
 + * BlogUser Class.
 + * BlogUser represents the user data that needs to be kept in session.
 + * Default implementation keeps username and role information.
 + */
 +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;
 +	}
 +
 +	/**
 +	 * 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');
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/application.xml b/demos/blog-tutorial/samples/day4/blog/protected/application.xml new file mode 100644 index 00000000..fd6781df --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/application.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?>
 +
 +<application id="blog" mode="Debug">
 +  <paths>
 +    <using namespace="Application.database.*" />
 +    <using namespace="Application.common.*" />
 +  </paths>
 +
 +  <!-- configurations for modules -->
 +  <modules>
 +    <!-- Remove this comment mark to enable caching
 +    <module id="cache" class="System.Caching.TDbCache" />
 +    -->
 +
 +    <!-- Remove this comment mark to enable PATH url format
 +    <module id="request" class="THttpRequest" UrlFormat="Path" />
 +    -->
 +
 +    <!-- Remove this comment mark to enable logging
 +    <module id="log" class="System.Util.TLogRouter">
 +      <route class="TBrowserLogRoute" Categories="System" />
 +    </module>
 +    -->
 +    <module id="db" class="System.Data.TDataSourceConfig">
 +      <database ConnectionString="sqlite:protected/data/blog.db" />
 +    </module>
 +
 +    <module
 +      class="System.Data.ActiveRecord.TActiveRecordConfig"
 +      ConnectionID="db" />
 +
 +    <module id="auth"
 +      class="System.Security.TAuthManager"
 +      UserManager="users"
 +      LoginPage="users.LoginUser" />
 +
 +    <module id="users"
 +      class="System.Security.TDbUserManager"
 +      UserClass="Application.BlogUser" />
 +
 +  </modules>
 +
 +  <!-- configuration for available services -->
 +  <services>
 +    <service id="page" class="TPageService" DefaultPage="posts.ListPost">
 +      <pages MasterClass="Application.layouts.MainLayout" />
 +    </service>
 +  </services>
 +
 +  <!-- application parameters
 +  <parameters>
 +    <parameter id="param1" value="value1" />
 +    <parameter id="param2" value="value2" />
 +  </parameters>
 +  -->
 +</application>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/data/blog.db b/demos/blog-tutorial/samples/day4/blog/protected/data/blog.db Binary files differnew file mode 100644 index 00000000..fa48526a --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/data/blog.db diff --git a/demos/blog-tutorial/samples/day4/blog/protected/database/PostRecord.php b/demos/blog-tutorial/samples/day4/blog/protected/database/PostRecord.php new file mode 100644 index 00000000..01f84437 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/database/PostRecord.php @@ -0,0 +1,28 @@ +<?php
 +/**
 + * Auto generated by prado-cli.php on 2007-04-07 10:44:20.
 + */
 +class PostRecord extends TActiveRecord
 +{
 +	const TABLE='posts';
 +
 +	public $post_id;
 +	public $author_id;
 +	public $create_time;
 +	public $title;
 +	public $content;
 +	public $status;
 +
 +	public $author;
 +
 +	protected static $RELATIONS=array
 +	(
 +		'author' => array(self::BELONGS_TO, 'UserRecord'),
 +	);
 +
 +	public static function finder($className=__CLASS__)
 +	{
 +		return parent::finder($className);
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/database/UserRecord.php b/demos/blog-tutorial/samples/day4/blog/protected/database/UserRecord.php new file mode 100644 index 00000000..18d5ebbe --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/database/UserRecord.php @@ -0,0 +1,28 @@ +<?php
 +/**
 + * Auto generated by prado-cli.php on 2007-04-07 10:44:25.
 + */
 +class UserRecord extends TActiveRecord
 +{
 +	const TABLE='users';
 +
 +	public $username;
 +	public $email;
 +	public $password;
 +	public $role;
 +	public $first_name;
 +	public $last_name;
 +
 +	public $posts=array();
 +
 +	protected static $RELATIONS=array
 +	(
 +		'posts' => array(self::HAS_MANY, 'PostRecord'),
 +	);
 +
 +	public static function finder($className=__CLASS__)
 +	{
 +		return parent::finder($className);
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.php b/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.php new file mode 100644 index 00000000..46c1483d --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.php @@ -0,0 +1,19 @@ +<?php
 +
 +class MainLayout extends TTemplateControl
 +{
 +	/**
 +	 * Logs out a user.
 +	 * This method responds to the "logout" button's OnClick event.
 +	 * @param mixed event sender
 +	 * @param mixed event parameter
 +	 */
 +	public function logoutButtonClicked($sender,$param)
 +	{
 +		$this->Application->getModule('auth')->logout();
 +		$url=$this->Service->constructUrl($this->Service->DefaultPage);
 +		$this->Response->redirect($url);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.tpl b/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.tpl new file mode 100644 index 00000000..3f0a9a4f --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/layouts/MainLayout.tpl @@ -0,0 +1,40 @@ +<html>
 +<com:THead />
 +<body>
 +<com:TForm>
 +
 +<div id="header">
 +<h1>My PRADO Blog</h1>
 +</div>
 +
 +<div id="main">
 +<com:TContentPlaceHolder ID="Main" />
 +</div>
 +
 +<div id="footer">
 +
 +<a href="<%= $this->Service->DefaultPageUrl %>">Home</a>
 +
 +<com:THyperLink Text="New Post"
 +	NavigateUrl="<%= $this->Service->constructUrl('posts.NewPost') %>"
 +	Visible="<%= !$this->User->IsGuest %>" />
 +
 +<com:THyperLink Text="New User"
 +	NavigateUrl="<%= $this->Service->constructUrl('users.NewUser') %>"
 +	Visible="<%= $this->User->IsAdmin %>" />
 +
 +<com:THyperLink Text="Login"
 +	NavigateUrl="<%= $this->Service->constructUrl('users.LoginUser') %>"
 +	Visible="<%= $this->User->IsGuest %>" />
 +
 +<com:TLinkButton Text="Logout"
 +	OnClick="logoutButtonClicked"
 +	Visible="<%= !$this->User->IsGuest %>" />
 +
 +<br/>
 +<%= PRADO::poweredByPrado() %>
 +</div>
 +
 +</com:TForm>
 +</body>
 +</html>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.page new file mode 100644 index 00000000..c36149ca --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.page @@ -0,0 +1,47 @@ +<%@ Title="My Blog - Contact" %>
 + 
 +<com:TContent ID="Main">
 + 
 +<h1>Contact</h1>
 +<p>Please fill out the following form to let me know your feedback on my blog. Thanks!</p>
 +
 +<span>Your Name:</span>
 +<com:TRequiredFieldValidator ControlToValidate="Name"
 +	ErrorMessage="Please provide your name." 
 +	Display="Dynamic"
 +	/>
 +<br/>
 +<com:TTextBox ID="Name" />
 +
 +<br/>
 +
 +<span>Your Email:</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" />
 +
 +<br/>
 +
 +<span>Feedback:</span>
 +<com:TRequiredFieldValidator ControlToValidate="Feedback"
 +	ErrorMessage="Please provide your feedback." 
 +	Display="Dynamic"
 +	/>
 +<br/>
 +<com:TTextBox ID="Feedback" 
 +	TextMode="MultiLine" 
 +	Rows="10"
 +	Columns="40" />
 +
 +<br/>
 +
 +<com:TButton Text="Submit" OnClick="submitButtonClicked" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.php new file mode 100644 index 00000000..b6ce575e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/Contact.php @@ -0,0 +1,30 @@ +<?php
 +
 +class Contact extends TPage
 +{
 +	/**
 +	 * 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
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/Home.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/Home.page new file mode 100644 index 00000000..7a9c4a7d --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/Home.page @@ -0,0 +1,7 @@ +<%@ Title="Welcome to PRADO" %>
 +
 +<com:TContent ID="Main">
 +
 +<h1>Welcome to PRADO!</h1>
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.page new file mode 100644 index 00000000..579d833e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.page @@ -0,0 +1,27 @@ +<%@ Title="My Blog - Edit Post" %>
 +
 +<com:TContent ID="Main">
 +
 +<h1>Edit Post</h1>
 +
 +<span>Title:</span>
 +<com:TRequiredFieldValidator
 +	ControlToValidate="TitleEdit"
 +	ErrorMessage="Please provide a title."
 +	Display="Dynamic" />
 +<br/>
 +<com:TTextBox ID="TitleEdit" Columns="50" />
 +
 +<br/>
 +<span>Content:</span>
 +<com:TRequiredFieldValidator
 +	ControlToValidate="ContentEdit"
 +	ErrorMessage="Please provide content."
 +	Display="Dynamic" />
 +<br/>
 +<com:THtmlArea ID="ContentEdit" />
 +
 +<br/>
 +<com:TButton Text="Save" OnClick="saveButtonClicked" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.php new file mode 100644 index 00000000..e137b85e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/EditPost.php @@ -0,0 +1,72 @@ +<?php
 +
 +class EditPost extends TPage
 +{
 +	/**
 +	 * Initializes the inputs with existing post 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);
 +		// Retrieves the existing user data. This is equivalent to:
 +		// $postRecord=$this->getPost();
 +		$postRecord=$this->Post;
 +		// Authorization check: only the author or the administrator can edit the post
 +		if($postRecord->author_id!==$this->User->Name && !$this->User->IsAdmin)
 +			throw new THttpException(500,'You are not allowed to edit this post.');
 +
 +		if(!$this->IsPostBack)  // if the page is initially requested
 +		{
 +			// Populates the input controls with the existing post data
 +			$this->TitleEdit->Text=$postRecord->title;
 +			$this->ContentEdit->Text=$postRecord->content;
 +		}
 +	}
 +
 +	/**
 +	 * Saves the post 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:
 +			// $postRecord=$this->getPost();
 +			$postRecord=$this->Post;
 +
 +			// Fetches the input data
 +			$postRecord->title=$this->TitleEdit->SafeText;
 +			$postRecord->content=$this->ContentEdit->SafeText;
 +
 +			// saves to the database via Active Record mechanism
 +			$postRecord->save();
 +
 +			// redirects the browser to the ReadPost page
 +			$url=$this->Service->constructUrl('posts.ReadPost',array('id'=>$postRecord->post_id));
 +			$this->Response->redirect($url);
 +		}
 +	}
 +
 +	/**
 +	 * Returns the post data to be editted.
 +	 * @return PostRecord the post data to be editted.
 +	 * @throws THttpException if the post data is not found.
 +	 */
 +	protected function getPost()
 +	{
 +		// the ID of the post to be editted is passed via GET parameter 'id'
 +		$postID=(int)$this->Request['id'];
 +		// use Active Record to look for the specified post ID
 +		$postRecord=PostRecord::finder()->findByPk($postID);
 +		if($postRecord===null)
 +			throw new THttpException(500,'Post is not found.');
 +		return $postRecord;
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.page new file mode 100644 index 00000000..e26bc2f5 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.page @@ -0,0 +1,14 @@ +<%@ Title="My Blog" %>
 +
 +<com:TContent ID="Main">
 +
 +<com:TRepeater ID="Repeater"
 +	ItemRenderer="Application.pages.posts.PostRenderer"
 +	AllowPaging="true"
 +	AllowCustomPaging="true"
 +	PageSize="5"
 +	/>
 +
 +<com:TPager ControlToPaginate="Repeater" OnPageIndexChanged="pageChanged" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.php new file mode 100644 index 00000000..7402dace --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ListPost.php @@ -0,0 +1,64 @@ +<?php
 +
 +class ListPost extends TPage
 +{
 +	/**
 +	 * Initializes the repeater.
 +	 * This method is invoked by the framework when initializing the page
 +	 * @param mixed event parameter
 +	 */
 +	public function onInit($param)
 +	{
 +		parent::onInit($param);
 +		if(!$this->IsPostBack)  // if the page is requested the first time
 +		{
 +			// get the total number of posts available
 +			$this->Repeater->VirtualItemCount=PostRecord::finder()->count();
 +			// populates post data into the repeater
 +			$this->populateData();
 +		}
 +	}
 +
 +	/**
 +	 * Event handler to the OnPageIndexChanged event of the pager.
 +	 * This method is invoked when the user clicks on a page button
 +	 * and thus changes the page of posts to display.
 +	 */
 +	public function pageChanged($sender,$param)
 +	{
 +		// change the current page index to the new one
 +		$this->Repeater->CurrentPageIndex=$param->NewPageIndex;
 +		// re-populate data into the repeater
 +		$this->populateData();
 +	}
 +
 +	/**
 +	 * Determines which page of posts to be displayed and
 +	 * populates the repeater with the fetched data.
 +	 */
 +	protected function populateData()
 +	{
 +		$offset=$this->Repeater->CurrentPageIndex*$this->Repeater->PageSize;
 +		$limit=$this->Repeater->PageSize;
 +		if($offset+$limit>$this->Repeater->VirtualItemCount)
 +			$limit=$this->Repeater->VirtualItemCount-$offset;
 +		$this->Repeater->DataSource=$this->getPosts($offset,$limit);
 +		$this->Repeater->dataBind();
 +	}
 +
 +	/**
 +	 * Fetches posts from database with offset and limit.
 +	 */
 +	protected function getPosts($offset, $limit)
 +	{
 +		// Construts a query criteria
 +		$criteria=new TActiveRecordCriteria;
 +		$criteria->OrdersBy['create_time']='desc';
 +		$criteria->Limit=$limit;
 +		$criteria->Offset=$offset;
 +		// query for the posts with the above criteria and with author information
 +		return PostRecord::finder()->withAuthor()->findAll($criteria);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.page new file mode 100644 index 00000000..bd46dfbb --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.page @@ -0,0 +1,27 @@ +<%@ Title="My Blog - New Post" %>
 +
 +<com:TContent ID="Main">
 +
 +<h1>Create New Post</h1>
 +
 +<span>Title:</span>
 +<com:TRequiredFieldValidator
 +	ControlToValidate="TitleEdit"
 +	ErrorMessage="Please provide a title."
 +	Display="Dynamic" />
 +<br/>
 +<com:TTextBox ID="TitleEdit" Columns="50" />
 +
 +<br/>
 +<span>Content:</span>
 +<com:TRequiredFieldValidator
 +	ControlToValidate="ContentEdit"
 +	ErrorMessage="Please provide content."
 +	Display="Dynamic" />
 +<br/>
 +<com:THtmlArea ID="ContentEdit" />
 +
 +<br/>
 +<com:TButton Text="Create" OnClick="createButtonClicked" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.php new file mode 100644 index 00000000..a5e3ea4d --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/NewPost.php @@ -0,0 +1,34 @@ +<?php
 +
 +class NewPost extends TPage
 +{
 +	/**
 +	 * Creates a new post if all inputs are valid.
 +	 * This method responds to the OnClick event of the "create" button.
 +	 * @param mixed event sender
 +	 * @param mixed event parameter
 +	 */
 +	public function createButtonClicked($sender,$param)
 +	{
 +		if($this->IsValid)  // when all validations succeed
 +		{
 +			// populates a PostRecord object with user inputs
 +			$postRecord=new PostRecord;
 +			// using SafeText instead of Text avoids Cross Site Scripting attack
 +			$postRecord->title=$this->TitleEdit->SafeText;
 +			$postRecord->content=$this->ContentEdit->SafeText;
 +			$postRecord->author_id=$this->User->Name;
 +			$postRecord->create_time=time();
 +			$postRecord->status=0;
 +
 +			// saves to the database via Active Record mechanism
 +			$postRecord->save();
 +
 +			// redirects the browser to the newly created post page
 +			$url=$this->Service->constructUrl('posts.ReadPost',array('id'=>$postRecord->post_id));
 +			$this->Response->redirect($url);
 +		}
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.php new file mode 100644 index 00000000..cf0539a1 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.php @@ -0,0 +1,7 @@ +<?php
 +
 +class PostRenderer extends TRepeaterItemRenderer
 +{
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.tpl b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.tpl new file mode 100644 index 00000000..862df1ab --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/PostRenderer.tpl @@ -0,0 +1,15 @@ +<h3>
 +<com:THyperLink Text="<%# $this->Data->title %>"
 +	NavigateUrl="<%# $this->Service->constructUrl('posts.ReadPost',array('id'=>$this->Data->post_id)) %>" />
 +</h3>
 +
 +<p>
 +Author:
 +<com:TLiteral Text="<%# $this->Data->author->username %>" /><br/>
 +Time:
 +<com:TLiteral Text="<%# date('m/d/Y h:m:sa', $this->Data->create_time) %>" />
 +</p>
 +
 +<p>
 +<com:TLiteral Text="<%# $this->Data->content %>" />
 +</p>
 diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.page new file mode 100644 index 00000000..60a8cf1e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.page @@ -0,0 +1,25 @@ +<com:TContent ID="Main">
 +
 +<h2>
 +<com:TLiteral Text="<%= $this->Post->title %>" />
 +</h2>
 +
 +<com:TControl Visible="<%= $this->canEdit() %>">
 +	<a href="<%= $this->Service->constructUrl('posts.EditPost',array('id'=>$this->Post->post_id))%>">Edit</a> |
 +	<com:TLinkButton Text="Delete"
 +		OnClick="deletePost"
 +		Attributes.onclick="javascript:if(!confirm('Are you sure?')) return false;" />
 +</com:TControl>
 +
 +<p>
 +Author:
 +<com:TLiteral Text="<%= $this->Post->author->username %>" /><br/>
 +Time:
 +<com:TLiteral Text="<%= date('m/d/Y h:m:sa', $this->Post->create_time) %>" />
 +</p>
 +
 +<p>
 +<com:TLiteral Text="<%= $this->Post->content %>" />
 +</p>
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.php new file mode 100644 index 00000000..2aeaa4d3 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/ReadPost.php @@ -0,0 +1,57 @@ +<?php
 +
 +class ReadPost extends TPage
 +{
 +	private $_post;
 +	/**
 +	 * Fetches the post data.
 +	 * This method is invoked by the framework when initializing the page
 +	 * @param mixed event parameter
 +	 */
 +	public function onInit($param)
 +	{
 +		parent::onInit($param);
 +		// post id is passed via the 'id' GET parameter
 +		$postID=(int)$this->Request['id'];
 +		// retrieves PostRecord with author information filled in
 +		$this->_post=PostRecord::finder()->withAuthor()->findByPk($postID);
 +		if($this->_post===null)  // if post id is invalid
 +			throw new THttpException(500,'Unable to find the specified post.');
 +		// set the page title as the post title
 +		$this->Title=$this->_post->title;
 +	}
 +
 +	/**
 +	 * @return PostRecord the PostRecord currently being viewed
 +	 */
 +	public function getPost()
 +	{
 +		return $this->_post;
 +	}
 +
 +	/**
 +	 * Deletes the post currently being viewed
 +	 * This method is invoked when the user clicks on the "Delete" button
 +	 */
 +	public function deletePost($sender,$param)
 +	{
 +		// only the author or the administrator can delete a post
 +		if(!$this->canEdit())
 +			throw new THttpException('You are not allowed to perform this action.');
 +		// delete it from DB
 +		$this->_post->delete();
 +		// redirect the browser to the homepage
 +		$this->Response->redirect($this->Service->DefaultPageUrl);
 +	}
 +
 +	/**
 +	 * @return boolean whether the current user can edit/delete the post being viewed
 +	 */
 +	public function canEdit()
 +	{
 +		// only the author or the administrator can edit/delete a post
 +		return $this->User->Name===$this->Post->author_id || $this->User->IsAdmin;
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/config.xml b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/config.xml new file mode 100644 index 00000000..64065ed5 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/posts/config.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<configuration>
 +  <authorization>
 +    <deny pages="NewPost,EditPost" roles="?" />
 +  </authorization>
 +</configuration>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.page new file mode 100644 index 00000000..af03b858 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.page @@ -0,0 +1,40 @@ +<%@ Title="My Blog - Manage User Accounts" %>
 +
 +<com:TContent ID="Main">
 + 
 +<h1>Manage User Accounts</h1>
 +
 +<a href="<%= $this->Service->constructUrl('users.NewUser')%>">Create New User</a>
 +<br/>
 +
 +<com:TDataGrid ID="UserGrid"
 +    DataKeyField="username"
 +    AutoGenerateColumns="false"
 +    OnDeleteCommand="deleteButtonClicked">
 +
 +    <com:THyperLinkColumn
 +        HeaderText="Username"
 +        DataTextField="username"
 +        DataNavigateUrlField="username">
 +        <prop:DataNavigateUrlFormatString>#
 +          $this->Service->constructUrl('users.EditUser',array('username'=>{0}))
 +        </prop:DataNavigateUrlFormatString>
 +    </com:THyperLinkColumn>
 +
 +    <com:TBoundColumn
 +        HeaderText="Email"
 +        DataField="email" />
 +    
 +    <com:TCheckBoxColumn
 +        HeaderText="Administrator"
 +        DataField="role" />
 +    
 +    <com:TButtonColumn
 +        HeaderText="Command"
 +        Text="Delete" 
 +        ButtonType="PushButton"
 +        CommandName="delete" />
 +
 +</com:TDataGrid>
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.php new file mode 100644 index 00000000..ad8f6e3d --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/AdminUser.php @@ -0,0 +1,36 @@ +<?php
 +
 +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);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.page new file mode 100644 index 00000000..8aa3670e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.page @@ -0,0 +1,61 @@ +<%@ 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>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.php new file mode 100644 index 00000000..81538c33 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/EditUser.php @@ -0,0 +1,83 @@ +<?php
 +
 +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;
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.page new file mode 100644 index 00000000..f7fc7367 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.page @@ -0,0 +1,28 @@ +<%@ Title="My Blog - Login" %>
 +
 +<com:TContent ID="Main">
 + 
 +<h1>Login</h1>
 +
 +<span>Username:</span>
 +<com:TRequiredFieldValidator 
 +	ControlToValidate="Username"
 +	ErrorMessage="Please provide your username." 
 +	Display="Dynamic" />
 +<br/>
 +<com:TTextBox ID="Username" />
 +
 +<br/>
 +<span>Password:</span>
 +<com:TCustomValidator
 +	ControlToValidate="Password"
 +	ErrorMessage="Your entered an invalid password."
 +	Display="Dynamic"
 +	OnServerValidate="validateUser" />
 +<br/>
 +<com:TTextBox ID="Password" TextMode="Password" />
 +
 +<br/>
 +<com:TButton Text="Login" OnClick="loginButtonClicked" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.php new file mode 100644 index 00000000..a0955490 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/LoginUser.php @@ -0,0 +1,37 @@ +<?php
 +
 +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->DefaultPageUrl;
 +			$this->Response->redirect($url);
 +		}
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.page b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.page new file mode 100644 index 00000000..d1547a9a --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.page @@ -0,0 +1,73 @@ +<%@ Title="My Blog - New User" %>
 +
 +<com:TContent ID="Main">
 + 
 +<h1>Create New User</h1>
 +
 +<span>Username:</span>
 +<com:TRequiredFieldValidator 
 +	ControlToValidate="Username"
 +	ErrorMessage="Please provide a username." 
 +	Display="Dynamic" />
 +<com:TCustomValidator
 +	ControlToValidate="Username"
 +	ErrorMessage="Sorry, your username is taken by someone else. Please choose another username."
 +	OnServerValidate="checkUsername"
 +	Display="Dynamic" />
 +<br/>
 +<com:TTextBox ID="Username" />
 +
 +<br/>
 +<span>Password:</span>
 +<com:TRequiredFieldValidator 
 +	ControlToValidate="Password"
 +	ErrorMessage="Please provide a password." 
 +	Display="Dynamic" />
 +<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" />
 +
 +<br/>
 +<span>Role:</span>
 +<br/>
 +<com:TDropDownList ID="Role">
 +	<com:TListItem Text="Normal User" Value="0" />
 +	<com:TListItem Text="Administrator" Value="1" />
 +</com:TDropDownList>
 +
 +<br/>
 +<span>First Name:</span>
 +<br/>
 +<com:TTextBox ID="FirstName" />
 +
 +<br/>
 +<span>Last Name:</span>
 +<br/>
 +<com:TTextBox ID="LastName" />
 +
 +<br/>
 +<com:TButton Text="Create" OnClick="createButtonClicked" />
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.php b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.php new file mode 100644 index 00000000..76e8cb88 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/NewUser.php @@ -0,0 +1,45 @@ +<?php
 +
 +class NewUser extends TPage
 +{
 +	/**
 +	 * Checks whether the username exists in the database.
 +	 * This method responds to the OnServerValidate event of username's custom validator.
 +	 * @param mixed event sender
 +	 * @param mixed event parameter
 +	 */
 +	public function checkUsername($sender,$param)
 +	{
 +		// valid if the username is not found in the database
 +		$param->IsValid=UserRecord::finder()->findByPk($this->Username->Text)===null;
 +	}
 +
 +	/**
 +	 * Creates a new user account if all inputs are valid.
 +	 * This method responds to the OnClick event of the "create" button.
 +	 * @param mixed event sender
 +	 * @param mixed event parameter
 +	 */
 +	public function createButtonClicked($sender,$param)
 +	{
 +		if($this->IsValid)  // when all validations succeed
 +		{
 +			// populates a UserRecord object with user inputs
 +			$userRecord=new UserRecord;
 +			$userRecord->username=$this->Username->Text;
 +			$userRecord->password=$this->Password->Text;
 +			$userRecord->email=$this->Email->Text;
 +			$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);
 +		}
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/pages/users/config.xml b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/config.xml new file mode 100644 index 00000000..56554441 --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/pages/users/config.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?>
 +<configuration>
 +  <authorization>
 +    <allow pages="NewUser,AdminUser" roles="admin" />
 +    <deny users="?" />
 +  </authorization>
 +</configuration>
\ No newline at end of file diff --git a/demos/blog-tutorial/samples/day4/blog/protected/schema.sql b/demos/blog-tutorial/samples/day4/blog/protected/schema.sql new file mode 100644 index 00000000..89f7388e --- /dev/null +++ b/demos/blog-tutorial/samples/day4/blog/protected/schema.sql @@ -0,0 +1,25 @@ +/* create users table */
 +CREATE TABLE users (
 +  username      VARCHAR(128) NOT NULL PRIMARY KEY,
 +  email         VARCHAR(128) NOT NULL,
 +  password      VARCHAR(128) NOT NULL,  /* in plain text */
 +  role          INTEGER NOT NULL,       /* 0: normal user, 1: administrator */
 +  first_name    VARCHAR(128),
 +  last_name     VARCHAR(128)
 +);
 +
 +/* create posts table */
 +CREATE TABLE posts (
 +  post_id       INTEGER NOT NULL PRIMARY KEY,
 +  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 */
 +);
 +
 +/* insert some initial data records for testing */
 +INSERT INTO users VALUES ('admin', 'admin@example.com', 'demo', 1, 'Qiang', 'Xue');
 +INSERT INTO users VALUES ('demo', 'demo@example.com', 'demo', 0, 'Wei', 'Zhuo');
 +INSERT INTO posts VALUES (NULL, 'admin', 1175708482, 'first post', 'this is my first post', 0);
  | 
