刚学的Flea的使用笔记.想一起学的来.绝对简单易懂.

FleaPHP 开发札记

开始学习PHP 的 Framework ,选中了一个国产的FleaPHP,它也是国内唯一一个比较成熟的。开始吧!

www.fleaphp.org上下载了一个最新的FleaPHP 1.7版本的。
先不管什么MVC了。照网上的教程一步一步来。

准备用它建立个GuestBook
先建立了个数据库 GuestBook 再建立两个数据表.
CREATE TABLE `message` (
  `mid` int(10) unsigned NOT NULL auto_increment,
  `author` varchar(20) default 'Guest',
  `email` varchar(60) default NULL,
  `ip` varchar(15) default '0.0.0.0',
  `time` int(11) default '0',
  PRIMARY KEY  (`mid`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312 AUTO_INCREMENT=1;

CREATE TABLE `content` (
  `mid` int(10) NOT NULL,
  `contest` text NOT NULL,
  KEY `mid` (`mid`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312;

建立目录结构 设定网站目录结构 根目录为 webroot/
webroot/
        Lib/
        FLEA/
       
        GuestBook/
        Images/
        Scripts/
        Styles/
        APP/
        Config/
        Controller/
        Model/
        View/

OK,简单的文件目录设置完毕。



再简单的设置好入口文件Index.php
File: Index.php
<?php
//设置基本目录
define('APP_DIR', dirname(__FILE__).'/APP');

//引入FLEA.php
require('../Lib/FLEA/FLEA.php');

//设置配置文件
FLEA::loadAppInf(APP_DIR .'/Config/DSN.php');

//引入基本目录s
FLEA::import(APP_DIR);

//运行
FLEA::runMVC();
?>       

在上面的入口Index.php中使用了配置文件。那就先编写配置文件DSN.php,该文件保存在App/Config/目录下。
File: DSN.php
<?php
return array(
        'responseCharset'                => 'gb2312',                //设置网页编码
        'databaseCharset'                => 'gb2312',                //设置数据库编码

        //设置缓存目录,目录建立在/APP/Config/_Cache/
        //这个目录设置很重要.不设置的话,可能无法运行程序.或者修改其他配置选项.

    'internalCacheDir'        => dirname(__FILE__).'/_Cache',
        //配置数据信息
    'dbDSN'     => array(
        'driver'        => 'mysql',
        'host'          => 'localhost',
        'login'         => 'root',
        'password'      =>'',
        'database'      => 'guestbook',
    ),
);
?>       

如果要让程序运行起来.还要添加几个文件.
第一个是要在APP/Controller目录下建立个Default.php文件,这个是控制器的默认动作处理文件,不能缺少.

File:Default.php
<?php
class Controller_Default extends FLEA_Controller_Action
{
        var $message;

        function Controller_Default(){
                $this->message = &FLEA::getSingleton('Model_Message');
        }

        function actionIndex(){
                //echo '<h1>Now. Echo Default Index Page</h1>';\
                include_once(APP_DIR.'/View/index.php');
        }
}
?>       

这上面的这个文件中.因为用了getSingleton()函数.所以涉及到数据库对象.
所以还要在Model文件夹下建立几个数据库处理文件.
File: /Model/Message.php
        <?php
       
        FLEA::loadClass('FLEA_Db_TableDataGateway');
       
        class Model_Message extends FLEA_Db_TableDataGateway
        {
                var $tableName = 'message';
                var $primaryKey = 'mid';
       
                var $hasMany = array(
                        array(
                                'tableClass' => 'Model_Content',
                                'foreignKey' => 'mid',
                    'mappingName' => 'contents'

                        ),
                );
        }
?>       
       
       
File: Model/Content.php
<?php

FLEA::loadClass('FLEA_Db_TableDataGateway');

class Model_Content  extends FLEA_Db_TableDataGateway
{
        var $tableName = 'content';
        var $primaryKey = 'mid';
}
?>
       
       
在Default.php 文件中我们还用了一/View/index.php来显示数据.所以也要建立这个文件
File: /View/index.php
<!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=gb2312" />
<title>Framework FLEA Application: GuestBook</title>
<style type="text/css">
<!--
.logo {
        font-size: xx-large;
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-style: normal;
        line-height: normal;
        font-weight: normal;
        font-variant: normal;
        text-transform: capitalize;
        color: #0000FF;
}
body,td,th {
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-size: small;
        color: #333333;
}
body {
        background-color: #FFFFFF;
        margin-top: 0px;
}
-->
</style>
</head>

<body>
<table width="800" border="0" align="center" cellpadding="0" cellspacing="0">
  <tr>
    <td height="150" align="left"><span class="logo">Flea Framework Application : GuestBook</span> </td>
  </tr>
  <?php foreach($posts as $lists){ ?>
  <tr>
    <td align="center">
        <table width="80%" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#DEDEDE">
      <tr bgcolor="#FFFFFF">
        <td height="40" colspan="2" align="left">  Contest:<br />    <?php echo $lists['contents'][0]['content'] ?></td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td width="59%" height="25" align="left"> Publish By:<a href="mailto:<?php echo $lists['email']; ?>"><?php echo $lists['author']; ?></a>   At: <?php echo date('Y-m-d H:i',$lists['time']); ?></td>
        <td width="41%" align="left"> From: <?php echo $lists['ip']; ?> </td>
        </tr>
    </table>
        </td>
  </tr>
  <tr>
    <td align="center" height="8"></td>
  </tr>
  <?php } ?>
  <tr>
    <td align="center">
        <table width="80%" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#DEDEDE">
        <form action="<?php echo $this->_url('new'); ?>" method="post" name="guestbook">
      <tr>
        <td height="25" colspan="2" align="left">  New Suggestion </td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td width="22%" height="20" align="left"> Author:</td>
        <td width="78%" align="left"> <input name="author" type="text" id="author" size="30" maxlength="80" /> *</td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td height="20" align="left"> E-mail:</td>
        <td align="left"> <input name="email" type="text" id="email" size="50" maxlength="80" /> *</td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td align="left" valign="top"> Content:</td>
        <td align="left"> <textarea name="contest" cols="50" rows="10" id="contest"></textarea></td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td height="40"> </td>
        <td align="left">    <input type="submit" name="Submit" value="Post Suggestion" /></td>
      </tr>
          </form>
    </table>
        </td>
  </tr>
  
  <tr>
    <td height="30" align="center"> </td>
  </tr>
  <tr>
    <td height="60" align="center">开发者:浮云 Version: 1.0 beta <br />
    没有版权 欢迎转载</td>
  </tr>
</table>
</body>
</html>
       
       


有了上面的几个文件之后.就能使用FleaPHP 1.7.x了.可以先自己在数据库插入几条记录试试,不过不用着急,先了解一下Default.php和Message.php的文件结构.调试起来会比较顺利. .....
       
        先看看Controller/Default.php文件.
        开始的时候建立一个默认的控制器类.
        class Controller_Default extends FLEA_Controller_Action
        这个类有一个属性. $message 和一个构造函数和一个默认的index函数.默认的actionIndex()函数就想网站目录下的index.php文件.打开网站某个目录时,自动的 执行index.php文件,这个当然是在Apache服务器先配置好的.FLEA默认的执行actionIndex()文件.
        我们在actionIndex()文件中include了/View/index.php文件.用来显示首页.这样不至于打开网站的时候显示一片空白.心理怪难受的.
        Controller_Default 关键的部分不是actionIndex()函数.而是那个构造函数.我们看看用了一个FLEA::getSingleton()函数.这个函数会调用 Model目录下的定义好的数据库操作类的一个实例给属性$message. getSingleton($className) 函数的参数命名的时候要特别注意.一定要'Model_xxx'这样.不知道为什么.改成'xxx'的时候.老是提示无法找到已经定义的xxx类.尽管你 在/Model/目录下的xxx.php文件里进行了
        class xxx extends FLEA_Db_TableDataGateway 这样的定义.最好是定义成 class Model_xxx extends FLEA_Db_TableDataGateway 这样就不会出错了.反正都是刚学习FLEA,有好的方法以后熟悉了后再修改. OK,在构造函数里$message 属性得到了一个数据库的实例.这样可以用它来操作数据库的数据.在actinoIndex()函数里我们使用了这样的一条语句:
        $posts = $this->message->findAll(null,'mid DESC');
        这样就得到了表的message 和表 content的所有关联数据. 排列顺序是以字段mid为降序的排列. 关于怎么得到这样的关联数据,我们在/Model/文件夹下的文件中已经做了定义.可以再看看Message.php和Content.php文件是怎么 定义的.
        在Message.php文件的中的Model_Message类中定义了3个属性.$tableName,$primaryKey和$hasMany. 这几个变量一看就知道代表什么意思了.$tableName 是你要操作的数据表的名称.$primaryKey是这个表的主键.现在我们的message表只有一个主键.多个主键的表还没有用到.具体用法还没有试 过.用的时候再研究.^o^. 这个$hasMany是比较有意思.它是个数组.用来设置关联其他表的信息的.数据模式为下面这样:
        var $hasMany = array(
                        array(
                                'tableClass' => 'Model_Content',        //要关联的表名
                                'foreignKey' => 'mid',                //关联的键名,就是外键啦
                  'mappingName' => 'contents'        //结果集的提取字段名,是个数组
                        ),
        // 在这里还可以继续添加和上面一样的数据用来增加关联表的数目.
        );
       
定义这个属性的时候一定要记得在Content.php文件中同时定义Model_Content类,不然就没有办法关联了.定义 Model_Content的时候就更简单了.因为它是被关联的.只要在类中定义2个基本属性就OK了.$tableName='content',$ primaryKey='mid'就这样搞定了.

然后我们再往数据库里添加2条数据:
INSERT INTO `message` (`mid`, `author`, `email`, `ip`, `time`) VALUES (1, 'Guest01', 'guest01@guestcom', '192.168.1.133', 111111111);
INSERT INTO `message` (`mid`, `author`, `email`, `ip`, `time`) VALUES (2, 'Guest02', 'guest02@guestcom', '192.168.1.200', 1212121212);
INSERT INTO `content` (`mid`, `content`) VALUES (1, 'test1<->test1');
INSERT INTO `content` (`mid`, `content`) VALUES (2, 'test2<->test2');

这样,GuestBook的读取功能就基本上可以使用了.截个图看看



接下来我们为它添加数据保存功能,这样就更像一个留言本了.在这直前我们先好好看FLEA的数据库操作函数findAll()的具体用法.累了.明天再继续.
/**
*                用FLEA_DB 获取数据表的数据的方法
*/
1.一般要先建立一个FLEA_DB_TableDataGetway的对象.通常要从它这里派生个子类.
        FLEA::loadClass('FLEA_DB_TableDataGetway');
        class Model_TestGetData extends FLEA_DB_TableDataGetway {
        var $tableName = 'yourTablename';
        var $primaryKey = 'yourTablePrimaryKey';
        }
        如果只是简单的单表数据读取的话,这样就可以了.一般在Controller里的控制文件里通过FLEA::getSingleton() 函数来取得对象名称.也可以直接获取.通过Controller里的文件来获取可能主要是体现MVC模式吧.在PHP4的环境下一般通过前加个 '&',可以反正复制对象.像这样:
        $this->dbAction = &FLEA::getSingleton('Model_className');
        上面的dbAction是Controller里的类的一个属性.getSingleton()函数的参数'Model_className'一定要注 意,'Model_'好象是表示在Model目录下的意思.如果不加这个,FLEA总是提示找不到已经被你定义好的类.
        FLEA获取的findAll(); 所有的结果可以用dump($rs) 来查看结果.
       
        参数方式1: findAll(null);
        $rs = $object->findAll(null);
        显示所有数据,没有排列顺序.
       
        参数方式2: findAll(null,'fields DESC/ASC');
        $rs = $object->findAll(null,'fields DESC/ASC');
        显示所有数据,按照fields 的DESC或者ASC对结果集进行排序返回.
       
        参数方式3: findAll(null,'fields DESC/ASC',number);
        $rs = $object->findAll(null,'fields DESC/ASC',number);
        按照排序结果,截取前number条记录.
       
        参数方式4: findAll(null,'fields DESC/ASC',number,fieldsArray);
        $fields = array('fields1','fields2',...);
        $rs = $object->findAll(null,'fields DESC/ASC',number,$fields);
        按照排序结果 只显示$fields数组里的字段,截取前number条记录.
       
        参数方式4: findAll(null,'fields DESC/ASC',numArr);
        $nums = array(99,10);
        $rs = $object->findAll(null,'fields DESC/ASC',$nums);
        按照排序结果 截取从第100条到109条的10条记录.
       
        参数方式5:findAll(condition);
        先前查询的时候都没有加条件,如果有查询条件的时候可以把上面的null部分换成查询条件.这样就可以方便的查询想要的数据了.如果条件比较多的话可以使用数组来处理.简单那的一点就像 $condition = 'mid>1';这样.
       
        需要注意一点是如果关联表里有多条的记录能与主表的一条记录关联,那么主表即使只限制取一条记录,mappingName的字段会把关联表里的符合要求的记录都取出来存放在改数组里.
       
        现在我们添加GuestBook的数据保存功能.
        保存数据到数据库,Flea主要用到的一个函数为: create()这样.
在Default.php文件的加入一个小小的函数就可以办到.像下面这样:
function actionNew(){
                $_POST['content'] = nl2br(htmlspecialchars($_POST['content']));
                $newArr = array(
                        'author' => htmlspecialchars($_POST['author']),
                        'email' => htmlspecialchars($_POST['email']),
                        'ip' => $_SERVER["REMOTE_ADDR"],
                        'time'=> time(),
                        'contents' => array(
                                array(
                                        'content'=>$_POST['content']
                                )
                        )
                );
               
                if(!empty($newArr['author'])&&!empty($newArr['email'])&&!empty($_POST['content'])){
                        $this->message->create($newArr);
                }
               
                echo 'Thanks,Suggestion save success! Please <a href="'.$this->_url().'">Click Here </a> to back!';
        //redirect($this->_url());
        }       

        可以看到.开始的部分.我们对表单的值进行了一些格式化.方便保存到数据库中.
如果按照现在的办法,执行页面操作。结果不会正确,出错的原因在于数据库的设计。可以查看access.log文件可以看到。Flea在执行数据库插入操 作的时候。本来该在Content表执行插入操作。结果却变成了更新操作。在咨询了Flea的开发者老廖后。他提供了如下的解决方法:
回复邮件内容:
问题知道了。

默认情况下,FleaPHP 调用 save() 操作来保存关联数据。

而 save() 操作判断数据是否包含主键值。如果包含主键值,则调用 update() 方法,否则调用 create() 方法。

由于你的 content 表使用 mid 字段作为主键,同时该字段还用于关联。因此在调用 create() 创建 message 记录时,FleaPHP 会自动将新创建的 message 记录的主键值填充到要保存的 content 记录中。

所以在接下来保存 content 记录时,就变成调用 update() 方法了。

解决办法很简单,在调用 $this->message->create() 之前执行:

$link =& $this->message->getLink('content');
$link->saveAssocMethod = 'create';

执行 create() 后,再修改

$link->saveAssocMethod = 'save';

上述代码使得在调用 create() 保存关联数据时总是使用 create() 方法。        

按照上面的方法可以解决数据插入的问题。问题在于我们把content表的外键mid同时定义成了主键了。解决的办法除了按照上面的办法外。修改数据库也能解决关联插入数据的问题。
看看重新修改的文件
先修改数据表content
CREATE TABLE `content` (
  `id` int(10) NOT NULL auto_increment,
  `mid` int(10) NOT NULL,
  `content` text NOT NULL,
  KEY `mid` (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=gb2312 AUTO_INCREMENT=1 ;       







/Model/Content.php
<?php
FLEA::loadClass('FLEA_Db_TableDataGateway');

class Model_Content  extends FLEA_Db_TableDataGateway
{
        var $tableName = 'content';
        var $primaryKey = 'id';
}       

这样问题就解决了。

现在的GuestBook虽然可以完成基本的留言和显示功能。但是还是很不好用。
第一是缺少分页功能。
第二是php和html混在一起。
不适合美工。
先来解决模板问题。
Flea1.7已经默认支持对很多模板的支持。我比较顺手的是SmartTemplate,就简称ST吧。使用ST,需要先配置ST参数信息。
看看修改过的DNS.php文件:
<?php
return array(
        'logEnabled'                                => true,
        'responseCharset'                => 'gb2312',
        'autoResponseHeader'        => true,
        'databaseCharset'                => 'gb2312',
        'defaultLanguage'       => 'chinese-gb2312',
    'internalCacheDir'        => dirname(__FILE__).'/_Cache',
    'dbDSN'     => array(
        'driver'        => 'mysql',
        'host'          => 'localhost',
        'login'         => 'root',
        'password'      =>'',
        'database'      => 'guestbook',
    ),

        'view' => 'FLEA_View_SmartTemplate',
        'viewConfig'                                => array(
        'smartDir'                                => dirname(dirname(dirname(__FILE__))) .'/Lib/SmartTemplate',
        'template_dir'                        => dirname(dirname(__FILE__)). '/View/Tpl',
        'temp_dir'                        => dirname(dirname(__FILE__)). '/View/Tpl_c',
                'cache_dir'                        => dirname(dirname(__FILE__)).'/View/Tpl_c',
    ),
);
?>       

使用时先做几个模板文件。由index.php文件截出来的。
/View/Tpl/page.htm
<!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=gb2312" />
<title>Framework FLEA Application: GuestBook</title>
<style type="text/css">
<!--
.logo {
        font-size: xx-large;
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-style: normal;
        line-height: normal;
        font-weight: normal;
        font-variant: normal;
        text-transform: capitalize;
        color: #0000FF;
}
body,td,th {
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-size: small;
        color: #333333;
}
body {
        background-color: #FFFFFF;
        margin-top: 0px;
}
-->
</style>
</head>

<body>
<table width="800" border="0" align="center" cellpadding="0" cellspacing="0">
  <tr>
    <td height="120" align="left"><span class="logo">Flea Framework Application : GuestBook</span> </td>
  </tr>
  <tr>
    <td height="25" align="left">      <a href="">My GuestBook</a></td>
  </tr>
  {out}
  <tr>
    <td align="center">
        <table width="80%" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#DEDEDE">
        <form action="{post_url}" method="post" name="guestbook">
      <tr>
        <td height="25" colspan="2" align="left">  New Suggestion </td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td width="22%" height="20" align="left"> Author:</td>
        <td width="78%" align="left"> <input name="author" type="text" id="author" size="30" maxlength="80" value="Camgame" /> *</td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td height="20" align="left"> E-mail:</td>
        <td align="left"> <input name="email" type="text" id="email" size="50" maxlength="80" value="cam_work@163.com" /> *</td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td align="left" valign="top"> Content:</td>
        <td align="left"> <textarea name="content" cols="50" rows="10" id="content">asdjflkjafalsdfjlaksd</textarea></td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td height="40"> </td>
        <td align="left">    <input type="submit" name="Submit" value="Post Suggestion" /></td>
      </tr>
          </form>
    </table>
        </td>
  </tr>
  
  <tr>
    <td height="30" align="center"> </td>
  </tr>
  <tr>
    <td height="60" align="center">开发者:浮云 Version: 1.0 beta <br />
    没有版权 欢迎转载</td>
  </tr>
</table>
</body>
</html>       

/View/box.htm
<!-- BEGIN row -->
  <tr>
    <td align="center">
        <table width="80%" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#DEDEDE">
      <tr bgcolor="#FFFFFF">
        <td height="40" colspan="2" align="left">  Contest:<br />    {text}</td>
      </tr>
      <tr bgcolor="#FFFFFF">
        <td width="59%" height="25" align="left"> Publish By:<a href="mailto:{email}">{author}</a>   At: {time}</td>
        <td width="41%" align="left"> From: {ip} </td>
        </tr>
    </table>
        </td>
  </tr>
  <tr>
    <td align="center" height="8"></td>
  </tr>
<!-- END row -->       

模板文件准备好了。
修改/Controller/Default.php
<?php
class Controller_Default extends FLEA_Controller_Action
{
        var $message;
        var $tpl;

        function Controller_Default(){
                $this->message = &FLEA::getSingleton('Model_Message');
                $this->tpl =& $this->_getView();
        }

        function actionIndex(){
                $posts = $this->message->findAll(null,'mid DESC');

                $out = '';

                $this->tpl->set_file('page.htm');
                $t = new FLEA_View_SmartTemplate();
                $t->set_file('box.htm');

                foreach($posts as $k=>$v){
                        $posts[$k]['time'] = date('Y-m-d H:i:s',$v['time']);
                        $posts[$k]['text'] = $v['contents'][0]['content'];
                        unset($posts[$k]['contents']);
                }

                $this->tpl->assign('post_url',$this->_url('new'));
                $t->assign('row',$posts);
                $out = $t->result();

                $this->tpl->assign('out',$out);
                $this->tpl->output();       
        }

        function actionNew(){
                $_POST['content'] = nl2br(htmlspecialchars($_POST['content']));
                $newArr = array(
                        'author' => htmlspecialchars($_POST['author']),
                        'email' => htmlspecialchars($_POST['email']),
                        'ip' => $_SERVER["REMOTE_ADDR"],
                        'time'=> time(),
                        'contents' => array(
                                array(
                                        'content'=>$_POST['content']
                                )
                        )
                );
               
                if(!empty($newArr['author'])&&!empty($newArr['email'])&&!empty($_POST['content'])){
                        $this->message->create($newArr);       
                }
               
                echo 'Thanks,Suggestion save success! Please <a href="'.$this->_url().'">Click Here </a> to back!';
        //redirect($this->_url());
        }
}       
因为ST对嵌套支持不是很好。必须要支持使用多个模板对象来处理.但是Flea::_getView() 总是返回同一个对象。所以要使用
$t = new FLEA_View_SmartTemplate();
来创建新的对象。记得把class.smarttemplate.php文件的299行的
unset ($_top);该成 unset($GLOBALS['_top']); 否则模板嵌套就不会成功。

好了。简单的Flea集成其他的模板类就OK了。
接下来就给GuestBook添加分页功能就可以叫成一个GuestBook了

先不写了。累的很。
感谢偶的MM放弃聊天时间,让出电脑让偶有机会玩玩FleaPHP,
也谢谢老廖!
以后的休息一段时间再写.