Gửi và nhận dữ liệu qua HTTP


nedka

nedka

Quản trị viên
28/08/2016 09:17

Xác định tên biến dữ liệu
Chính là giá trị của thuộc tính name="..." trong các thẻ nhập liệu HTML như:

Chép
<input name="..." ...>
<textarea name="..."></textarea>
<select name="...>
	<option>...</option>
</select>

Khai báo
Trước khi tập tin bạn đang viết có thể gửi và nhận dữ liệu qua HTTP, hãy chắc chắn bạn đã khai báo đối tượng request trong phương thức khởi tạo __construct() cũng như tập tin config/services.yml.
Chép
protected $request;

public function __construct(\phpbb\request\request $request)
{
	$this->request= $request;
}
Chép
        arguments:
             - '@request'
Nhưng nếu bạn đang viết một gói chức năng thì thêm vào trong phương thức main():
Chép
$this->request = $phpbb_container->get('request');

Dạng chuỗi ký tự
Chép
$x = $this->request->variable('tên_mục_dữ_liệu', 'giá_trị_mặc_định');
$abc = $this->request->variable('abc', '');
Nếu muốn hỗ trợ Unicode thì xác định tham số thứ ba bằng true:
Chép
$abc = $this->request->variable('abc', '', true);

Dạng số
Chép
$abc = $this->request->variable('abc', 0);

Dạng nhị nhân "có/không"
Dùng cho các thiết lập bật/tắt với <input type="radio".
Chép
$abc = $this->request->variable('abc', true);
$xyz = $this->request->variable('xyz', false);

Dạng mảng
Dùng cho danh sách xổ xuống chọn nhiều mục với <select multiple="multiple" hoặc là nhiều thẻ <input type="checkbox" với thuộc tính name giống nhau. Lưu ý, lúc này trong mã HTML, thuộc tính name phải có thêm [] đứng cuối như ví dụ sau.

HTML:
Chép
<select name="abc[]" multiple="multiple">
	<option value="1">1</option>
	<option value="2">2</option>
	<option value="3">3</option>
</select>
Chép
<input type="checkbox" name="abc[]" value="1">
<input type="checkbox" name="abc[]" value="2">
<input type="checkbox" name="abc[]" value="3">
PHP:
Chép
$abc = $this->request->variable('abc', array(0));
Trong mã PHP ta không thêm [] trong tên biến dữ liệu như mã HTML.
Nếu giá trị muốn lấy dạng chuỗi, không phải số:
Chép
$abc = $this->request->variable('abc', array(''));

Biến môi trường PHP ($_SERVER)
Xem thêm danh sách tại: http://php.net/manual/en/reserved.variables.server.php. Ví dụ, lấy địa chỉ IP ngưới dùng:
Chép
$ip = $this->request->server('REMOTE_ADDR');

Kiểm tra
Kiểm tra biến đã được gửi đi chưa? Ví dụ, kiểm tra người dùng đã bấm vào nút Gửi có thuộc tính namesubmit chưa:
Chép
if ($this->request->is_set_post('submit'))
Kiểm tra biến đã được thiết lập toàn cục chưa?
Chép
if ($this->request->is_set('abc'))
Kiểm tra có phải là yêu cầu AJAX không? (XMLHttpRequest)
Chép
if ($this->request->is_ajax())
Kiểm tra dữ liệu có gửi qua SSL không?
Chép
if ($this->request->is_secure())


Các hàm xử lý Unicode


nedka

nedka

Quản trị viên
28/08/2016 09:17

Nếu dữ liệu cần xử lý chính xác trong Unicode, hãy thay các hàm PHP dưới đây bằng hàm tương tự nhưng hỗ trợ Unicode của phpBB. Hầu hết là thêm tiền tố utf8_ trước tên hàm gốc của PHP.

Viết thường toàn bộ
PHP:

Chép
strtolower('chuỗi');
phpBB:
Chép
utf8_strtolower('chuỗi');

Viết hoa toàn bộ
PHP:
Chép
strtoupper('chuỗi')
phpBB:
Chép
utf8_strtoupper('chuỗi')

Viết hoa chỉ 1 chữ cái đầu tiên
PHP:
Chép
ucfirst('chuỗi')
phpBB:
Chép
utf8_ucfirst('chuỗi')

Lấy độ dài chuỗi
PHP:
Chép
strlen('chuỗi')
phpBB:
Chép
utf8_strlen('chuỗi')

Kiểm tra nội dung có chứa chuỗi cần tìm
PHP:
Chép
if (strpos('chuỗi_nội_dung', 'chuỗi_cần_tìm') !== false)
phpBB:
Chép
if (utf8_strpos('chuỗi_nội_dung', 'chuỗi_cần_tìm') !== false)

