由于是国内框架,框架是很大很全,功能很多,但是一点都谈不上精美。
光看文档的组织,根本就不能够满足最基本的开发要求,大部分还是的脑补,于是,补完之后还是得乖乖连文档也补一下。
权当是开源精神帮助官方写文档。
在这里,有必要先列一个提纲,因为研究得比较快,要点也比较散乱。
- 安装 b2b2c 环境
- 使用 php5.6 + Nginx + Zend Guard Loader 的基础配置
- 处理好的 Docker 镜像
- 开发目录 /custom 的配置
- 反射 ego.php 的类库
- 创建并启用 app
- 使用 controller 和路由创建视图层
- 使用 dbschema 创建数据库表
- 目录结构
- 定义语法
- 映射到数据库
- 创建 model 类
- 目录结构
- 创建与 dbschma 对应的模型
- 调用方式
- 直接编写 SQL 语句
- 创建
/myapp/lib
下面的工具类- 目录结构
- 创建指定的工具类
- 单例模式
- 调用方式
- 后台 desktop 应用创建
- permission
- panelgroup/adminpanel
- workground/menugroup/menu
- 模板开发
- 模板渲染模型
- 自定义模板
- 模板语言
<{$variable}>
变量引入<{if $case}><{/if}>
条件语句<{foreach from=$list item=val name=key}>
循环<{include}>
引入模板<{require}>
引入主题模板<{pagers}>
分页<{assign}>
语句<{im shop_id=$shop_id type=small}>
标签?在会员商品列表中出现过(估计是 QQ 控件)
安装 b2b2c 环境
使用
首先,我们开发的基础就是拿到的商派框架代码,b2b2c 的一个压缩包,然后我们第一步需要让它跑起来。
重要的事情说三遍:opcache 不能开,opcache 要关掉,opcache 不能开!!!!
下表是 php -m
得到的需要安装的模块列表:
[PHP Modules]
bcmath
bz2
calendar
Core
ctype
curl
date
dba
dom
ereg
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
json
libxml
mbstring
mcrypt
mhash
mysql
mysqli
openssl
pcntl
pcre
PDO
pdo_mysql
Phar
posix
readline
Reflection
session
shmop
SimpleXML
soap
sockets
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
wddx
xml
xmlreader
xmlrpc
xmlwriter
Zend Guard Loader
zip
zlib
[Zend Modules]
Zend Guard Loader
如果使用 docker,可以尝试在 php 容器内部的 /usr/local/etc/php/conf.d
下面添加 ZendLoader 的库引入。
创建并启用 app
首先,其实框架里面对 /custom
目录的支持不可谓不粗糙,导致我在开头掉进坑里转了好久。
ATTENTION: 如何才能避免掉进这个坑
切记!开发全程切勿将应用目录
myapp
放到/custom
里面,正确的使用方法是,一直将myapp
目录放在/app
目录下面,直到上线之后,进后台启动这个 app,再用./cmd update
进行更新,然后再将 app 目录移动到/custom
下面,否则 app 根本不能在注册器中出现!
创建一个 app 文件夹(此处用 sysmyapp
),注意,要么使用 sys
开头,要么使用 top
开头来命名你的 app。
然后里面按照文档编写一个 app.xml
,最精简的例子大概如下:
<!-- file: /app/myapp/app.xml -->
<app>
<name>我的APP</name>
<type>service</type>
<author>
<name>Alfred Huang (呆滞的慢板)</name>
<email>57082212@qq.com</email>
<url>https://www.huangwenchao.com.cn</url>
</author>
<version>0.1.0</version>
<license>MIT license</license>
</app>
注意上面的 <type>
节,可以选择 service 或者 site,如果是纯逻辑和数据,请使用 sys
开头命名你的 app,这里的 type
填写 service
;否则使用 top
开头命名,这里的 type
填写 site
。文档链接
使用 dbschema 创建数据库表
创建 model 类
目录结构
创建与 dbschma 对应的模型
类继承自 dbeav_model
,例如:
class myapp_mdl_article extends dbeav_model {
}
调用方式
创建 myapp/lib
下面的工具类
目录结构
在 myapp
目录下创建 lib
文件夹,每一个工具类创建一个 php 文件,可以创建下级的目录。
注意命名规范,例如 /app/sysclearing
下面的内容是一个很好的例子:
lib
├── data
│ └── clean.php
├── finder
│ └── settlement.php
├── settlement.php
└── tasks
└── settlement.php
那么会展开成这些类:
sysclearing_data_clean
sysclearing_finder_settlement
sysclearing_tasks_settlement
sysclearing_settlement
创建指定的工具类
按照上面的命名方式即可创建工具类,注意一个文件仅包含这个类的定义,不要包含其他代码。
阅读系统里面定义的其他一些 app 之后,发现基本上采用单例模式,并没有继承自其他的系统基类,内部基本上仅定义各种 function,(注意 public 要显式声明,protected 要以单下划线开头,private 要以双下划线开头)。
单例模式
在工具类的定义惯例上面,这里基本使用单例模式,关于静态类和单例模式的比较,可以参考:
http://stackoverflow.com/q/519520/2544762
http://stackoverflow.com/q/137975/2544762
对于单例模式的调用,管理上使用如下的语法:
kernel::single('____classname____')
后台 desktop 应用创建
permission
panelgroup/adminpanel
这部分配置下的菜单会显示在右上角的《控制面板》页面下面。
注意,icon 的目录其实应该是 /public/myapp/images/bundle
的路径开始算,这点略坑。
workground/menugroup/menu
如何分页
首先,在页面 view 里面可以嵌入标签:<{pagers data=$pagers}>
,这样就可以输出所有分页的 markup。
那么我们来看一下如何在对应的 controller 上下文里面构造这个 $pagers
。
首先我们可以在对应的 Controller 里面定义一个私有方法 __pages()
:
sysmyapp_ctl_example extends topc_controller {
// ...
/**
* 分页处理
*
* @param $current int 当前页数(编号从 1 开始)
* @param $filter array 除开翻页参数之外,当前查询集的其他条件(querystring 的字典)
* @param $count int 查询集全集的项目数
* @param $action string 列表页面不带参数的 action 字符串,例如 `sysmyapp_ctl_example@articleList`
* @return array 返回 pagers 标签适配的分页对象格式。
*/
private function __pages($current, $filter, $count, $action) {
$current = $current ? $current : 1; // 当前页面序号
$filter['pages'] = time(); // 这个用作 nonce
$limit = @$this->limit ?: 10; // 每页多少个
$totalPage = $count ?
ceil($count / $limit - 1e-5) : 0;
$pagers = array(
'link'=>url::action($action, $filter),
'current'=>$current,
'total'=>$totalPage,
'token'=>time(),
);
return $pagers;
}
// ...
}
然后在当前页面的 action 函数上下文里面,先根据实际情况构造好 $current
$filter
和 $count
的值,然后将其放入上下文,即可使用。
systest_ctl_example extends topc_controller {
// ...
/**
* 实际的列表页面 action
*
* @return mixed HTTP 响应对象
*/
private function articleList() {
$current = @intval(input::get('current')) ?: 1; // 当前页面序号
$limit = @$this->limit ?: 10; // 每页多少个
$offset = ($current - 1) * $limit;
$filter = array(
'author_id' => userAuth::id(),
'status' => 'ACTIVE',
);
$modelArticle = app::get('sysmyapp')->model('article'); // sysmyapp_mdl_article
$count = $modelArticle->count($filter);
$pagedata['pagers'] =
$pagers = $this->__pages($current, $filter, $count, 'sysmyapp_ctl_example@articleList');
$pagedata['pagers'] =
$articles = $modelArticle->getList('*', $filter, $offset, $limit);
return $this->page('sysmyapp/article/list.html', $pagedata); // 构造响应并输出,这是基类 topc_controller 的方法
}
// ...
}
直接编写 SQL 语句
如果我们要编写一些复杂的查询结构,我们可以先构造一个底层的 database()
对象,然后在上面就提供了底层的 SQL 执行方法。
我们可以通过任意一个 model 对象的 database()
方法产生数据库访问对象,然后通过 executeQuery($sql)
方法执行查询。
执行的结果通过 fetch()
或者 fetchAll()
方法就可以得到想要的结果。
// 这里随便拿一个 model 类,其实什么都行
$db = app::get('sysshop')->model('shop')->database();
$result = $db.executeQuery("
select * from sys_shop
where id < 10000;
")->fetchALL();
So easy,如果不需要返回整个结果表,只需要第一行,将上面的 fetchAll
换成 fetch
即可。
关于上传图片路径的问题
通过这个方法来获取图片前端的路径
kernel::get_host_mirror_img()
【转载请附】愿以此功德,回向 >>
原文链接:http://www.huangwenchao.com.cn/2016/03/onex-b2b2c-1.html【商派 ONex_b2b2c 框架开发手札(一)- 概述】
等着看第二篇、第三篇:)
请问这是自己二开还是一个项目需要呢?