Elgg  Version 6.0
Plugins.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
6 use Elgg\Config;
7 use Elgg\Context;
8 use Elgg\Database;
13 use Elgg\Invoker;
21 
28 class Plugins {
29 
30  use Profilable;
31  use Loggable;
32 
33  const BUNDLED_PLUGINS = [
34  'activity',
35  'blog',
36  'bookmarks',
37  'ckeditor',
38  'custom_index',
39  'dashboard',
40  'developers',
41  'discussions',
42  'externalpages',
43  'file',
44  'friends',
45  'friends_collections',
46  'garbagecollector',
47  'groups',
48  'invitefriends',
49  'likes',
50  'members',
51  'messageboard',
52  'messages',
53  'notifications',
54  'pages',
55  'profile',
56  'reportedcontent',
57  'search',
58  'site_notifications',
59  'system_log',
60  'tagcloud',
61  'theme_sandbox',
62  'thewire',
63  'uservalidationbyemail',
64  'web_services',
65  ];
66 
70  protected ?array $boot_plugins;
71 
72  protected Context $context;
73 
88  public function __construct(
89  protected BaseCache $cache,
90  protected Database $db,
91  protected SessionManagerService $session_manager,
92  protected EventsService $events,
93  protected Translator $translator,
94  protected ViewsService $views,
95  protected Config $config,
96  protected SystemMessagesService $system_messages,
97  protected Invoker $invoker,
99  ) {
100  $this->context = $request->getContextStack();
101  }
102 
108  public function getPath(): string {
109  return $this->config->plugins_path ?: Paths::project() . 'mod/';
110  }
111 
120  public function setBootPlugins(array $plugins = null, bool $order_plugins = true): void {
121  $this->cache->clear();
122  if (!is_array($plugins)) {
123  unset($this->boot_plugins);
124  return;
125  }
126 
127  // Always (re)set the boot_plugins. This makes sure that even if you have no plugins active this is known to the system.
128  $this->boot_plugins = [];
129 
130  if ($order_plugins) {
131  $plugins = $this->orderPluginsByPriority($plugins);
132  }
133 
134  foreach ($plugins as $plugin) {
135  if (!$plugin instanceof \ElggPlugin) {
136  continue;
137  }
138 
139  $plugin_id = $plugin->getID();
140  if (!$plugin_id) {
141  continue;
142  }
143 
144  $plugin->registerLanguages();
145 
146  $this->boot_plugins[$plugin_id] = $plugin;
147 
148  // make sure the plugin is in the entity and plugin cache
149  $plugin->cache();
150 
151  // can't use ElggEntity::cache() as it conflict with metadata preloading
152  $this->cache->save($plugin_id, $plugin);
153  }
154  }
155 
164  public function getDirsInDir(string $dir = null): array {
165  if (!$dir) {
166  $dir = $this->getPath();
167  }
168 
169  if (!is_dir($dir)) {
170  return [];
171  }
172 
173  $handle = opendir($dir);
174  if ($handle === false) {
175  return [];
176  }
177 
178  $plugin_dirs = [];
179  while (($plugin_dir = readdir($handle)) !== false) {
180  // must be directory and not begin with a .
181  if (!str_starts_with($plugin_dir, '.') && is_dir($dir . $plugin_dir)) {
182  $plugin_dirs[] = $plugin_dir;
183  }
184  }
185 
186  sort($plugin_dirs);
187 
188  return $plugin_dirs;
189  }
190 
199  public function generateEntities(): bool {
200  // ignore access in case this is called with no admin logged in - needed for creating plugins perhaps?
201  // show hidden entities so that we can enable them if appropriate
202  return $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() {
203  $mod_dir = $this->getPath();
204 
205  $known_plugins = $this->find('all');
206 
207  // keeps track if reindexing is needed
208  $reindex = false;
209 
210  // map paths to indexes
211  $id_map = [];
212  $latest_priority = 0;
213  foreach ($known_plugins as $i => $plugin) {
214  // if the ID is wrong, delete the plugin because we can never load it.
215  $id = $plugin->getID() . $plugin->guid;
216  if (!$id) {
217  $plugin->delete();
218  unset($known_plugins[$i]);
219  continue;
220  }
221 
222  $id_map[$plugin->getID()] = $i;
223 
224  // disabled plugins should have no priority, so no need to check if the priority is incorrect
225  if (!$plugin->isEnabled()) {
226  continue;
227  }
228 
229  $current_priority = $plugin->getPriority();
230  if (($current_priority - $latest_priority) > 1) {
231  $reindex = true;
232  }
233 
234  $latest_priority = $current_priority;
235  }
236 
237  $physical_plugins = $this->getDirsInDir($mod_dir);
238  if (empty($physical_plugins)) {
239  return false;
240  }
241 
242  // check real plugins against known ones
243  foreach ($physical_plugins as $plugin_id) {
244  // is this already in the db?
245  if (array_key_exists($plugin_id, $id_map)) {
246  $index = $id_map[$plugin_id];
247  $plugin = $known_plugins[$index];
248  // was this plugin deleted and its entity disabled?
249  if (!$plugin->isEnabled()) {
250  $plugin->enable();
251  try {
252  $plugin->deactivate();
253  } catch (PluginException $e) {
254  // do nothing
255  }
256 
257  $plugin->setPriority('new');
258  }
259 
260  // remove from the list of plugins to disable
261  unset($known_plugins[$index]);
262  } else {
263  // create new plugin
264  // priority is forced to last in save() if not set.
265  \ElggPlugin::fromId($plugin_id);
266  }
267  }
268 
269  // everything remaining in $known_plugins needs to be disabled
270  // because they are entities, but their dirs were removed.
271  // don't delete the entities because they hold settings.
272  foreach ($known_plugins as $plugin) {
273  if (!$plugin->isEnabled()) {
274  continue;
275  }
276 
277  $reindex = true;
278 
279  if ($plugin->isActive()) {
280  try {
281  $plugin->deactivate();
282  } catch (PluginException $e) {
283  // do nothing
284  }
285  }
286 
287  // remove the priority.
288  $plugin->deleteMetadata(\ElggPlugin::PRIORITY_SETTING_NAME);
289 
290  $plugin->disable();
291  }
292 
293  if ($reindex) {
294  $this->reindexPriorities();
295  }
296 
297  return true;
298  });
299  }
300 
308  public function get(string $plugin_id): ?\ElggPlugin {
309  if (empty($plugin_id)) {
310  return null;
311  }
312 
313  $plugin = $this->cache->load($plugin_id);
314  if ($plugin instanceof \ElggPlugin) {
315  return $plugin;
316  }
317 
318  $plugins = elgg_get_entities([
319  'type' => 'object',
320  'subtype' => 'plugin',
321  'metadata_name_value_pairs' => [
322  'name' => 'title',
323  'value' => $plugin_id,
324  ],
325  'limit' => 1,
326  'distinct' => false,
327  ]);
328 
329  if (empty($plugins)) {
330  return null;
331  }
332 
333  $plugin = $plugins[0];
334 
335  $this->cache->save($plugin_id, $plugin);
336 
337  return $plugin;
338  }
339 
351  public function exists(string $id): bool {
352  return $this->get($id) instanceof \ElggPlugin;
353  }
354 
360  public function getMaxPriority(): int {
362  $qb->select('MAX(CAST(md.value AS unsigned)) as max')
363  ->join($qb->getTableAlias(), MetadataTable::TABLE_NAME, 'md', "{$qb->getTableAlias()}.guid = md.entity_guid")
364  ->where($qb->compare('md.name', '=', \ElggPlugin::PRIORITY_SETTING_NAME, ELGG_VALUE_STRING))
365  ->andWhere($qb->compare("{$qb->getTableAlias()}.type", '=', 'object', ELGG_VALUE_STRING))
366  ->andWhere($qb->compare("{$qb->getTableAlias()}.subtype", '=', 'plugin', ELGG_VALUE_STRING));
367 
368  $data = $this->db->getDataRow($qb);
369  if (empty($data)) {
370  return 1;
371  }
372 
373  return max(1, (int) $data->max);
374  }
375 
383  public function isActive(string $plugin_id): bool {
384  if (isset($this->boot_plugins) && is_array($this->boot_plugins)) {
385  return array_key_exists($plugin_id, $this->boot_plugins);
386  }
387 
388  $plugin = $this->get($plugin_id);
389  if (!$plugin instanceof \ElggPlugin) {
390  return false;
391  }
392 
393  return $plugin->hasRelationship(1, 'active_plugin');
394  }
395 
405  public function build(): bool {
406  $plugins_path = $this->getPath();
407 
408  // temporary disable all plugins if there is a file called 'disabled' in the plugin dir
409  if (file_exists("{$plugins_path}/disabled")) {
410  if ($this->session_manager->isAdminLoggedIn() && $this->context->contains('admin')) {
411  $this->system_messages->addSuccessMessage($this->translator->translate('plugins:disabled'));
412  }
413 
414  return false;
415  }
416 
417  $this->events->registerHandler('plugins_load', 'system', [$this, 'register']);
418  $this->events->registerHandler('plugins_boot:before', 'system', [$this, 'boot']);
419  $this->events->registerHandler('init', 'system', [$this, 'init']);
420  $this->events->registerHandler('ready', 'system', [$this, 'ready']);
421  $this->events->registerHandler('upgrade', 'system', [$this, 'upgrade']);
422  $this->events->registerHandler('shutdown', 'system', [$this, 'shutdown']);
423 
424  return true;
425  }
426 
433  public function register(): void {
434  $plugins = $this->find('active');
435  if (empty($plugins)) {
436  return;
437  }
438 
439  $this->beginTimer([__METHOD__]);
440 
441  foreach ($plugins as $plugin) {
442  try {
443  $plugin->register();
444  } catch (\Exception $ex) {
445  $this->disable($plugin, $ex);
446  }
447  }
448 
449  $this->endTimer([__METHOD__]);
450  }
451 
457  public function boot(): void {
458  $plugins = $this->find('active');
459  if (empty($plugins)) {
460  return;
461  }
462 
463  $this->beginTimer([__METHOD__]);
464 
465  foreach ($plugins as $plugin) {
466  try {
467  $plugin->boot();
468  } catch (\Exception $ex) {
469  $this->disable($plugin, $ex);
470  }
471  }
472 
473  $this->endTimer([__METHOD__]);
474  }
475 
481  public function init(): void {
482  $plugins = $this->find('active');
483  if (empty($plugins)) {
484  return;
485  }
486 
487  $this->beginTimer([__METHOD__]);
488 
489  foreach ($plugins as $plugin) {
490  try {
491  $plugin->init();
492  } catch (\Exception $ex) {
493  $this->disable($plugin, $ex);
494  }
495  }
496 
497  $this->endTimer([__METHOD__]);
498  }
499 
505  public function ready(): void {
506  $plugins = $this->find('active');
507  if (empty($plugins)) {
508  return;
509  }
510 
511  $this->beginTimer([__METHOD__]);
512 
513  foreach ($plugins as $plugin) {
514  try {
515  $plugin->getBootstrap()->ready();
516  } catch (\Exception $ex) {
517  $this->disable($plugin, $ex);
518  }
519  }
520 
521  $this->endTimer([__METHOD__]);
522  }
523 
529  public function upgrade(): void {
530  $plugins = $this->find('active');
531  if (empty($plugins)) {
532  return;
533  }
534 
535  $this->beginTimer([__METHOD__]);
536 
537  foreach ($plugins as $plugin) {
538  try {
539  $plugin->getBootstrap()->upgrade();
540  } catch (\Exception $ex) {
541  $this->disable($plugin, $ex);
542  }
543  }
544 
545  $this->endTimer([__METHOD__]);
546  }
547 
553  public function shutdown(): void {
554  $plugins = $this->find('active');
555  if (empty($plugins)) {
556  return;
557  }
558 
559  $this->beginTimer([__METHOD__]);
560 
561  foreach ($plugins as $plugin) {
562  try {
563  $plugin->getBootstrap()->shutdown();
564  } catch (\Exception $ex) {
565  $this->disable($plugin, $ex);
566  }
567  }
568 
569  $this->endTimer([__METHOD__]);
570  }
571 
580  protected function disable(\ElggPlugin $plugin, \Exception $previous): void {
581  $this->getLogger()->log(LogLevel::ERROR, $previous, [
582  'context' => [
583  'plugin' => $plugin,
584  ],
585  ]);
586 
587  if (!$this->config->auto_disable_plugins) {
588  return;
589  }
590 
591  try {
592  $id = $plugin->getID();
593  $plugin->deactivate();
594 
595  $msg = $this->translator->translate(
596  'PluginException:CannotStart',
597  [$id, $plugin->guid, $previous->getMessage()]
598  );
599 
600  elgg_add_admin_notice("cannot_start {$id}", $msg);
601  } catch (PluginException $ex) {
602  $this->getLogger()->log(LogLevel::ERROR, $ex, [
603  'context' => [
604  'plugin' => $plugin,
605  ],
606  ]);
607  }
608  }
609 
617  public function find(string $status = 'active'): array {
618  if (!$this->db || !$this->config->installed) {
619  return [];
620  }
621 
622  if ($status === 'active' && isset($this->boot_plugins)) {
623  // boot_plugins is an already ordered list of plugins
624  return array_values($this->boot_plugins);
625  }
626 
627  $volatile_data_name = null;
628  $site_guid = 1;
629 
630  // grab plugins
631  $options = [
632  'type' => 'object',
633  'subtype' => 'plugin',
634  'limit' => false,
635  'order_by' => false,
636  ];
637 
638  switch ($status) {
639  case 'active':
640  $options['relationship'] = 'active_plugin';
641  $options['relationship_guid'] = $site_guid;
642  $options['inverse_relationship'] = true;
643 
644  // shorten callstack
645  $volatile_data_name = 'select:value';
646  $options['select'] = [MetadataTable::DEFAULT_JOIN_ALIAS . '.value'];
647  $options['metadata_names'] = [
649  ];
650  break;
651 
652  case 'inactive':
653  $options['wheres'][] = function (QueryBuilder $qb, $main_alias) use ($site_guid) {
654  $subquery = $qb->subquery('entity_relationships', 'active_er');
655  $subquery->select('active_er.guid_one')
656  ->where($qb->compare('active_er.relationship', '=', 'active_plugin', ELGG_VALUE_STRING))
657  ->andWhere($qb->compare('active_er.guid_two', '=', $site_guid, ELGG_VALUE_GUID));
658 
659  return $qb->compare("{$main_alias}.guid", 'NOT IN', $subquery->getSQL());
660  };
661  break;
662 
663  case 'all':
664  default:
665  break;
666  }
667 
668  $plugins = $this->invoker->call(ELGG_IGNORE_ACCESS, function () use ($options) {
669  return elgg_get_entities($options) ?: [];
670  });
671 
672  $result = $this->orderPluginsByPriority($plugins, $volatile_data_name);
673 
674  if ($status === 'active' && !isset($this->boot_plugins)) {
675  // populate local cache if for some reason this is not set yet
676  $this->setBootPlugins($result, false);
677  }
678 
679  foreach ($plugins as $plugin) {
680  // can't use ElggEntity::cache() as it conflict with metadata preloading
681  $this->cache->save($plugin->getID(), $plugin);
682  }
683 
684  return $result;
685  }
686 
695  protected function orderPluginsByPriority(array $plugins = [], string $volatile_data_name = null): array {
696  $priorities = [];
697  $sorted_plugins = [];
698 
699  foreach ($plugins as $plugin) {
700  $priority = null;
701  if (!empty($volatile_data_name)) {
702  $priority = $plugin->getVolatileData($volatile_data_name);
703  }
704 
705  if (!isset($priority)) {
706  $priority = $plugin->getPriority();
707  }
708 
709  $priorities[$plugin->guid] = (int) $priority;
710  $sorted_plugins[$plugin->guid] = $plugin;
711  }
712 
713  asort($priorities);
714 
715  return array_values(array_replace($priorities, $sorted_plugins));
716  }
717 
730  public function setPriorities(array $order): bool {
732 
733  $plugins = $this->find('all');
734  if (empty($plugins)) {
735  return false;
736  }
737 
738  // reindex to get standard counting. no need to increment by 10.
739  // though we do start with 1
740  $order = array_values($order);
741 
742  /* @var \ElggPlugin[] $missing_plugins */
743  $missing_plugins = [];
744 
745  $priority = 0;
746  foreach ($plugins as $plugin) {
747  if (!$plugin->isEnabled()) {
748  // disabled plugins should not have a priority
749  if ($plugin->getPriority() !== null) {
750  // remove the priority
751  unset($plugin->$name);
752  }
753 
754  continue;
755  }
756 
757  $plugin_id = $plugin->getID();
758 
759  if (!in_array($plugin_id, $order)) {
760  $missing_plugins[] = $plugin;
761  continue;
762  }
763 
764  $priority = array_search($plugin_id, $order) + 1;
765 
766  if (!$plugin->setMetadata($name, $priority)) {
767  return false;
768  }
769  }
770 
771  // set the missing plugins' priorities
772  if (empty($missing_plugins)) {
773  return true;
774  }
775 
776  foreach ($missing_plugins as $plugin) {
777  $priority++;
778  if (!$plugin->setMetadata($name, $priority)) {
779  return false;
780  }
781  }
782 
783  return true;
784  }
785 
791  public function reindexPriorities(): bool {
792  return $this->setPriorities([]);
793  }
794 
803  public function setPriority(\ElggPlugin $plugin, int $priority): int|false {
804  $old_priority = $plugin->getPriority() ?: 1;
805 
807 
808  if (!$plugin->setMetadata($name, $priority)) {
809  return false;
810  }
811 
812  if (!$plugin->guid) {
813  return false;
814  }
815 
817  $qb->where($qb->compare('name', '=', $name, ELGG_VALUE_STRING))
818  ->andWhere($qb->compare('entity_guid', '!=', $plugin->guid, ELGG_VALUE_INTEGER));
819 
820  if ($priority > $old_priority) {
821  $qb->set('value', 'CAST(value AS UNSIGNED) - 1');
822  $qb->andWhere($qb->between('CAST(value AS UNSIGNED)', $old_priority, $priority, ELGG_VALUE_INTEGER));
823  } else {
824  $qb->set('value', 'CAST(value AS UNSIGNED) + 1');
825  $qb->andWhere($qb->between('CAST(value AS UNSIGNED)', $priority, $old_priority, ELGG_VALUE_INTEGER));
826  }
827 
828  if (!$this->db->updateData($qb)) {
829  return false;
830  }
831 
832  return $priority;
833  }
834 }
isActive(string $plugin_id)
Returns if a plugin is active for a current site.
Definition: Plugins.php:383
trait Profilable
Make an object accept a timer.
Definition: Profilable.php:12
static project()
Get the project root (where composer is installed) path with "/".
Definition: Paths.php:25
static table(string $table)
Returns a QueryBuilder for updating data in a given table.
Definition: Update.php:17
getID()
Returns the ID (dir name) of this plugin.
Definition: ElggPlugin.php:139
setMetadata(string $name, $value, string $value_type= '', bool $multiple=false)
Set metadata on this entity.
Definition: ElggEntity.php:383
$plugin
Elgg HTTP request.
Definition: Request.php:17
reindexPriorities()
Reindexes all plugin priorities starting at 1.
Definition: Plugins.php:791
getMaxPriority()
Returns the highest priority of the plugins.
Definition: Plugins.php:360
Plugin class containing helper functions for plugin activation/deactivation, dependency checking capa...
Definition: ElggPlugin.php:17
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
subquery(string $table, string $alias=null)
Creates a new SelectQueryBuilder for join/where sub queries using the DB connection of the primary Qu...
build()
Registers lifecycle events for all active plugins sorted by their priority.
Definition: Plugins.php:405
The Elgg database.
Definition: Database.php:26
$request
Definition: livesearch.php:12
const ELGG_VALUE_INTEGER
Value types.
Definition: constants.php:111
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
Definition: LICENSE.txt:215
const ELGG_VALUE_GUID
Definition: constants.php:113
Events service.
Database abstraction query builder.
getDirsInDir(string $dir=null)
Returns a list of plugin directory names from a base directory.
Definition: Plugins.php:164
boot()
Boot the plugins.
Definition: Plugins.php:457
disable(\ElggPlugin $plugin,\Exception $previous)
Disable a plugin upon exception.
Definition: Plugins.php:580
$plugin_id
Remove all user and plugin settings from the give plugin ID.
Definition: remove.php:8
$config
Advanced site settings, debugging section.
Definition: debugging.php:6
if($who_can_change_language=== 'nobody') elseif($who_can_change_language=== 'admin_only'&&!elgg_is_admin_logged_in()) $options
Definition: language.php:20
if(!$entity instanceof\ElggUser) $data
Definition: attributes.php:13
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:130
exists(string $id)
Returns if a plugin exists in the system.
Definition: Plugins.php:351
setBootPlugins(array $plugins=null, bool $order_plugins=true)
Set the list of active plugins according to the boot data cache.
Definition: Plugins.php:120
orderPluginsByPriority(array $plugins=[], string $volatile_data_name=null)
Sorts plugins by priority.
Definition: Plugins.php:695
const ELGG_SHOW_DISABLED_ENTITIES
Definition: constants.php:132
elgg_get_entities(array $options=[])
Fetches/counts entities or performs a calculation on their properties.
Definition: entities.php:507
ready()
Run plugin ready handlers.
Definition: Plugins.php:505
init()
Initialize plugins.
Definition: Plugins.php:481
foreach($recommendedExtensions as $extension) if(empty(ini_get('session.gc_probability'))||empty(ini_get('session.gc_divisor'))) $db
generateEntities()
Discovers plugins in the plugins_path setting and creates entities for them if they don&#39;t exist...
Definition: Plugins.php:199
compare(string $x, string $comparison, $y=null, string $type=null, bool $case_sensitive=null)
Build value comparison clause.
Views service.
upgrade()
Run plugin upgrade handlers.
Definition: Plugins.php:529
The Elgg cache base class.
Definition: BaseCache.php:9
const PRIORITY_SETTING_NAME
Definition: ElggPlugin.php:19
getLogger()
Returns logger.
Definition: Loggable.php:37
deactivate()
Deactivates the plugin.
Definition: ElggPlugin.php:653
getContextStack()
Returns context stack.
Definition: Request.php:110
setPriority(\ElggPlugin $plugin, int $priority)
Set plugin priority and adjust the priorities of other plugins.
Definition: Plugins.php:803
const ELGG_VALUE_STRING
Definition: constants.php:112
beginTimer(array $keys)
Start the timer (when enabled)
Definition: Profilable.php:43
System messages service.
getPath()
Get the plugin path for this installation, ending with slash.
Definition: Plugins.php:108
getPriority()
Gets the plugin&#39;s load priority.
Definition: ElggPlugin.php:226
setPriorities(array $order)
Reorder plugins to an order specified by the array.
Definition: Plugins.php:730
static fromTable(string $table, string $alias=null)
Returns a QueryBuilder for selecting data from a given table.
Definition: Select.php:18
elgg_add_admin_notice(string $id, string $message)
Write a persistent message to the admin view.
Definition: admin.php:51
shutdown()
Run plugin shutdown handlers.
Definition: Plugins.php:553
$index
Definition: gallery.php:40
Persistent, installation-wide key-value storage.
Definition: Plugins.php:28
static fromId(string $plugin_id, string $path=null)
Load a plugin object from its ID Create a new plugin entity if doesn&#39;t exist.
Definition: ElggPlugin.php:82
find(string $status= 'active')
Returns an ordered list of plugins.
Definition: Plugins.php:617
$id
Generic annotation delete action.
Definition: delete.php:6
$qb
Definition: queue.php:12
$priority
Manages a global stack of strings for sharing information about the current execution context...
Definition: Context.php:27
$views
Definition: item.php:17
endTimer(array $keys)
Ends the timer (when enabled)
Definition: Profilable.php:59
Invocation service.
Definition: Invoker.php:10
__construct(protected BaseCache $cache, protected Database $db, protected SessionManagerService $session_manager, protected EventsService $events, protected Translator $translator, protected ViewsService $views, protected Config $config, protected SystemMessagesService $system_messages, protected Invoker $invoker, Request $request)
Constructor.
Definition: Plugins.php:88