Cắt chuỗi
PHP:
Chép
substr('chuỗi', vị_trí_cắt, số_ký_tự_cắt)
phpBB:
Chép
utf8_substr('chuỗi', vị_trí_cắt, số_ký_tự_cắt)

Cắt chuỗi thành mảng
PHP:
Chép
str_split('chuỗi', số_ký_tự_cắt)
phpBB:
Chép
utf8_str_split('chuỗi', số_ký_tự_cắt)

Chuyển chuỗi sang UTF-8
Chép
utf8_recode('chuỗi', dạng_mã_hóa_gốc)

Chuyển chuỗi UTF-8 sang NCR
Chép
utf8_encode_ncr('chuỗi')

Chuyển chuỗi NCR sang UTF-8
Chép
utf8_decode_ncr('chuỗi')

Chuyển chuỗi UTF-8 sang ASCII (Tiếng Việt có dấu sang không dấu)
Chép
utf8_clean_string('chuỗi')


Dữ liệu tạm


nedka

nedka

Quản trị viên
28/08/2016 09:18

Tất cả dữ liệu tạm đều được lưu trong thư mục cache. Mục đích của những dữ liệu này là giảm bớt số lượng truy vấn mới từ cơ sở dữ liệu khi tần suất thay đổi của chúng là rất ít.

Trước khi lưu và lấy dữ liệu tạm, ta cần khai báo đối tượng cache vào phương thức khởi tạo __construct() và tập tin config/services.yml.

Chép
protected $cache;

public function __construct(\phpbb\cache\driver\driver_interface $cache)
{
	$this->cache = $cache;
}
Chép
        arguments:
             - '@cache.driver'
Lưu dữ liệu tạm:
Chép
$this->cache->put('_vinabb_demo_data', $data);
Trong đó, _vinabb_demo_data là tên tập tin dữ liệu tạm và $data là biến chứa dữ liệu cần lưu. Tập tin này sẽ được thêm vào tiền tố data đầu và lưu vào đường dẫn cache/production/data_vinabb_demo_data.php.

Lưu dữ liệu tạm có thời hạn:
Chép
$this->cache->put('_vinabb_demo_data', $data, 3600);
3600 là số giây tính từ khi dữ liệu tạm này được tạo và sẽ hết hạn. Khi hết hạn, dữ liệu mới từ nguồn sẽ được cập nhật lại tự động.

Lấy dữ liệu tạm:
Chép
$data = $this->cache->get('_vinabb_demo_data');

if ($data === false)
{
	// Lấy dữ liệu lại từ nguồn chính
	$data = '...';
}
Ta cần kiểm tra xem dữ liệu tạm đã có chưa (do có thể vừa xóa hết dữ liệu tạm và chưa phát sinh truy vấn đến nó), nếu chưa có thì phải lấy từ nguồn chính thay vì dữ liệu tạm.

Kham thảo thêm Tạo bộ đệm cho dữ liệu truy vấn để tìm hiểu cách mở rộng đối tượng cache của phpBB.


Dữ liệu trình duyệt


nedka

nedka

Quản trị viên
28/08/2016 09:18

Dữ liệu trình duyệt (cookie) được lưu vào trình duyệt của người dùng, thường chứa trạng thái đăng nhập của người dùng và các dữ liệu, thiết lập dành cho khách.

Trước khi có thể lấy và lưu dữ liệu trình duyệt, ta cần khai báo 3 đối tượng: request, config, user vào phương thức khởi tạo __construct() và tập tin config/services.yml.

Chép
protected $request;
protected $config;
protected $user;

public function __construct(
	\phpbb\request\request $request,
	\phpbb\config\config $config,
	\phpbb\user $user
)
{
	$this-> request = $request;
	$this-> config = $config;
	$this-> user = $user;
}
Chép
        arguments:
             - '@request'
             - '@config'
             - '@user'
Lấy dữ liệu trình duyệt:
Chép
$this->request->variable($this->config['cookie_name'] . '_data', '', true, \phpbb\request\request_interface::COOKIE)
Trong đó, _data là tên mục dữ liệu trình duyệt. Tên mục này được chèn thêm tiền tố mà người dùng thiết lập trong bảng quản trị. Nếu kết quả trả về rỗng nghĩa là mục dữ liệu này không tồn tại (do người dùng xóa hoặc chưa được lưu).

Lưu dữ liệu trình duyệt:
Chép
$this->user->set_cookie('data', $data, 0, false);
Trong đó, data là tên mục dữ liệu trình duyệt và $data là biến dữ liệu cần lưu của chúng ta. Lưu ý là khi lưu thì tên mục dữ liệu không cần có ký tự _ ở đầu như khi lấy.


Tạo trang mới


nedka

nedka

Quản trị viên
28/08/2016 09:21

