Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
  • Sign Up
  • entries
    3
  • comments
    12
  • views
    3,982

Реализация событий в 2.3, 3.x, 4.x


halfhope

1,811 views

Всем привет, дорогие друзья!

 

Эта статья написана специально для конкурса (коих у нас на форуме не было уже давно). Статья предназначена для разработчиков дополнений. Пишу без воды, сухо и по делу. Немного истории, нюансов, список аргументов для обработчиков событий, также приведу пример простой и понятной реализации большого кол-ва событий в ваших дополнениях для OpenCart 2.3, 3.x, 4.x (скачать примеры модулей можно будет в конце статьи).

 

Как все начиналось

 

Для изменения кодовой базы движка нам всегда нужно было либо вмешиваться в код, либо использовать vqmod. Использование vqmod порождало проблемы при работе нескольких модификаторов с одним участком кода, а также другие, касающиеся поддержки дополнений. Использование хуков помогло бы решить часть из них. Вспоминаю первую, известную мне реализацию "Override Engine" (2012 г), а также тему "hook pre render Идея и примерная реализация". Начиная с версии 2.0 (2014 г) в движке появился первый встроенный механизм событий (хуков), а концепция vqmod была реализована в самом движке и получила название ocmod. С версии 2.2 (2016 г) в событиях изменились пути триггеров, они стали аналогичны роутам. В версии 3.x (2017 г) механизм событий и ocmod обошлись без существенных изменений. А с версии 4.x поддержки ocmod больше не будет.

 

"Embrace, extend and extinguish". Однако, у нас всегда будет vqmod.

 

Зачем нужны события?

 

События позволяют запускать пользовательские функции до/после вызова какой-либо функции в парадигме MVCL+Config+Library для изменения входных/выходных данных. По задумке мэйнтэйнера движка они должны заменить vqmod/ocmod. 

 

P.S. Я уже переписал некоторые старые модули с использованием событий. Например, раньше модуль "перс. шаблонов" с помощью ocmod внедрялся в код основных разделов каталога и подменял их шаблоны, а теперь он может подменять любой шаблон в движке. Так что события очень хорошо решают некоторые типы задач.

 

