Do not Modify the Core, Trick the Missing Event


Do not Modify the Core, Trick the Missing Event
nedka

nedka

21/12/2016 15:35
With a limited number of events, how can we implement features without modifying the phpBB core? Make an event request to phpBB Development Team and wait until a new version is released? Oh no, you still can resolve your problems without missing events!

Tip 1: How to catch a successful action?
Face the logs! Almost admin actions have a log entry. Let's catch it via the event core.add_log.

Example: You want to purge group cache data from the table phpbb_groups. Do it once phpBB has logged 3 actions: create new group, edit group and delete group.

Example code:
Chép
if ($event['log_operation'] == 'LOG_GROUP_CREATED' || $event['log_operation'] == 'LOG_GROUP_DELETE' || $event['log_operation'] == 'LOG_GROUP_UPDATED')
{
	$this->cache->clear_group_data();
}

Tip 2: How to execute the code in a page without events?
Each page in phpBB always initializes the user session. Catch the wanted page via the filename of the current PHP script or a routing path that you are accessing to, get it by $this->user->page['page_name']. Single pages return their physical filenames as viewforum.php, ucp.php... As of routes, they return: app.php/demo/, app.php/post/123/report...

Example code:
Chép
if (in_array($this->user->page['page_name'], array("app.$phpEx/demo/", "app.$phpEx/demo/acp", "app.$phpEx/demo/acp/")))
{
	$helper = $phpbb_container->get('controller.helper');
	$response = new \Symfony\Component\HttpFoundation\RedirectResponse(
		$helper->route('vinabb_stylesdemo_route', array('mode' => '')),
		301
	);
	$response->send();
}

Tip 3: How to rewrite URLs for SEO without editing webserver files?
All of URLs in phpBB pass through the function append_sid(), and this event comes with the event core.append_sid.

Using the event core.append_sid, catch links that contain viewforum.php:
Chép
if (strpos($event['url'], "viewforum.{$this->php_ext}") !== false)
Then, get URL parameters, e.g. ?f=...&t=..., resolve them and return the SEO friendly URL as: .../forum/forum-name.17/page-2/.

Example code:
Chép
if (strpos($event['url'], "viewforum.{$this->php_ext}") !== false)
{
	$forum_data = $this->cache->get_forum_data();

	if (!sizeof($this->route_data))
	{
		$this->route_data['f'] = '';
	}

	if (isset($this->route_data['f']))
	{
		$this->route_data['forum_id'] = $this->route_data['f'];

		unset($this->route_data['f']);

		if ($this->route_data['forum_id'])
		{
			$this->route_data['seo'] = $forum_data[$this->route_data['forum_id']]['name_seo'] . constants::REWRITE_URL_SEO;
		}
	}

	$this->route_name = 'vinabb_web_board_forum_route';
}

Tip 4: How to execute the code in a module without events?
This tip is extended from the tip #2 above. We can not apply the tip #2 to modules, because they always return the same PHP filename:
  • ACP: Returns index.php.
  • MCP: Returns mcp.php.
  • UCP: Returns ucp.php.
How to specify a module correctly? Look in the browser address when you are accessing to a module link, it always has 2 URL paremeters: i and mode. E.g.
Chép
ucp.php?i=ucp_prefs&mode=post
mcp.php?i=mcp_logs&mode=front
adm/index.php?i=acp_update&mode=version_check
i is the module basename and mode is the module mode. Take an example module, ucp_prefs is an UCP-class module (the prefix ucp_) allowing you to change your account settings, with 4 modes: Edit global settings, edit posting defaults, edit display options, edit notification options. From the parameter i and mode, we catch the wanted module correctly via the class request.

Example code:
Chép
$i = $this->request->variable('i', '');
$mode = $this->request->variable('mode', '');

if ($this->user->page['page_name'] == 'ucp.php' && $i == 'ucp_prefs' && $mode == 'post')
{
	// Code go here...
}
To know how many modes within a module, you can open the module info file to look up. These files are put on following locations:
Chép
./includes/acp/info/
./includes/mcp/info/
./includes/ucp/info/
Please note, if the module comes from an extension, its basename will be different, not same as original modules.
Extension package name: vinabb/demo
Path of the mpdule file: ./vinabb/demo/acp/config_module.php
Module basename (Value of i on the URL): -vinabb-demo-acp-config_module

