yershop商城系统是基于thinkphp和onethink开发而来,此系列将详细分析我在二次开发中所面临的种种问题。
(我使用的yershop版本较早,大概是去年5月份左右发布的。支付宝后台配置没有用,商品不支持多规格。本次介绍如果讲到这方面的问题,没有的亲请忽略。)
本篇简要分析日常在二次开发中涉及到的thinkphp和onethink知识。
此为我的项目中在zendstudio中截图
Addons:扩展插件目录,里面包含了第三方登陆插件、编辑器插件等;
Application:项目目录,之后详细介绍
Data:数据库备份目录
Public:js、css、image网站图片资源保存
Uploads:上传图片、文件目录(SAE环境下存储于storage中)
Runtime:运行中动态生成的程序(在检查标签语法出错时很有用,文件可删除)
Thinkphp:Thinkphp包,yershop系统或onethink在开发中均对Thinkphp包有改动,勿直接换该文件
Common:公共配置,进入应用程序后,首先加载此文件夹内容;
User:用户模块,提供用户注册之类的核心方法;
Install:安装模块,安装异常时可在此检查代码;
Home:PC网站模块;
Wap:手机网站模块;(个人开发,免费下载包无)
Wei:嫁接weiphp2.0到商城所用模块(个人自定义模块,免费下载包无)
此处重点关注 Common文件夹/function.php 和 Conf文件夹/config.php 两个文件
function.php为全局方法,Home、Wap、自定义模块等其它模块 均可调用其内方法;
config.php 为全局配置文件,需要注意的是数据库连接以及User模块下同名文件的数据库连接。
问:PC站和手机站如何在输入主域名后直接访问对应模块(Home or Wap)?
答: 在config.php文件开头根据访问源指定要加载的模块,代码如下
if(!ismobile()){
$module = 'Home';
}else{
$module = 'Wap';
}
return array(
/* 模块相关配置 */
'AUTOLOAD_NAMESPACE' => array('Addons' => ONETHINK_ADDON_PATH), //扩展模块列表
'DEFAULT_MODULE' => $module,
...
ismobile()方法可使用function.php里已有的判断说否为手机方法,此处贴代码:
function ismobile() {
// 如果有HTTP_X_WAP_PROFILE则一定是移动设备
if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
return true;
//此条摘自TPM智能切换模板引擎,适合TPM开发
if(isset ($_SERVER['HTTP_CLIENT']) &&'PhoneClient'==$_SERVER['HTTP_CLIENT'])
return true;
//如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
if (isset ($_SERVER['HTTP_VIA']))
//找不到为flase,否则为true
return stristr($_SERVER['HTTP_VIA'], 'wap') ? true : false;
//判断手机发送的客户端标志,兼容性有待提高
if (isset ($_SERVER['HTTP_USER_AGENT'])) {
$clientkeywords = array(
'nokia','sony','ericsson','mot','samsung','htc','sgh','lg','sharp','sie-','philips','panasonic','alcatel','lenovo','iphone','ipod','blackberry','meizu','android','netfront','symbian','ucweb','windowsce','palm','operamini','operamobi','openwave','nexusone','cldc','midp','wap','mobile'
);
//从HTTP_USER_AGENT中查找手机浏览器的关键字
if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
}
//协议法,因为有可能不准确,放到最后判断
if (isset ($_SERVER['HTTP_ACCEPT'])) {
// 如果只支持wml并且不支持html那一定是移动设备
// 如果支持wml和html但是wml在html之前则是移动设备
if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
return true;
}
}
return false;
}
Home下也有 Common/function.php 和 Conf/config.php 两个文件,但作用域仅限Home模块
注意:该function.php里的方法不能有和Common模块下总function.php里 重名 的方法,否则报 “不可重载”的错误。
此文件内可配置仅针对PC端网站使用的配置,例如支付宝配置信息
有学习价值的配置信息:
/* 主题设置 */
'DEFAULT_THEME' => 'monkey', // 默认模板主题名称,与View文件相关
'URL_MODEL' => '2', //URL模式:2为隐藏index.php的rewrite模式
'PICTURE_UPLOAD_DRIVER'=>defined('SAE_TMP_PATH') ? 'Sae' : 'local',
//本地上传文件驱动配置
'UPLOAD_LOCAL_CONFIG'=>array(),
'UPLOAD_SAE_CONFIG'=>array(
'rootPath'=>'',
'domain'=>'upload',
),
'SAE_Domain' => 'http://' . $_SERVER['HTTP_APPNAME'] . '-upload.stor.sinaapp.com',//sae的storage支持所需
thinkphp设置默认加载Index控制器中index()方法,在这里所有文件都继承了HomeController,在HomeController.class.php文件里可定义多数页面都需要加载的方法,如
/* 空操作,用于输出404页面 */
public function _empty(){
$this->redirect('Index/index');
}
//初始化方法,本方法总会被最先加载
protected function _initialize(){
/* 读取站点配置 */
$config = api('Config/lists');
C($config); //添加配置
if(!C('WEB_SITE_CLOSE')){
$this->error('站点已经关闭,请稍后访问~');
}
}
因为在Home模块的config.php文件中设置了'DEFAULT_THEME' => 'monkey'
,故会加载View/monkey文件夹
套模版是二次开发日常很常用的功能,套模板首先要做的是定义css、js、image的路径,定义路径的文件是当前模块Home下的Conf/config.php中
/* 模板相关配置 */
'TMPL_PARSE_STRING' => array(
'__STATIC__' => __ROOT__ . '/Public/static',
'__ADDONS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/Addons',
'__IMG__' => __ROOT__ . '/Public/' . MODULE_NAME . '/images',
'__CSS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/css',
'__JS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/js',
//仿站模版monkey的自定义路径
'__MIMG__' => __ROOT__ . '/Public/' . MODULE_NAME . '/monkey/images',
'__MCSS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/monkey/css',
'__MJS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/monkey/js',
//仿站模版分销的自定义路径
'__FIMG__' => __ROOT__ . '/Public/' . MODULE_NAME . '/fenxiao/img',
'__FCSS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/fenxiao/css',
'__FJS__' => __ROOT__ . '/Public/' . MODULE_NAME . '/fenxiao/js',
),
问:Controller与View的关联?
答:需要前台展现的页面,如用户登陆页面,只需在UserController.class.php文件login()方法最后使用
//显示登录表单
$this->display();
如果需要指定加载模版,
//显示登录表单
$this->display('User/index');
则会调用User控制器下login方法,展现User文件夹下index.html模版页面
一定要学会根据URL判断所加载文件的位置!
例如:www.xxx.com/index.php/Home/User/login.html
文件后台代码位置:Home/Controller/UserController.class.php->login()方法;
默认前台代码位置:Home/View/(default文件夹 or 自定义 or null)/User/login.html。
少数文件会加载指定模版,但后台代码位置一般不会有误。
问:我自己创建了一个控制器,但每次访问都直接跳转到了Index/index里?
答:排除代码错误问题
1.控制器命名:
(1)首字母大写;
(2)XxxController.class.php中,Xxx中有其它大写字母,例如WxPayController.class.php;
2.类名与文件名不统一
文件名为:UserController.class.php,则类名必须为UserController
namespace Home\Controller;
/**
* 用户控制器
* 包括用户中心,用户登录及注册
*/
class UserController extends HomeController {...
3.在Thinkphp核心程序中设置了跳转(weiphp中),Thinkphp包是最先被加载的,在weiphp中Thinkphp/Library/Think/Controller.class.php中有一个初始化函数,设定了未登录跳转。作为参考
4.View文件夹中base母版文件被添加了跳转代码(同样存在与weiphp)
5.后台设置了限制访问的目录(weiphp含有)
6.在没有以上问题,请新建控制器文件,从已有能正常访问的控制器代码复制,修改class类名。
打开Index/index.html文件,可以看到
"Base/common" />
"body">
...
extend,母版位置为Base文件夹/common.html文件,找到打开
<html>
<head>
<include file="Public/head"/>
head>
<body>
<include file="Public/toolbar"/>
<div class="yershop_wrapper">
<include file="Public/header"/>
<include file="Public/menu"/>
<include file="Public/body"/>
<include file="Public/cart_js"/>
<include file="Public/footer"/>div>
<include file="Public/kefu"/>
body>
html>
母版页使用 include 将其它页面包含进来,注意写法。
而在被包含的页面中打开Public文件夹/body.html文件,在其中我们会看到
<block name="body">
block>
这段代码,这就决定了index.html文件
中内容部分最终被加载到哪个位置。
...内容
block这段代码对于内容部分、额外加载的css、js代码部分常用,因为每个页面都要使用同样的母版,但内容以及内容的css、js可能不同,block就起到很好的自定义作用。
其它固定的内容,则不需要使用。
后台:
...某控制器下的方法内{
//参数
$a = 3;
$this -> assign('xxx',$a);
//一维数组
$yidata = M('order')->where(array('id'=>$a))->find();
$this -> assign('yiwei',$yidata);
//二维数组
$erdata = M('order')->where(array('status'=>1))->select();
$this -> assign('erwei',$erdata);
$this -> display();
}
对应前台使用
后台传了参数:
{$xxx}
后台传递了一维数组获取:
{$yiwei.id} or {$yiwei['id']}
后台传递了二维数组获取:
"erwei" id="vo">
第{$key}个参数id是:{$vo.id} or {$vo['id']}
</volist>
对于不确定的数组内容,使用var_dump()函数打印数据在前台输出查看
{:data("Y-m-d H:i:s",$vo['create_time'])}
{:U('Wap/Article/index',array('category'=>'jste'))}//调用wap模块下Article控制器下index方法,url传递参数category为jste
{:U('Article/detail?id='.$vo['id'])}//调用当前模块下Article控制器下detail方法,并传递参数id为变量值
绝对不要将上述形式的函数(冒号开头)的参数写成 $vo.create_time形式,否则无法解析,写成原生数组形式
{$vo.id|get_cover_id|get_cover='path'}
/* 先解析{$vo.id},之后其作为get_cover_id函数的参数,返回商品封面图片的cover_id,第三步通过第二步得到的cover_id,将其和path作为get_cover两个参数传递。
*/
<php>
$a = 1;
if($a > 0 ){
php>
<h1>a > 0显示h1>
<php> } php>
或者
$a = 1;
if($a > 0 ){
echo 'a > 0显示
';
}
?>
此两种方法各有千秋,如果html代码较多,使用第一种;较少可用第二种。
===================
原版出处-csdn:blog.csdn.net/afanxingzhou。
学习交流Q724122005,承接小项目开发。