-
Notifications
You must be signed in to change notification settings - Fork 2
Tutorial.Theme and Block II.zh_cn
- 区块
2.1 简介
在上面的我们提到过,页面的布局是模块+区块的形式,通过对CSS的调整可以呈现出两栏的或三栏,甚至其他形式的页面布局,这在目前很多互联网页面上都可以见到。模块主要负责主体内容的显示,区块用于展示跟这个模块相关的或者其他的信息。
比如对于一个新闻页面,文章内容就是页面的主体,也就是模块的输出,文章内容的周围可能还有广告、与当前文章相关的其他文章列表、图片列表等,这些不是模块输出的内容,但也是页面的一部分,因此就可以用区块来展示。当然模块在页面里也不是必须的,比如主页一般都是由很多区块组装而成的。
图5-5 模块+区块布局实例
在Pi Engine的default主题里,页面总共被分为8个区块,并围绕在模块的周边,这种布局方式能满足大多数的页面布局情况。default主题的页面布局如下:
图5-6 default主题的模块+区块布局示意图
2.2 layout-front.phtml中实现区块布局
在主题一节里,我们介绍了如何向layout-front.phtml文件里添加代码,但并没有涉及到区块的代码。区块也是在这个模板里实现,并且紧跟着导航和面包屑的输出。因此我们需要将$content的输出替换成如下代码:
路径:usr/theme/course/template/layout-front.phtml
Code 5.2.1
<?php
$blocks = $this->blocks();
$blockTempalte = $this->template('block');
?>
<div class="row">
<?php if (isset($blocks['1'])) {?>
<div class="span3 pi-zone-1">
<?php foreach ($blocks['1'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
<div class="<?php echo (isset($blocks['1']) && isset($blocks['7'])) ? 'span6' : 'span9'; ?>">
<?php if(isset($blocks['2'])) {
?>
<div class="pi-zone-2">
<?php foreach ($blocks['2'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
<?php if(isset($blocks['3'])) {
?>
<div class="pi-zone-3">
<?php foreach ($blocks['3'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
<?php if (isset($blocks['4'])) {
?>
<div class="pi-zone-4">
<?php foreach ($blocks['4'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
<!-- Module content starts -->
<?php if (!empty($content)) { ?>
<div class="pi-zone-module row-fluid"><?php echo $content; ?></div>
<?php } ?>
<!-- Module content ends -->
<?php if (isset($blocks['5'])) {
?>
<div class="pi-zone-5">
<?php foreach ($blocks['5'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
<?php if (isset($blocks['6'])) {
?>
<div class="pi-zone-6">
<?php foreach ($blocks['6'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
</div>
<?php if (isset($blocks['7'])) { ?>
<div class="span3 pi-zone-7">
<?php foreach ($blocks['7'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
</div>
<?php if (isset($blocks['8'])) {?>
<div class="pi-zone-8">
<?php foreach ($blocks['8'] as $key => $block) {
include $blockTempalte;
} ?>
</div>
<?php } ?>
上述的代码就是按图5-6进行布局的,通过CSS调整各zone间的位置。页面与区块的关系保存在core_page_block表里,比如一个页面有哪些区块,每个zone里有哪些区块,这些区块的顺序是什么。而模块的src下都有一个Block类,这个类里定义相应的方法对应一个区块,它负责区块数据的处理与生成。 在layout-front模板里,block() helper负责将这个页面所有的区块从数据库里读取出来,同时根据读取的区块数据从相应的模块的Block类里调用匹配的方法,生成数据,这些数据将会发送给区块的模板,生成静态页面数据返回给layout-front模板,最后在layout-front里会调用主题里的block模板显示这些区块的内容。
因此最后我们还需要在course主题的template下创建一个block.phtml文件来显示区块,这里我们直接将default里的复制过来。这样区块就可以显示了。
注意,区块+模块布局并不一定是图5-6展示的形式,开发者可以根据不同的需求对layout-front进行修改,更换布局形式。
- 区块开发
我们已经基本介绍了区块的概念及其实现原理,这一节里,我们将重点介绍如何在模块中进行区块开发。区块的开发主要涉及到几个方面:
- 配置文件
- Block类
- 区块模板
在下面的介绍中,我们将创建两个区块,一个显示最近注册的5个用户,另一个显示男性用户,用户数据可通过区块后台配置。
3.1 创建配置文件
配置文件主要用于定义模块有多少区块,每个区块的基本信息、Block类里执行区块的方法以及区块的模板。这个数据在安装的时候将会被写到core_block_root表里。在config目录下创建block.php并添加如下代码:
路径:usr/module/member/config/block.php
Code 5.3.1
<?php
return array(
'recent-register-users' => array(
'title' => __('Recent Register Users'),
'description' => __('Block to display recent reigster users'),
'render' => array('block', 'recentRegisterUsers'),
'template' => 'recent-register',
),
'male-users' => array(
'title' => __('Male users'),
'description' => __('Block to display male users'),
'render' => 'block::maleUsers',
'template' => 'male-users',
'config' => array(
'count' => array(
'title' => __('Item Count'),
'description' => __('Item count for male users block'),
'edit' => 'text',
'filter' => 'number_int',
'value' => 2,
),
'feedback' => array(
'title' => __('Feedback'),
'description' => __('Whether users want to receive feedback'),
'edit' => array(
'type' => 'select',
'attributes' => array(
'options' => array(
'y' => __('Yes'),
'n' => __('No'),
),
),
),
'filter' => 'string',
'value' => 'y',
),
),
),
);
在上述配置里定义了两个区块:recent-register-users和male-users。tilte和description字段分别为区块的名称和描述;render定义了这个区块由哪个方法来处理,比如recent-register-user用Block类的recentRegisterUsers()方法来处理,这两个例子里的数组和字符串的效果是一致的;template字段定义了区块所要使用的模板,这个模板在template/block目录下。 在male-users区块里,我们还为区块添加了两个配置,分别用于配置显示的条数和筛选是否反馈的用户。配置用config字段标识,每个配置的基本信息都放在一个数组里。其中title和description为配置的名称和说明;edit字段标识表单的类型,这个例子里定义了两种类型,text表单和select表单,对于select表单,用options字段列出表单的每一项,而字段名count和feedback将来就是区块配置里表单的name值;filter字段定义了对表单值的处理方式,number_int为过滤掉非数字字符,string为过滤掉非字符串字符,即空格和tab;value字段定义了表单的默认值。
创建完block配置文件后,别忘了在module.php里添加相应的代码,也就是要告诉系统有一个block配置需要在模块安装的时候写入数据库,需要在module.php里的resource数组里添加如下代码:
路径:usr/module/member/config/module.php
Code 5.3.2
<?php
return array(
...
'maintenance' => array(
'resource' => array(
'database' => array(
...
),
'block' => 'block.php',
),
),
);
重新安装member模块后,进入模块后台就可以看到图5-7(a)所示的两个区块,点击Male users后的edit可以看到这个区块里有两个配置,如图5-7(b)所示:
(a)
(b)
图5-7 后台区块管理界面
3.2 创建Block类
虽然现在可以在后台看见创建的区块,但这些区块都是空区块,因为没有相应的方法来处理数据并生成静态区块页面,因此我们需要创建一个Block类,并实现block配置里指定的recentRegisterUsers()方法和maleUsers()方法。在src目录下创建Block.php,这个路径和文件名都固定,不能更改,否则系统找不到相应的类来实现区块。在Block.php里添加如下代码:
路径:usr/module/member/src/Block.php
Code 5.3.3
<?php
namespace Module\Member;
use Pi;
class Block
{
public static function recentRegisterUsers($options, $module = null)
{
$columns = array('id', 'username', 'gender');
$limit = 5;
$model = Pi::model('account', $module);
$select = $model->select()
->columns($columns)
->offset(0)
->limit($limit)
->order('id DESC');
$rows = $model->selectWith($select)->toArray();
$result = array(
'items' => $rows,
);
return $result;
}
public static function maleUsers($options, $module = null)
{
$columns = array('id', 'username', 'gender');
$limit = $options['count'];
$where = array(
'feedback' => $options['feedback'],
);
$model = Pi::model('account', $module);
$select = $model->select()
->where($where)
->columns($columns)
->offset(0)
->limit($limit)
->order('id ASC');
$rows = $model->selectWith($select)->toArray();
$block = array(
'items' => $rows,
);
return $block;
}
}
在Block.php里,首先定义了命名空间为Module\Member,因为后要用到Pi类的方法,因此需要引用Pi的命名空间。在类Block里,定义了两个方法recentRegisterUsers和maleUsers,方法的类型都为公有静态的。方法的两个参数都是已经定义好的,不能更改,$options为区块配置的值,如在maleUsers()方法里,我们通过$options['count']和$options['feedback']分别获取count和feedback配置的值,count和feedback就是区块配置里表单的name值,$module为区块所属的模块的模块名,如Pi::model('account', $module)关联的就是member_account表。
在两个方法里,都根据要求设置了筛选条件,然后从数据库里读取出数据并转换成二维数组。最后把结果以数组的形式返回给区块模板,返回的数组将会赋给区块模板的$block变量。
3.3 创建区块模板
有了处理后的数据,就需要在模板里显示,在模块配置block.php里,我们已经为两个区块设定好模板,分别是recent-register.phtml和male-users.phtml,现在我们需要创建这两个模板。区块的模板也放在template目录下,不过需要再创建一个文件夹来存放区块的模板:
member
|- template
|- block
|- recent-register.phtml
|- male-users.phtml
这两个模板我们采用同一套代码,代码为:
路径:usr/module/member/template/block/recent-register.phtml
路径:usr/module/member/template/block/male-users.phtml
Code 5.3.4
<table>
<?php foreach ($block['items'] as $item) { ?>
<tr>
<td><?php echo $item['id'] ?></td>
<td><?php echo $item['username'] ?></td>
<td><?php echo $item['gender'] ?></td>
</tr>
<?php } ?>
</table>
从上面的代码里可以看出,返回的数据保存在$block变量里。至此,区块的代码开发都已经完成了,最后就是如何在页面上显示区块。
3.4 显示区块
区块的显示有两种方式,一种是在后台把区块拖到相关的页面,区块的数据就会保存在core_page_block表里,在layout-front.phtml里会自动将这些区块显示出来;另一种方法是通过widget helper在layout-front.phtml里手动添加。
- 后台拖拽
后台的拖拽需要这个页面具有dress up的功能,也就是支持区块+模块布局。这个功能可以在模块配置config/page.php里为相关的页面添加,如:
路径:usr/module/member/config/page.php
<?php
return array(
'front' => array(
array(
'title' => __('Login page'),
'controller' => 'login',
'action' => 'login',
'block' => 1,
...
),
),
);
这个配置就是指为LoginController的loginAction这个页面指定dress up的功能,即block值为1。在此我们先以系统首页为例介绍如何添加区块。
进入系统后台的System page页,点击System Homepage后的dress up链接将会出现如图5-8所示的页面,将member模块的两个区块拖拽到zone7里并提交:
图5-8 区块后台拖拽界面
回到Pi系统首页,将会看到,在页面右侧多了两个区块:
图5-9 首页区块的显示
- widget手动添加
打开当前主题的layout-front.phtml文件(这里使用的是course主题),并在区块显示的最开头处添加如下代码:
路径:usr/theme/course/template/layout.phtml
Code 5.3.5
...
<div class="container">
<div style="float:left">
<?php echo $this->widget('member-recent-register-users'); ?>
</div>
...
其中,widget的参数为模块名-区块名的形式,这样在页面里就可以显示区块了,当然这种方式将会让所有前台页面里都显示这个区块:
图5-10 widget方式显示区块