Tạo tập tin chứa mã PHP
Tạo thư mục controller trong gói mở rộng của bạn. Tất cả những trang bạn muốn tạo mới, sẽ có tập tin chứa mã PHP của chúng nằm trong thư mục này.

Ta sẽ thử tạo một trang mới tên là test, đường dẫn đầy đủ sẽ là ext/vinabb/demo/controller/test.php. Trong tập tin này, ta cũng sẽ khai báo sẵn các đối tượng hay dùng trong phương thức khởi tạo __construct() của nó. Bạn nên bỏ bớt các đối tượng không dùng đến.

Chép
<?php

class test
{
	protected $auth;
	protected $db;
	protected $config;
	protected $config_text;
	protected $user;
	protected $language;
	protected $template;
	protected $request;
	protected $helper;
	protected $phpbb_root_path;
	protected $php_ext;

	public function __construct(
		\phpbb\auth\auth $auth,
		\phpbb\db\driver\driver_interface $db,
		\phpbb\config\config $config,
		\phpbb\config\db_text $config_text,
		\phpbb\user $user,
		\phpbb\language\language $language,
		\phpbb\template\template $template,
		\phpbb\request\request $request,
		\phpbb\controller\helper $helper,
		$phpbb_root_path,
		$php_ext	)
	{
		$this->auth = $auth;
		$this->db = $db;
		$this->config = $config;
		$this->config_text = $config_text;
		$this->user = $user;
		$this->language = $language;
		$this->template = $template;
		$this->request = $request;
		$this->helper = $helper;
		$this->phpbb_root_path = $phpbb_root_path;
		$this->php_ext = $php_ext;
	}

	public function index()
	{
		$this->helper->message('HELLO_WORLD');
	}
}
Trong đó, HELLO_WORLD là biến ngôn ngữ và index() là phương thức hiển thị nội dung chính của trang. Hãy nhớ từ khóa index này vì bạn cần khai báo nó trong tập tin routing.yml bên dưới.


Gán tập tin giao diện
Nếu trang cần đến tập tin giao diện, hãy để phương thức hiển thị index() ở trên trả về nội dung tập tin giao diện:
Chép
	public function index()
	{
		return $this->helper->render('test.html', 'TEST');
	}
Trong đó, test.html là tên tập tin giao diện chứa mã HTML và TEST là biến ngôn ngữ dùng làm tên trang.


Khai báo cấu hình
Đầu tiên là tập tin config/services.yml đã quá quen thuộc qua các ví dụ:
Chép
services:
    vinabb.demo.test:
        class: vinabb\demo\controller\test
        arguments:
            - '@auth'
            - '@dbal.conn'
            - '@config'
            - '@config_text'
            - '@user'
            - '@language'
            - '@template'
            - '@request'
            - '@controller.helper'
            - '%core.root_path%'
            - '%core.php_ext%'

Khai báo đường dẫn
Mỗi trang mới cần một đường dẫn mới để truy cập đến thông qua tập tin app.php. Hãy tạo tập tin routing.yml trong thư mục config của gói mở rộng.
Chép
vinabb_demo_route:
    path: /test
    defaults: { _controller: vinabb.demo.test:index }
Trong đó, index chính là phương thức hiển thị nội dung của trang mà chúng ta đã tạo ở trên và /test là đường dẫn con chúng ta thêm vào sau đường dẫn chính truy cập đến hệ thống phpBB. Giờ đây, bạn đã có thể truy cập trang mới này bằng cách thêm /test vào sau địa chỉ chính trên trình duyệt, ví dụ: http://localhost/forum/app.php/test. Nếu máy chủ hỗ trợ mod_rewrite, ta có thể bỏ app.php cho gọn thành http://localhost/forum/test.


Tạo thêm nhiều chế độ nhỏ cho trang
Ví dụ bạn muốn tạo trang có 2 chế độ là main (mặc định, hiển thị nội dung trang) và config để người dùng thay đổi thiết lập. Lúc này, đường dẫn đến trang sẽ chia làm 2: Ta cần sửa lại tập tin routing.yml như sau:
Chép
vinabb_demo_route:
    path: /test/{mode}
    defaults: { _controller: vinabb.demo.test:index }
    requirements:
        mode: (|main|main\/|config|config\/)
Ý nghĩa của tham số mode trong phần requirements như sau:
  • Nếu mode rỗng hoặc bằng main hay main/ (có thể có người có thói quen gõ ký tự / ở cuối địa chỉ, có người lại không) đều chấp nhận và chuyển về main.
  • Nếu mode bằng config hay config/ thì chuyển về config.
  • Nếu người dùng gõ các trường hợp khác thì báo lỗi sai đường dẫn.
