Elgg  Version 4.x
ElggPlugin.php
Go to the documentation of this file.
1 <?php
2 
8 use Elgg\Includer;
10 
15 class ElggPlugin extends ElggObject {
16 
17  const PRIORITY_SETTING_NAME = 'elgg:internal:priority';
18  const STATIC_CONFIG_FILENAME = 'elgg-plugin.php';
19  const PUBLIC_SERVICES_FILENAME = 'elgg-services.php';
20 
21  use ElggLoggable;
22 
29  'README.txt',
30  'CHANGES.txt',
31  'INSTALL.txt',
32  'COPYRIGHT.txt',
33  'LICENSE.txt',
34  'README',
35  'README.md',
36  'README.markdown',
37  ];
38 
42  protected $composer;
43 
47  protected $path;
48 
54  protected $static_config;
55 
59  protected $activated;
60 
64  protected function initializeAttributes() {
65  parent::initializeAttributes();
66 
67  $this->attributes['subtype'] = 'plugin';
68  }
69 
80  public static function fromId($plugin_id, $path = null) {
81  if (empty($plugin_id)) {
82  throw new ElggInvalidArgumentException('Plugin ID must be set');
83  }
84 
86  if (!$plugin) {
87  $plugin = elgg_call(ELGG_IGNORE_ACCESS, function() use ($plugin_id) {
88  $plugin = new ElggPlugin();
89  $plugin->title = $plugin_id;
90  $plugin->save();
91 
92  return $plugin;
93  });
94  }
95 
96  if (!$path) {
98  }
99 
100  $path = rtrim($path, '/');
101  $plugin->setPath($path . '/' . $plugin_id);
102 
103  return $plugin;
104  }
105 
109  public function save() : bool {
110 
112 
113  $this->attributes['owner_guid'] = $site->guid;
114  $this->attributes['container_guid'] = $site->guid;
115  $this->attributes['access_id'] = ACCESS_PUBLIC;
116 
117  $new = !$this->guid;
118  $priority = null;
119  if ($new) {
120  $priority = elgg_extract(self::PRIORITY_SETTING_NAME, $this->temp_private_settings, 'new');
121  } elseif ($this->getPriority() === null) {
122  $priority = 'last';
123  }
124 
125  if ($priority) {
126  $this->setPriority($priority);
127  }
128 
129  return parent::save();
130  }
131 
137  public function getID() {
138  return (string) $this->title;
139  }
140 
147  public function getDisplayName() {
148  $name = elgg_extract('name', $this->getStaticConfig('plugin', []), '');
149  if (!empty($name)) {
150  return $name;
151  }
152 
153  return ucwords(str_replace(['-', '_'], ' ', $this->getID()));
154  }
155 
164  public function setPath($path) {
165  $this->path = \Elgg\Project\Paths::sanitize($path, true);
166  }
167 
173  public function getPath() {
174  if (isset($this->path)) {
175  return $this->path;
176  }
177 
178  $this->setPath(elgg_get_plugins_path() . $this->getID());
179  return $this->path;
180  }
181 
188  protected function getLanguagesPath() {
189  return $this->getPath() . 'languages/';
190  }
191 
203  public function getStaticConfig($key, $default = null) {
204  if ($this->static_config === null) {
205  $this->static_config = [];
206 
207  try {
208  $this->static_config = $this->includeFile(self::STATIC_CONFIG_FILENAME);
209  } catch (PluginException $ex) {
210  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
211  }
212  }
213 
214  return $this->static_config[$key] ?? $default;
215  }
216 
217  // Load Priority
218 
224  public function getPriority(): ?int {
225  $priority = $this->getPrivateSetting(self::PRIORITY_SETTING_NAME);
226  if (isset($priority)) {
227  return (int) $priority;
228  }
229 
230  return null;
231  }
232 
244  public function setPriority($priority) {
246 
247  return _elgg_services()->plugins->setPriority($this, $priority);
248  }
249 
258  protected function normalizePriority($priority): int {
259  // if no priority assume a priority of 1
260  $old_priority = $this->getPriority();
261  $old_priority = $old_priority ? : 1;
262  $max_priority = _elgg_services()->plugins->getMaxPriority() ? : 1;
263 
264  // can't use switch here because it's not strict and php evaluates +1 == 1
265  if ($priority === '+1') {
266  $priority = $old_priority + 1;
267  } else if ($priority === '-1') {
268  $priority = $old_priority - 1;
269  } else if ($priority === 'first') {
270  $priority = 1;
271  } else if ($priority === 'last') {
272  $priority = $max_priority;
273  } else if ($priority === 'new') {
274  $max_priority++;
275  $priority = $max_priority;
276  }
277 
278  return min($max_priority, max(1, (int) $priority));
279  }
280 
281  // Plugin settings
282 
291  public function getSetting(string $name, $default = null) {
292  $values = $this->getAllSettings();
293  return elgg_extract($name, $values, $default);
294  }
295 
303  public function getAllSettings(): array {
304 
305  try {
306  $defaults = [];
307  if ($this->isActive()) {
308  // only load settings from static config for active plugins to prevent issues
309  // with internal plugin references ie. classes and language keys
310  $defaults = $this->getStaticConfig('settings', []);
311  }
312 
313  $settings = $this->getAllPrivateSettings();
314 
315  return array_merge($defaults, $settings);
316  } catch (DatabaseException $ex) {
317  return [];
318  }
319  }
320 
329  public function setSetting(string $name, $value): bool {
330 
331  $value = _elgg_services()->hooks->trigger('setting', 'plugin', [
332  'plugin_id' => $this->getID(),
333  'plugin' => $this,
334  'name' => $name,
335  'value' => $value,
336  ], $value);
337 
338  if (is_array($value)) {
339  elgg_log('Plugin settings cannot store arrays.', 'ERROR');
340 
341  return false;
342  }
343 
344  return $this->setPrivateSetting($name, $value);
345  }
346 
354  public function unsetSetting(string $name): bool {
355  return $this->removePrivateSetting($name);
356  }
357 
362  public function unsetAllSettings(): bool {
363  $settings = $this->getAllSettings();
364 
365  foreach ($settings as $name => $value) {
366  if (strpos($name, 'elgg:internal:') === 0) {
367  continue;
368  }
369 
370  $this->unsetSetting($name);
371  }
372 
373  return true;
374  }
375 
376  // User settings
377 
389  public function getUserSetting(string $name, int $user_guid = 0, $default = null) {
390  $this->logDeprecatedMessage(__METHOD__ . ' is deprecated use \ElggUser::getPluginSetting()', '4.0');
391 
392  $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid);
393  if (!$user instanceof ElggUser) {
394  return $default;
395  }
396 
397  return $user->getPluginSetting($this->getID(), $name, $default);
398  }
399 
411  public function setUserSetting(string $name, $value, int $user_guid = 0): bool {
412  $this->logDeprecatedMessage(__METHOD__ . ' is deprecated use \ElggUser::setPluginSetting()', '4.0');
413 
414  $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid);
415  if (!$user instanceof ElggUser) {
416  return false;
417  }
418 
419  return $user->setPluginSetting($this->getID(), $name, $value);
420  }
421 
432  public function unsetUserSetting(string $name, int $user_guid = 0): bool {
433  $this->logDeprecatedMessage(__METHOD__ . ' is deprecated use \ElggUser::removePluginSetting()', '4.0');
434 
435  $user = _elgg_services()->entityTable->getUserForPermissionsCheck($user_guid);
436  if (!$user instanceof ElggUser) {
437  return false;
438  }
439 
440  return $user->removePluginSetting($this->getID(), $name);
441  }
442 
449  public function unsetAllEntityAndPluginSettings(): bool {
450  // remove all plugin settings
451  $result = $this->unsetAllSettings();
452 
453  // entity plugin settings are stored with the entity
454  $delete = Delete::fromTable('private_settings');
455  $delete->andWhere($delete->compare('name', 'like', "plugin:%_setting:{$this->getID()}:%", ELGG_VALUE_STRING));
456 
457  try {
458  _elgg_services()->db->deleteData($delete);
459  _elgg_services()->dataCache->private_settings->clear();
460 
461  $result &= true;
462  } catch (DatabaseException $e) {
463  elgg_log($e, 'ERROR');
464 
465  $result &= false;
466  }
467 
468  // trigger a hook, so plugin devs can also remove settings
469  $params = [
470  'entity' => $this,
471  ];
472  return (bool) _elgg_services()->hooks->trigger('remove:settings', 'plugin', $params, $result);
473  }
474 
481  public function isValid(): bool {
482  try {
483  $this->assertValid();
484  return true;
485  } catch (PluginException $e) {
486  return false;
487  }
488  }
489 
498  public function assertValid(): void {
499  if (!$this->getID()) {
500  throw PluginException::factory([
501  'message' => elgg_echo('ElggPlugin:MissingID', [$this->guid]),
502  'plugin' => $this,
503  ]);
504  }
505 
506  $this->getComposer()->assertPluginId();
507 
508  if (file_exists($this->getPath() . 'start.php')) {
509  throw PluginException::factory([
510  'message' => elgg_echo('ElggPlugin:StartFound', [$this->getID()]),
511  'plugin' => $this,
512  ]);
513  }
514  }
515 
521  public function isActive(): bool {
522  if (isset($this->activated)) {
523  return $this->activated;
524  }
525 
526  $this->activated = elgg_is_active_plugin($this->getID());
527  return $this->activated;
528  }
529 
536  public function canActivate(): bool {
537  if ($this->isActive()) {
538  return false;
539  }
540 
541  try {
542  $this->assertCanActivate();
543  return true;
544  } catch (PluginException $e) {
545  return false;
546  }
547  }
548 
557  public function assertCanActivate(): void {
558  $this->assertValid();
559  $this->assertDependencies();
560  }
561 
562  // activating and deactivating
563 
570  public function activate(): bool {
571  if ($this->isActive()) {
572  return false;
573  }
574 
575  $this->assertCanActivate();
576 
577  // Check this before setting status because the file could potentially throw
578  $this->assertStaticConfigValid();
579 
580  if (!$this->setStatus(true)) {
581  return false;
582  }
583 
584  // perform tasks and emit events
585  // emit an event. returning false will make this not be activated.
586  // we need to do this after it's been fully activated
587  // or the deactivate will be confused.
588  $params = [
589  'plugin_id' => $this->getID(),
590  'plugin_entity' => $this,
591  ];
592 
593  $return = _elgg_services()->events->trigger('activate', 'plugin', $params);
594 
595  // if there are any on_enable functions, start the plugin now and run them
596  // Note: this will not run re-run the init hooks!
597  if ($return) {
598  try {
600 
601  $this->register();
602 
603  // directly load languages to have them available during runtime
604  $this->loadLanguages();
605 
606  $this->boot();
607 
608  $this->getBootstrap()->activate();
609 
610  $this->init();
611  } catch (PluginException $ex) {
612  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
613 
614  $return = false;
615  }
616  }
617 
618  if ($return === false) {
619  $this->deactivate();
620  } else {
621  elgg_delete_admin_notice("cannot_start {$this->getID()}");
622 
624  _elgg_services()->logger->notice("Plugin {$this->getID()} has been activated");
625  }
626 
627  return $return;
628  }
629 
635  public function getDependencies(): array {
636  $plugin_config = $this->getStaticConfig('plugin', []);
637  return (array) elgg_extract('dependencies', $plugin_config, []);
638  }
639 
647  public function canDeactivate(): bool {
648  if (!$this->isActive()) {
649  return false;
650  }
651 
652  try {
653  $this->assertcanDeactivate();
654  return true;
655  } catch (PluginException $e) {
656  return false;
657  }
658  }
659 
668  public function assertCanDeactivate(): void {
669  $dependents = [];
670 
671  $active_plugins = elgg_get_plugins();
672 
673  foreach ($active_plugins as $plugin) {
674  $dependencies = $plugin->getDependencies();
675  if (!array_key_exists($this->getID(), $dependencies)) {
676  continue;
677  }
678 
679  if (elgg_extract('must_be_active', $dependencies[$this->getID()], true)) {
680  $dependents[$plugin->getID()] = $plugin;
681  }
682  }
683 
684  if (empty($dependents)) {
685  return;
686  }
687 
688  $list = array_map(function (\ElggPlugin $plugin) {
689  $css_id = preg_replace('/[^a-z0-9-]/i', '-', $plugin->getID());
690 
691  return elgg_view('output/url', [
692  'text' => $plugin->getDisplayName(),
693  'href' => "#{$css_id}",
694  ]);
695  }, $dependents);
696 
697  $list = implode(', ', $list);
698  throw PluginException::factory([
699  'message' => elgg_echo('ElggPlugin:Dependencies:ActiveDependent', [$this->getDisplayName(), $list]),
700  'plugin' => $this,
701  ]);
702  }
703 
711  public function deactivate(): bool {
712  if (!$this->isActive()) {
713  return false;
714  }
715 
716  $this->assertCanDeactivate();
717 
718  // emit an event. returning false will cause this to not be deactivated.
719  $params = [
720  'plugin_id' => $this->getID(),
721  'plugin_entity' => $this,
722  ];
723 
724  $return = _elgg_services()->events->trigger('deactivate', 'plugin', $params);
725  if ($return === false) {
726  return false;
727  }
728 
729  $this->getBootstrap()->deactivate();
730 
731  $this->deactivateEntities();
732 
734 
735  _elgg_services()->logger->notice("Plugin {$this->getID()} has been deactivated");
736 
737  return $this->setStatus(false);
738  }
739 
748  public function getBootstrap(): \Elgg\PluginBootstrapInterface {
749  $bootstrap = $this->getStaticConfig('bootstrap');
750  if ($bootstrap) {
751  if (!is_subclass_of($bootstrap, \Elgg\PluginBootstrapInterface::class)) {
752  throw PluginException::factory([
753  'message' => elgg_echo('LogicException:InterfaceNotImplemented', [
754  $bootstrap,
755  \Elgg\PluginBootstrapInterface::class
756  ]),
757  'plugin' => $this,
758  ]);
759  }
760 
761  return new $bootstrap($this, elgg());
762  }
763 
764  return new \Elgg\DefaultPluginBootstrap($this, elgg());
765  }
766 
773  public function autoload(): void {
774  $this->registerClasses();
775 
776  $autoload_file = 'vendor/autoload.php';
777  if (!$this->canReadFile($autoload_file)) {
778  return;
779  }
780 
781  $autoloader = Includer::requireFileOnce("{$this->getPath()}{$autoload_file}");
782 
783  if (!$autoloader instanceof \Composer\Autoload\ClassLoader) {
784  return;
785  }
786 
787  $autoloader->unregister();
788 
789  // plugins should be appended, composer defaults to prepend
790  $autoloader->register(false);
791  }
792 
801  public function register(): void {
802  $this->autoload();
803 
804  $this->registerPublicServices();
805  $this->activateEntities();
806  $this->registerLanguages();
807  $this->registerViews();
808 
809  $this->getBootstrap()->load();
810  }
811 
818  public function boot(): void {
819  $this->getBootstrap()->boot();
820  }
821 
828  public function init(): void {
829  $this->registerRoutes();
830  $this->registerActions();
831  $this->registerEntities();
832  $this->registerWidgets();
833  $this->registerHooks();
834  $this->registerEvents();
835  $this->registerViewExtensions();
836  $this->registerGroupTools();
837  $this->registerViewOptions();
838  $this->registerNotifications();
839 
840  $this->getBootstrap()->init();
841  }
842 
851  protected function includeFile(string $filename) {
852  $filepath = "{$this->getPath()}{$filename}";
853 
854  if (!$this->canReadFile($filename)) {
855  $msg = elgg_echo(
856  'ElggPlugin:Exception:CannotIncludeFile',
857  [$filename, $this->getID(), $this->guid, $this->getPath()]
858  );
859 
860  throw PluginException::factory([
861  'message' => $msg,
862  'plugin' => $this,
863  ]);
864  }
865 
866  try {
867  $ret = Includer::requireFile($filepath);
868  } catch (Exception $e) {
869  $msg = elgg_echo(
870  'ElggPlugin:Exception:IncludeFileThrew',
871  [$filename, $this->getID(), $this->guid, $this->getPath()]
872  );
873 
874  throw PluginException::factory([
875  'message' => $msg,
876  'previous' => $e,
877  'plugin' => $this,
878  ]);
879  }
880 
881  return $ret;
882  }
883 
891  protected function canReadFile(string $filename): bool {
892  return is_file("{$this->getPath()}{$filename}");
893  }
894 
901  protected function assertStaticConfigValid(): void {
902  if (!$this->canReadFile(self::STATIC_CONFIG_FILENAME)) {
903  return;
904  }
905 
906  ob_start();
907  $value = $this->includeFile(self::STATIC_CONFIG_FILENAME);
908  if (ob_get_clean() !== '') {
909  throw PluginException::factory([
910  'message' => elgg_echo('ElggPlugin:activate:ConfigSentOutput'),
911  'plugin' => $this,
912  ]);
913  }
914 
915  // make sure can serialize
916  $value = @unserialize(serialize($value));
917  if (!is_array($value)) {
918  throw PluginException::factory([
919  'message' => elgg_echo('ElggPlugin:activate:BadConfigFormat'),
920  'plugin' => $this,
921  ]);
922  }
923  }
924 
930  protected function registerPublicServices(): void {
931  $services_path = $this->getPath() . self::PUBLIC_SERVICES_FILENAME;
932  if (!is_file($services_path)) {
933  return;
934  }
935 
936  $services = Includer::includeFile($services_path);
937  foreach ($services as $name => $definition) {
938  elgg()->set($name, $definition);
939  }
940  }
941 
948  protected function registerViews(): void {
949  if (_elgg_services()->config->system_cache_loaded) {
950  return;
951  }
952 
953  $views = _elgg_services()->views;
954 
955  // Declared views first
956  $spec = $this->getStaticConfig('views');
957  if ($spec) {
958  $views->mergeViewsSpec($spec);
959  }
960 
961  // Allow /views directory files to override
962  if (!$views->registerPluginViews($this->getPath())) {
963  $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews', [$this->getID(), $this->guid, $this->getPath()]);
964 
965  throw PluginException::factory([
966  'message' => $msg,
967  'plugin' => $this,
968  ]);
969  }
970  }
971 
977  protected function registerEntities(): void {
978  $spec = (array) $this->getStaticConfig('entities', []);
979 
980  foreach ($spec as $entity) {
981  if (!isset($entity['type']) || !isset($entity['subtype'])) {
982  continue;
983  }
984 
985  $searchable = elgg_extract('searchable', $entity);
986  if ($searchable) {
987  elgg_deprecated_notice("Registering the [{$entity['type']}-{$entity['subtype']}] entity as searchable should be done in the capabilities section of your elgg-plugin.php.", '4.1');
988 
989  elgg_entity_enable_capability($entity['type'], $entity['subtype'], 'searchable');
990  }
991 
992  $capabilities = elgg_extract('capabilities', $entity, []);
993  foreach ($capabilities as $capability => $value) {
994  _elgg_services()->entity_capabilities->setCapability($entity['type'], $entity['subtype'], $capability, $value);
995  }
996  }
997  }
998 
1004  protected function registerActions(): void {
1005  $actions = _elgg_services()->actions;
1006  $root_path = rtrim($this->getPath(), '/\\');
1007 
1008  $spec = (array) $this->getStaticConfig('actions', []);
1009 
1010  foreach ($spec as $action => $action_spec) {
1011  if (!is_array($action_spec)) {
1012  continue;
1013  }
1014 
1015  $access = elgg_extract('access', $action_spec, 'logged_in');
1016  $handler = elgg_extract('controller', $action_spec);
1017  if (!$handler) {
1018  $handler = elgg_extract('filename', $action_spec);
1019  if (!$handler) {
1020  $handler = "$root_path/actions/{$action}.php";
1021  }
1022  }
1023 
1024  $actions->register($action, $handler, $access);
1025  }
1026  }
1027 
1033  protected function registerRoutes(): void {
1034  $routes = _elgg_services()->routes;
1035 
1036  $spec = (array) $this->getStaticConfig('routes', []);
1037  foreach ($spec as $name => $route_spec) {
1038  if (!is_array($route_spec)) {
1039  continue;
1040  }
1041 
1042  $routes->register($name, $route_spec);
1043  }
1044  }
1045 
1051  protected function registerWidgets(): void {
1052  $widgets = _elgg_services()->widgets;
1053 
1054  $spec = (array) $this->getStaticConfig('widgets', []);
1055  foreach ($spec as $widget_id => $widget_definition) {
1056  if (!is_array($widget_definition)) {
1057  continue;
1058  }
1059  if (!isset($widget_definition['id'])) {
1060  $widget_definition['id'] = $widget_id;
1061  }
1062 
1063  $definition = \Elgg\WidgetDefinition::factory($widget_definition);
1064 
1065  $widgets->registerType($definition);
1066  }
1067  }
1068 
1076  public function registerLanguages(): void {
1077  _elgg_services()->translator->registerLanguagePath($this->getLanguagesPath());
1078  }
1079 
1089  protected function loadLanguages(): void {
1090  $languages_path = $this->getLanguagesPath();
1091  if (!is_dir($languages_path)) {
1092  return;
1093  }
1094 
1095  _elgg_services()->translator->registerTranslations($languages_path);
1096  }
1097 
1103  protected function registerClasses(): void {
1104  _elgg_services()->autoloadManager->addClasses("{$this->getPath()}classes");
1105  }
1106 
1112  protected function activateEntities(): void {
1113  $spec = (array) $this->getStaticConfig('entities', []);
1114 
1115  foreach ($spec as $entity) {
1116  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1117  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype'], $entity['class']);
1118  }
1119  }
1120  }
1121 
1127  protected function deactivateEntities(): void {
1128  $spec = (array) $this->getStaticConfig('entities', []);
1129 
1130  foreach ($spec as $entity) {
1131  if (isset($entity['type'], $entity['subtype'], $entity['class'])) {
1132  _elgg_services()->entityTable->setEntityClass($entity['type'], $entity['subtype']);
1133  }
1134  }
1135  }
1136 
1142  protected function registerHooks(): void {
1143  $hooks = _elgg_services()->hooks;
1144 
1145  $spec = (array) $this->getStaticConfig('hooks', []);
1146 
1147  foreach ($spec as $name => $types) {
1148  foreach ($types as $type => $callbacks) {
1149  foreach ($callbacks as $callback => $hook_spec) {
1150  if (!is_array($hook_spec)) {
1151  continue;
1152  }
1153 
1154  $unregister = (bool) elgg_extract('unregister', $hook_spec, false);
1155 
1156  if ($unregister) {
1157  $hooks->unregisterHandler($name, $type, $callback);
1158  } else {
1159  $priority = (int) elgg_extract('priority', $hook_spec, 500);
1160 
1161  $hooks->registerHandler($name, $type, $callback, $priority);
1162  }
1163  }
1164  }
1165  }
1166  }
1167 
1173  protected function registerEvents(): void {
1174  $events = _elgg_services()->events;
1175 
1176  $spec = (array) $this->getStaticConfig('events', []);
1177 
1178  foreach ($spec as $name => $types) {
1179  foreach ($types as $type => $callbacks) {
1180  foreach ($callbacks as $callback => $hook_spec) {
1181  if (!is_array($hook_spec)) {
1182  continue;
1183  }
1184 
1185  $unregister = (bool) elgg_extract('unregister', $hook_spec, false);
1186 
1187  if ($unregister) {
1188  $events->unregisterHandler($name, $type, $callback);
1189  } else {
1190  $priority = (int) elgg_extract('priority', $hook_spec, 500);
1191 
1192  $events->registerHandler($name, $type, $callback, $priority);
1193  }
1194  }
1195  }
1196  }
1197  }
1198 
1204  protected function registerViewExtensions(): void {
1205  $views = _elgg_services()->views;
1206 
1207  $spec = (array) $this->getStaticConfig('view_extensions', []);
1208 
1209  foreach ($spec as $src_view => $extensions) {
1210  foreach ($extensions as $extention => $extention_spec) {
1211  if (!is_array($extention_spec)) {
1212  continue;
1213  }
1214 
1215  $unextend = (bool) elgg_extract('unextend', $extention_spec, false);
1216 
1217  if ($unextend) {
1218  $views->unextendView($src_view, $extention);
1219  } else {
1220  $priority = (int) elgg_extract('priority', $extention_spec, 501);
1221 
1222  $views->extendView($src_view, $extention, $priority);
1223  }
1224  }
1225  }
1226  }
1227 
1233  protected function registerGroupTools(): void {
1234  $tools = _elgg_services()->group_tools;
1235 
1236  $spec = (array) $this->getStaticConfig('group_tools', []);
1237 
1238  foreach ($spec as $tool_name => $tool_options) {
1239  if (!is_array($tool_options)) {
1240  continue;
1241  }
1242 
1243  $unregister = (bool) elgg_extract('unregister', $tool_options, false);
1244 
1245  if ($unregister) {
1246  $tools->unregister($tool_name);
1247  } else {
1248  $tools->register($tool_name, $tool_options);
1249  }
1250  }
1251  }
1252 
1258  protected function registerViewOptions(): void {
1259  $spec = (array) $this->getStaticConfig('view_options', []);
1260 
1261  foreach ($spec as $view_name => $options) {
1262  if (!is_array($options)) {
1263  continue;
1264  }
1265 
1266  if (isset($options['ajax'])) {
1267  if ($options['ajax'] === true) {
1268  _elgg_services()->ajax->registerView($view_name);
1269  } else {
1270  _elgg_services()->ajax->unregisterView($view_name);
1271  }
1272  }
1273 
1274  if (isset($options['simplecache']) && $options['simplecache'] === true) {
1275  _elgg_services()->views->registerCacheableView($view_name);
1276  }
1277  }
1278  }
1279 
1285  protected function registerNotifications(): void {
1286  $spec = (array) $this->getStaticConfig('notifications', []);
1287 
1288  foreach ($spec as $type => $subtypes) {
1289  foreach ($subtypes as $subtype => $actions) {
1290  foreach ($actions as $action => $callback) {
1291  if ($callback === false) {
1292  _elgg_services()->notifications->unregisterEvent($type, $subtype, [$action]);
1293  } elseif ($callback === true) {
1294  _elgg_services()->notifications->registerEvent($type, $subtype, [$action]);
1295  } else {
1296  _elgg_services()->notifications->registerEvent($type, $subtype, [$action], $callback);
1297  }
1298  }
1299  }
1300  }
1301  }
1302 
1310  public function __get($name) {
1311  // See if its in our base attribute
1312  if (array_key_exists($name, $this->attributes)) {
1313  return $this->attributes[$name];
1314  }
1315 
1316  // object title and description are stored as metadata
1317  if (in_array($name, ['title', 'description'])) {
1318  return parent::__get($name);
1319  }
1320 
1321  $result = $this->getPrivateSetting($name);
1322  if ($result !== null) {
1323  return $result;
1324  }
1325 
1326  $defaults = $this->getStaticConfig('settings', []);
1327 
1328  return elgg_extract($name, $defaults, $result);
1329  }
1330 
1341  public function __set($name, $value) {
1342  if (array_key_exists($name, $this->attributes)) {
1343  // Check that we're not trying to change the guid!
1344  if ((array_key_exists('guid', $this->attributes)) && ($name == 'guid')) {
1345  return;
1346  }
1347 
1348  $this->attributes[$name] = $value;
1349 
1350  return;
1351  }
1352 
1353  // object title and description are stored as metadata
1354  if (in_array($name, ['title', 'description'])) {
1355  parent::__set($name, $value);
1356 
1357  return;
1358  }
1359 
1360  // to make sure we trigger the correct hooks
1361  $this->setSetting($name, $value);
1362  }
1363 
1371  protected function setStatus(bool $active): bool {
1372  if (!$this->guid) {
1373  return false;
1374  }
1375 
1377  if ($active) {
1378  $result = _elgg_services()->relationshipsTable->add($this->guid, 'active_plugin', $site->guid);
1379  } else {
1380  $result = _elgg_services()->relationshipsTable->remove($this->guid, 'active_plugin', $site->guid);
1381  }
1382 
1383  if ($result) {
1384  $this->activated = $active;
1385  }
1386 
1387  $this->invalidateCache();
1388 
1389  return $result;
1390  }
1391 
1395  public function isCacheable() {
1396  return true;
1397  }
1398 
1402  public function cache($persist = true) {
1403  _elgg_services()->plugins->cache($this);
1404 
1405  parent::cache($persist);
1406  }
1407 
1411  public function invalidateCache() {
1412 
1413  _elgg_services()->boot->clearCache();
1414  _elgg_services()->plugins->invalidateCache($this->getID());
1415 
1416  parent::invalidateCache();
1417  }
1418 
1426  protected function getComposer(): \Elgg\Plugin\Composer {
1427  if (isset($this->composer)) {
1428  return $this->composer;
1429  }
1430 
1431  $this->composer = new \Elgg\Plugin\Composer($this);
1432  return $this->composer;
1433  }
1434 
1442  public function meetsDependencies(): bool {
1443  try {
1444  $this->assertDependencies();
1445 
1446  return true;
1447  } catch (PluginException $e) {
1448  return false;
1449  }
1450  }
1451 
1460  public function assertDependencies(): void {
1461  $this->getComposer()->assertConflicts();
1462  $this->getComposer()->assertActivePluginConflicts();
1463  $this->getComposer()->assertRequiredPhpVersion();
1464  $this->getComposer()->assertRequiredPhpExtensions();
1465  $this->assertPluginDependencies();
1466  }
1467 
1476  protected function assertPluginDependencies(): void {
1477  foreach ($this->getDependencies() as $plugin_id => $plugin_dep) {
1478  $must_be_active = elgg_extract('must_be_active', $plugin_dep, true);
1479  $position = elgg_extract('position', $plugin_dep);
1480 
1481  $dependent_plugin = elgg_get_plugin_from_id($plugin_id);
1482 
1483  if ($must_be_active && (!$dependent_plugin instanceof \ElggPlugin || !$dependent_plugin->isActive())) {
1484  throw PluginException::factory([
1485  'message' => elgg_echo('PluginException:PluginMustBeActive', [$plugin_id]),
1486  'plugin' => $this,
1487  ]);
1488  }
1489 
1490  if ($dependent_plugin instanceof \ElggPlugin && $position && $dependent_plugin->isActive()) {
1491  if ($position == 'after' && ($this->getPriority() < $dependent_plugin->getPriority())) {
1492  throw PluginException::factory([
1493  'message' => elgg_echo('PluginException:PluginMustBeAfter', [$plugin_id]),
1494  'plugin' => $this,
1495  ]);
1496  } elseif ($position == 'before' && ($this->getPriority() > $dependent_plugin->getPriority())) {
1497  throw PluginException::factory([
1498  'message' => elgg_echo('PluginException:PluginMustBeBefore', [$plugin_id]),
1499  'plugin' => $this,
1500  ]);
1501  }
1502  }
1503  }
1504  }
1505 
1511  public function getVersion(): string {
1512  // composer version
1513  $version = $this->getComposer()->getConfiguration()->version();
1514  if (!elgg_is_empty($version)) {
1515  return $version;
1516  }
1517 
1518  // elgg-plugin version
1519  $plugin_config = $this->getStaticConfig('plugin', []);
1520  $version = elgg_extract('version', $plugin_config);
1521  if (!elgg_is_empty($version)) {
1522  return $version;
1523  }
1524 
1525  // bundled plugins use elgg version
1526  if (in_array($this->getID(), Plugins::BUNDLED_PLUGINS)) {
1527  return elgg_get_release();
1528  }
1529 
1530  return '0.1';
1531  }
1532 
1540  public function getCategories(): array {
1541  return $this->getComposer()->getCategories();
1542  }
1543 
1551  public function getLicense(): string {
1552  return $this->getComposer()->getLicense();
1553  }
1554 
1562  public function getDescription(): string {
1563  return (string) $this->getComposer()->getConfiguration()->description();
1564  }
1565 
1573  public function getRepositoryURL(): string {
1574  return (string) $this->getComposer()->getConfiguration()->support()->source();
1575  }
1576 
1584  public function getBugTrackerURL(): string {
1585  return (string) $this->getComposer()->getConfiguration()->support()->issues();
1586  }
1587 
1595  public function getWebsite(): string {
1596  return (string) $this->getComposer()->getConfiguration()->homepage();
1597  }
1598 
1606  public function getAuthors(): array {
1607  return (array) $this->getComposer()->getConfiguration()->authors();
1608  }
1609 
1617  public function getConflicts(): array {
1618  return $this->getComposer()->getConflicts();
1619  }
1620 }
$default
Definition: checkbox.php:31
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:731
registerViews()
Registers the plugin&#39;s views.
Definition: ElggPlugin.php:948
registerEntities()
Registers the plugin&#39;s entities.
Definition: ElggPlugin.php:977
getID()
Returns the ID (dir name) of this plugin.
Definition: ElggPlugin.php:137
elgg_get_release()
Get the current Elgg release.
elgg_get_plugins(string $status= 'active')
Returns an ordered list of plugins.
Definition: plugins.php:55
$user_guid
Definition: login_as.php:10
$plugin
registerActions()
Registers the plugin&#39;s actions provided in the plugin config file.
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
$params
Saves global plugin settings.
Definition: save.php:13
getAllPrivateSettings()
Returns all private settings.
Definition: ElggEntity.php:659
getLanguagesPath()
Returns the plugin&#39;s languages directory full path with trailing slash.
Definition: ElggPlugin.php:188
registerClasses()
Registers the plugin&#39;s classes.
assertCanDeactivate()
Asserts if a plugin can be deactivated.
Definition: ElggPlugin.php:668
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: deprecation.php:52
const STATIC_CONFIG_FILENAME
Definition: ElggPlugin.php:18
removePrivateSetting($name)
Removes private setting.
Definition: ElggEntity.php:674
setSetting(string $name, $value)
Set a plugin setting for the plugin.
Definition: ElggPlugin.php:329
elgg_get_plugin_from_id(string $plugin_id)
Elgg plugins library Contains functions for managing plugins.
Definition: plugins.php:15
setPrivateSetting($name, $value)
Adds a private setting to this entity.
Definition: ElggEntity.php:608
$defaults
getAllSettings()
Returns an array of all settings saved for this plugin.
Definition: ElggPlugin.php:303
$title
Definition: generic.php:50
getUserSetting(string $name, int $user_guid=0, $default=null)
Returns a user&#39;s setting for this plugin.
Definition: ElggPlugin.php:389
if(elgg_view_exists("widgets/{$widget->handler}/edit")) $access
Definition: save.php:19
getPrivateSetting($name)
Returns a private setting value.
Definition: ElggEntity.php:646
$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
setUserSetting(string $name, $value, int $user_guid=0)
Sets a user setting for a plugin.
Definition: ElggPlugin.php:411
assertValid()
Asserts if a plugin is valid.
Definition: ElggPlugin.php:498
invalidateCache()
{}
$subtype
Definition: delete.php:22
registerPublicServices()
Registers the plugin public services.
Definition: ElggPlugin.php:930
meetsDependencies()
Checks if dependencies are met.
$delete
cache($persist=true)
{}
unsetSetting(string $name)
Removes a plugin setting name and value.
Definition: ElggPlugin.php:354
getDescription()
Return the description.
$type
Definition: delete.php:21
registerRoutes()
Registers the plugin&#39;s routes provided in the plugin config file.
setPriority($priority)
Sets the priority of the plugin Returns the new priority or false on error.
Definition: ElggPlugin.php:244
$site
Definition: icons.php:5
isCacheable()
{}
activateEntities()
Activates the plugin&#39;s entities.
if($type!= 'user') $settings
Definition: save.php:16
elgg_echo($message_key, array $args=[], $language="")
Elgg language module Functions to manage language and translations.
Definition: languages.php:18
elgg_entity_enable_capability(string $type, string $subtype, string $capability)
Enables the capability for a specified type/subtype.
Definition: entities.php:751
assertCanActivate()
Asserts if a plugin can activate.
Definition: ElggPlugin.php:557
$position
Definition: move.php:7
const PUBLIC_SERVICES_FILENAME
Definition: ElggPlugin.php:19
$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:201
canDeactivate()
Checks if this plugin can be deactivated on the current Elgg installation.
Definition: ElggPlugin.php:647
elgg_invalidate_caches()
Invalidate all the registered caches.
Definition: cache.php:183
getDependencies()
Returns an array of dependencies as configured in the static config.
Definition: ElggPlugin.php:635
const ADDITIONAL_TEXT_FILES
Definition: ElggPlugin.php:28
getDisplayName()
Returns the name from elgg-plugin.php if available, otherwise a nicely formatted ID.
Definition: ElggPlugin.php:147
assertStaticConfigValid()
If a static config file is present, is it a serializable array?
Definition: ElggPlugin.php:901
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:146
assertDependencies()
Assert plugin dependencies.
isActive()
Is this plugin active?
Definition: ElggPlugin.php:521
$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:17
setStatus(bool $active)
Sets the plugin to active or inactive.
init()
Init the plugin.
Definition: ElggPlugin.php:828
elgg_log($message, $level=\Psr\Log\LogLevel::NOTICE)
Log a message.
Definition: elgglib.php:399
initializeAttributes()
{}
Definition: ElggPlugin.php:64
A generic parent class for database exceptions.
normalizePriority($priority)
Normalize and validate new priority.
Definition: ElggPlugin.php:258
$user
Definition: ban.php:7
unsetAllSettings()
Removes all settings for this plugin.
Definition: ElggPlugin.php:362
getBugTrackerURL()
Returns the bug tracker page.
getStaticConfig($key, $default=null)
Get a value from the plugins&#39;s static config file.
Definition: ElggPlugin.php:203
if(!$menu instanceof\Elgg\Menu\PreparedMenu) $actions
Definition: user_hover.php:16
getWebsite()
Return the website.
getBootstrap()
Bootstrap object.
Definition: ElggPlugin.php:748
isValid()
Returns if the plugin is complete, meaning has all required files and Elgg can read them and they mak...
Definition: ElggPlugin.php:481
elgg_get_site_entity()
Get the current site entity.
Definition: entities.php:99
const PRIORITY_SETTING_NAME
Definition: ElggPlugin.php:17
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:686
$widgets
Definition: widgets.php:37
$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:570
registerWidgets()
Registers the plugin&#39;s widgets provided in the plugin config file.
boot()
Boot the plugin.
Definition: ElggPlugin.php:818
deactivate()
Deactivates the plugin.
Definition: ElggPlugin.php:711
__get($name)
Get an attribute, metadata or private setting value.
$searchable
Definition: numentities.php:5
setPath($path)
Set path.
Definition: ElggPlugin.php:164
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
getComposer()
Returns the composer parser.
const ELGG_VALUE_STRING
Definition: constants.php:127
canReadFile(string $filename)
Checks whether a plugin file with the given name exists.
Definition: ElggPlugin.php:891
registerNotifications()
Registers the plugin&#39;s notification events.
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:224
__set($name, $value)
Set a value as attribute, metadata or private setting.
$filename
static sanitize($path, $append_slash=true)
Sanitise file paths ensuring that they begin and end with slashes etc.
Definition: Paths.php:76
_elgg_services()
Get the global service provider.
Definition: elgglib.php:777
loadLanguages()
Loads the plugin&#39;s translations.
const ACCESS_PUBLIC
Definition: constants.php:14
elgg_get_plugins_path()
Get the plugin path for this installation, ending with slash.
$handler
Definition: add.php:7
getSetting(string $name, $default=null)
Returns a plugin setting.
Definition: ElggPlugin.php:291
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:536
includeFile(string $filename)
Includes one of the plugins files.
Definition: ElggPlugin.php:851
elgg_view($view, $vars=[], $viewtype= '')
Return a parsed view.
Definition: views.php:205
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
getPath()
Returns the plugin&#39;s full path with trailing slash.
Definition: ElggPlugin.php:173
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:773
unsetAllEntityAndPluginSettings()
Remove all entity and plugin settings for this plugin.
Definition: ElggPlugin.php:449
$priority
$views
Definition: item.php:17
unsetUserSetting(string $name, int $user_guid=0)
Removes a user setting name and value.
Definition: ElggPlugin.php:432
registerViewOptions()
Registers the plugin&#39;s view options provided in the plugin config file.
$guid
Reset an ElggUpgrade.
Definition: reset.php:6
getAuthors()
Returns an array of authors.
logDeprecatedMessage(string $message, string $version)
Sends a message about deprecated use of a function, view, etc.
Definition: Loggable.php:80