有了前面“Hello,World”的例子和对Yii Framework Web应用基础的介绍,可以开始介绍一个简单而相对而有比较完整的Web应用-Hangman(猜单词游戏),这个例子是随Yii 开发包发布的。通过这个例子可以了解开发Yii应用的基本步骤.

说起“Hangman”,让我想起80年代末期高中时在CPC464计算机上完过的“猜单词游戏”-Hangman,每猜错一次,就把一个小人离绞刑架前进一步。当时DOS才刚刚出来:-)。

开发一个Web应用,首先是进行需求分析,这个不在本教程之内,但为完整起见,还是把“猜单词游戏”的规则列在下面:

猜单词游戏(英文:Hangman,“上吊的人”之意)是一个双人游戏。一位玩家想一个字,另一位尝试猜该玩家所想的字中的每一个字母。

要猜的字以一列横线表示,让玩家知道该字有多少个字母。如果猜字的玩家猜中其中一个字母,另一位便须于该字母出现的所有位置上写上该字母。如果猜的字母没有于该字中出现,另一位玩家便会画吊颈公仔的其中一笔。游戏会在以下情况结束:

“我要t字。”“有, 在第八和第十一位。”

  • 猜字的玩家猜完所有字母,或猜中整个字
  • 另一位玩家画完整幅图:

今天给出的例子就不画出“上吊人”了,猜对了显示“You Win”,猜错了显示“You Lose”。 因此我们可以设计四个页面:

这四个页面对应到Yii Framework为 四个View,可以分别取名为play, guess, win,lose ,每个页面都显示了“Hangman Game”的标题,因此可以设计一个”MasterPage”,在Yii中成为Layout布局的模板以供四个View共享。Yii应用采用了MVC设计模式,因此我们可以为四个View设计一个Controller–>GameController.

前面的教程说过Yii应用使用缺省的目录结构来存放应用的不同部分,可以使用Yii提供的工具来参加一个缺省的项目目录。不过我个人还是比较喜欢自己创建各个目录,因此根据上面的需求和界面设计,可以创建项目的目录结构如下:

  • 创建的GameController.php 放在 protected/controller 目录下。
  • 创建的四个View guess.php, lose.php, play.php, win.php 放在 protected/views/game 目录下 。目录名game 对应到所使用到GameController.
  • 创建的共享的Layout放在 protected/views/layout 目录下,缺省的布局名称为main.php
  • 应用的配置文件放在 protected/config ,缺省配置文件为main.php
  • 应用的入口脚本为 index.php
  • 此外,供猜单词的文本文件为 word.txt

1. 首先来看看配置文件protected/config/main.php

return array('name'=>'Hangman Game','defaultController'=>'game','components'=>array('urlManager'=>array('urlFormat'=>'path','rules'=>array('game/guess/<g:\w>'=>'game/guess',),),),
);

CWebApplication应用的所有可写的属性都可以通过配置文件来定义,我们看到配置文件定义了应用的名称为”Hangman Game” ,然后修改Web应用缺省的Controller名字为game 对应到 GameController, 如果没有重新定义defaultController,则缺省的Controller名字为SiteController,这样对于的View就要存放到 protected/views/site 目录下。另外这个Yii应用打开了urlManager组件,这个组件的功能就在后面介绍,主要是用来定义用户可以访问的URL的格式(路由格式)。

2. 有了这个配置文件,就可以在入口脚本中使用它,每个Yii应用的入口脚本index.php都是大同小异的,大部分情况下都是Copy & Paste

$yii=dirname(__FILE__).'/../../framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';
require_once($yii);
Yii::createWebApplication($config)->run();

3. 然后定义View使用的布局文件 protected/views/layout/main.php main.php 为缺省的布局模板,应用可以修改View使用的布局,本例就是要缺省的布局名称main.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Hangman Game</title>
</head><body>
<h1>Hangman Game</h1><?php echo $content; ?></body>
</html>