Đồng thời, thêm vào tham số $mode cho phương thức index() của tập tin PHP.
Chép
	public function index($mode)
	{
		// Chuyển rỗng hay "main/" về "main"
		if (empty($mode) || $mode == 'main/')
		{
			$mode = 'main';
		}
		// Chuyển "config/" về "config"
		else if ($mode == 'config/')
		{
			$mode = 'config';
		}

		// Chia 2 chế độ
		switch ($mode)
		{
			case 'main':
				$this->helper->message('HELLO_MAIN');
			break;

			case 'config':
				$this->helper->message('HELLO_CONFIG');
			break;
		}
	}

Tạo biến giao diện chứa liên kết đến trang
Ta sẽ thêm liên kết đến trang từ giao diện người dùng. Muốn vậy, ta cần thêm vào một biến giao diện thông qua sự kiện core.user_setup. Hãy xem lại phần sự kiện nếu bạn chưa rõ.
Chép
public function user_setup($event)
{
	$this->template->assign_vars(array(
		'U_TEST' => $this->helper->route('vinabb_demo_route', array('mode' => 'main')),
	));
}
Nhớ khai báo thêm đối tượng templatehelper cho event/listener.php nếu chưa có trong phương thức khởi tạo __construct() và tập tin config/services.yml.
Chép
protected $template;
protected $helper;

public function __construct(
	\phpbb\template\template $template,
	\phpbb\controller\helper $helper
)
{
	$this->template = $template;
	$this->helper = $helper;
}
Chép
        arguments:
            - '@template'
            - '@controller.helper'
Khi khai báo hoàn tất, bạn đã có thể dùng biến giao diện U_TEST trong bất cứ tập tin giao diện nào để đặt liên kết đến trang mới của mình.
Chép
<a href={{ U_TEST }}>{{ lang('TEST') }}</a>


Tạo trang trợ giúp mới


nedka

nedka

Quản trị viên
28/08/2016 09:22

Trang trợ giúp sử dụng chung tập tin giao diện faq_body.html của phpBB, chúng ta chỉ phải tùy biến phần mã PHP và thêm vào biến ngôn ngữ.

Ta sẽ tạo tập tin help.php nằm trong thư mục ext/vinabb/demo/controller với cấu trúc sau:

Chép
<?php

namespace vinabb\demo\controller;

class help extends \phpbb\help\controller\controller
{
	public function display()
	{
		// Thêm tập tin ngôn ngữ
		$this->language->add_lang('help', 'vinabb/demo');

		// Thêm nhóm câu hỏi 1
		$this->manager->add_block(
			'HELP_BLOCK_1',
			false,
			array(
				'HELP_QUESTION_1' => 'HELP_ANSWER_1',
				'HELP_QUESTION_2' => 'HELP_ANSWER_2',
				'HELP_QUESTION_3' => 'HELP_ANSWER_3',
			)
		);

		// Thêm nhóm câu hỏi 2
		$this->manager->add_block(
			'HELP_BLOCK_2',
			false,
			array(
				// Tương tự như trên...
			)
		);

		return $this->language->lang('HELP_TITLE');
	}
}
Trong đó:
  • HELP_BLOCK_1: là biến ngôn ngữ của tên nhóm câu hỏi đầu tiên.
  • Tham số thứ hai bằng false nghĩa là nhóm câu hỏi này sẽ nằm bên trái, ngược lại là true sẽ nằm bên phải.
  • HELP_QUESTION_1: là biến ngôn ngữ của câu hỏi, tương ứng là biến ngôn ngữ trả lời HELP_ANSWER_1 cho câu hỏi này.
  • HELP_TITLE: là biến ngôn ngữ tên trang trợ giúp này.
Khai báo các đối tượng sử dụng trong config/services.yml:
Chép
services:
    vinabb.demo.help:
        class: vinabb\demo\controller\help
        arguments:
            - '@controller.helper'
            - '@phpbb.help.manager'
            - '@template'
            - '@language'
            - '%core.root_path%'
            - '%core.php_ext%'
Tạo đường dẫn cho trang trợ giúp mới này trong config/routing.yml:
Chép
vinabb_demo_help:
    path: /test/help
    defaults: { _controller: vinabb.demo.help:handle }
Cuối cùng là tạo liên kết dùng trong giao diện:
Chép
$this->template->assign_vars(array(
	'U_HELP' => $this->helper->route('vinabb_demo_help'),
));


Tích hợp BBCode và biểu tượng vui


nedka

nedka

Quản trị viên
28/08/2016 09:22

Đầu tiên, giả sử biến $text chứa văn bản ta đang muốn định dạng và biến này lưu vào cột product_text. Để xử lý các thẻ BBCode và biểu tượng vui, ta cần tạo thêm 3 biến trong tập tin PHP đang viết, đồng thời cũng thêm 3 cột vào bảng dữ liệu để lưu.

Danh sách ta có như sau:

