Elgg  Version 4.x
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;
21 
28 class Plugins {
29 
30  use Profilable;
31  use Cacheable;
32  use Loggable;
33 
34  const BUNDLED_PLUGINS = [
35  'activity',
36  'blog',
37  'bookmarks',
38  'ckeditor',
39  'custom_index',
40  'dashboard',
41  'developers',
42  'discussions',
43  'embed',
44  'externalpages',
45  'file',
46  'friends',
47  'friends_collections',
48  'garbagecollector',
49  'groups',
50  'invitefriends',
51  'likes',
52  'members',
53  'messageboard',
54  'messages',
55  'notifications',
56  'pages',
57  'profile',
58  'reportedcontent',
59  'search',
60  'site_notifications',
61  'system_log',
62  'tagcloud',
63  'thewire',
64  'uservalidationbyemail',
65  'web_services',
66  ];
67 
71  protected $boot_plugins;
72 
76  protected $db;
77 
81  protected $session;
82 
86  protected $events;
87 
91  protected $translator;
92 
96  protected $views;
97 
102 
106  protected $config;
107 
111  protected $system_messages;
112 
116  protected $context;
117 
118 
133  public function __construct(
134  \ElggCache $cache,
135  Database $db,
141  Config $config,
144  ) {
145  $this->cache = $cache;
146  $this->db = $db;
147  $this->session = $session;
148  $this->events = $events;
149  $this->translator = $translator;
150  $this->views = $views;
151  $this->private_settings_cache = $private_settings_cache;
152  $this->config = $config;
153  $this->system_messages = $system_messages;
154 
155  $this->context = $request->getContextStack();
156  }
157 
163  public function getPath() {
164  $path = $this->config->plugins_path;
165  if (!$path) {
166  $path = Paths::project() . 'mod/';
167  }
168  return $path;
169  }
170 
179  public function setBootPlugins($plugins, $order_plugins = true) {
180  if (!is_array($plugins)) {
181  unset($this->boot_plugins);
182  return;
183  }
184 
185  // Always (re)set the boot_plugins. This makes sure that even if you have no plugins active this is known to the system.
186  $this->boot_plugins = [];
187 
188  if ($order_plugins) {
190  }
191 
192  foreach ($plugins as $plugin) {
193  if (!$plugin instanceof \ElggPlugin) {
194  continue;
195  }
196 
197  $plugin_id = $plugin->getID();
198  if (!$plugin_id) {
199  continue;
200  }
201 
202  $plugin->registerLanguages();
203 
204  $this->boot_plugins[$plugin_id] = $plugin;
205  $this->cache->save($plugin_id, $plugin);
206  }
207  }
208 
213  public function clear() {
214  $this->cache->clear();
215  }
216 
222  public function invalidate() {
223  $this->cache->invalidate();
224  }
225 
234  public function getDirsInDir($dir = null) {
235  if (!$dir) {
236  $dir = $this->getPath();
237  }
238 
239  if (!is_dir($dir)) {
240  return [];
241  }
242 
243  $handle = opendir($dir);
244  if ($handle === false) {
245  return [];
246  }
247 
248  $plugin_dirs = [];
249  while (($plugin_dir = readdir($handle)) !== false) {
250  // must be directory and not begin with a .
251  if (substr($plugin_dir, 0, 1) !== '.' && is_dir($dir . $plugin_dir)) {
252  $plugin_dirs[] = $plugin_dir;
253  }
254  }
255 
256  sort($plugin_dirs);
257 
258  return $plugin_dirs;
259  }
260 
269  public function generateEntities(): bool {
270 
271  $mod_dir = $this->getPath();
272 
273  // ignore access in case this is called with no admin logged in - needed for creating plugins perhaps?
274  $old_ia = $this->session->setIgnoreAccess(true);
275 
276  // show hidden entities so that we can enable them if appropriate
277  $old_access = $this->session->setDisabledEntityVisibility(true);
278 
279  $known_plugins = $this->find('all');
280  if (empty($known_plugins)) {
281  $known_plugins = [];
282  }
283 
284  // keeps track if reindexing is needed
285  $reindex = false;
286 
287  // map paths to indexes
288  $id_map = [];
289  $latest_priority = -1;
290  foreach ($known_plugins as $i => $plugin) {
291  // if the ID is wrong, delete the plugin because we can never load it.
292  $id = $plugin->getID();
293  if (!$id) {
294  $plugin->delete();
295  unset($known_plugins[$i]);
296  continue;
297  }
298  $id_map[$plugin->getID()] = $i;
299  $plugin->cache();
300 
301  // disabled plugins should have no priority, so no need to check if the priority is incorrect
302  if (!$plugin->isEnabled()) {
303  continue;
304  }
305 
306  $current_priority = $plugin->getPriority();
307  if (($current_priority - $latest_priority) > 1) {
308  $reindex = true;
309  }
310 
311  $latest_priority = $current_priority;
312  }
313 
314  $physical_plugins = $this->getDirsInDir($mod_dir);
315  if (empty($physical_plugins)) {
316  $this->session->setIgnoreAccess($old_ia);
317  $this->session->setDisabledEntityVisibility($old_access);
318 
319  return false;
320  }
321 
322  // check real plugins against known ones
323  foreach ($physical_plugins as $plugin_id) {
324  // is this already in the db?
325  if (array_key_exists($plugin_id, $id_map)) {
326  $index = $id_map[$plugin_id];
327  $plugin = $known_plugins[$index];
328  // was this plugin deleted and its entity disabled?
329  if (!$plugin->isEnabled()) {
330  $plugin->enable();
331  try {
332  $plugin->deactivate();
333  } catch (PluginException $e) {
334  // do nothing
335  }
336  $plugin->setPriority('new');
337  }
338 
339  // remove from the list of plugins to disable
340  unset($known_plugins[$index]);
341  } else {
342  // create new plugin
343  // priority is forced to last in save() if not set.
344  $plugin = \ElggPlugin::fromId($plugin_id);
345  $plugin->cache();
346  }
347  }
348 
349  // everything remaining in $known_plugins needs to be disabled
350  // because they are entities, but their dirs were removed.
351  // don't delete the entities because they hold settings.
352  foreach ($known_plugins as $plugin) {
353  if (!$plugin->isEnabled()) {
354  continue;
355  }
356 
357  $reindex = true;
358 
359  if ($plugin->isActive()) {
360  try {
361  $plugin->deactivate();
362  } catch (PluginException $e) {
363  // do nothing
364  }
365  }
366 
367  // remove the priority.
368  $plugin->removePrivateSetting(\ElggPlugin::PRIORITY_SETTING_NAME);
369 
370  $plugin->disable();
371  }
372 
373  if ($reindex) {
374  $this->reindexPriorities();
375  }
376 
377  $this->session->setIgnoreAccess($old_ia);
378  $this->session->setDisabledEntityVisibility($old_access);
379 
380  return true;
381  }
382 
390  public function cache(\ElggPlugin $plugin) {
391  if (!$plugin->getID()) {
392  return;
393  }
394  $this->cache->save($plugin->getID(), $plugin);
395  }
396 
404  public function invalidateCache($plugin_id) {
405  try {
406  $this->cache->delete($plugin_id);
407  } catch (InvalidArgumentException $ex) {
408  // A plugin must have been deactivated due to missing folder
409  // without proper cleanup
411  }
412  }
413 
421  public function get(string $plugin_id): ?\ElggPlugin {
422  if (!$plugin_id) {
423  return null;
424  }
425 
426  $fallback = function () use ($plugin_id) {
428  'type' => 'object',
429  'subtype' => 'plugin',
430  'metadata_name_value_pairs' => [
431  'name' => 'title',
432  'value' => $plugin_id,
433  ],
434  'limit' => 1,
435  'distinct' => false,
436  ]);
437 
438  if ($plugins) {
439  return $plugins[0];
440  }
441 
442  return null;
443  };
444 
445  $plugin = $this->cache->load($plugin_id);
446  if (!isset($plugin)) {
447  $plugin = $fallback();
448  if ($plugin instanceof \ElggPlugin) {
449  $plugin->cache();
450  }
451  }
452 
453  return $plugin;
454  }
455 
467  public function exists(string $id): bool {
468  return $this->get($id) instanceof \ElggPlugin;
469  }
470 
476  public function getMaxPriority() {
477  $qb = Select::fromTable('entities', 'e');
478  $qb->select('MAX(CAST(ps.value AS unsigned)) as max')
479  ->join('e', 'private_settings', 'ps', 'e.guid = ps.entity_guid')
480  ->where($qb->compare('ps.name', '=', \ElggPlugin::PRIORITY_SETTING_NAME, ELGG_VALUE_STRING))
481  ->andWhere($qb->compare('e.type', '=', 'object', ELGG_VALUE_STRING))
482  ->andWhere($qb->compare('e.subtype', '=', 'plugin', ELGG_VALUE_STRING));
483 
484  $data = $this->db->getDataRow($qb);
485  if (empty($data)) {
486  return 1;
487  }
488 
489  return max(1, (int) $data->max);
490  }
491 
499  public function isActive(string $plugin_id): bool {
500  if (isset($this->boot_plugins) && is_array($this->boot_plugins)) {
501  return array_key_exists($plugin_id, $this->boot_plugins);
502  }
503 
504  $plugin = $this->get($plugin_id);
505  if (!$plugin) {
506  return false;
507  }
508 
509  return check_entity_relationship($plugin->guid, 'active_plugin', 1) instanceof \ElggRelationship;
510  }
511 
521  public function build() {
522 
523  $plugins_path = $this->getPath();
524 
525  // temporary disable all plugins if there is a file called 'disabled' in the plugin dir
526  if (file_exists("$plugins_path/disabled")) {
527  if ($this->session->isAdminLoggedIn() && $this->context->contains('admin')) {
528  $this->system_messages->addSuccessMessage($this->translator->translate('plugins:disabled'));
529  }
530 
531  return false;
532  }
533 
534  $this->events->registerHandler('plugins_load', 'system', [$this, 'register']);
535  $this->events->registerHandler('plugins_boot:before', 'system', [$this, 'boot']);
536  $this->events->registerHandler('init', 'system', [$this, 'init']);
537  $this->events->registerHandler('ready', 'system', [$this, 'ready']);
538  $this->events->registerHandler('upgrade', 'system', [$this, 'upgrade']);
539  $this->events->registerHandler('shutdown', 'system', [$this, 'shutdown']);
540 
541  return true;
542  }
543 
551  public function register() {
552  $plugins = $this->find('active');
553  if (empty($plugins)) {
554  return;
555  }
556 
557  $this->beginTimer([__METHOD__]);
558 
559  /* @var $plugin \ElggPlugin */
560  foreach ($plugins as $plugin) {
561  try {
562  $plugin->register();
563  } catch (\Exception $ex) {
564  $this->disable($plugin, $ex);
565  }
566  }
567 
568  $this->endTimer([__METHOD__]);
569  }
570 
577  public function boot() {
578  $plugins = $this->find('active');
579  if (empty($plugins)) {
580  return;
581  }
582 
583  $this->beginTimer([__METHOD__]);
584 
585  foreach ($plugins as $plugin) {
586  try {
587  $plugin->boot();
588  } catch (\Exception $ex) {
589  $this->disable($plugin, $ex);
590  }
591  }
592 
593  $this->endTimer([__METHOD__]);
594  }
595 
602  public function init() {
603  $plugins = $this->find('active');
604  if (empty($plugins)) {
605  return;
606  }
607 
608  $this->beginTimer([__METHOD__]);
609 
610  foreach ($plugins as $plugin) {
611  try {
612  $plugin->init();
613  } catch (\Exception $ex) {
614  $this->disable($plugin, $ex);
615  }
616  }
617 
618  $this->endTimer([__METHOD__]);
619  }
620 
627  public function ready() {
628  $plugins = $this->find('active');
629  if (empty($plugins)) {
630  return;
631  }
632 
633  $this->beginTimer([__METHOD__]);
634 
635  foreach ($plugins as $plugin) {
636  try {
637  $plugin->getBootstrap()->ready();
638  } catch (\Exception $ex) {
639  $this->disable($plugin, $ex);
640  }
641  }
642 
643  $this->endTimer([__METHOD__]);
644  }
645 
652  public function upgrade() {
653  $plugins = $this->find('active');
654  if (empty($plugins)) {
655  return;
656  }
657 
658  $this->beginTimer([__METHOD__]);
659 
660  foreach ($plugins as $plugin) {
661  try {
662  $plugin->getBootstrap()->upgrade();
663  } catch (\Exception $ex) {
664  $this->disable($plugin, $ex);
665  }
666  }
667 
668  $this->endTimer([__METHOD__]);
669  }
670 
677  public function shutdown() {
678  $plugins = $this->find('active');
679  if (empty($plugins)) {
680  return;
681  }
682 
683  $this->beginTimer([__METHOD__]);
684 
685  foreach ($plugins as $plugin) {
686  try {
687  $plugin->getBootstrap()->shutdown();
688  } catch (\Exception $ex) {
689  $this->disable($plugin, $ex);
690  }
691  }
692 
693  $this->endTimer([__METHOD__]);
694  }
695 
704  protected function disable(\ElggPlugin $plugin, \Exception $previous) {
705  $this->getLogger()->log(LogLevel::ERROR, $previous, [
706  'context' => [
707  'plugin' => $plugin,
708  ],
709  ]);
710 
711  $disable_plugins = $this->config->auto_disable_plugins;
712  if ($disable_plugins === null) {
713  $disable_plugins = true;
714  }
715 
716  if (!$disable_plugins) {
717  return;
718  }
719 
720  try {
721  $id = $plugin->getID();
722  $plugin->deactivate();
723 
724  $msg = $this->translator->translate(
725  'PluginException:CannotStart',
726  [$id, $plugin->guid, $previous->getMessage()]
727  );
728 
729  elgg_add_admin_notice("cannot_start $id", $msg);
730  } catch (PluginException $ex) {
731  $this->getLogger()->log(LogLevel::ERROR, $ex, [
732  'context' => [
733  'plugin' => $plugin,
734  ],
735  ]);
736  }
737  }
738 
746  public function find(string $status = 'active'): array {
747  if (!$this->db || !$this->config->installed) {
748  return [];
749  }
750 
751  if ($status === 'active' && isset($this->boot_plugins)) {
752  // boot_plugins is an already ordered list of plugins
753  return array_values($this->boot_plugins);
754  }
755 
756  $volatile_data_name = null;
757  $site_guid = 1;
758 
759  // grab plugins
760  $options = [
761  'type' => 'object',
762  'subtype' => 'plugin',
763  'limit' => false,
764  // ORDER BY CAST(ps.value) is super slow. We custom sorting below.
765  'order_by' => false,
766  // preload private settings because private settings will probably be used, at least priority
767  'preload_private_settings' => true,
768  ];
769 
770  switch ($status) {
771  case 'active':
772  $options['relationship'] = 'active_plugin';
773  $options['relationship_guid'] = $site_guid;
774  $options['inverse_relationship'] = true;
775 
776  // shorten callstack
777  $volatile_data_name = 'select:value';
778  $options['select'] = ['ps.value'];
779  $options['private_setting_names'] = [
781  ];
782  break;
783 
784  case 'inactive':
785  $options['wheres'][] = function (QueryBuilder $qb, $main_alias) use ($site_guid) {
786  $subquery = $qb->subquery('entity_relationships', 'active_er');
787  $subquery->select('active_er.guid_one')
788  ->where($qb->compare('active_er.relationship', '=', 'active_plugin', ELGG_VALUE_STRING))
789  ->andWhere($qb->compare('active_er.guid_two', '=', $site_guid, ELGG_VALUE_GUID));
790 
791  return $qb->compare("{$main_alias}.guid", 'NOT IN', $subquery->getSQL());
792  };
793  break;
794 
795  case 'all':
796  default:
797  break;
798  }
799 
800  $old_ia = $this->session->setIgnoreAccess(true);
802  $this->session->setIgnoreAccess($old_ia);
803 
804  $result = $this->orderPluginsByPriority($plugins, $volatile_data_name);
805 
806  if ($status === 'active' && !isset($this->boot_plugins)) {
807  // populate local cache if for some reason this is not set yet
808  $this->setBootPlugins($result, false);
809  }
810 
811  return $result;
812  }
813 
822  protected function orderPluginsByPriority($plugins = [], $volatile_data_name = null) {
823  $priorities = [];
824  $sorted_plugins = [];
825 
826  foreach ($plugins as $plugin) {
827  $priority = null;
828  if (!empty($volatile_data_name)) {
829  $priority = $plugin->getVolatileData($volatile_data_name);
830  }
831 
832  if (!isset($priority)) {
833  $priority = $plugin->getPriority();
834  }
835 
836  $priorities[$plugin->guid] = (int) $priority;
837  $sorted_plugins[$plugin->guid] = $plugin;
838  }
839 
840  asort($priorities);
841 
842  return array_values(array_replace($priorities, $sorted_plugins));
843  }
844 
857  public function setPriorities(array $order) {
859 
860  $plugins = $this->find('any');
861  if (empty($plugins)) {
862  return false;
863  }
864 
865  // reindex to get standard counting. no need to increment by 10.
866  // though we do start with 1
867  $order = array_values($order);
868 
869  /* @var \ElggPlugin[] $missing_plugins */
870  $missing_plugins = [];
871 
872  $priority = 0;
873  foreach ($plugins as $plugin) {
874  if (!$plugin->isEnabled()) {
875  // disabled plugins should not have a priority
876  if ($plugin->getPriority() !== null) {
877  // remove the priority
878  $plugin->removePrivateSetting($name);
879  }
880  continue;
881  }
882 
883  $plugin_id = $plugin->getID();
884 
885  if (!in_array($plugin_id, $order)) {
886  $missing_plugins[] = $plugin;
887  continue;
888  }
889 
890  $priority = array_search($plugin_id, $order) + 1;
891 
892  if (!$plugin->setPrivateSetting($name, $priority)) {
893  return false;
894  }
895  }
896 
897  // set the missing plugins' priorities
898  if (empty($missing_plugins)) {
899  return true;
900  }
901 
902  foreach ($missing_plugins as $plugin) {
903  $priority++;
904  if (!$plugin->setPrivateSetting($name, $priority)) {
905  return false;
906  }
907  }
908 
909  return true;
910  }
911 
917  public function reindexPriorities() {
918  return $this->setPriorities([]);
919  }
920 
930 
931  $old_priority = $plugin->getPriority() ? : 1;
932 
934 
935  if (!$plugin->setPrivateSetting($name, $priority)) {
936  return false;
937  }
938 
939  if (!$plugin->guid) {
940  return false;
941  }
942 
943  $qb = Update::table('private_settings');
944  $qb->where($qb->compare('name', '=', $name, ELGG_VALUE_STRING))
945  ->andWhere($qb->compare('entity_guid', '!=', $plugin->guid, ELGG_VALUE_INTEGER));
946 
947  if ($priority > $old_priority) {
948  $qb->set('value', "CAST(value AS UNSIGNED) - 1");
949  $qb->andWhere($qb->between('CAST(value AS UNSIGNED)', $old_priority, $priority, ELGG_VALUE_INTEGER));
950  } else {
951  $qb->set('value', "CAST(value AS UNSIGNED) + 1");
952  $qb->andWhere($qb->between('CAST(value AS UNSIGNED)', $priority, $old_priority, ELGG_VALUE_INTEGER));
953  }
954 
955  if (!$this->db->updateData($qb)) {
956  return false;
957  }
958 
959  return $priority;
960  }
961 }
isActive(string $plugin_id)
Returns if a plugin is active for a current site.
Definition: Plugins.php:499
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
getID()
Returns the ID (dir name) of this plugin.
Definition: ElggPlugin.php:137
$plugin
Elgg HTTP request.
Definition: Request.php:17
reindexPriorities()
Reindexes all plugin priorities starting at 1.
Definition: Plugins.php:917
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
Base exception of invalid argument exceptions in the Elgg system.
getMaxPriority()
Returns the highest priority of the plugins.
Definition: Plugins.php:476
static table($table, $alias=null)
{}
Definition: Update.php:13
setPrivateSetting($name, $value)
Adds a private setting to this entity.
Definition: ElggEntity.php:608
build()
Registers lifecycle hooks for all active plugins sorted by their priority.
Definition: Plugins.php:521
The Elgg database.
Definition: Database.php:24
$request
Definition: livesearch.php:11
const ELGG_VALUE_INTEGER
Value types.
Definition: constants.php:126
const ELGG_VALUE_GUID
Definition: constants.php:128
Events service.
if(elgg_trigger_plugin_hook('usersettings:save', 'user', $hooks_params, true)) foreach($request->validation() ->all() as $item) $data
Definition: save.php:53
Database abstraction query builder.
$plugins
Definition: categories.php:3
boot()
Boot the plugins.
Definition: Plugins.php:577
invalidate()
Invalidate plugin cache.
Definition: Plugins.php:222
getDirsInDir($dir=null)
Returns a list of plugin directory names from a base directory.
Definition: Plugins.php:234
$options
Elgg admin footer.
Definition: footer.php:6
disable(\ElggPlugin $plugin,\Exception $previous)
Disable a plugin upon exception.
Definition: Plugins.php:704
$plugin_id
Remove all user and plugin settings from the give plugin ID.
Definition: remove.php:8
elgg_invalidate_caches()
Invalidate all the registered caches.
Definition: cache.php:183
$path
Definition: details.php:68
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
exists(string $id)
Returns if a plugin exists in the system.
Definition: Plugins.php:467
orderPluginsByPriority($plugins=[], $volatile_data_name=null)
Sorts plugins by priority.
Definition: Plugins.php:822
elgg_get_entities(array $options=[])
Fetches/counts entities or performs a calculation on their properties.
Definition: entities.php:545
ready()
Run plugin ready handlers.
Definition: Plugins.php:627
init()
Initialize plugins.
Definition: Plugins.php:602
In memory cache of known private settings values stored by entity.
generateEntities()
Discovers plugins in the plugins_path setting and creates entities for them if they don&#39;t exist...
Definition: Plugins.php:269
setBootPlugins($plugins, $order_plugins=true)
Set the list of active plugins according to the boot data cache.
Definition: Plugins.php:179
__construct(\ElggCache $cache, Database $db,\ElggSession $session, EventsService $events, Translator $translator, ViewsService $views, PrivateSettingsCache $private_settings_cache, Config $config, SystemMessagesService $system_messages, Request $request)
Constructor.
Definition: Plugins.php:133
compare($x, $comparison, $y=null, $type=null, $case_sensitive=null)
Build value comparison clause.
Views service.
upgrade()
Run plugin upgrade handlers.
Definition: Plugins.php:652
check_entity_relationship($guid_one, $relationship, $guid_two)
Check if a relationship exists between two entities.
clear()
Clear plugin caches.
Definition: Plugins.php:213
invalidateCache($plugin_id)
Remove plugin from cache.
Definition: Plugins.php:404
const PRIORITY_SETTING_NAME
Definition: ElggPlugin.php:17
subquery($table, $alias=null)
Creates a new SelectQueryBuilder for join/where subqueries using the DB connection of the primary Que...
static fromTable($table, $alias=null)
{}
Definition: Select.php:13
getLogger()
Returns logger.
Definition: Loggable.php:37
deactivate()
Deactivates the plugin.
Definition: ElggPlugin.php:711
getContextStack()
Returns context stack.
Definition: Request.php:102
const ELGG_VALUE_STRING
Definition: constants.php:127
beginTimer(array $keys)
Start the timer (when enabled)
Definition: Profilable.php:46
System messages service.
getPath()
Get the plugin path for this installation, ending with slash.
Definition: Plugins.php:163
getPriority()
Gets the plugin&#39;s load priority.
Definition: ElggPlugin.php:224
setPriorities(array $order)
Reorder plugins to an order specified by the array.
Definition: Plugins.php:857
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:677
$index
Definition: gallery.php:40
Persistent, installation-wide key-value storage.
Definition: Plugins.php:28
cache(\ElggPlugin $plugin)
Cache a reference to this plugin by its ID.
Definition: Plugins.php:390
find(string $status= 'active')
Returns an ordered list of plugins.
Definition: Plugins.php:746
$id
Generic annotation delete action.
Definition: delete.php:6
$qb
Definition: queue.php:11
static fromId($plugin_id, $path=null)
Load a plugin object from its ID Create a new plugin entity if doesn&#39;t exist.
Definition: ElggPlugin.php:80
trait Cacheable
Utility trait for injecting cache.
Definition: Cacheable.php:13
$priority
endTimer(array $keys)
Ends the timer (when enabled)
Definition: Profilable.php:62
setPriority(\ElggPlugin $plugin, $priority)
Set plugin priority and adjust the priorities of other plugins.
Definition: Plugins.php:929