布局基本上就是HTML文件,其中 作为 view 的placeholder ,也就是在显示具体的View时,比如play.php 就用 play.php 的内容来替代 $content。从而实现了类似“MasterPage” 的功能。
4. 下面就可以逐一定义四个View,这里就不一一列出了,以play.php 为例:

<p>This is the game of Hangman.
You must guess a word, a letter at a time.
If you make too many mistakes, you lose the game!</p><?php echo CHtml::beginForm(); ?><?php echo CHtml::radioButtonList('level', null, $levels); ?><br/>
<?php echo CHtml::submitButton('Play!'); ?><?php if($error): ?>
<span style="color:red">You must choose a difficulty level!</span>
<?php endif; ?><?php echo CHtml::endForm(); ?>

可以看到基本上也是HTML ,其中CHtml 为Yii 框架支持的一个辅助类,用来帮助生成HTML代码。 Hangman比较简单,因此没有使用单独的Model,而是通过render推送的方式传入参数。

需通过传递视图的名称调用CController::render()。这个方法将在protected/views/ControllerID目录下寻找对应的视图文件.

在视图脚本内部,我们可以通过$this来访问控制器实例.我们可以在视图里以$this->propertyName的方式拉取控制器的任何属性.

我们也可以用以下推送的方式传递数据到视图里:

$this->render('edit', array('var1'=>$value1,'var2'=>$value2,
));

在以上的方式中,render()方法将提取数组的第二个参数到变量里.其产生的结果是,在视图脚本里,我们可以直接访问变量$var1$var2.

5. 定义好布局和View之后,就可以写GameController了,

class GameController extends CController
{/*** @var string sets the default action to be 'play'*/public $defaultAction='play';/*** The 'play' action.* In this action, users are asked to choose a difficulty level* of the game.*/public function actionPlay(){...}/*** The 'guess' action.* This action is invoked each time when the user makes a guess.*/public function actionGuess(){...}/*** The 'guess' action.* This action is invoked when the user gives up the game.*/public function actionGiveup(){...}...
}

一般情况下Controller缺省的action 为 index ,可以通过$defaultAction修改缺省的Action,本例修改为play. 因此如果本例的 url 为 http://127.0.0.1:8888/yii/demos/hangman/
那么使用 http://127.0.0.1:8888/yii/demos/hangman/index.php 和使用 http://127.0.0.1:8888/yii/demos/hangman/index.php?game/play的效果是一样的。缺省的Controller为GameController,GameController缺省的action为play.

Action (动作),动作可以被定义为一个以 action 单词作为前缀命名的方法。Hangman定义了三个action ,actionPlay ,actionGuess, actionGiveup ,GameController 其它方法和属性和生成单词,判断是否猜对等为具体的游戏逻辑和Yii框架关系不大,就不介绍了。

6. 首先看看缺省的playAction ,这是用户调用的缺省方法,也就是说当用户组地址栏输入http://127.0.0.1:8888/yii/demos/hangman/index.php (或http://127.0.0.1:8888/yii/demos/hangman/index.php?game/play)所调用的Action。

public function actionPlay()
{static $levels=array('10'=>'Easy game; you are allowed 10 misses.','5'=>'Medium game; you are allowed 5 misses.','3'=>'Hard game; you are allowed 3 misses.',);// if a difficulty level is correctly chosenif(isset($_POST['level'])&& isset($levels[$_POST['level']])){$this->word=$this->generateWord();$this->guessWord=str_repeat('_',strlen($this->word));$this->level=$_POST['level'];$this->misses=0;$this->setPageState('guessed',null);// show the guess page$this->render('guess');}else{$params=array('levels'=>$levels,// if this is a POST request,//it means the level is not chosen'error'=>Yii::app()->request->isPostRequest,);// show the difficulty level page$this->render('play',$params);}
}

这个方法定义了游戏的三个难度等级$levels, 有两个分支,如果没有选择难易等级,则调用$this->render(‘play’,$params),显示Play页面,就$params (Array)推送到对应的View ,protected/views/play.php,参考上面View的定义:

<?php echo CHtml::radioButtonList('level', null, $levels); ?>

