2011年(264)
分类: 系统运维
2011-04-13 21:24:11
实战doophp
项目文件存放结构
App/global目录下面均存放的是静态资源相关的如css\img\js\swf等相关的
Protected目录下面存放的是真正的代码相关的内容
cache文件夹 - 存储缓存文件
class文件夹 - 存放第三方类 (比如像分页类、上传类等相关的文件)
config文件夹 - 包括三个配置文件: common,
routes, database configs. (相关配置信息)
controller文件夹 - 存放控制器文件,默认有一个MainController
model文件夹 - 存放模型类
plugin文件夹 - 里面有一个
template_tags.php 文件用户添加新的功能(for you to add features to
the View)
view文件夹 - 存放视图文件 (全部的视图文件)
viewc文件夹 - 存放编译模版文件(Consist of
compiled template files.)当然,最常用的文件夹就是model, view,
controller 和 config 这四个。
查看一下相关的配置文件信息
说明相关配置文件的作用common.conf.php文件里面的
//For framework use. Must be defined. Use full absolute paths and end them with '/' eg. /var/www/project/
$config['SITE_PATH'] = realpath('..').'/app/';定义站点的绝对路径也可以写死绝对路径的如/var/www/project/
//$config['PROTECTED_FOLDER'] = 'protected/';
$config['BASE_PATH'] = realpath('..').'/dooframework/';
定义核心包的位置,只需要与app在同一层次即可
定义了相关的配置信息!
再看db.conf.php文件
Example Database connection settings and DB relationship mapping
定义了数据库连接与DB之间的关联相关(比如一对一或一对多的类型其实就是ORM将表之间的关联信息抽象出来)
数据库连接
$dbconfig['dev'] = array('localhost', 'blog', 'root', '1234', 'mysql', true, 'collate'=>'utf8_unicode_ci', 'charset'=>'utf8');
$dbconfig['prod'] = array('localhost', 'blog', 'root', '1234', 'mysql', true, 'collate'=>'utf8_unicode_ci', 'charset'=>'utf8');
$dbconfig[ Environment or connection name] 定义了连接环境或连接名称。这种情况可以适应于连接不同的数据库非常类似于CI的情况
再看routes.conf.php文件
其实这个文件的作用非常类似于django里面的urls.py文件的作用。将各个URL关系定义在一个配置文件里面全部的URL可以
$route[Request Method][Uri] = array( Controller class, action method, other options, etc. )
非常类似于django里面的urls.py的功能
它还支持REST模式的路由功能支持GET\POST\PUT\DELETE这四种服务要求模式。
PS:比如我现在POST一个数据或GET一段数据或想DELETE一个数据
摘:Get是最常用的,就是向Web 发请求“获取”资源;那么Post就是向Web Server“邮寄”一些封装的数据包获取资源,这两者方法严格的说都是“索取”行为。
顾名思义,Delete方法就是通过http请求删除指定的URL上的资源啦,Delete请求一般会返回3种状态码:(将删除指定的URL上面的资源)
200 (OK) - 删除成功,同时返回已经删除的资源
202 (Accepted) - 删除请求已经接受,但没有被立即执行(资源也许已经被转移到了待删除区域)
204 (No Content) - 删除请求已经被执行,但是没有返回资源(也许是请求删除不存在的资源造成的)
Put方法就不多废话了,就是往Web Server上直接扔资源(上传资源)嘛。
这两种协议需要web-server支持,然后客户端才可以去使用这些协议通讯
比如:
$route['*']['/api/list'] = array('RestController', 'listFood');
PS:这种写法默认的是get的方式。带*的形式
// Post request only(相当于是做select查询操作)
$route['post']['/api/create'] =
array('RestController', 'createFood');
// Put request only(表示客户端进行一次post提交动作)
$route['put']['/api/update'] =
array('RestController', 'updateFood');
// Delete request only
$route['delete']['/api/delete'] =
array('RestController', 'deleteFood');(进行delete操作)
PS:如果客户端进行一次post动作那可以在此进行配置处理。
还有一种情况就是解决像django里面的urls.py里面的正则变量替换行为。即URL里面也支持带变量传递的。
$route['*']['/archive/:year/:month'] = array('NewsController', 'archive');
这种URL结构如下
在Action里面我们可以这样来获取变量的参数值
$a = $this->params $this->year;
echo $this->params['year'];
还可以添加URL后缀
示例$route['*']['/simple.rss'] = array('FeedController', 'getRss');
表示后缀为.rss相应的映射到了'getRss' 这个Action上面!
如果URL里面带有变量可以
$route['*']['/news/list/:id'] = array('FeedController','listNews',
'extension'=>'.json');
直接将这个后缀扩展名写上去即可。
//支持多个后缀名.
$route['*']['/news/list/:id'] = array('FeedController','listNews',
'extension'=>array('.json', '.xml'));
访问方式为: OR 168.xml
还可以支持重定向的功能
$route['*']['/doophp'] = array('redirect', '');
对URL传递过来的参数进行验证。比如输入的ID为数字可以在URL里面直接正则过滤掉
示例:
$route['*']['/news/:id'] = array('NewsController', 'show_news_by_id',
'match'=> array(
'id'=>'/^\d+$/'
)
);
这样我的URL 才正常否则如果输入的是字符串就有问题
PS:
Common.conf.php里面配置了像什么路由之类的全局配置文件。
Db.conf.php里面定义了ORM中常用到的表关联与连接相关信息
Routes.conf.php里面实现了类似于django中的urls.py功能配置整体的路由功能
以这个示例来说明
常规示例$route['*']['/'] = array('BlogController', 'home');
表示的是整个站的根访问目录。映射到这个控制器的方法Action上面。
带参数的示例
$route['*']['/page/:pindex'] = array('BlogController', 'page');
表示了带参数的传递可以接收到参数$this->params[“pindex”];
带了其他的option可选项情况
$route['*']['/admin/post'] = array('AdminController', 'home',
'authName'=>'Blog Admin', 'auth'=>array('admin'=>'1234'), 'authFailURL'=>'./error/loginFail');
后面的这几个选项是什么含义的?
REST类型的POST的URL规则
$route['post']['/admin/post/save'] = array('AdminController', 'savePostChanges','authName'=>'Blog Admin', 'auth'=>array('admin'=>'1234'), 'authFailURL'=>'./error/loginFail');
以POST的方式将数据提交到WEB-SERVER!
说明:最好的做法就是按照一个模块一个模块来将URL进行归类编写。这样方便日后维护
开始分析MVC里面的代码结构吧
分析一下控制器
文件存放目录是在SITE_PATH/protected/crontroller文件夹下面的
AdminController.php这个文件的作用就是将管理员相关的控制器操作全部统一放到这里面
跟CI的控制器写法一样,也是继承了父类。所以有些关键字你不可以再去取了为啥呢?因为父类的保留关键字。比如有这几个是不可以再去取的关键字
$params
$puts
$extension
//methods 以下这些个方法也是不可以再去重命名了。因为会覆盖掉~
init_put_vars()
load()
language()
accept_type()
render()
setContentType()
is_SSL()
view()
db()
上面的我们谈到了URL的路由那现在来看看在控制器里面如何去将这里面的参数值提取出来的
echo $this->extension; 获取到路由里面的扩展名
echo $this->params[0]; 对于有参数的URL可以这样来获取参数值
如果控制器里面有分目录级别的话可以这样
protected/
controller/
MainController.php
PhotoController.php
admin/
AdminController.php
AdminPhotoController.php
那这样的控制器的话可以这样来使用
$route['*']['/admin/photo'] = array('admin/AdminPhotoController', 'main');
控制器的嵌套使用了~
上面讲了一大堆原理的话那现在来看看实际是怎么操作的。
class AdminController extends DooController {
//测试URL路由
public function index() {
echo "hello";
}
}
配置一下路由
访问地址:
其中我的App-Name 为app。都是基于这个进行配置的
$config['SITE_PATH'] = realpath('..').'/app/';
现在将其修改成blog吧。
修改两处一个是app的名字修改成blog另外一个是配置文件common.conf.php修改!
现在来测试上面我们所提到的路由配置相关
URL里面带参数如何获取这个参数值
路由配置如下$route['*']['/index/:year/:month'] = array('AdminController', 'index');
带有两个参数一个是年份另外一个是月份
控制器接收方式echo $this->params["year"];
我的Action的代码如下
public function index() {
echo "hello";
echo $this->params["year"];
}
访问地址:http://localhost/DoophpDemo/doophp/blog/index.php/index/1998/2
PS:以后开发我们规定像URL这种带参的传递方式都这样处理。
路由配置:
$route['*']['/index/:year/:month'] = array('AdminController', 'index');
URL的格式为:http://localhost/DoophpDemo/doophp/blog/index.php/index/1998/2
相应的Action中接收参数的方式
echo $this->params["year"];
对URL里面的参数进行过滤处理
路由配置$route['*']['/index/:id'] = array('AdminController', 'index','match'=>array('id'=>'/^\d+$/'));
对这个参数id进行一次正则过滤处理!
如果现在这样访问:http://localhost/DoophpDemo/doophp/blog/index.php/index/1986s
就会提示404
提取URL里面的后缀名
$route['*']['/simple.rss'] = array('FeedController', 'getRss');
问题在控制器里面居然拿不到后缀名的值~~~
继续学习控制器里面的相关细节
如何加载帮助类CI里面有$this->CI->load 类似于这样的功能。这边的语法
Doo::loadHelper('DooPager');将其写成了静态方法的形式进行一些加载处理
控制器加载模型进来。
Doo::loadModel('Post');
$p = new Post(); 构建出来模型对象出来!
引用配置文件里面的常量
我的控制器代码
public function index() {
echo Doo::conf()->APP_URL;
}
输出:http://localhost/DoophpDemo/doophp/blog/ 可以提取common.conf.php文件的相关常量值到时在应用编程的时候也是可以提取得到相应的常量值的~
渲染视图的代码
$this->render('admin', $data);
大致上的话跟CI的实现差不多。包括加载第三方的帮助类、加载Model、加载视图进来与渲染
有些不太好理解的概念
# You might want to use Firefox Poster addon for a quick test.
- GET return result in Json format
- GET return result in Xml format
- POST request, post variable to test
- PUT request, send a PUT request to test
- DELETE request, send a DELETE request to test
这是应用REST的方式在GET数据的时候返回的是一段JSON数据类型的数据。这个需要深入理解一下!
测试路由带有权限认证的情况
# Login with 'admin'=>'1234' or 'demo'=>'abc'.
我们来写一个简单的demo测试一下
路由规则这样写
$route['*']['/home'] = array('AdminController', 'home','authName'=>'Blog标题 ','auth'=>array('admin'=>'1234'),'authFailURL'=>'./error/loginFail');
那当我访问这个URL的时候http://localhost/DoophpDemo/doophp/blog/index.php/home/
就会弹出一个对话框出来。需要身份认证
填写admin/1234 验证通过.显示成功的action操作的内容~
不过一般的情况下是不需要使用这块的内容了~
对Model的深入学习
看看我们的模型层代码要怎么写。
模型层的代码结构如下
Doo::loadCore('db/DooModel'); 加载父类进来
class Post extends DooModel{ 也是需要继承父类
类属性跟JAVABEAN的类型也即MYSQL表里面的字段值
public $id;
/**
* @var varchar Max length is 145.
*/
public $title;
/**
* @var text
*/
public $content;
/**
* @var datetime
*/
public $createtime;
/**
* @var tinyint Max length is 1.
*/
public $status;
/**
* @var smallint Max length is 11. unsigned.
*/
public $totalcomment;
public $_table = 'post'; 相当于ORM里面的表名
public $_primarykey = 'id'; ORM里面定义的主键ID
public $_fields = array('id','title','content','createtime','status','totalcomment');
当前这个表的相关字段信息包括了这几个字段值
//构造函数
public function __construct($data=null) {
parent::__construct( $data );
parent::setupModel(__CLASS__);
}
在控制器里面$p->count() 我估计是调用了父类的一个方法实现统计这个表的个数
$p->limit($pager->limit, null, $this->sortField,
//we don't want to select the Content (waste of resources)
array('select'=>'id,createtime,status,title,totalcomment')
);
实现分页的条件。也是继承自父类的一个方法中~
如果需要实现ORM的话需要在入口文件index.php那里添加上这么一条
Doo::db()->setDb($dbconfig, $config['APP_MODE']);
而在db.conf.php里面有对$dbconfig['dev'] = array('localhost', 'db', 'root', '1234', 'mysql',true);
而在common.conf.php里面又有对$config['APP_MODE']的定义。
现在已成功加载了数据库信息如何实现常规的CRUD操作呢/
选择数据
public function index() {
// $tmp = Doo::db()->find('user'); 第一种方式调用
// $tmp = $this->db()->find('User'); 第二种方式调用
Doo::loadModel('User'); 通过调用模型层
$user = new User;
$user->username = 'a';
$tmp = $this->db()->find( $user, array('limit'=>1) );
var_dump($tmp);
$tmp = $this->db()->find('User');
foreach($tmp as $a) {
echo $a->username; //查询的遍历方法
}
}
还有这种写法$archive_list = $this->find( array('select'=>'createtime', 'desc'=>'createtime', 'asArray'=>true));应该是带有参数的查询吧?
前提条件是必须要有user.php这个模型层代码。而且里面要把创建表的相关字段信息补充掉
插入数据
public function index() {
Doo::loadModel('User');
$user = new User;
$user->username = 'a788';
$user->id = 4;
$result = $this->db()->insert($user);
} 跟django非常类似的处理方式~
更新数据
public function index() {
Doo::loadModel('User');
$user = new User;
$user->id = 4;
$options['limit'] = 1;
$user = $this->db()->find($user,$options);
$user->username = 'hello';
$this->db()->update($user);
}
操作与django非常类似。先是找到一个对象然后将属性赋上再次更新即可!
删除数据
public function index() {
Doo::loadModel('User');
$user = new User;
$user->id = 4;
$this->db()->delete($user);
}
可以深入学习的内容
public function countArchive($year, $month){
$startdate= "$year-$month-01";
$opt['where'] = 'createtime BETWEEN ? AND DATE_ADD(?, INTERVAL 1 MONTH)';
$opt['param'] = array($startdate,$startdate);
return $this->count($opt);
}
非常类似于preparestatment语句将? 代替掉相应的参数值。$opt['param'] = array($startdate,$startdate);它的作用其实就是把两个变量赋到这个?值去。
需要进一步深入掌握的内容主要是模型层这块的代码。特别是表关联查询这块的内容!
来讨论一下视图层
存放目录SITE_PATH/protected/view与SITE_PATH/protected/viewc中!
来创建一个视图。
控制器代码如下
public function index() {
$data['content'] = 'Some ...';
$this->render('admin', $data);
}
发现跟CI的实现一样。渲染的是admin.html这个视图文件。
视图文件代码
<body>
<p>{{content}}p>
body>
还可以在视图里面使用PHP语法的!使用情况如下
编写控制器里面的代码
public function index() {
$data['content'] = '5Some ...';
$this->renderc('admin', $data,true);//true表示的是让模板可以正确使用这个控制器里面的属性与方法
}
这里一定要注意这个视图文件的存放位置是在viewc目录下面的。放一些PHP文件可以再编译渲染处理~
来看一下我们的示例吧
对admin.html的渲染处理
对分页的处理
控制器这块的
if($this->sortField=='createtime' && $this->orderType=='desc'){
$pager = new DooPager(Doo::conf()->APP_URL.'admin/post/page', $p->count(), 6, 10);
}else{
$pager = new DooPager(Doo::conf()->APP_URL."admin/post/sort/$this->sortField/$this->orderType/page", $p->count(), 6, 10);
}
获取到limit的分割值
if(isset($this->params['pindex']))
$pager->paginate(intval($this->params['pindex']));
else
$pager->paginate(1);
$data['pager'] = $pager->output;
这段值的作用就是渲染到分页
{{pager}} 渲染处的标签值!
注意对静态资源的调用渲染均:
渲染的时候$data['rootUrl'] = Doo::conf()->APP_URL;
这样就可以避免CSS的路径
PublishedDraft
{{posts'
value.@title}}
{{formatDate(posts'
value.@createtime)}}
这个语法是什么?
深入讨论一下模板的语法使用情况
最基本的{{$variable}}
使用关联数据$data[‘user’][‘fullname’] = ‘DoopPHP’
使用情况就是{{user.fullname}} 利用关联数组进行渲染处理
在模板里面使用php函数{{upper(variable)}} 将其大写了!{{upper(user.fullname)}}
还可以传递参数到一个函数中去
{{sample_with_args(variable,’this is an argument’)}}
将这个参数值传递给这个变量去!
模板里面进行include操作
à
还可以引入一个包含了变量的文件名
这个是我们经常会应用到的就是加载一个列表loop list比如SELECT一个查询操作
$data['users']=array('john','doo','marie')
遍历操作
标准的一个写法吧!
还可以对其进行加上语法
如果是一个二维数组的话如何快速遍历呢/
$data['users']=array(
'john'=>array('name'=>'John Smith', 'gender'=>'male'),
'lee'=>array('name'=>'Bruce Lee', 'gender'=>'male')
);
遍历方式
明白了:数组的value原来是这样的一个含义。Users’ value 表示这个数组的value了!
还可以支持对象的形式
Doo::loadModel('SomeModel');
$obj = new SomeModel;
$obj->fullname = 'My Cool Name';
$obj->SomeObject->weight = 88
$data['obj'] = $obj;
应用模板的话可以这样
遍历对象的时候是这样处理的
{{upper(obj.@fullname)}}
对象再套对象的处理方式是这样的~
如果是一个数组的对象的遍历方式如下
Name: {{users' }
Gender: {{users' value.@gender}}
Weight: {{users' v.@Physical.@weight}}
Height: {{l' v.@Physical.@height}}
因为首先是一个数组然后数组里面再是对象所以是先遍历数组然后再把其相应的属性给套出来