Elgg  Version 6.1
ElggPlugin.php
Go to the documentation of this file.
1 <?php
2 
9 use Elgg\Includer;
12 
17 class ElggPlugin extends ElggObject {
18 
19  const PRIORITY_SETTING_NAME = 'elgg:internal:priority';
20  const STATIC_CONFIG_FILENAME = 'elgg-plugin.php';
21  const PUBLIC_SERVICES_FILENAME = 'elgg-services.php';
22 
23  use ElggLoggable;
24 
31  'README.txt',
32  'CHANGES.txt',
33  'INSTALL.txt',
34  'COPYRIGHT.txt',
35  'LICENSE.txt',
36  'README',
37  'README.md',
38  'README.markdown',
39  ];
40 
44  protected $composer;
45 
49  protected $path;
50 
56  protected $static_config;
57 
61  protected $activated;
62 
66  protected function initializeAttributes() {
67  parent::initializeAttributes();
68 
69  $this->attributes['subtype'] = 'plugin';
70  }
71 
82  public static function fromId(string $plugin_id, string $path = null): \ElggPlugin {
83  if (empty($plugin_id)) {
84  throw new ElggInvalidArgumentException('Plugin ID must be set');
85  }
86 
87  $plugin = elgg_get_plugin_from_id($plugin_id);
88  if (!$plugin) {
89  $plugin = elgg_call(ELGG_IGNORE_ACCESS, function() use ($plugin_id) {
90  $plugin = new ElggPlugin();
91  $plugin->title = $plugin_id;
92  $plugin->save();
93 
94  return $plugin;
95  });
96  }
97 
98  if (empty($path)) {
100  }
101 
102  $path = Paths::sanitize($path);
103  $plugin->setPath($path . $plugin_id);
104 
105  return $plugin;
106  }
107 
111  public function save(): bool {
112 
114 
115  $this->attributes['owner_guid'] = $site->guid;
116  $this->attributes['container_guid'] = $site->guid;
117  $this->attributes['access_id'] = ACCESS_PUBLIC;
118 
119  $new = !$this->guid;
120  $priority = null;
121  if ($new) {
122  $priority = elgg_extract(self::PRIORITY_SETTING_NAME, $this->temp_metadata, 'new');
123  } elseif ($this->getPriority() === null) {
124  $priority = 'last';
125  }
126 
127  if ($priority) {
128  $this->setPriority($priority);
129  }
130 
131  return parent::save();
132  }
133 
139  public function getID(): string {
140  return (string) $this->title;
141  }
142 
149  public function getDisplayName(): string {
150  $name = elgg_extract('name', $this->getStaticConfig('plugin', []), '');
151  if (!empty($name)) {
152  return $name;
153  }
154 
155  return ucwords(str_replace(['-', '_'], ' ', $this->getID()));
156  }
157 
166  public function setPath(string $path): void {
167  $this->path = Paths::sanitize($path, true);
168  }
169 
175  public function getPath(): string {
176  if (isset($this->path)) {
177  return $this->path;
178  }
179 
180  $this->setPath(elgg_get_plugins_path() . $this->getID());
181  return $this->path;
182  }
183 
190  protected function getLanguagesPath(): string {
191  return $this->getPath() . 'languages/';
192  }
193 
205  public function getStaticConfig(string $key, $default = null) {
206  if ($this->static_config === null) {
207  $this->static_config = [];
208 
209  try {
210  $this->static_config = $this->includeFile(self::STATIC_CONFIG_FILENAME);
211  } catch (PluginException $ex) {
212  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
213  }
214  }
215 
216  return $this->static_config[$key] ?? $default;
217  }
218 
219  // Load Priority
220 
226  public function getPriority(): ?int {
227  $priority = $this->getMetadata(self::PRIORITY_SETTING_NAME);
228  if (isset($priority)) {
229  return (int) $priority;
230  }
231 
232  return null;
233  }
234 
246  public function setPriority($priority): int|false {
248 
249  return _elgg_services()->plugins->setPriority($this, $priority);
250  }
251 
260  protected function normalizePriority($priority): int {
261  // if no priority assume a priority of 1
262  $old_priority = $this->getPriority();
263  $old_priority = $old_priority ?: 1;
264  $max_priority = _elgg_services()->plugins->getMaxPriority() ?: 1;
265 
266  // can't use switch here because it's not strict and php evaluates +1 == 1
267  if ($priority === '+1') {
268  $priority = $old_priority + 1;
269  } else if ($priority === '-1') {
270  $priority = $old_priority - 1;
271  } else if ($priority === 'first') {
272  $priority = 1;
273  } else if ($priority === 'last') {
274  $priority = $max_priority;
275  } else if ($priority === 'new') {
276  $max_priority++;
277  $priority = $max_priority;
278  }
279 
280  return min($max_priority, max(1, (int) $priority));
281  }
282 
283  // Plugin settings
284 
294  public function getSetting(string $name, $default = null) {
295  $values = $this->getAllSettings();
296  return elgg_extract($name, $values, $default);
297  }
298 
307  public function getAllSettings(): array {
308  try {
309  if (!$this->isActive()) {
310  return [];
311  }
312 
313  $defaults = (array) $this->getStaticConfig('settings', []);
314 
315  $settings = $this->getAllMetadata();
316 
317  // title, description and priority are not considered settings
318  unset($settings['title'], $settings['description'], $settings[self::PRIORITY_SETTING_NAME]);
319 
320  return array_merge($defaults, $settings);
321  } catch (DatabaseException $ex) {
322  return [];
323  }
324  }
325 
334  public function setSetting(string $name, $value): bool {
335 
336  $value = _elgg_services()->events->triggerResults('setting', 'plugin', [
337  'plugin_id' => $this->getID(),
338  'plugin' => $this,
339  'name' => $name,
340  'value' => $value,
341  ], $value);
342 
343  if (is_array($value)) {
344  elgg_log('Plugin settings cannot store arrays.', \Psr\Log\LogLevel::ERROR);
345 
346  return false;
347  }
348 
349  return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) {
350  return $this->setMetadata($name, $value);
351  });
352  }
353 
361  public function unsetSetting(string $name): bool {
362  return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) {
363  return (bool) $this->deleteMetadata($name);
364  });
365  }
366 
371  public function unsetAllSettings(): bool {
372  $settings = $this->getAllMetadata();
373 
374  // title, description and priority are not considered settings
375  unset($settings['title'], $settings['description'], $settings[self::PRIORITY_SETTING_NAME]);
376 
377  foreach ($settings as $name => $value) {
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(MetadataTable::TABLE_NAME);
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()->metadataCache->clear();
401 
402  $result &= true;
403  } catch (DatabaseException $e) {
404  elgg_log($e, \Psr\Log\LogLevel::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->registerEvents();
775  $this->registerViewExtensions();
776  $this->registerGroupTools();
777  $this->registerViewOptions();
778  $this->registerNotifications();
779 
780  $this->getBootstrap()->init();
781  }
782 
791  protected function includeFile(string $filename) {
792  $filepath = "{$this->getPath()}{$filename}";
793 
794  if (!$this->canReadFile($filename)) {
795  $msg = elgg_echo(
796  'ElggPlugin:Exception:CannotIncludeFile',
797  [$filename, $this->getID(), $this->guid, $this->getPath()]
798  );
799 
800  throw PluginException::factory([
801  'message' => $msg,
802  'plugin' => $this,
803  ]);
804  }
805 
806  try {
807  $ret = Includer::requireFile($filepath);
808  } catch (Exception $e) {
809  $msg = elgg_echo(
810  'ElggPlugin:Exception:IncludeFileThrew',
811  [$filename, $this->getID(), $this->guid, $this->getPath()]
812  );
813 
814  throw PluginException::factory([
815  'message' => $msg,
816  'previous' => $e,
817  'plugin' => $this,
818  ]);
819  }
820 
821  return $ret;
822  }
823 
831  protected function canReadFile(string $filename): bool {
832  return is_file("{$this->getPath()}{$filename}");
833  }
834 
841  protected function assertStaticConfigValid(): void {
842  if (!$this->canReadFile(self::STATIC_CONFIG_FILENAME)) {
843  return;
844  }
845 
846  ob_start();
847  $value = $this->includeFile(self::STATIC_CONFIG_FILENAME);
848  if (ob_get_clean() !== '') {
849  throw PluginException::factory([
850  'message' => elgg_echo('ElggPlugin:activate:ConfigSentOutput'),
851  'plugin' => $this,
852  ]);
853  }
854 
855  // make sure can serialize
856  $value = @unserialize(serialize($value));
857  if (!is_array($value)) {
858  throw PluginException::factory([
859  'message' => elgg_echo('ElggPlugin:activate:BadConfigFormat'),
860  'plugin' => $this,
861  ]);
862  }
863  }
864 
870  protected function registerPublicServices(): void {
871  $services_path = $this->getPath() . self::PUBLIC_SERVICES_FILENAME;
872  if (!is_file($services_path)) {
873  return;
874  }
875 
876  $services = Includer::includeFile($services_path);
877  foreach ($services as $name => $definition) {
878  elgg()->set($name, $definition);
879  }
880  }
881 
888  protected function registerViews(): void {
889  if (_elgg_services()->views->isViewLocationsLoadedFromCache()) {
890  return;
891  }
892 
893  $views = _elgg_services()->views;
894 
895  // Declared views first
896  $spec = $this->getStaticConfig('views');
897  if ($spec) {
898  $views->mergeViewsSpec($spec);
899  }
900 
901  // Allow /views directory files to override
902  if (!$views->registerViewsFromPath($this->getPath())) {
903  $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews', [$this->getID(), $this->guid, $this->getPath()]);
904 
905  throw PluginException::factory([
906  'message' => $msg,
907  'plugin' => $this,
908  ]);
909  }
910  }
911 
917  protected function registerEntities(): void {
918  $spec = (array) $this->getStaticConfig('entities', []);
919 
920  foreach ($spec as $entity) {
921  if (!isset($entity['type']) || !isset($entity['subtype'])) {
922  continue;
923  }
924 
925  $capabilities = elgg_extract('capabilities', $entity, []);
926  foreach ($capabilities as $capability => $value) {
927  _elgg_services()->entity_capabilities->setCapability($entity['type'], $entity['subtype'], $capability, $value);
928  }
929  }
930  }
931 
937  protected function registerActions(): void {
938  $actions = _elgg_services()->actions;
939  $root_path = $this->getPath();
940 
941  $spec = (array) $this->getStaticConfig('actions', []);
942 
943  foreach ($spec as $action => $action_spec) {
944  if (!is_array($action_spec)) {
945  continue;
946  }
947 
948  $access = elgg_extract('access', $action_spec, 'logged_in');
949  $handler = elgg_extract('controller', $action_spec);
950  if (!$handler) {
951  $handler = elgg_extract('filename', $action_spec);
952  if (!$handler) {
953  $handler = "{$root_path}actions/{$action}.php";
954  }
955  }
956 
957  // unset handled action specs, pass the rest to the action service
958  unset($action_spec['access']);
959  unset($action_spec['controller']);
960  unset($action_spec['filename']);
961 
962  $actions->register($action, $handler, $access, $action_spec);
963  }
964  }
965 
971  protected function registerRoutes(): void {
972  $routes = _elgg_services()->routes;
973 
974  $spec = (array) $this->getStaticConfig('routes', []);
975  foreach ($spec as $name => $route_spec) {
976  if (!is_array($route_spec)) {
977  continue;
978  }
979 
980  $routes->register($name, $route_spec);
981  }
982  }
983 
989  protected function registerWidgets(): void {
990  $widgets = _elgg_services()->widgets;
991 
992  $spec = (array) $this->getStaticConfig('widgets', []);
993  foreach ($spec as $widget_id => $widget_definition) {
994  if (!is_array($widget_definition)) {
995  continue;
996  }
997 
998  if (!isset($widget_definition['id'])) {
999  $widget_definition['id'] = $widget_id;
1000  }
1001 
1002  $definition = \Elgg\WidgetDefinition::factory($widget_definition);
1003 
1004  $widgets->registerType($definition);
1005  }
1006  }
1007 
1015  public function registerLanguages(): void {
1016  _elgg_services()->translator->registerLanguagePath($this->getLanguagesPath());
1017  }
1018 
1028  protected function loadLanguages(): void {
1029  $languages_path = $this->getLanguagesPath();
1030  if (!is_dir($languages_path)) {
1031  return;
1032  }
1033 
1034  _elgg_services()->translator->registerTranslations($languages_path);
1035  }
1036 
1042  protected function registerClasses(): void {
1043  _elgg_services()->autoloadManager->addClasses("{$this->getPath()}classes");
1044  }
1045 
1051  protected function activateEntities(): void {
1052  $spec = (array) $this->getStaticConfig('entities', []);
1053 
1054  foreach ($spec as $entity) {
1055  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1056  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype'], $entity['class']);
1057  }
1058  }
1059  }
1060 
1066  protected function deactivateEntities(): void {
1067  $spec = (array) $this->getStaticConfig('entities', []);
1068 
1069  foreach ($spec as $entity) {
1070  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1071  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype']);
1072  }
1073  }
1074  }
1075 
1081  protected function registerEvents(): void {
1082  $events = _elgg_services()->events;
1083 
1084  $spec = (array) $this->getStaticConfig('events', []);
1085 
1086  foreach ($spec as $name => $types) {
1087  foreach ($types as $type => $callbacks) {
1088  foreach ($callbacks as $callback => $event_spec) {
1089  if (!is_array($event_spec)) {
1090  continue;
1091  }
1092 
1093  $unregister = (bool) elgg_extract('unregister', $event_spec, false);
1094 
1095  if ($unregister) {
1096  $events->unregisterHandler($name, $type, $callback);
1097  } else {
1098  $priority = (int) elgg_extract('priority', $event_spec, 500);
1099 
1100  $events->registerHandler($name, $type, $callback, $priority);
1101  }
1102  }
1103  }
1104  }
1105  }
1106 
1112  protected function registerViewExtensions(): void {
1113  $views = _elgg_services()->views;
1114 
1115  $spec = (array) $this->getStaticConfig('view_extensions', []);
1116 
1117  foreach ($spec as $src_view => $extensions) {
1118  foreach ($extensions as $extention => $extention_spec) {
1119  if (!is_array($extention_spec)) {
1120  continue;
1121  }
1122 
1123  $unextend = (bool) elgg_extract('unextend', $extention_spec, false);
1124 
1125  if ($unextend) {
1126  $views->unextendView($src_view, $extention);
1127  } else {
1128  $priority = (int) elgg_extract('priority', $extention_spec, 501);
1129 
1130  $views->extendView($src_view, $extention, $priority);
1131  }
1132  }
1133  }
1134  }
1135 
1141  protected function registerGroupTools(): void {
1142  $tools = _elgg_services()->group_tools;
1143 
1144  $spec = (array) $this->getStaticConfig('group_tools', []);
1145 
1146  foreach ($spec as $tool_name => $tool_options) {
1147  if (!is_array($tool_options)) {
1148  continue;
1149  }
1150 
1151  $unregister = (bool) elgg_extract('unregister', $tool_options, false);
1152 
1153  if ($unregister) {
1154  $tools->unregister($tool_name);
1155  } else {
1156  $tools->register($tool_name, $tool_options);
1157  }
1158  }
1159  }
1160 
1166  protected function registerViewOptions(): void {
1167  $spec = (array) $this->getStaticConfig('view_options', []);
1168 
1169  foreach ($spec as $view_name => $options) {
1170  if (!is_array($options)) {
1171  continue;
1172  }
1173 
1174  if (isset($options['ajax'])) {
1175  if ($options['ajax'] === true) {
1176  _elgg_services()->ajax->registerView($view_name);
1177  } else {
1178  _elgg_services()->ajax->unregisterView($view_name);
1179  }
1180  }
1181 
1182  if (isset($options['simplecache']) && $options['simplecache'] === true) {
1183  _elgg_services()->simpleCache->registerCacheableView($view_name);
1184  }
1185  }
1186  }
1187 
1193  protected function registerNotifications(): void {
1194  $spec = (array) $this->getStaticConfig('notifications', []);
1195 
1196  foreach ($spec as $type => $subtypes) {
1197  foreach ($subtypes as $subtype => $actions) {
1198  foreach ($actions as $action => $callback) {
1199  if ($callback === false) {
1200  _elgg_services()->notifications->unregisterEvent($type, $subtype, [$action]);
1201  } elseif ($callback === true) {
1202  _elgg_services()->notifications->registerEvent($type, $subtype, [$action]);
1203  } else {
1204  _elgg_services()->notifications->registerEvent($type, $subtype, [$action], $callback);
1205  }
1206  }
1207  }
1208  }
1209  }
1210 
1218  public function __get($name) {
1219  // See if its in our base attribute
1220  if (array_key_exists($name, $this->attributes)) {
1221  return $this->attributes[$name];
1222  }
1223 
1224  // object title and description are stored as metadata
1225  if (in_array($name, ['title', 'description'])) {
1226  return parent::__get($name);
1227  }
1228 
1229  return $this->getSetting($name);
1230  }
1231 
1240  public function __set($name, $value) {
1241  if (array_key_exists($name, $this->attributes)) {
1242  // Check that we're not trying to change the guid!
1243  if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) {
1244  return;
1245  }
1246 
1247  $this->attributes[$name] = $value;
1248 
1249  return;
1250  }
1251 
1252  // object title and description are stored as metadata
1253  if (in_array($name, ['title', 'description'])) {
1254  parent::__set($name, $value);
1255 
1256  return;
1257  }
1258 
1259  // to make sure we trigger the correct events
1260  $this->setSetting($name, $value);
1261  }
1262 
1270  protected function setStatus(bool $active): bool {
1271  if (!$this->guid) {
1272  return false;
1273  }
1274 
1276  if ($active) {
1277  $result = $this->addRelationship($site->guid, 'active_plugin');
1278  } else {
1279  $result = $this->removeRelationship($site->guid, 'active_plugin');
1280  }
1281 
1282  if ($result) {
1283  $this->activated = $active;
1284  }
1285 
1286  $this->invalidateCache();
1287 
1288  return $result;
1289  }
1290 
1294  public function isCacheable(): bool {
1295  return true;
1296  }
1297 
1301  public function invalidateCache(): void {
1302  _elgg_services()->boot->clearCache();
1303  _elgg_services()->pluginsCache->delete($this->getID());
1304 
1305  parent::invalidateCache();
1306  }
1307 
1315  protected function getComposer(): \Elgg\Plugin\Composer {
1316  if (isset($this->composer)) {
1317  return $this->composer;
1318  }
1319 
1320  $this->composer = new \Elgg\Plugin\Composer($this);
1321  return $this->composer;
1322  }
1323 
1331  public function meetsDependencies(): bool {
1332  try {
1333  $this->assertDependencies();
1334 
1335  return true;
1336  } catch (PluginException $e) {
1337  return false;
1338  }
1339  }
1340 
1349  public function assertDependencies(): void {
1350  $this->getComposer()->assertConflicts();
1351  $this->getComposer()->assertActivePluginConflicts();
1352  $this->getComposer()->assertRequiredPhpVersion();
1353  $this->getComposer()->assertRequiredPhpExtensions();
1354  $this->assertPluginDependencies();
1355  }
1356 
1365  protected function assertPluginDependencies(): void {
1366  foreach ($this->getDependencies() as $plugin_id => $plugin_dep) {
1367  $must_be_active = elgg_extract('must_be_active', $plugin_dep, true);
1368  $position = elgg_extract('position', $plugin_dep);
1369 
1370  $dependent_plugin = elgg_get_plugin_from_id($plugin_id);
1371 
1372  if ($must_be_active && (!$dependent_plugin instanceof \ElggPlugin || !$dependent_plugin->isActive())) {
1373  throw PluginException::factory([
1374  'message' => elgg_echo('PluginException:PluginMustBeActive', [$plugin_id]),
1375  'plugin' => $this,
1376  ]);
1377  }
1378 
1379  if ($dependent_plugin instanceof \ElggPlugin && $position && $dependent_plugin->isActive()) {
1380  if ($position == 'after' && ($this->getPriority() < $dependent_plugin->getPriority())) {
1381  throw PluginException::factory([
1382  'message' => elgg_echo('PluginException:PluginMustBeAfter', [$plugin_id]),
1383  'plugin' => $this,
1384  ]);
1385  } elseif ($position == 'before' && ($this->getPriority() > $dependent_plugin->getPriority())) {
1386  throw PluginException::factory([
1387  'message' => elgg_echo('PluginException:PluginMustBeBefore', [$plugin_id]),
1388  'plugin' => $this,
1389  ]);
1390  }
1391  }
1392  }
1393  }
1394 
1400  public function getVersion(): string {
1401  // composer version
1402  $version = $this->getComposer()->getConfiguration()->version();
1403  if (!elgg_is_empty($version)) {
1404  return $version;
1405  }
1406 
1407  // elgg-plugin version
1408  $plugin_config = $this->getStaticConfig('plugin', []);
1409  $version = elgg_extract('version', $plugin_config);
1410  if (!elgg_is_empty($version)) {
1411  return $version;
1412  }
1413 
1414  // bundled plugins use elgg version
1415  if (in_array($this->getID(), Plugins::BUNDLED_PLUGINS)) {
1416  return elgg_get_release();
1417  }
1418 
1419  return '0.1';
1420  }
1421 
1429  public function getCategories(): array {
1430  return $this->getComposer()->getCategories();
1431  }
1432 
1440  public function getLicense(): string {
1441  return $this->getComposer()->getLicense();
1442  }
1443 
1451  public function getDescription(): string {
1452  return (string) $this->getComposer()->getConfiguration()->description();
1453  }
1454 
1462  public function getRepositoryURL(): string {
1463  return (string) $this->getComposer()->getConfiguration()->support()->source();
1464  }
1465 
1473  public function getBugTrackerURL(): string {
1474  return (string) $this->getComposer()->getConfiguration()->support()->issues();
1475  }
1476 
1484  public function getWebsite(): string {
1485  return (string) $this->getComposer()->getConfiguration()->homepage();
1486  }
1487 
1495  public function getAuthors(): array {
1496  return (array) $this->getComposer()->getConfiguration()->authors();
1497  }
1498 
1506  public function getConflicts(): array {
1507  return $this->getComposer()->getConflicts();
1508  }
1509 }
$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:306
elgg
Definition: install.js:27
registerViews()
Registers the plugin&#39;s views.
Definition: ElggPlugin.php:888
const ELGG_DISABLE_SYSTEM_LOG
Definition: constants.php:125
registerEntities()
Registers the plugin&#39;s entities.
Definition: ElggPlugin.php:917
getID()
Returns the ID (dir name) of this plugin.
Definition: ElggPlugin.php:139
elgg_get_release()
Get the current Elgg release.
elgg_get_plugins(string $status= 'active')
Returns an ordered list of plugins.
Definition: plugins.php:39
$plugin
registerActions()
Registers the plugin&#39;s actions provided in the plugin config file.
Definition: ElggPlugin.php:937
$params
Saves global plugin settings.
Definition: save.php:13
$position
Definition: add.php:11
getLanguagesPath()
Returns the plugin&#39;s languages directory full path with trailing slash.
Definition: ElggPlugin.php:190
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:17
const STATIC_CONFIG_FILENAME
Definition: ElggPlugin.php:20
$defaults
Generic entity header upload helper.
Definition: header.php:6
setSetting(string $name, $value)
Set a plugin setting for the plugin.
Definition: ElggPlugin.php:334
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 when the plugin is active. ...
Definition: ElggPlugin.php:307
$title
Definition: generic.php:50
if(elgg_view_exists("widgets/{$widget->handler}/edit")) $access
Definition: save.php:19
$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:870
meetsDependencies()
Checks if dependencies are met.
$delete
$type
Definition: delete.php:21
deleteMetadata(string $name=null)
Deletes all metadata on this object (metadata.entity_guid = $this->guid).
Definition: Metadata.php:198
unsetSetting(string $name)
Removes a plugin setting name and value.
Definition: ElggPlugin.php:361
getDescription()
Return the description.
registerRoutes()
Registers the plugin&#39;s routes provided in the plugin config file.
Definition: ElggPlugin.php:971
setPriority($priority)
Sets the priority of the plugin Returns the new priority or false on error.
Definition: ElggPlugin.php:246
$site
Definition: icons.php:5
isCacheable()
{}
activateEntities()
Activates the plugin&#39;s entities.
if($type!= 'user') $settings
Definition: save.php:16
getAllMetadata()
Get all entity metadata.
Definition: Metadata.php:37
assertCanActivate()
Asserts if a plugin can activate.
Definition: ElggPlugin.php:498
const PUBLIC_SERVICES_FILENAME
Definition: ElggPlugin.php:21
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof\ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
$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:88
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:256
getDependencies()
Returns an array of dependencies as configured in the static config.
Definition: ElggPlugin.php:576
const ADDITIONAL_TEXT_FILES
Definition: ElggPlugin.php:30
if($who_can_change_language=== 'nobody') elseif($who_can_change_language=== 'admin_only'&&!elgg_is_admin_logged_in()) $options
Definition: language.php:20
getDisplayName()
Returns the name from elgg-plugin.php if available, otherwise a nicely formatted ID.
Definition: ElggPlugin.php:149
assertStaticConfigValid()
If a static config file is present, is it a serializable array?
Definition: ElggPlugin.php:841
setPath(string $path)
Set path.
Definition: ElggPlugin.php:166
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:121
elgg_view(string $view, array $vars=[], string $viewtype= '')
Return a parsed view.
Definition: views.php:156
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:27
$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:88
initializeAttributes()
{}
Definition: ElggPlugin.php:66
A generic parent class for database exceptions.
normalizePriority($priority)
Normalize and validate new priority.
Definition: ElggPlugin.php:260
unsetAllSettings()
Removes all settings for this plugin.
Definition: ElggPlugin.php:371
getBugTrackerURL()
Returns the bug tracker page.
if(!$menu instanceof\Elgg\Menu\PreparedMenu) $actions
Definition: user_hover.php:16
setMetadata(string $name, mixed $value, string $value_type= '', bool $multiple=false)
Set metadata on this entity.
Definition: Metadata.php:78
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:101
const PRIORITY_SETTING_NAME
Definition: ElggPlugin.php:19
$extensions
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:989
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:831
registerNotifications()
Registers the plugin&#39;s notification events.
$subtype
Definition: delete.php:22
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:226
__set($name, $value)
Set a value as attribute or setting.
_elgg_services()
Get the global service provider.
Definition: elgglib.php:353
loadLanguages()
Loads the plugin&#39;s translations.
const ACCESS_PUBLIC
Definition: constants.php:12
getMetadata(string $name)
Return the value of a piece of metadata.
Definition: Metadata.php:27
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:82
getSetting(string $name, $default=null)
Returns a plugin setting when the plugin is active.
Definition: ElggPlugin.php:294
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:791
getPath()
Returns the plugin&#39;s full path with trailing slash.
Definition: ElggPlugin.php:175
getLicense()
Returns the license.
assertPluginDependencies()
Assert required plugins or plugin position.
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
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; static config file.
Definition: ElggPlugin.php:205
$guid
Reset an ElggUpgrade.
Definition: reset.php:6
getAuthors()
Returns an array of authors.