View使用Radiobutton来显示 $levels 定义的列表。

如果用户选择了难易等级,在把Level,单词等存放到GameController所定义的属性中,如word,level等。GameController拍手与CController 也是CComponent的子类,CComponent支持了类似C#,Java的属性功能。具体后面再介绍。
然后调用$this->render(‘guess’); 显示Guess页面。
Guess页面 guess.php 定义如下:

<h2>Please make a guess</h2><h3 style="letter-spacing: 4px;"><?php echo $this->guessWord; ?></h3><p>You have made<?php echo $this->misses; ?>bad guesses out of a maximum of<?php echo $this->level; ?>.</p><?php echo CHtml::statefulForm(); ?><p>Guess:
<?php
for($i=ord('A');$i<=ord('Z');++$i)
{if(!$this->isGuessed(chr($i)))echo "\n".CHtml::linkButton(chr($i),array('submit'=>array('guess','g'=>chr($i))));
}
?>
</p><p><?php echo CHtml::linkButton('Give up?',
array('submit'=>array('giveup'))); ?></p></form>

在View中可以直接通过$this 来访问对应的Controller实例对象的方法和属性。 如$this->guessWord,$this->isGuessed(chr($i))等。
其中点击26个字母触发guessAction (array(‘submit’=>array(‘guess’,'g’=>chr($i))))).

7. 下面为guessAction 的定义

public function actionGuess()
{// check to see if the letter is guessed correctlyif(isset($_GET['g'][0]) && ($result=$this->guess($_GET['g'][0]))!==null)$this->render($result ? 'win' : 'lose');else // the letter is guessed correctly, but not win yet{$guessed=$this->getPageState('guessed',array());$guessed[$_GET['g'][0]]=true;$this->setPageState('guessed',$guessed,array());$this->render('guess');}
}

其中参数 ‘g’由 guess 页面提交是传入, 如果单词全部猜对在显示”You win” 或用完所有次数猜错显示“You lose” , $this->render($result ? ‘win’ : ‘lose’),
如果还有机会猜还是回到guess 页面$this->render(‘guess’);

8. 在Guess页面上还有一个“Give up” 按钮,用户点击则触发giveupAction.这个方法比较简单,直接显示lose 页面

public function actionGiveup()
{$this->render('lose');
}

至此Hangman游戏基本就完成了。游戏虽然简单,但说明了使用Yii开发应用的基本流程,下面给出Yii开发文档给出的开发流程,Hangman比较简单,没有用到数据库和国际化等。

此处的开发流程假设我们已经完成了对应用的需求分析和必要的设计分析。

  1. 创建目录结构骨架。创建第一个Web应用中讲到的yiic工具可以快速实现此步骤。
  2. 配置此应用。这是通过修改应用配置文件实现的。 此步骤可能也需要编写一些应用组件(例如用户组件)。
  3. 为所管理的每个类型的数据创建一个模型类。Creating First Yii Application和Automatic Code Generation中讲述的Gii工具可以用于快速为每个数据表创建active record类。4.为每个类型的用户请求 创建一个控制器类。 具体如何对用户请求归类要看实际需求。总体来说,如果一个模型类需要被用户访问,他就应该有一个相应的控制器类。Gii工具也可以自动实现这一步骤。
  4. 实现动作和他们相应的视图。 这是真正所需要做的工作。
  5. 在控制器类中配置必要的动作过滤器。
  6. 如果需要主题功能,创建主题。
  7. 如果需要国际化(I18N),创建翻译信息。
  8. 对可缓存的数据点和视图点应用适当的缓存技术。
  9. 最终调整与部署。

上述的每个步骤中,可能需要创建并执行测试用例。

Yii Framework 开发教程(4) Hangman 猜单词游戏实例相关推荐

  1. Yii Framework 开发教程(32) Zii组件-GridView示例

     CGridView 以表格的形式显示数据,CGridView 也支持分页和排序,CGridView最基本的用法和ListView类型,也是通过设置 data provider,通常是CActiv ...

  2. Yii Framework 开发教程(30) Zii组件-ListView 示例

    CListView可以用来显示列表,CListView支持使用自定义的View模板显示列表的的记录,因此可以非常灵活的显示数据的表,这点有点像Android的ListView:-). CListVie ...

  3. Yii Framework 开发教程(31) Zii组件-DetailView 示例

     CDetailView为某个Model显示详细内容.这个要显示的Model可以为CModel或是关联数组. CDetailView通过配置 attributes来决定Model的那些属性需要显示 ...

  4. Yii Framework 开发教程Zii组件-Tabs示例

    有关Yii Tab类: http://www.yiichina.com/api/CTabView http://www.yiichina.com/api/CJuiTabs http://blog.cs ...

  5. Yii Framework 开发教程(41) Zii组件-Tabs示例

     CJuiTabs 显示分页UI组件,和Yii Framework 开发教程(17) UI 组件 TabView示例功能类似,它封装了 JUI tabs插件. 前基本用法如下: [php] vie ...

  6. Yii Framework 开发教程(29) Zii组件-Menu 示例

    介绍完Yii数据库接口外,从本篇开始介绍Zii组件,包括列表视图ListView,表格视图GridView,此外还包括一些基于JQuery的UI组件,如AutoComplete,DataPicker, ...

  7. Yii Framework 开发教程(22) UI 组件 Zii组件简介

     前面介绍了Yii框架支持的部分UI组件,除了前面介绍的UI组件外,Yii框架还提供了Zii组件库,包括列表视图ListView,表格视图GridView,此外还包括一些基于JQuery的UI组件 ...

  8. Yii Framework 开发教程(45) Zii组件-Selectable示例

    CJuiSelectable可以显示一个列表,列表的每个项支持Select事件,它封装了 JUI Selectable插件,其基本用法如下: <?php Yii::app()->clien ...

  9. Yii Framework 开发教程(36) Zii组件-DatePicker示例

     CJuiDatePicker 用于日期输入,它封装了 JUI datepicker插件,其基本用法如下: [php] view plaincopyprint? <?php echo $fo ...

最新文章

  1. Facebook是如何做搜索的?
  2. RedHat Linux网络配置过程笔记
  3. 前端:前端安全编码规范
  4. java程序优化快捷键_Java 代码中针对性能优化的总结方案
  5. gitter 卸载_最佳Gitter渠道:PHP
  6. 对称加密 与 非对称加密
  7. oracle md,Oracle笔记.md
  8. java用链表 编写记事本_(超详细) 动手编写 — 链表 (Java实现)
  9. JDK安装环境变量配置以及java命令可用但javac命令不可用解决方案
  10. linux如何添加虚拟打印机,Linux下虚拟打印机CUPS-PDF教程
  11. CAD-Cass小结(5)————WIN10安装并运行CAD2006及Cass7.0
  12. sel4 手册总结之介绍与内核服务和对象
  13. 让理科生沉默,让文科生流泪的综合题详解
  14. csr8811蓝牙芯片porting总结
  15. [Squirrel基础]-- squirrel安装(通过Phoenix连接 HBase)
  16. android关闭触摸声音,如何在Android中关闭所有触摸声音 | MOS86
  17. 16家上市车企2018年度中期经营业绩
  18. 一个40岁老码农的总结,奋斗没有意义,选择大于努力
  19. JAVA中将图片转化为圆形图片
  20. Code::Blocks使用教程

热门文章

  1. htmlimg图片加载失败_html网页图片未加载完成或失败时显示默认图片
  2. 关于object转换成string类型出现错误的解决办法
  3. 【Python】手把手教你——如何生成属于自己的二维码 ~
  4. 交换机同时设置多个观察口,解决镜像口不足问题
  5. 粤嵌携手华工汽车学院举办嵌入式大赛
  6. php 生成PDF的方法之一 --mpdf使用
  7. 曲面屏手机截屏图片像素与手机像素不一致
  8. C++传递参数给Python
  9. vue 生成二维码登录
  10. windows CMD 命令