Elgg  Version 5.1
ElggPlugin.php
Go to the documentation of this file.
1 <?php
2 
8 use Elgg\Includer;
11 
16 class ElggPlugin extends ElggObject {
17 
18  const PRIORITY_SETTING_NAME = 'elgg:internal:priority';
19  const STATIC_CONFIG_FILENAME = 'elgg-plugin.php';
20  const PUBLIC_SERVICES_FILENAME = 'elgg-services.php';
21 
22  use ElggLoggable;
23 
30  'README.txt',
31  'CHANGES.txt',
32  'INSTALL.txt',
33  'COPYRIGHT.txt',
34  'LICENSE.txt',
35  'README',
36  'README.md',
37  'README.markdown',
38  ];
39 
43  protected $composer;
44 
48  protected $path;
49 
55  protected $static_config;
56 
60  protected $activated;
61 
65  protected function initializeAttributes() {
66  parent::initializeAttributes();
67 
68  $this->attributes['subtype'] = 'plugin';
69  }
70 
81  public static function fromId(string $plugin_id, string $path = null): \ElggPlugin {
82  if (empty($plugin_id)) {
83  throw new ElggInvalidArgumentException('Plugin ID must be set');
84  }
85 
86  $plugin = elgg_get_plugin_from_id($plugin_id);
87  if (!$plugin) {
88  $plugin = elgg_call(ELGG_IGNORE_ACCESS, function() use ($plugin_id) {
89  $plugin = new ElggPlugin();
90  $plugin->title = $plugin_id;
91  $plugin->save();
92 
93  return $plugin;
94  });
95  }
96 
97  if (empty($path)) {
99  }
100 
101  $path = Paths::sanitize($path);
102  $plugin->setPath($path . $plugin_id);
103 
104  return $plugin;
105  }
106 
110  public function save(): bool {
111 
113 
114  $this->attributes['owner_guid'] = $site->guid;
115  $this->attributes['container_guid'] = $site->guid;
116  $this->attributes['access_id'] = ACCESS_PUBLIC;
117 
118  $new = !$this->guid;
119  $priority = null;
120  if ($new) {
121  $priority = elgg_extract(self::PRIORITY_SETTING_NAME, $this->temp_metadata, 'new');
122  } elseif ($this->getPriority() === null) {
123  $priority = 'last';
124  }
125 
126  if ($priority) {
127  $this->setPriority($priority);
128  }
129 
130  return parent::save();
131  }
132 
138  public function getID(): string {
139  return (string) $this->title;
140  }
141 
148  public function getDisplayName(): string {
149  $name = elgg_extract('name', $this->getStaticConfig('plugin', []), '');
150  if (!empty($name)) {
151  return $name;
152  }
153 
154  return ucwords(str_replace(['-', '_'], ' ', $this->getID()));
155  }
156 
165  public function setPath(string $path): void {
166  $this->path = Paths::sanitize($path, true);
167  }
168 
174  public function getPath(): string {
175  if (isset($this->path)) {
176  return $this->path;
177  }
178 
179  $this->setPath(elgg_get_plugins_path() . $this->getID());
180  return $this->path;
181  }
182 
189  protected function getLanguagesPath(): string {
190  return $this->getPath() . 'languages/';
191  }
192 
204  public function getStaticConfig(string $key, $default = null) {
205  if ($this->static_config === null) {
206  $this->static_config = [];
207 
208  try {
209  $this->static_config = $this->includeFile(self::STATIC_CONFIG_FILENAME);
210  } catch (PluginException $ex) {
211  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
212  }
213  }
214 
215  return $this->static_config[$key] ?? $default;
216  }
217 
218  // Load Priority
219 
225  public function getPriority(): ?int {
226  $priority = $this->getMetadata(self::PRIORITY_SETTING_NAME);
227  if (isset($priority)) {
228  return (int) $priority;
229  }
230 
231  return null;
232  }
233 
245  public function setPriority($priority): int|false {
247 
248  return _elgg_services()->plugins->setPriority($this, $priority);
249  }
250 
259  protected function normalizePriority($priority): int {
260  // if no priority assume a priority of 1
261  $old_priority = $this->getPriority();
262  $old_priority = $old_priority ?: 1;
263  $max_priority = _elgg_services()->plugins->getMaxPriority() ?: 1;
264 
265  // can't use switch here because it's not strict and php evaluates +1 == 1
266  if ($priority === '+1') {
267  $priority = $old_priority + 1;
268  } else if ($priority === '-1') {
269  $priority = $old_priority - 1;
270  } else if ($priority === 'first') {
271  $priority = 1;
272  } else if ($priority === 'last') {
273  $priority = $max_priority;
274  } else if ($priority === 'new') {
275  $max_priority++;
276  $priority = $max_priority;
277  }
278 
279  return min($max_priority, max(1, (int) $priority));
280  }
281 
282  // Plugin settings
283 
292  public function getSetting(string $name, $default = null) {
293  $values = $this->getAllSettings();
294  return elgg_extract($name, $values, $default);
295  }
296 
304  public function getAllSettings(): array {
305 
306  try {
307  $defaults = [];
308  if ($this->isActive()) {
309  // only load settings from static config for active plugins to prevent issues
310  // with internal plugin references ie. classes and language keys
311  $defaults = $this->getStaticConfig('settings', []);
312  }
313 
314  $settings = $this->getAllMetadata();
315 
316  // title and description are not considered settings
317  unset($settings['title'], $settings['description']);
318 
319  return array_merge($defaults, $settings);
320  } catch (DatabaseException $ex) {
321  return [];
322  }
323  }
324 
333  public function setSetting(string $name, $value): bool {
334 
335  $value = _elgg_services()->events->triggerResults('setting', 'plugin', [
336  'plugin_id' => $this->getID(),
337  'plugin' => $this,
338  'name' => $name,
339  'value' => $value,
340  ], $value);
341 
342  if (is_array($value)) {
343  elgg_log('Plugin settings cannot store arrays.', 'ERROR');
344 
345  return false;
346  }
347 
348  return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) {
349  return $this->setMetadata($name, $value);
350  });
351  }
352 
360  public function unsetSetting(string $name): bool {
361  return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) {
362  return (bool) $this->deleteMetadata($name);
363  });
364  }
365 
370  public function unsetAllSettings(): bool {
371  $settings = $this->getAllSettings();
372 
373  foreach ($settings as $name => $value) {
374  if (str_starts_with($name, 'elgg:internal:')) {
375  continue;
376  }
377 
378  $this->unsetSetting($name);
379  }
380 
381  return true;
382  }
383 
390  public function unsetAllEntityAndPluginSettings(): bool {
391  // remove all plugin settings
392  $result = $this->unsetAllSettings();
393 
394  // entity plugin settings are stored with the entity
395  $delete = Delete::fromTable('metadata');
396  $delete->andWhere($delete->compare('name', 'like', "plugin:%_setting:{$this->getID()}:%", ELGG_VALUE_STRING));
397 
398  try {
399  _elgg_services()->db->deleteData($delete);
400  _elgg_services()->dataCache->metadata->clear();
401 
402  $result &= true;
403  } catch (DatabaseException $e) {
404  elgg_log($e, 'ERROR');
405 
406  $result &= false;
407  }
408 
409  // trigger an event, so plugin devs can also remove settings
410  $params = [
411  'entity' => $this,
412  ];
413  return (bool) _elgg_services()->events->triggerResults('remove:settings', 'plugin', $params, $result);
414  }
415 
422  public function isValid(): bool {
423  try {
424  $this->assertValid();
425  return true;
426  } catch (PluginException $e) {
427  return false;
428  }
429  }
430 
439  public function assertValid(): void {
440  if (!$this->getID()) {
441  throw PluginException::factory([
442  'message' => elgg_echo('ElggPlugin:MissingID', [$this->guid]),
443  'plugin' => $this,
444  ]);
445  }
446 
447  $this->getComposer()->assertPluginId();
448 
449  if (file_exists($this->getPath() . 'start.php')) {
450  throw PluginException::factory([
451  'message' => elgg_echo('ElggPlugin:StartFound', [$this->getID()]),
452  'plugin' => $this,
453  ]);
454  }
455  }
456 
462  public function isActive(): bool {
463  if (isset($this->activated)) {
464  return $this->activated;
465  }
466 
467  $this->activated = elgg_is_active_plugin($this->getID());
468  return $this->activated;
469  }
470 
477  public function canActivate(): bool {
478  if ($this->isActive()) {
479  return false;
480  }
481 
482  try {
483  $this->assertCanActivate();
484  return true;
485  } catch (PluginException $e) {
486  return false;
487  }
488  }
489 
498  public function assertCanActivate(): void {
499  $this->assertValid();
500  $this->assertDependencies();
501  }
502 
503  // activating and deactivating
504 
511  public function activate(): bool {
512  if ($this->isActive()) {
513  return false;
514  }
515 
516  $this->assertCanActivate();
517 
518  // Check this before setting status because the file could potentially throw
519  $this->assertStaticConfigValid();
520 
521  if (!$this->setStatus(true)) {
522  return false;
523  }
524 
525  // perform tasks and emit events
526  // emit an event. returning false will make this not be activated.
527  // we need to do this after it's been fully activated
528  // or the deactivate will be confused.
529  $params = [
530  'plugin_id' => $this->getID(),
531  'plugin_entity' => $this,
532  ];
533 
534  $return = _elgg_services()->events->trigger('activate', 'plugin', $params);
535 
536  // if there are any on_enable functions, start the plugin now and run them
537  // Note: this will not run re-run the init events!
538  if ($return) {
539  try {
541 
542  $this->register();
543 
544  // directly load languages to have them available during runtime
545  $this->loadLanguages();
546 
547  $this->boot();
548 
549  $this->getBootstrap()->activate();
550 
551  $this->init();
552  } catch (PluginException $ex) {
553  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
554 
555  $return = false;
556  }
557  }
558 
559  if ($return === false) {
560  $this->deactivate();
561  } else {
562  elgg_delete_admin_notice("cannot_start {$this->getID()}");
563 
565  _elgg_services()->logger->notice("Plugin {$this->getID()} has been activated");
566  }
567 
568  return $return;
569  }
570 
576  public function getDependencies(): array {
577  $plugin_config = $this->getStaticConfig('plugin', []);
578  return (array) elgg_extract('dependencies', $plugin_config, []);
579  }
580 
588  public function canDeactivate(): bool {
589  if (!$this->isActive()) {
590  return false;
591  }
592 
593  try {
594  $this->assertcanDeactivate();
595  return true;
596  } catch (PluginException $e) {
597  return false;
598  }
599  }
600 
609  public function assertCanDeactivate(): void {
610  $dependents = [];
611 
612  $active_plugins = elgg_get_plugins();
613 
614  foreach ($active_plugins as $plugin) {
615  $dependencies = $plugin->getDependencies();
616  if (!array_key_exists($this->getID(), $dependencies)) {
617  continue;
618  }
619 
620  if (elgg_extract('must_be_active', $dependencies[$this->getID()], true)) {
621  $dependents[$plugin->getID()] = $plugin;
622  }
623  }
624 
625  if (empty($dependents)) {
626  return;
627  }
628 
629  $list = array_map(function (\ElggPlugin $plugin) {
630  $css_id = preg_replace('/[^a-z0-9-]/i', '-', $plugin->getID());
631 
632  return elgg_view('output/url', [
633  'text' => $plugin->getDisplayName(),
634  'href' => "#{$css_id}",
635  ]);
636  }, $dependents);
637 
638  $list = implode(', ', $list);
639  throw PluginException::factory([
640  'message' => elgg_echo('ElggPlugin:Dependencies:ActiveDependent', [$this->getDisplayName(), $list]),
641  'plugin' => $this,
642  ]);
643  }
644 
652  public function deactivate(): bool {
653  if (!$this->isActive()) {
654  return false;
655  }
656 
657  $this->assertCanDeactivate();
658 
659  // emit an event. returning false will cause this to not be deactivated.
660  $params = [
661  'plugin_id' => $this->getID(),
662  'plugin_entity' => $this,
663  ];
664 
665  $return = _elgg_services()->events->trigger('deactivate', 'plugin', $params);
666  if ($return === false) {
667  return false;
668  }
669 
670  $this->getBootstrap()->deactivate();
671 
672  $this->deactivateEntities();
673 
675 
676  _elgg_services()->logger->notice("Plugin {$this->getID()} has been deactivated");
677 
678  return $this->setStatus(false);
679  }
680 
689  public function getBootstrap(): \Elgg\PluginBootstrapInterface {
690  $bootstrap = $this->getStaticConfig('bootstrap');
691  if ($bootstrap) {
692  if (!is_subclass_of($bootstrap, \Elgg\PluginBootstrapInterface::class)) {
693  throw PluginException::factory([
694  'message' => elgg_echo('LogicException:InterfaceNotImplemented', [
695  $bootstrap,
696  \Elgg\PluginBootstrapInterface::class
697  ]),
698  'plugin' => $this,
699  ]);
700  }
701 
702  return new $bootstrap($this, elgg());
703  }
704 
705  return new \Elgg\DefaultPluginBootstrap($this, elgg());
706  }
707 
714  public function autoload(): void {
715  $this->registerClasses();
716 
717  $autoload_file = 'vendor/autoload.php';
718  if (!$this->canReadFile($autoload_file)) {
719  return;
720  }
721 
722  $autoloader = Includer::requireFileOnce("{$this->getPath()}{$autoload_file}");
723 
724  if (!$autoloader instanceof \Composer\Autoload\ClassLoader) {
725  return;
726  }
727 
728  $autoloader->unregister();
729 
730  // plugins should be appended, composer defaults to prepend
731  $autoloader->register(false);
732  }
733 
742  public function register(): void {
743  $this->autoload();
744 
745  $this->registerPublicServices();
746  $this->activateEntities();
747  $this->registerLanguages();
748  $this->registerViews();
749 
750  $this->getBootstrap()->load();
751  }
752 
759  public function boot(): void {
760  $this->getBootstrap()->boot();
761  }
762 
769  public function init(): void {
770  $this->registerRoutes();
771  $this->registerActions();
772  $this->registerEntities();
773  $this->registerWidgets();
774  $this->registerHooks();
775  $this->registerEvents();
776  $this->registerViewExtensions();
777  $this->registerGroupTools();
778  $this->registerViewOptions();
779  $this->registerNotifications();
780 
781  $this->getBootstrap()->init();
782  }
783 
792  protected function includeFile(string $filename) {
793  $filepath = "{$this->getPath()}{$filename}";
794 
795  if (!$this->canReadFile($filename)) {
796  $msg = elgg_echo(
797  'ElggPlugin:Exception:CannotIncludeFile',
798  [$filename, $this->getID(), $this->guid, $this->getPath()]
799  );
800 
801  throw PluginException::factory([
802  'message' => $msg,
803  'plugin' => $this,
804  ]);
805  }
806 
807  try {
808  $ret = Includer::requireFile($filepath);
809  } catch (Exception $e) {
810  $msg = elgg_echo(
811  'ElggPlugin:Exception:IncludeFileThrew',
812  [$filename, $this->getID(), $this->guid, $this->getPath()]
813  );
814 
815  throw PluginException::factory([
816  'message' => $msg,
817  'previous' => $e,
818  'plugin' => $this,
819  ]);
820  }
821 
822  return $ret;
823  }
824 
832  protected function canReadFile(string $filename): bool {
833  return is_file("{$this->getPath()}{$filename}");
834  }
835 
842  protected function assertStaticConfigValid(): void {
843  if (!$this->canReadFile(self::STATIC_CONFIG_FILENAME)) {
844  return;
845  }
846 
847  ob_start();
848  $value = $this->includeFile(self::STATIC_CONFIG_FILENAME);
849  if (ob_get_clean() !== '') {
850  throw PluginException::factory([
851  'message' => elgg_echo('ElggPlugin:activate:ConfigSentOutput'),
852  'plugin' => $this,
853  ]);
854  }
855 
856  // make sure can serialize
857  $value = @unserialize(serialize($value));
858  if (!is_array($value)) {
859  throw PluginException::factory([
860  'message' => elgg_echo('ElggPlugin:activate:BadConfigFormat'),
861  'plugin' => $this,
862  ]);
863  }
864  }
865 
871  protected function registerPublicServices(): void {
872  $services_path = $this->getPath() . self::PUBLIC_SERVICES_FILENAME;
873  if (!is_file($services_path)) {
874  return;
875  }
876 
877  $services = Includer::includeFile($services_path);
878  foreach ($services as $name => $definition) {
879  elgg()->set($name, $definition);
880  }
881  }
882 
889  protected function registerViews(): void {
890  if (_elgg_services()->config->system_cache_loaded) {
891  return;
892  }
893 
894  $views = _elgg_services()->views;
895 
896  // Declared views first
897  $spec = $this->getStaticConfig('views');
898  if ($spec) {
899  $views->mergeViewsSpec($spec);
900  }
901 
902  // Allow /views directory files to override
903  if (!$views->registerPluginViews($this->getPath())) {
904  $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews', [$this->getID(), $this->guid, $this->getPath()]);
905 
906  throw PluginException::factory([
907  'message' => $msg,
908  'plugin' => $this,
909  ]);
910  }
911  }
912 
918  protected function registerEntities(): void {
919  $spec = (array) $this->getStaticConfig('entities', []);
920 
921  foreach ($spec as $entity) {
922  if (!isset($entity['type']) || !isset($entity['subtype'])) {
923  continue;
924  }
925 
926  $capabilities = elgg_extract('capabilities', $entity, []);
927  foreach ($capabilities as $capability => $value) {
928  _elgg_services()->entity_capabilities->setCapability($entity['type'], $entity['subtype'], $capability, $value);
929  }
930  }
931  }
932 
938  protected function registerActions(): void {
939  $actions = _elgg_services()->actions;
940  $root_path = $this->getPath();
941 
942  $spec = (array) $this->getStaticConfig('actions', []);
943 
944  foreach ($spec as $action => $action_spec) {
945  if (!is_array($action_spec)) {
946  continue;
947  }
948 
949  $access = elgg_extract('access', $action_spec, 'logged_in');
950  $handler = elgg_extract('controller', $action_spec);
951  if (!$handler) {
952  $handler = elgg_extract('filename', $action_spec);
953  if (!$handler) {
954  $handler = "{$root_path}actions/{$action}.php";
955  }
956  }
957 
958  // unset handled action specs, pass the rest to the action service
959  unset($action_spec['access']);
960  unset($action_spec['controller']);
961  unset($action_spec['filename']);
962 
963  $actions->register($action, $handler, $access, $action_spec);
964  }
965  }
966 
972  protected function registerRoutes(): void {
973  $routes = _elgg_services()->routes;
974 
975  $spec = (array) $this->getStaticConfig('routes', []);
976  foreach ($spec as $name => $route_spec) {
977  if (!is_array($route_spec)) {
978  continue;
979  }
980 
981  $routes->register($name, $route_spec);
982  }
983  }
984 
990  protected function registerWidgets(): void {
991  $widgets = _elgg_services()->widgets;
992 
993  $spec = (array) $this->getStaticConfig('widgets', []);
994  foreach ($spec as $widget_id => $widget_definition) {
995  if (!is_array($widget_definition)) {
996  continue;
997  }
998 
999  if (!isset($widget_definition['id'])) {
1000  $widget_definition['id'] = $widget_id;
1001  }
1002 
1003  $definition = \Elgg\WidgetDefinition::factory($widget_definition);
1004 
1005  $widgets->registerType($definition);
1006  }
1007  }
1008 
1016  public function registerLanguages(): void {
1017  _elgg_services()->translator->registerLanguagePath($this->getLanguagesPath());
1018  }
1019 
1029  protected function loadLanguages(): void {
1030  $languages_path = $this->getLanguagesPath();
1031  if (!is_dir($languages_path)) {
1032  return;
1033  }
1034 
1035  _elgg_services()->translator->registerTranslations($languages_path);
1036  }
1037 
1043  protected function registerClasses(): void {
1044  _elgg_services()->autoloadManager->addClasses("{$this->getPath()}classes");
1045  }
1046 
1052  protected function activateEntities(): void {
1053  $spec = (array) $this->getStaticConfig('entities', []);
1054 
1055  foreach ($spec as $entity) {
1056  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1057  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype'], $entity['class']);
1058  }
1059  }
1060  }
1061 
1067  protected function deactivateEntities(): void {
1068  $spec = (array) $this->getStaticConfig('entities', []);
1069 
1070  foreach ($spec as $entity) {
1071  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1072  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype']);
1073  }
1074  }
1075  }
1076 
1084  protected function registerHooks(): void {
1085  $events = _elgg_services()->events;
1086 
1087  $spec = (array) $this->getStaticConfig('hooks', []);
1088 
1089  if (!empty($spec)) {
1090  elgg_deprecated_notice("The plugin {$this->getID()} still has hooks definitions in the elgg-plugin.php. This should be moved to the events configuration.", '5.0');
1091  }
1092 
1093  foreach ($spec as $name => $types) {
1094  foreach ($types as $type => $callbacks) {
1095  foreach ($callbacks as $callback => $hook_spec) {
1096  if (!is_array($hook_spec)) {
1097  continue;
1098  }
1099 
1100  $unregister = (bool) elgg_extract('unregister', $hook_spec, false);
1101 
1102  if ($unregister) {
1103  $events->unregisterHandler($name, $type, $callback);
1104  } else {
1105  $priority = (int) elgg_extract('priority', $hook_spec, 500);
1106 
1107  $events->registerHandler($name, $type, $callback, $priority);
1108  }
1109  }
1110  }
1111  }
1112  }
1113 
1119  protected function registerEvents(): void {
1120  $events = _elgg_services()->events;
1121 
1122  $spec = (array) $this->getStaticConfig('events', []);
1123 
1124  foreach ($spec as $name => $types) {
1125  foreach ($types as $type => $callbacks) {
1126  foreach ($callbacks as $callback => $event_spec) {
1127  if (!is_array($event_spec)) {
1128  continue;
1129  }
1130 
1131  $unregister = (bool) elgg_extract('unregister', $event_spec, false);
1132 
1133  if ($unregister) {
1134  $events->unregisterHandler($name, $type, $callback);
1135  } else {
1136  $priority = (int) elgg_extract('priority', $event_spec, 500);
1137 
1138  $events->registerHandler($name, $type, $callback, $priority);
1139  }
1140  }
1141  }
1142  }
1143  }
1144 
1150  protected function registerViewExtensions(): void {
1151  $views = _elgg_services()->views;
1152 
1153  $spec = (array) $this->getStaticConfig('view_extensions', []);
1154 
1155  foreach ($spec as $src_view => $extensions) {
1156  foreach ($extensions as $extention => $extention_spec) {
1157  if (!is_array($extention_spec)) {
1158  continue;
1159  }
1160 
1161  $unextend = (bool) elgg_extract('unextend', $extention_spec, false);
1162 
1163  if ($unextend) {
1164  $views->unextendView($src_view, $extention);
1165  } else {
1166  $priority = (int) elgg_extract('priority', $extention_spec, 501);
1167 
1168  $views->extendView($src_view, $extention, $priority);
1169  }
1170  }
1171  }
1172  }
1173 
1179  protected function registerGroupTools(): void {
1180  $tools = _elgg_services()->group_tools;
1181 
1182  $spec = (array) $this->getStaticConfig('group_tools', []);
1183 
1184  foreach ($spec as $tool_name => $tool_options) {
1185  if (!is_array($tool_options)) {
1186  continue;
1187  }
1188 
1189  $unregister = (bool) elgg_extract('unregister', $tool_options, false);
1190 
1191  if ($unregister) {
1192  $tools->unregister($tool_name);
1193  } else {
1194  $tools->register($tool_name, $tool_options);
1195  }
1196  }
1197  }
1198 
1204  protected function registerViewOptions(): void {
1205  $spec = (array) $this->getStaticConfig('view_options', []);
1206 
1207  foreach ($spec as $view_name => $options) {
1208  if (!is_array($options)) {
1209  continue;
1210  }
1211 
1212  if (isset($options['ajax'])) {
1213  if ($options['ajax'] === true) {
1214  _elgg_services()->ajax->registerView($view_name);
1215  } else {
1216  _elgg_services()->ajax->unregisterView($view_name);
1217  }
1218  }
1219 
1220  if (isset($options['simplecache']) && $options['simplecache'] === true) {
1221  _elgg_services()->views->registerCacheableView($view_name);
1222  }
1223  }
1224  }
1225 
1231  protected function registerNotifications(): void {
1232  $spec = (array) $this->getStaticConfig('notifications', []);
1233 
1234  foreach ($spec as $type => $subtypes) {
1235  foreach ($subtypes as $subtype => $actions) {
1236  foreach ($actions as $action => $callback) {
1237  if ($callback === false) {
1238  _elgg_services()->notifications->unregisterEvent($type, $subtype, [$action]);
1239  } elseif ($callback === true) {
1240  _elgg_services()->notifications->registerEvent($type, $subtype, [$action]);
1241  } else {
1242  _elgg_services()->notifications->registerEvent($type, $subtype, [$action], $callback);
1243  }
1244  }
1245  }
1246  }
1247  }
1248 
1256  public function __get($name) {
1257  // See if its in our base attribute
1258  if (array_key_exists($name, $this->attributes)) {
1259  return $this->attributes[$name];
1260  }
1261 
1262  // object title and description are stored as metadata
1263  if (in_array($name, ['title', 'description'])) {
1264  return parent::__get($name);
1265  }
1266 
1267  $result = $this->getSetting($name);
1268  if ($result !== null) {
1269  return $result;
1270  }
1271 
1272  $defaults = $this->getStaticConfig('settings', []);
1273 
1274  return elgg_extract($name, $defaults, $result);
1275  }
1276 
1285  public function __set($name, $value) {
1286  if (array_key_exists($name, $this->attributes)) {
1287  // Check that we're not trying to change the guid!
1288  if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) {
1289  return;
1290  }
1291 
1292  $this->attributes[$name] = $value;
1293 
1294  return;
1295  }
1296 
1297  // object title and description are stored as metadata
1298  if (in_array($name, ['title', 'description'])) {
1299  parent::__set($name, $value);
1300 
1301  return;
1302  }
1303 
1304  // to make sure we trigger the correct events
1305  $this->setSetting($name, $value);
1306  }
1307 
1315  protected function setStatus(bool $active): bool {
1316  if (!$this->guid) {
1317  return false;
1318  }
1319 
1321  if ($active) {
1322  $result = _elgg_services()->relationshipsTable->add($this->guid, 'active_plugin', $site->guid);
1323  } else {
1324  $result = _elgg_services()->relationshipsTable->remove($this->guid, 'active_plugin', $site->guid);
1325  }
1326 
1327  if ($result) {
1328  $this->activated = $active;
1329  }
1330 
1331  $this->invalidateCache();
1332 
1333  return $result;
1334  }
1335 
1339  public function isCacheable(): bool {
1340  return true;
1341  }
1342 
1346  public function cache(bool $persist = true): void {
1347  _elgg_services()->plugins->cache($this);
1348 
1349  parent::cache($persist);
1350  }
1351 
1355  public function invalidateCache(): void {
1356 
1357  _elgg_services()->boot->clearCache();
1358  _elgg_services()->plugins->invalidateCache($this->getID());
1359 
1360  parent::invalidateCache();
1361  }
1362 
1370  protected function getComposer(): \Elgg\Plugin\Composer {
1371  if (isset($this->composer)) {
1372  return $this->composer;
1373  }
1374 
1375  $this->composer = new \Elgg\Plugin\Composer($this);
1376  return $this->composer;
1377  }
1378 
1386  public function meetsDependencies(): bool {
1387  try {
1388  $this->assertDependencies();
1389 
1390  return true;
1391  } catch (PluginException $e) {
1392  return false;
1393  }
1394  }
1395 
1404  public function assertDependencies(): void {
1405  $this->getComposer()->assertConflicts();
1406  $this->getComposer()->assertActivePluginConflicts();
1407  $this->getComposer()->assertRequiredPhpVersion();
1408  $this->getComposer()->assertRequiredPhpExtensions();
1409  $this->assertPluginDependencies();
1410  }
1411 
1420  protected function assertPluginDependencies(): void {
1421  foreach ($this->getDependencies() as $plugin_id => $plugin_dep) {
1422  $must_be_active = elgg_extract('must_be_active', $plugin_dep, true);
1423  $position = elgg_extract('position', $plugin_dep);
1424 
1425  $dependent_plugin = elgg_get_plugin_from_id($plugin_id);
1426 
1427  if ($must_be_active && (!$dependent_plugin instanceof \ElggPlugin || !$dependent_plugin->isActive())) {
1428  throw PluginException::factory([
1429  'message' => elgg_echo('PluginException:PluginMustBeActive', [$plugin_id]),
1430  'plugin' => $this,
1431  ]);
1432  }
1433 
1434  if ($dependent_plugin instanceof \ElggPlugin && $position && $dependent_plugin->isActive()) {
1435  if ($position == 'after' && ($this->getPriority() < $dependent_plugin->getPriority())) {
1436  throw PluginException::factory([
1437  'message' => elgg_echo('PluginException:PluginMustBeAfter', [$plugin_id]),
1438  'plugin' => $this,
1439  ]);
1440  } elseif ($position == 'before' && ($this->getPriority() > $dependent_plugin->getPriority())) {
1441  throw PluginException::factory([
1442  'message' => elgg_echo('PluginException:PluginMustBeBefore', [$plugin_id]),
1443  'plugin' => $this,
1444  ]);
1445  }
1446  }
1447  }
1448  }
1449 
1455  public function getVersion(): string {
1456  // composer version
1457  $version = $this->getComposer()->getConfiguration()->version();
1458  if (!elgg_is_empty($version)) {
1459  return $version;
1460  }
1461 
1462  // elgg-plugin version
1463  $plugin_config = $this->getStaticConfig('plugin', []);
1464  $version = elgg_extract('version', $plugin_config);
1465  if (!elgg_is_empty($version)) {
1466  return $version;
1467  }
1468 
1469  // bundled plugins use elgg version
1470  if (in_array($this->getID(), Plugins::BUNDLED_PLUGINS)) {
1471  return elgg_get_release();
1472  }
1473 
1474  return '0.1';
1475  }
1476 
1484  public function getCategories(): array {
1485  return $this->getComposer()->getCategories();
1486  }
1487 
1495  public function getLicense(): string {
1496  return $this->getComposer()->getLicense();
1497  }
1498 
1506  public function getDescription(): string {
1507  return (string) $this->getComposer()->getConfiguration()->description();
1508  }
1509 
1517  public function getRepositoryURL(): string {
1518  return (string) $this->getComposer()->getConfiguration()->support()->source();
1519  }
1520 
1528  public function getBugTrackerURL(): string {
1529  return (string) $this->getComposer()->getConfiguration()->support()->issues();
1530  }
1531 
1539  public function getWebsite(): string {
1540  return (string) $this->getComposer()->getConfiguration()->homepage();
1541  }
1542 
1550  public function getAuthors(): array {
1551  return (array) $this->getComposer()->getConfiguration()->authors();
1552  }
1553 
1561  public function getConflicts(): array {
1562  return $this->getComposer()->getConflicts();
1563  }
1564 }
$default
Definition: checkbox.php:30
elgg_call(int $flags, Closure $closure)
Calls a callable autowiring the arguments using public DI services and applying logic based on flags...
Definition: elgglib.php:299
registerViews()
Registers the plugin&#39;s views.
Definition: ElggPlugin.php:889
const ELGG_DISABLE_SYSTEM_LOG
Definition: constants.php:134
registerEntities()
Registers the plugin&#39;s entities.
Definition: ElggPlugin.php:918
getID()
Returns the ID (dir name) of this plugin.
Definition: ElggPlugin.php:138
elgg_get_release()
Get the current Elgg release.
elgg_get_plugins(string $status= 'active')
Returns an ordered list of plugins.
Definition: plugins.php:55
setMetadata(string $name, $value, string $value_type= '', bool $multiple=false)
Set metadata on this entity.
Definition: ElggEntity.php:370
$plugin
registerActions()
Registers the plugin&#39;s actions provided in the plugin config file.
Definition: ElggPlugin.php:938
cache(bool $persist=true)
{}
$params
Saves global plugin settings.
Definition: save.php:13
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:115
$position
Definition: add.php:11
getLanguagesPath()
Returns the plugin&#39;s languages directory full path with trailing slash.
Definition: ElggPlugin.php:189
registerClasses()
Registers the plugin&#39;s classes.
assertCanDeactivate()
Asserts if a plugin can be deactivated.
Definition: ElggPlugin.php:609
Plugin class containing helper functions for plugin activation/deactivation, dependency checking capa...
Definition: ElggPlugin.php:16
const STATIC_CONFIG_FILENAME
Definition: ElggPlugin.php:19
$defaults
Generic entity header upload helper.
Definition: header.php:6
setSetting(string $name, $value)
Set a plugin setting for the plugin.
Definition: ElggPlugin.php:333
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
elgg_get_plugin_from_id(string $plugin_id)
Elgg plugins library Contains functions for managing plugins.
Definition: plugins.php:15
if(empty($page_owner)||$owner->guid!==$page_owner->guid) $widgets
Definition: widgets.php:40
getAllSettings()
Returns an array of all settings saved for this plugin.
Definition: ElggPlugin.php:304
$title
Definition: generic.php:50
if(elgg_view_exists("widgets/{$widget->handler}/edit")) $access
Definition: save.php:25
$version
getConflicts()
Returns an array of projectnames with their conflicting version.
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
assertValid()
Asserts if a plugin is valid.
Definition: ElggPlugin.php:439
elgg_echo(string $message_key, array $args=[], string $language= '')
Elgg language module Functions to manage language and translations.
Definition: languages.php:17
invalidateCache()
{}
registerPublicServices()
Registers the plugin public services.
Definition: ElggPlugin.php:871
meetsDependencies()
Checks if dependencies are met.
$delete
$type
Definition: delete.php:22
unsetSetting(string $name)
Removes a plugin setting name and value.
Definition: ElggPlugin.php:360
getDescription()
Return the description.
registerRoutes()
Registers the plugin&#39;s routes provided in the plugin config file.
Definition: ElggPlugin.php:972
setPriority($priority)
Sets the priority of the plugin Returns the new priority or false on error.
Definition: ElggPlugin.php:245
$site
Definition: icons.php:5
isCacheable()
{}
activateEntities()
Activates the plugin&#39;s entities.
if($type!= 'user') $settings
Definition: save.php:16
assertCanActivate()
Asserts if a plugin can activate.
Definition: ElggPlugin.php:498
const PUBLIC_SERVICES_FILENAME
Definition: ElggPlugin.php:20
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof\ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
$options
Elgg admin footer.
Definition: footer.php:6
$plugin_id
Remove all user and plugin settings from the give plugin ID.
Definition: remove.php:8
elgg_delete_admin_notice(string $id)
Remove an admin notice by ID.
Definition: admin.php:63
deactivateEntities()
Deactivates the plugin&#39;s entities.
$value
Definition: generic.php:51
elgg_is_empty($value)
Check if a value isn&#39;t empty, but allow 0 and &#39;0&#39;.
Definition: input.php:176
canDeactivate()
Checks if this plugin can be deactivated on the current Elgg installation.
Definition: ElggPlugin.php:588
elgg_invalidate_caches()
Invalidate all the registered caches.
Definition: cache.php:183
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:254
getDependencies()
Returns an array of dependencies as configured in the static config.
Definition: ElggPlugin.php:576
const ADDITIONAL_TEXT_FILES
Definition: ElggPlugin.php:29
getDisplayName()
Returns the name from elgg-plugin.php if available, otherwise a nicely formatted ID.
Definition: ElggPlugin.php:148
assertStaticConfigValid()
If a static config file is present, is it a serializable array?
Definition: ElggPlugin.php:842
setPath(string $path)
Set path.
Definition: ElggPlugin.php:165
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:130
elgg_view(string $view, array $vars=[], string $viewtype= '')
Return a parsed view.
Definition: views.php:177
assertDependencies()
Assert plugin dependencies.
isActive()
Is this plugin active?
Definition: ElggPlugin.php:462
$entity
Definition: reset.php:8
getRepositoryURL()
Returns the repository url.
static factory(array $options)
Create an WidgetDefinition from an associative array.
registerLanguages()
Registers the plugin&#39;s languages.
getCategories()
Returns an array with categories.
elgg_is_active_plugin(string $plugin_id)
Returns if a plugin is active for a current site.
Definition: plugins.php:43
$active
Definition: full.php:20
setStatus(bool $active)
Sets the plugin to active or inactive.
init()
Init the plugin.
Definition: ElggPlugin.php:769
elgg_log($message, $level=\Psr\Log\LogLevel::NOTICE)
Log a message.
Definition: elgglib.php:86
initializeAttributes()
{}
Definition: ElggPlugin.php:65
A generic parent class for database exceptions.
normalizePriority($priority)
Normalize and validate new priority.
Definition: ElggPlugin.php:259
unsetAllSettings()
Removes all settings for this plugin.
Definition: ElggPlugin.php:370
deleteMetadata(string $name=null)
Deletes all metadata on this object (metadata.entity_guid = $this->guid).
Definition: ElggEntity.php:483
getBugTrackerURL()
Returns the bug tracker page.
if(!$menu instanceof\Elgg\Menu\PreparedMenu) $actions
Definition: user_hover.php:16
getWebsite()
Return the website.
getBootstrap()
Bootstrap object.
Definition: ElggPlugin.php:689
isValid()
Returns if the plugin is complete, meaning has all required files and Elgg can read them and they mak...
Definition: ElggPlugin.php:422
elgg_get_site_entity()
Get the current site entity.
Definition: entities.php:98
const PRIORITY_SETTING_NAME
Definition: ElggPlugin.php:18
$extensions
registerHooks()
Registers the plugin&#39;s hooks provided in the plugin config file.
getVersion()
Returns the plugin version.
$action
Definition: subscribe.php:11
if($container instanceof ElggGroup &&$container->guid!=elgg_get_page_owner_guid()) $key
Definition: summary.php:44
registerViewExtensions()
Registers the plugin&#39;s view extensions provided in the plugin config file.
activate()
Activates the plugin for the current site.
Definition: ElggPlugin.php:511
registerWidgets()
Registers the plugin&#39;s widgets provided in the plugin config file.
Definition: ElggPlugin.php:990
boot()
Boot the plugin.
Definition: ElggPlugin.php:759
deactivate()
Deactivates the plugin.
Definition: ElggPlugin.php:652
__get($name)
Get an attribute or setting value.
getComposer()
Returns the composer parser.
const ELGG_VALUE_STRING
Definition: constants.php:112
canReadFile(string $filename)
Checks whether a plugin file with the given name exists.
Definition: ElggPlugin.php:832
registerNotifications()
Registers the plugin&#39;s notification events.
$subtype
Definition: delete.php:23
registerEvents()
Registers the plugin&#39;s events provided in the plugin config file.
$subtypes
getPriority()
Gets the plugin&#39;s load priority.
Definition: ElggPlugin.php:225
__set($name, $value)
Set a value as attribute or setting.
getAllMetadata()
Get all entity metadata.
Definition: ElggEntity.php:343
_elgg_services()
Get the global service provider.
Definition: elgglib.php:346
loadLanguages()
Loads the plugin&#39;s translations.
const ACCESS_PUBLIC
Definition: constants.php:12
elgg_get_plugins_path()
Get the plugin path for this installation, ending with slash.
$handler
Definition: add.php:7
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:81
getSetting(string $name, $default=null)
Returns a plugin setting.
Definition: ElggPlugin.php:292
registerGroupTools()
Registers the plugin&#39;s group tools provided in the plugin config file.
canActivate()
Checks if this plugin can be activated on the current Elgg installation.
Definition: ElggPlugin.php:477
includeFile(string $filename)
Includes one of the plugins files.
Definition: ElggPlugin.php:792
getPath()
Returns the plugin&#39;s full path with trailing slash.
Definition: ElggPlugin.php:174
getLicense()
Returns the license.
assertPluginDependencies()
Assert required plugins or plugin position.
var elgg
Definition: elgglib.js:4
autoload()
Register plugin classes and require composer autoloader.
Definition: ElggPlugin.php:714
unsetAllEntityAndPluginSettings()
Remove all entity and plugin settings for this plugin.
Definition: ElggPlugin.php:390
$priority
$views
Definition: item.php:17
getMetadata(string $name)
Return the value of a piece of metadata.
Definition: ElggEntity.php:333
registerViewOptions()
Registers the plugin&#39;s view options provided in the plugin config file.
getStaticConfig(string $key, $default=null)
Get a value from the plugins&#39;s static config file.
Definition: ElggPlugin.php:204
$guid
Reset an ElggUpgrade.
Definition: reset.php:6
getAuthors()
Returns an array of authors.