Нюансы при использовании событий

 

  1. События могут быть добавлены только из контроллеров админки. Удобнее всего делать это при установке модуля, в функции install. 
  2. Пути всех триггеров начинаются с названия нужного раздела, admin, catalog или library. Разделы admin и catalog содержат controller, view, language и config.
  3. В путях триггеров можно использовать знак "*", чтобы назначать триггеры по маске. Например, catalog/view/*/template/common/header/after.
  4. Для изменения данных в обработчиках событий config и language используйте $this->config->set(), $this->language->set(), соответственно.
  5. Данные полученные из обработчиков событий можно сохранять внутри класса и использовать их в других обработчиках, которые запускаются позднее.

 

Для редактирования событий из админки используйте "Event Manager" или adminer ([сtrl+click], для быстрого редактирования записи).

 

Нюансы для разных версий движка

 

  • Код события для версии 2.3 должен иметь длину не более 32 символов. Для версий 3.x и 4.x не более 64.
  • В версии 2.3 событиями (регистрация, удаление и т.д.) занимается модель extension/event, у 3.x и 4.x setting/event.
  • В версии 2.3 в разделе catalog пути триггеров представлений (view) before/after будут отличаться. Например, catalog/view/common/header/before, catalog/view/default/template/common/header/after. Это связано использованием шаблонов оформления в разделе catalog.
  • С версии 3.x добавлен порядок сортировки событий.
  • С версии 4.x у каждого события должен быть description.
  • Триггеры для библиотек (library) доступны только с версии 4.x.

 

Передаваемые аргументы

 

В обработчики событий аргументы передаются по ссылке. Т.е. можно менять значения аргументов не заботясь о передаче результата куда-либо еще. 

 

2.3 controller model view language config  
before $route, $data $route, $args $route, $data, $output $route $route  
after $route, $data, $output $route, $args, $output $route, $data, $output $route, $output $route  
3.x controller model view language config  
before $route, $args $route, $args $route, $data, $code $route, $key $route  
after $route, $data, $output $route, $args, $output $route, $data, $output $route, $key, $output $route  
4.x controller model view language config library
before $route, $args $route, $args $route, $data, $code $route, $prefix, $code $route $route, $args
after $route, $data, $output $route, $args, $output $route, $data, $output $route, $prefix, $code, $data $route, $data $route, $args

 

Возвращаемые значения 

 

Помимо изменения данных через аргументы, обработчики событий также могут возвращать значения, используя return. Например, если обработчик события controller/common/home/before вернет через return сгенерированный html код, то весь вывод контроллера common/header будет заменен им, а сам контроллер common/header не будет выполнен, но запустится событие after. Т.е. можно подменять данные выполнения функций без их выполнения.

 

2.3 controller model view
before mixed mixed string
after mixed mixed string
3.x controller model view
before mixed mixed string
after mixed mixed string
4.x controller model view
before   mixed  
after   mixed  

 

Простая и понятная реализация 

 

<?php

class ControllerExtensionModuleSample extends Controller {

	public function install() {
		$this->checkEvent();
	}

	public function uninstall() {
		$this->removeEvent();
	}

	public function index() {
		# code
	}
	
	private $_events = [
		[
			'code'		=> 'sample_394beb748918d3ce260756703',
			'trigger'	=> 'admin/controller/design/layout/before',
			'action'	=> '/eventControllerDesignLayoutBefore'
		],
		[
			'code'		=> 'sample_7a2b613ccb07a2c0e9c8cb844',
			'trigger'	=> 'admin/view/design/layout_list/after',
			'action'	=> '/eventViewDesignLayoutListAfter'
		],
		[
			'code'		=> 'sample_968b25d7939ec60e0008d670c',
			'trigger'	=> 'admin/model/design/layout/getLayouts/after',
			'action'	=> '/eventModelDesignLayoutGetLayoutsAfter'
		],
		[
			'code'		=> 'sample_172e1deab50793d6c4bec3b42',
			'trigger'	=> 'catalog/model/design/layout/getLayoutModules/after',
			'action'	=> '/filter'
		]
	];

	public function eventControllerDesignLayoutBefore(&$route, &$args) {
		# code
	}

	public function eventViewDesignLayoutListAfter(&$route, &$data, &$output) {
		# code
	}

	public function eventModelDesignLayoutgetLayoutsAfter(&$route, &$args, &$output) {
		# code
	}

	private function checkEvent() {
		$this->load->model('extension/event');

		foreach($this->_events as $event) {
			if(!$result = $this->model_extension_event->getEvent($event['code'], $event['trigger'], 'extension/module/sample' . $event['action'])) {
				$this->model_extension_event->addEvent($event['code'], $event['trigger'], 'extension/module/sample' . $event['action']);
			}
		}
	}

	private function removeEvent() {
		$this->load->model('extension/event');

		foreach($this->_events as $event) {
			$this->model_extension_event->deleteEvent($event['code']);
		}
	}
}

 

Скачать примеры

 

 

  • +1 26

5 Comments


Recommended Comments

Добавлю от себя, что триггеры-события съедают 10-20% времени генерации страницы.

Причина банальная - реализация сделана через ягодичную мышцу.

В аттаче файл system/engine/event.php для 2.3 который позволяет существенно ускорить данный момент (и даже снизить PeakMemory)

event.php

  • +1 3
Link to comment
Цитата

В catalog пути триггеров представлений (view) before/after будут отличаться. Например, catalog/view/common/header/before, catalog/view/default/template/common/header/after. Это связано использованием шаблонов оформления в разделе каталога.

Не совсем так

 

	public function view($route, $data = array()) {
		// Sanitize the call
		$route = preg_replace('/[^a-zA-Z0-9_\/]/', '', (string)$route);
		
		// Keep the original trigger
		$trigger = $route;
		
		// Template contents. Not the output!
		$template = '';
		
		// Trigger the pre events
		$result = $this->registry->get('event')->trigger('view/' . $trigger . '/before', array(&$route, &$data, &$template));



Т.е. не надо указывать имя темы

'trigger' => 'catalog/view/common/header/after',

Имя темы подтянется в самом последнем событии

  • +1 1
Link to comment
Цитата

В версии 3.x (2017 г) механизм событий обошлись без существенных изменений.

добавилась сортировка (порядок выполнения)

 

Link to comment
1 час назад, chukcha сказал:

Не совсем так

 

Действительно, то что я написал справедливо только для версии 2.3, там роут меняет обработчик catalog/controller/event/theme, который назначается в конфигах каталога. Внесу правки в статью, спасибо!

  • +1 1
Link to comment
Yoda

Posted (edited)

Ну хоть кто-то написал вменяемый текст!
А не "перевод", не рекламу своего ресурса, не еще какую то пургу.

Лайк!

Но если честно, то я бы добавил это дело простым мануалом для песочницы to do hello world!

Edited by Yoda
  • +1 2
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

On our site, cookies are used and personal data is processed to improve the user interface. To find out what and what personal data we are processing, please go to the link. If you click "I agree," it means that you understand and accept all the conditions specified in this Privacy Notice.