TinyMVC 中文手册
翻译:淡水河边<kissjava#vip.qq.com>
TinyMVC官网:http://www.tinymvc.com/
中文反馈:http://www.tsingfeng.com/
版本:1.0(2010年2月2日 19:01:47)
目录
文件结构如下:
/htdocs/
index.php
/tinymvc/
/myapp/
/myfiles/
/sysfiles/
这是你的根目录的内容,现在里面是index.php默认的入口文件
这是TinyMVC的安装主目录。建议安装在网站根目录外面。
这是你应用程序的目录。一般,你的添加和编辑的文件都会在这个目录下。
这是一个共享安装目录。如果你有多个应用,就可以把都用到的插件从/myapp/plugins/目录,移动到/myfiles/plugins/。单个应用和多个应用的安装,后面会由介绍。
这是TinyMVC的系统目录。你不能编辑它,如果你升级TinyMVC,你会在这里找到更新的文件。
l 解压到你的网站根目录
l 浏览器中查看 htdocs/index.php 文件
你会看到欢迎界面。
这个是单个网站的安装。如果你有多个站点,需要tinymvc的核心以及一些共享,你需要使用共享安装。
解压到某个临时位置,你会看到如下结构:
/htdocs/
index.php
/tinymvc/
/myapp/
/myfiles/
/sysfiles/
l 把index.php文件放到网站根目录
Index.php是浏览器直接查看的文件。其他文件无需放到网站的根目录里。
l 把 /tinymvc/目录(包括其内容)放到网站根目录外面
/tinymvc/目录包含了所有系统文件和应用程序文件。我们建议(更安全,但不是必须这样)放到网站的根目录外面。
如果你要把/tinymvc/放在根目录下,为了安全起见,最好设置权限,使之无法直接从浏览器访问他们。
安装示例:
/var/www.foo.com/htdocs/
index.php
/var/www.foo.com/tinymvc/
/myapp/
/myfiles/
/sysfiles/
l 编辑index.php文件,并配置选项
在index.php里你会看到:
/* PHP error reporting level */
//error_reporting(E_ALL);
/* if your /tinymvc/ dir is not up one directory, uncomment and set here */
//define('TMVC_BASEDIR','../tinymvc/');
如有需要,可以取消错误报告的注释。开发时,你可能需要的错误报告是E_ALL,直接去掉注释就可以了。
如有需要,可以去掉定义TMVC_BASEDIR路径的注释。如果/tinymvc/目录在index.php文件的上一级,那默认是可以运行的。
配置路径,一定要包含结尾的斜杠。
一旦完成,你就可以从浏览器打开http://localhost/index.php (替换成你自己的路径)。你会看到欢迎界面。如果不是,检查错误信息,重新检查路径和配置设定。
如果你要使用数据库,你需要在这里设定:
/tinymvc/
/myapp/
/configs/
database.php
database.php
$config['plugin'] = 'TMVC_PDO'; // plugin for db access
$config['type'] = 'mysql'; // connection type
$config['host'] = 'localhost'; // db hostname
$config['name'] = 'dbname'; // db name
$config['user'] = 'dbuser'; // db username
$config['pass'] = 'dbpass'; // db password
$config['persistent'] = false; // db connection persistence?
Plugin设定为TMVC_PDO,除非你使用自定义的数据库library。根据你的数据库服务器设定类型(type),主机(host),数据库名(name),数据库用户(user),数据库用户密码(pass)和是否持久连接(persistent)。
每个网站都有自己的index.php和/myapp/目录与之关联。他们共享TinyMVC的基础代码。
/sysfiles/是你更新TinyMVC的目录,永远都不要动他。/myfiles/是你自定义的想要跨站共享的插件目录。
对每个网站,你都要安装一个index.php文件和一个/myapp/目录。
l 安装/tinymvc/目录到一个中央位置
l 复制根目录下的index.php文件
l 从/tinymvc/下,复制/myapp/到index.php同一位置,使之对应
l 编辑index.php的TMVC_BASEDIR和TMVC_MYAPPDIR的路径。
例如设置三个不同的网站:
# shared code
/usr/local/lib/tinymvc/
/myfiles/
/sysfiles/
#website 1
/var/www.foo1.com/htdocs/index.php
/var/www.foo1.com/myapp/
#website 2
/var/www.foo2.com/htdocs/index.php
/var/www.foo2.com/myapp/
#website 3
/var/www.foo3.com/htdocs/index.php
/var/www.foo3.com/myapp/
为每个网站,编辑index.php的TMVC_BASEDIR和TMVC_MYAPPDIR的路径。例如:
Index.php:
/* TinyMVC base library path */define('TMVC_BASEDIR','/usr/local/lib/tinymvc/');
/* application library path */define('TMVC_MYAPPDIR','../myapp/');
确认包含了结尾的斜线。
控制器文件是应用程序的粘合剂。他们加载模型(model),显示视图(view),还要配合插件工作等。可以说他就是个交警(指挥调度)。
一个TinyMVC页面的典型URL如下:
http://[host]/index.php/[controller]/[action]/[param1]/[param2]/[param3...]
controller是控制器的文件名/类名,action是你要访问的控制器的方法名。其他的是你的应用程序的参数。所以,一个真实的URL看上去如下:
http://localhost/index.php/hello/intro/name/joe
控制器文件在controllers目录下。我们建立一个控制器:
/myapp/
/controllers/
hello.php
hello.php
class Hello_Controller extends TinyMVC_Controller
{function index()
{
echo "Hello World.";
}
}url的控制器名称是区分大小写的,并且没有.php后缀。
类名前缀(prefix_Controller)必须符合控制器文件名。
现在我们可以看看这个,直接浏览:
http://localhost/index.php/hello
请使用你自己的安装路径访问到index.php
你会在浏览器里看到“Hello World.”字符
如果你在URL中不提供控制器名称,default就是默认值。你可以在/myapp/configs/application.php 文件里修改。
为简洁起见,我们直接在控制器里输出了。一般会是通过一个视图(view)输出,下一章我们将进行介绍。
现在,在控制器里新建一个方法:
Hello.php
class Hello_Controller extends TinyMVC_Controller
{function index()
{
echo "Hello World.";
}
function time()
{
echo "The time is now.";
}
}现在访问:
http://localhost/index.php/hello/time
如你所见,URL里方法名的改变,产生了对应的输出。
如果URL里没有方法名,默认的方法就是index。
用下面的Apache重写规则,你可以隐藏index.php:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
这个保存为.htaccess文件,放到根目录下,或是写道apache的配置里。
现在你可以直接访问http://localhost/hello这样的url了。
这将重写一切不是真正的文件或是目录的访问到index.php。务必创建一个robots.txt文件供网络爬虫浏览。还要创建一个favicon.ico文件,以便浏览器没有重定向而尝试加载网站图标文件。
视图文件就是你要显示的内容,包括html和css。
视图文件保存在views目录下。我们建立一个视图:
/myapp/
/views/
hello_view.php
在文件名后添加_view是推荐做法,不是必须这样。这样在编辑器里你一眼就可以看出这是什么文件。
hello_view.php
<html><head><title>Hello</title></head>
<body>
Hello World. </body></html>我们通过控制器调用视图文件。
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$this->view->display('hello_view');
}
}
不需要提供视图文件名的.php后缀。
在浏览器里加载:
http://localhost/index.php/hello
你可以看到hello_view视图文件的内容。
视图输出到一个变量,使用$this->view->fetch().
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$output = $this->view->fetch('hello_view');
}
}
有几种方法可以指定变量到视图。第一种方法使用assign().
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$this->view->assign('title','Hello');
$this->view->assign('body_text','Hello World.');
$this->view->display('hello_view');
}
}
Hello_view.php
<html><head><title><?=$title?></title></head>
<body><?=$body_text?>
</body></html>你可以看到一样的输出,但是这次内容是变量赋值的。
你还可以通过数组(array)赋值,而不是键/值对(key/value):
$data['title'] = 'Hello';
$data['body_text'] = 'Hello world.';
$this->view->assign($data);
当你通过$this->view->assign()分配数组,他会在内部通过$this->view->view_vars自动分配到各个变量。
通过$this->view->assign()指派变量,这些变量对之后的每个视图都是适用的(display(‘a’)后,还可以display(‘b’))。如果你想只对当前视图有效,可以使用$this->view->display()方法调用,把变量放入第二个参数传入。
$data['title'] = 'Hello';
$data['body_text'] = 'Hello world.';
$this->view->display('hello_view',$data);
为简洁起见,值都来源于控制器。实际应用中一般来源于model(database)等。
模型是MVC中汇总数据的那一层。基础数据源是典型的数据库,其他如LADP或文本文件等都可以是数据源。
模型文件在models目录下。我们建立一个模型:
/myapp/
/models/
page_model.php
page_model.php
class Page_Model extends TinyMVC_Model
{
function get_title()
{
return 'Hello';
}
function get_body_text()
{
return 'Hello World.';
}
}
模型文件名必须和模型类名匹配。类名无所谓,但是文件名必须小写。_model不是必须的后缀,但是这有助于组织结构。
我们从控制器加载一个模型,看看例子:
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
// load the model
$this->load->model('Page_Model','page');
// use the model to gather data
$title = $this->page->get_title();
$body_text = $this->page->get_body_text();
$this->view->assign('title',$title);
$this->view->assign('body_text',$body_text);
$this->view->display('hello_view');
}
}
$this->load->model()的第一个参数是模型的类名。第二个参数是可选的别名。加载模型类,得到他的成员属性,然后就可以使用这些属性收集数据了。如果你在前面的章节里保留了同样的视图文件。你就会看到这次来源于模型的变量指派还是一样的结果。
TinyMVC使用PDO进行数据库的访问,这需要PHP5.1以上的版本。确认你的myapp/configs/database.php已经根据你的数据库进行了配置。
示例:
members_model.php
class Members_Model extends TinyMVC_Model
{
function get_members()
{
$this->db->query('select * from members');
while($row = $this->db->next())
$results[] = $row;
return $results;
}
}
假设你有一个members数据表,get_members()方法将返回members表的全部记录。
class Members_Model extends TinyMVC_Model
{function get_member($id)
{
return $this->db->query_one('select * from members where id=?',array($id));
}
}上面将从数据库返回一天记录。这个示例展现了如何将变量传递给查询参数。query_one() 返回一天记录。
class Members_Model extends TinyMVC_Model
{
function get_members()
{
return $this->db->query_all('select * from members');
}
}
query_all()返回所有记录从查询。实际上和第一个query()例子一样。
你可以选择传值的方式用PDO::FETCH_ASSOC , PDO::FETCH_NUM或是 PDO::FETCH_BOTH . PDO::FETCH_ASSOC 是默认方式。
可用方法:
l $this->db->query($sql,$params) 执行一个查询,用 $this->db->next() 循环
l $this->db->query_one($sql,$params,$format) 返回一条记录
l $this->db->query_all($sql,$params,$format) 返回所有记录
l $this->db->next($format) 用于结果集的循环
l $this->db->last_insert_id() 获得最后插入数据库的id
l $this->db->num_rows() 返回上次查询的记录数
如果你想直接使用PDO对象,可以用 $this->db->pdo
这样你就可以充分使用PDO的特性了,但是你必须遵守他的语法和规则。例如:
class Members_Model extends TinyMVC_Model
{function get_members()
{
$results = null;
try {
foreach ($this->db->pdo->query('SELECT * from members') as $row)
$results[] = $row;
$this->db->pdo = null;
} catch (PDOException $e) {
trigger_error($e->getMessage());
return false;
}
return $results;
}
}插件是用来扩展框架功能的。目前有两个类型的插件:libraries,scripts。Libraries是php类,框架实例化它后使用。Scripts就是php脚本,直接包含进来。
插件文件存放在/myapp/plugins/目录下。我们建立一个library插件名叫demo:
/myapp/
/plugins/
library.demo.php
library的名称随意,但是类名必须匹配library名。
library.demo.php
class Demo {
function test()
{
return "This is a test.";
}
}
使用我们的新插件,我们通过控制器加载他.
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$this->load->library('demo','mydemo');
$this->view->assign('output', $this->mydemo->test());
$this->view->display('hello_view');
}
}
第二个参数是设定属性别名,可选项。
为测试demo的输出,你必须有个变量$output在你的视图文件中。
我们建立一个script插件叫myhelpers:
/myapp/
/plugins/
script.myhelpers.php
script命名随意。
Script.myhelpers.php
function esc($string)
{return htmlentities($string);
}function anchor($url,$text)
{return "<a href=\"$url\">$text</a>";
}使用我们的新插件,我们在控制器加载他.
/myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$this->load->script('myhelpers');
$this->view->display('hello_view');
}
}
现在,script中的php函数,你都可以在视图文件中使用了。
Libraries和scripts可以有选择的自动加载。详情见 自动加载插件。
如果想用其他数据库插件而不是内置的PDO,执行下列操作:
假设你的数据库插件名为 MYDB :
l 从 /sysfiles/plugins/ 复制db.TMVC_PDO.php 到 /myapp/plugins/db.MYDB.php
l 编辑这个文件,重命名类名把TMVC_PDO 改为 MYDB .
l 按自己的喜欢编辑添加功能 。
l 编辑 /myapp/configs/database.php 更改plugin 为 MYDB 。
我们扩展TinyMVC_Controller类:
myapp/plugins/internal.My_Controller.php
class My_Controller extends TinyMVC_Controller
{
function __construct()
{
parent::__construct();
}
// do your class extensions here
}
然后你的应用控制器,只要继承你扩展的自定义控制器就可以了:
class Hello_Controller extends My_Controller
{
function index()
{
$this->view->display('hello_view');
}
}
你不必包含你的扩展文件,TinyMVC会自动加载,只是命名必须是internal.classname.php 在plugins目录下。
同样的方法可以扩展TinyMVC_Model和TinyMVC_View.
代替在控制器中使用 $this->load->library() 和 $this->load->script() 方法加载插件,他们自动加载。这样你可以在每个控制器中随意使用他们了。
myapp/configs/autoload.php
/* auto-loaded libraries */$config['libraries'] = array('mylib','myotherlib');
/* auto-loaded scripts */$config['scripts'] = array('myhelpers','myscripts');
只要添加你的插件到自动加载数组。
如果你想用别名自动加载library,可以使用数组方式:
/* auto-loaded libraries */$config['libraries'] = array(
array('mylib','myalias'),
array('myotherlib','otheralias')
);
有时你会需要获得一个当前对象的实例,比如在library里,这样你就可以使用控制器的功能了。你可以在任何时候获得这个实例对象:
$tmvc = tmvc::instance();
$myvars['foo'] = 'bar';
$myvars['baz'] = 'gaz';
$output = $tmvc->view->fetch('some_view',$myvars);
模板引擎虽非必要,但是你也可以集成进去使用。下面的例子中我们将集成smarty作为视图层。我们把smartyclass作为一个library加载。
首先,我们使用快速但是难看的方式来做,一切都在控制器里。
请确认你的Smarty已经正确安装和部署。在这里,我们如下放置:
/var/smarty/
/libs/
Smarty.class.php
...
/templates_c/
/configs/
/cache/
这里我们没有建立smarty 的template 目录,因为我们的视图文件在 /myapp/views/ 目录下。
myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
// require the Smarty class
require('/var/smarty/libs/Smarty.class.php');
// instantiate the library
$this->load->library('Smarty','smarty');
// configure Smarty
$this->smarty->compile_dir = '/var/smarty/templates_c/';
$this->smarty->config_dir = '/var/smarty/configs/';
$this->smarty->cache_dir = '/var/smarty/cache/';
// we will use our view directory for template files
$this->smarty->template_dir = TMVC_MYAPPDIR . 'views/';
// now just use smarty for the view layer
$this->smarty->assign('foo','bar');
$this->smarty->display('hello_view.tpl');
}
}
如果library名称已经存在了,那么TinyMVC将不会尝试加载这个plugin。
现在控制器里有很多的代码,而且也许你还想在其他地方使用smarty。所以,更好的方案是建立一个library包:
myapp/plugins/library.Smarty_Wrapper.php
// require the Smarty class
require('/var/smarty/libs/Smarty.class.php');
class Smarty_Wrapper Extends Smarty
{
function __construct()
{
parent::Smarty();
$this->compile_dir = '/var/smarty/templates_c/';
$this->config_dir = '/var/smarty/configs/';
$this->cache_dir = '/var/smarty/cache/';
// we will use our view directory for template files
$this->template_dir = TMVC_MYAPPDIR . 'views/';
}
}
myapp/controllers/hello.php
class Hello_Controller extends TinyMVC_Controller
{
function index()
{
$this->load->library('Smarty_Wrapper','smarty');
// now just use smarty for the view layer
$this->smarty->assign('foo','bar');
$this->smarty->display('hello_view.tpl');
}
}
现在,在控制器里你可以用一行代码加载smarty了。当然,你还可以使他自动加载,放到 /myapp/configs/autoload.php 里。
要设定自定义错误处理程序,执行以下步骤:
假设你的错误处理类叫 My_ErrorHandler :
l 从 /sysfiles/plugins/ 复制 internal.TinyMVC_ErrorHandler.php 到 /myapp/plugins/internal.My_ErrorHandler.php
l 编辑文件,类名从 TinyMVC_ErrorHandler 改为 My_ErrorHandler
l 编辑添加你想要的功能
l 编辑 /myapp/configs/application.php 错误处理改为 My_ErrorHandler .