Jump to content
  • entries
    5
  • comments
    15
  • views
    2,236

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


halfhope

1,751 views

 Share

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

Статья предназначена для разработчиков дополнений. Пишу без воды, сухо и по делу. Немного истории, нюансов, список аргументов для обработчиков событий, также приведу пример простой и понятной реализации большого кол-ва событий в ваших дополнениях для 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 внедрялся в код основных разделов каталога и подменял их шаблоны, а теперь его брат «Custom templates Pro» подменять любой шаблон в движке. Так что события очень хорошо решают некоторые типы задач.

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

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

 

Для редактирования событий из админки используйте «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']);
		}
	}
}

Примеры

2.3

sample_2.3.ocmod.zip

3.x

sample_3.x.ocmod.zip

4.x

sample.ocmod.zip

 Share

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...