Tip 5: How to catch HTTP errors?
phpBB is a Symfony application, all of HTTP errors are triggered by Symfony. So as, none of phpBB events could help you to catch them. You need to contact to the Symfony component HttpKernel.

E.g. you were typing an incorrect link, this is the 404 HTTP error. You will be seen the message: No route found for "GET /...". Now let's change this text.

Example code: ./event/listener.php
Chép
<?php

namespace vinabb\demo\event;

use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class listener implements EventSubscriberInterface
{
	protected $template;

	public function __construct(\phpbb\template\template $template)
	{
		$this->template = $template;
	}

	static public function getSubscribedEvents()
	{
		return [
			KernelEvents::EXCEPTION => ['onKernelException', 2000]
		];
	}

	public function onKernelException(GetResponseForExceptionEvent $event)
	{
		$exception = $event->getException();
		$status_code = ($exception instanceof HttpException) ? $exception->getStatusCode() : 500;

		if ($status_code == 404)
		{
			trigger_error('Page not found :(');
		}

		$response = new Response($this->template->assign_display('body'), $status_code);
		$event->setResponse($response);
	}
}
Example code: ./config/services.yml
Chép
services:
    vinabb.demo.listener:
        class: vinabb\demo\event\listener
        arguments:
            - '@template'
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

Tip 6: How to modify template files without events?
Template events allowing you to insert HTML code into original template files of phpBB. What's happen with non-event files? Wait for phpBB Development Team add to? No, just use the power of jQuery to modify the output HTML.

Another example, in index_body.html, at the end, the display order of blocks is: Who is online / Birthdays / Statistics. You want to move up the "Statistics" above the "Birthdays", but there are no template events between "Who is online" and "Birthdays". Look the code, "Who is online" is within the block <div class="stat-block online-list">...</div>, and the "Statistics" is within <div class="stat-block statistics">...</div>. Using jQuery, we will remove the HTML code of "Statistics" at the end, then put it below the online list.

In order to modify HTML code via jQuery, we use the template event overall_footer_body_after because it is below the line including jQuery and above the ending tag </body>.

Example code: ./styles/prosilver/template/event/overall_footer_body_after.html
Chép
<script>
	$(document).ready(
		function()
		{
			// Copy HTML code of the "Statistics"
			var copyHTML = $('.stat-block.statistics').clone();

			// Remove the "Statistics" at the end
			$('.stat-block.statistics').remove();

			// Put the copied HTML code below the online list
			copyHTML.appendTo('.stat-block.online-list');
		}
	);
</script>

Tip 7: How to override an original template file?
The tip #6 allowing you to modify some blocks of HTML code, specified by the HTML attribute class or id. What's happen if you could not find these attributes, or there is a lot of blocks to modify? The best way is replace the current template file with a new one from your extension. Our task: rename the template file to be sent to Twig to compile, via the event core.page_footer_after.

Now, we will try to replace the original template file index_body.html that used by the file index.php with another file from our extension.

Example code: ./event/listener.php
Chép
<?php

namespace vinabb\demo\event;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class listener implements EventSubscriberInterface
{
	protected $template;
	protected $user;
	protected $php_ext;

	public function __construct(\phpbb\template\template $template, \phpbb\user $user, $php_ext)
	{
		$this->template = $template;
		$this->user = $user;
		$this->php_ext = $php_ext;
	}

	static public function getSubscribedEvents()
	{
		return [
			'core.page_footer_after' => 'page_footer_after'
		];
	}

	public function page_footer_after($event)
	{
		if ($this->user->page['page_name'] == "index.{$this->php_ext}")
		{
			$this->template->set_filenames(['body' => '@vinabb_demo/index_body.html']);
		}
	}
}
Example code: ./config/services.yml
Chép
services:
    vinabb.demo.listener:
        class: vinabb\demo\event\listener
        arguments:
            - '@template'
            - '@user'
            - '%core.php_ext%'
        tags:
            - { name: event.listener }


VinaBB

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.