$text lưu vào cột product_text
$text_uid lưu vào cột product_text_uid
$text_bitfield lưu vào cột product_text_bitfield
$text_options lưu vào cột product_text_options
Các biến và cột này dùng để làm gì?
  • $text_uid: ID của người dùng, ví dụ ID người dùng được trích dẫn trong thẻ [ quote ].
  • $text_bitfield: một chuỗi mã xác định bởi giao diện, thêm vào tên thẻ nhằm phân biệt đâu là thẻ BBCode, đâu là nội dung thường nhưng có ký tự [ và ].
  • $text_options: giá trị 3 tùy chọn BBCode:
    • Bật BBCode: giá trị 1, có hằng là OPTION_FLAG_BBCODE.
    • Bật biểu tượng vui: giá trị 2, có hằng là OPTION_FLAG_SMILIES.
    • Bật liên kết tự động: giá trị 4, có hằng là OPTION_FLAG_LINKS.
    • 3 tùy chọn này tương tự kiểu giá trị CHMOD, tức nếu thiết lập có giá trị 3 nghĩa là 3 = 1 + 2 => Bật BBCode, bật biểu tượng vui nhưng tắt liên kết tự động.
Ngoài các thẻ BBCode mặc định, ta cần gọi thêm hàm display_custom_bbcodes() để hiện các thẻ BBCode tùy biến nếu có. Hàm này nằm trong tập tin includes/functions_display.php:
Chép
if (!function_exists('display_custom_bbcodes'))
{
	include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext);
}

display_custom_bbcodes();
Nếu đoạn văn bản đang truyền vào thẻ textarea để người dùng nhập liệu, tức chế độ thô không cần nhận dạng BBCode, ta dùng hàm generate_text_for_edit():
Chép
$text_edit = generate_text_for_edit($text, $text_uid , $text_options);
Sau khi nhập, người dùng bấm nút Gửi, ta cần xử lý văn bản nhập này trước khi lưu vào cơ sở dữ liệu. Giá sử nút Gửi có thuộc tính namesubmit:
Chép
if ($this->request->is_set_post('submit'))
{
	generate_text_for_storage(
		$text,
		$text_uid,
		$text_bitfield,
		$text_options,
		!$this->request->variable('disable_bbcode', false),
		!$this->request->variable('disable_magic_url', false),
		!$this->request->variable('disable_smilies', false)
	);
}
Mã HTML của khung soạn thảo BBCode trong giao diện:
Chép
{# Hiện dãy nút bấm BBCode #}
{% include 'acp_posting_buttons.html' %}

<dl class="responsive-columns">
	{# Bảng chọn màu #}
	<dt style="width: 90px;" id="color_palette_placeholder" data-orientation="v" data-height="12" data-width="15" data-bbcode="true"></dt>
	{# Khung soạn thảo nội dung #}
	<dd style="margin-{{ S_CONTENT_FLOW_BEGIN }}: 90px;">
		<textarea name="text" rows="10" cols="60" style="width: 95%;" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onfocus="initInsertions();" data-bbcode="true">{{ TEXT }}</textarea>
	</dd>
	{# 3 nút tùy chọn bật/tắt BBCode, biểu tượng vui và liên kết tự động #}
	<dd style="margin-{{ S_CONTENT_FLOW_BEGIN }}: 90px; margin-top: 5px;">
		<label><input type="checkbox" class="radio" name="disable_bbcode"> {{ lang('DISABLE_BBCODE') }}</label>
		<label><input type="checkbox" class="radio" name="disable_smilies"> {{ lang('DISABLE_SMILIES') }}</label>
		<label><input type="checkbox" class="radio" name="disable_magic_url"> {{ lang('DISABLE_MAGIC_URL') }}</label>
	</dd>
</dl>
Nếu không phải gói chức năng quản trị, bạn thay acp_posting_buttons.html trong đoạn mã trên thành posting_buttons.html và tham khảo tập tin posting_editor.html trong giao diện đang xài để điều chỉnh mã HTML cho phù hợp.

Và khi hiển thị nội dung kèm BBCode đã xử lý:
Chép
$text_display = generate_text_for_display($text, $text_uid, $text_bitfield, $text_options);
Nếu bạn muốn sử dụng nội dung này ở một nơi khác và gỡ bỏ hết thẻ BBCode bên trong, hãy dùng:
Chép
$text = strip_bbcode($text);


Phân trang


nedka

nedka

Quản trị viên
29/08/2016 11:03

Khai báo
Trước khi phân trang, hãy chắc chắn bạn đã khai báo đối tượng pagination trong phương thức khởi tạo __construct() cũng như tập tin config/services.yml.

Chép
protected $pagination;

public function __construct(\phpbb\pagination $pagination)
{
	$this->pagination= $pagination;
}
Chép
        arguments:
             - '@pagination'
Nhưng nếu bạn đang viết một gói chức năng thì thêm vào trong phương thức main():
Chép
$this->pagination= $phpbb_container->get('pagination');

Phân trang
Ta cần tạo thêm 2 biến:
  • $per_page Số lượng mục mỗi trang.
  • $start: Số thứ tự mục bắt đầu của trang hiện tại. Biến này thêm vào cả địa chỉ truy cập của trang, ví dụ http://localhost/forum/test/?start=50
  • Chép
    $per_page = 20;
    
    $start = 0: Trang 1.
    $start = 10: Trang 1.
    $start = 50: Trang 3.
Giờ hãy thêm 2 biến trên vào mã của chúng ta:
Chép
$start = $this->request->variable('start', 0);
$per_page = 20;
Trong đoạn mã trên, ta cố định 20 mục mỗi trang trong mã PHP. Bạn có thể tùy biến biến này, như tạo thêm mục cấu hình cho nó trong bảng quản trị, hay để người dùng tự nhập số lượng họ thích.

Lấy từ mục cấu hình:
Chép
$per_page = $this->config['items_per_page'];
Xem lại Tạo mới mục cấu hìnhGói chức năng nếu bạn chưa rõ về cách tạo mục cấu hình trong bảng quản trị.

Hoặc do người dùng tự chọn, nhưng mặc định lấy từ mục cấu hình:
Chép
$per_page = $this->request->variable('per_page', (int) $this->config['items_per_page']);
Bạn còn nhớ ví dụ trong bài Tạo danh sách dữ liệu trong giao diện không? Chúng ta sẽ phân trang thử cho ví dụ này nhé! Hãy xem lại đoạn mã gốc (hiện tất cả dòng tìm thấy):
Chép
$sql = 'SELECT username, user_email, user_posts
	FROM ' . USERS_TABLE . '
	WHERE user_posts > 10
	ORDER BY user_posts DESC';
$result = $this->db->sql_query($sql);

while ($row = $this->db->sql_fetchrow($result))
{
	$this->template->assign_block_vars('users', array(
		'USERNAME' => $row['username'],
		'EMAIL' => $row['user_email'],
		'POSTS' => $row['user_posts'],
	));
}
$this->db->sql_freeresult($result);
Và bạn nhớ cách nào giới hạn kết quả truy vấn không? Nếu chưa, thì câu trả lời là hàm $this->db->sql_query_limit() đấy. Hãy xem lại phần LIMIT trong bài Truy vấn dữ liệu.

Chúng ta sẽ sửa lại đoạn mã trên thành:
Chép
$users = array();
$user_count = 0;

$start = $this->list_users($users, $user_count, $per_page, $start);

foreach ($users as $row)
{
	$this->template->assign_block_vars('users', array(
		'USERNAME' => $row['username'],
		'EMAIL' => $row['user_email'],
		'POSTS' => $row['user_posts'],
	));
}
Phần xuất ra giao diện mã HTML vẫn như cũ, chỉ khác phần truy vấn SQL đã trở thành:
Chép
$start = $this->list_users($users, $user_count, $per_page, $start);
Với $users là mảng chứa kết quả và $user_count là tổng số kết quả.

Giờ ta hãy viết tiếp cho phương thức $this->list_users() kia:
Chép
private function list_users(&$users, &$user_count, $limit = 0, $offset = 0)
{
	// Lấy tổng số mục trước khi phân trang
	$sql = 'SELECT COUNT(user_id) AS user_count
		FROM ' . USERS_TABLE . '
		WHERE user_posts > 10';
	$result = $this->db->sql_query($sql);
	$user_count = (int) $this->db->sql_fetchfield('user_count');
	$this->db->sql_freeresult($result);

	// Nếu không có không cần hiển thị
	if ($user_count == 0)
	{
		return 0;
	}

	// Có đứa nào nghịch sửa ?start=... số lớn hơn tổng số mục
	if ($offset >= $user_count)
	{
		$offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
	}

	// Lấy dữ liệu trong khoảng cần cho trang hiện tại
	$sql = 'SELECT username, user_email, user_posts
		FROM ' . USERS_TABLE . '
		WHERE user_posts > 10
		ORDER BY user_posts DESC';
	$result = $this->db->sql_query_limit($sql, $limit, $offset);

	while ($row = $this->db->sql_fetchrow($result))
	{
		$users[] = $row;
	}
	$this->db->sql_freeresult($result);

	return $offset;
}
Sau đó, xuất thanh chọn trang ra giao diện.
Nếu là gói chức năng:
Chép
$this->pagination->generate_template_pagination($this->u_action, 'pagination', 'start', $user_count, $per_page, $start);
Nếu không phải gói chức năng:
Chép
$this->pagination->generate_template_pagination($this->helper->get_current_url(), 'pagination', 'start', $user_count, $per_page, $start);
$this->u_action chứa liên kết hiện tại của gói chức năng và luôn có sẵn trong mọi gói chức năng. Khi tập tin ta viết không phải gói chức năng, dùng $this->helper->get_current_url() sẽ trả về liên kết hiện tại của trang, tương tự với $this->u_action. Mục đích của dòng mã trên là xuất thanh chọn trang ra giao diện, đồng thời thêm biến ?start= vào liên kết hiện có.

Cuối cùng, ta phải hiển thị thanh trang ra giao diện:
Chép
{% if pagination %}
	<div class="pagination">
		{% include 'pagination.html' %}
	</div>
{% endif %}

Xem lại các liên kết
Nếu trang bạn đang định phân ra có nhiều liên kết, ví dụ liên kết tạo/sửa/xóa, hay có khung nhập liệu thẻ <form> thì hãy nhớ thêm start=$start vào liên kết nếu cần. Ví dụ, khi nhập liệu xong và bấm lưu thay đổi sẽ trả về đúng số trang mà trước khi bấm nút đã duyệt nhờ thêm vào biến start trong liên kết.
Chép
'U_ACTION' => $this->u_action . "&amp;start=$start",

Điều chỉnh cho phpBB 3.1.x
Chỉ khác ở phần mã giao diện HTML, ta phải thêm tiền tố loops. cho vòng lặp pagination:
Chép
{% if loops.pagination %}
	<div class="pagination">
		{% include 'pagination.html' %}
	</div>
{% endif %}


Xử lý dữ liệu đặc biệt với s9e/TextFormatter


nedka

nedka

Quản trị viên
29/08/2016 11:04

Nhúng nội dung từ mạng xã hội
Để nhúng nội dung từ các liên kết mạng xã hội mà người dùng gửi trong bài viết, ta cần đến gói MediaPack đi kèm với s9e/TextFormatter. Tất cả những gói này đã có sẵn trong phpBB, ta không cần thêm vào gì cả, chỉ cần cấu hình chúng qua tập tin event/listener.php từ gói mở rộng đang viết.

Thêm vào MediaPack:

Chép
use s9e\TextFormatter\Bundles\MediaPack;

class listener implements EventSubscriberInterface
{
	...
Các sự kiện cần "can thiệp":
Chép
static public function getSubscribedEvents()
{
	return array(
		'core. text_formatter_s9e_configure_before' => 'text_formatter_s9e_configure_before',
		'core.modify_text_for_edit_before' => 'modify_text_for_edit_before',
		'core.modify_submit_post_data' => 'modify_submit_post_data',
		'core.submit_pm_before' => 'submit_pm_before',
		'core.modify_text_for_storage_after' => 'modify_text_for_storage_after',
		'core.modify_format_display_text_after' => 'modify_format_display_text_after',
		'core.modify_text_for_display_after' => 'modify_text_for_display_after',
	);
}
Từ danh sách sự kiện đã bắt ở trên, ta sẽ lần lượt viết từng phương thức triển khai cho chúng.

Đầu tiên là khai báo chúng với s9e/TextFormatter:
Chép
public function text_formatter_s9e_configure_before($event)
{
	$configurator = $event['configurator'];
	
	// Mã khai báo tại đây...
}
GIờ tại vị trí mã khai báo, nếu bạn muốn thêm hết toàn bộ các trang mạng xã hội mà MediaPack hỗ trợ:
Chép
foreach ($configurator->MediaEmbed->defaultSites->getIds() as $site_id)
{
	$configurator->MediaEmbed->add($site_id);
}
Hoặc chỉ vài trang phổ biến:
Chép
foreach ($configurator->MediaEmbed->defaultSites->getIds() as $site_id)
{
	if (in_array($site_id, array('facebook', 'twitter', 'googleplus', 'youtube', 'flickr', 'instagram', 'gist')))
	{
		$configurator->MediaEmbed->add($site_id);
	}
}
Xem danh sách các trang hỗ trợ và mã ID của chúng tại đây.

Hoặc bạn cũng có thể thêm vào chính diễn đàn phpBB của mình, ví dụ với vinabb.vn:
Chép
$configurator->MediaEmbed->add('vinabb', array(
	'host' => 'vinabb.vn',
	'extract' => array(
		"!vinabb\\.vn/viewtopic\\.php\\?f=(?'f'[0-9]+)\\&t=(?'t'[0-9]+)!",
		"!vinabb\\.vn/viewtopic\\.php\\?t=(?'t'[0-9]+)!",
	),
	'iframe' => array(
		'width' => 560,
		'height' => 260,
		'src' => 'http://vinabb.vn/embed/topic/{@t}',
	),
));
Trong chế độ chỉnh sửa, ta cần trả lại nguyên gốc liên kết người dùng đã nhập, dùng hàm unparse() cho sự kiện core.modify_text_for_edit_before
Chép
public function modify_text_for_edit_before($event)
{
	$event['text'] = $this->unparse($event['text']);
}
Trước khi lưu vào cơ sở dữ liệu, ta cần thêm thẻ nhận diện của s9e/TextFormatter vào nội dung, dùng hàm parse() cho các sự kiện: core.modify_submit_post_data, core.submit_pm_before, core.modify_text_for_storage_after
Chép
public function modify_submit_post_data($event)
{
	$data = $event['data'];
	$data['message'] = $this->parse($data['message']);
	$event['data'] = $data;
}
Chép
public function submit_pm_before($event)
{
	$data = $event['data'];
	$data['message'] = $this->parse($data['message']);
	$event['data'] = $data;
}
Chép
public function modify_text_for_storage_after($event)
{
	$event['text'] = $this->parse($event['text']);
}
Và cuối cùng, trong chế độ hiển thị, hiện các liên kết nhận diện thành nội dung nhúng, dùng hàm render() cho các sự kiện: core.modify_format_display_text_after, core.modify_text_for_display_after
Chép
public function modify_format_display_text_after($event)
{
	$event['text'] = $this->render($this->parse($event['text']));
}
Chép
public function modify_text_for_display_after($event)
{
	$event['text'] = $this->render($event['text']);
}
Cuối cùng là viết thêm mã cho 3 hàm: unparse(), parse()render() mà ở trên chúng ta đã dùng:
Chép
	/**
	* Render MediaEmbed markup tags when displaying text
	*
	* https://github.com/s9e/phpbb-ext-mediaembed
	* @copyright Copyright (c) 2014-2016 The s9e Authors
	*
	* @param $text
	* @return mixed
	*/
	private function render($text)
	{
		if (strpos($text, '<!-- s9e:mediaembed') === false)
		{
			return $text;
		}

		return preg_replace_callback(
			'(<!-- s9e:mediaembed:([^ ]+) --><!-- m -->.*?<!-- m -->)',
			function ($m)
			{
				return MediaPack::render(base64_decode($m[1]));
			},
			$text
		);
	}
	/**
	* Insert MediaEmbed markup tags when saving text
	*
	* https://github.com/s9e/phpbb-ext-mediaembed
	* @copyright Copyright (c) 2014-2016 The s9e Authors
	*
	* @param $text
	* @return mixed
	*/
	private function parse($text)
	{
		if (strpos($text, '<!-- m -->') === false)
		{
			return $text;
		}

		return preg_replace_callback(
			'(<!-- m -->.*?href="([^"]+).*?<!-- m -->)',
			function ($m)
			{
				$xml = MediaPack::parse(htmlspecialchars_decode($m[1]));
				return ($xml[1] === 'r') ? '<!-- s9e:mediaembed:' . base64_encode($xml) . ' -->' . $m[0] : $m[0];
			},
			$text
		);
	}
	/**
	* Remove MediaEmbed markup tags when editing text
	*
	* https://github.com/s9e/phpbb-ext-mediaembed
	* @copyright Copyright (c) 2014-2016 The s9e Authors
	*
	* @param $text
	* @return mixed
	*/
	private function unparse($text)
	{
		if (strpos($text, '<!-- s9e:mediaembed') === false)
		{
			return $text;
		}

		return preg_replace('(<!-- s9e:mediaembed:([^ ]+) -->)', '', $text);
	}


Quan điểm

  • Không đề cập chính trị, tôn giáo, nội dung đồi trụy.
  • Giữ gìn sự trong sáng của Tiếng Việt.
  • Không chia sẻ phần mềm vi phạm bản quyền.
  • Không rao vặt và không nhận đặt quảng cáo.
  • Dù trong túi hết tiền thì diễn đàn phpBB của anh cũng phải ngay ngắn.

Chuyện tình VinaBB

17/07/2004: Yêu phpBB từ phiên bản 2.0.10.
22/10/2006: Cất tiếng cười chào đời.
11/06/2007: Chính thức định cư trên Olympus, Sao Hỏa.
11/06/2009: Mất liên lạc với Trái Đất. [ Phiên bản 2007 ]
28/07/2016: Trôi dạt đến mặt trăng Rhea, Sao Thổ.
12/12/2016: Cuộc hành trình mới lại bắt đầu…

Code in Viet Nam

Cống hiến hết mình vì Tổ Quốc Việt Nam Xã Hội Chủ Nghĩa

Quản trị viên

nedka

VinaBB

NEDKA Solutions

Đơn vị chủ quản

Chúng tôi chịu trách nhiệm toàn bộ nội dung có trên VinaBB.vn trước pháp luật.