3 # FILE: PluginManager.php 5 # Part of the ScoutLib application support library 6 # Copyright 2009-2013 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu 16 # ---- PUBLIC INTERFACE -------------------------------------------------- 25 public function __construct($AppFramework, $PluginDirectories)
27 # save framework and directory list for later use 28 $this->AF = $AppFramework;
30 $this->DirsToSearch = $PluginDirectories;
32 # get our own database handle 35 # hook into events to load plugin PHP and HTML files 36 $this->AF->HookEvent(
"EVENT_PHP_FILE_LOAD", array($this,
"FindPluginPhpFile"),
38 $this->AF->HookEvent(
"EVENT_HTML_FILE_LOAD", array($this,
"FindPluginHtmlFile"),
41 # tell PluginCaller helper object how to get to us 42 PluginCaller::$Manager = $this;
53 # look for plugin files 54 $this->PluginFiles = $this->FindPluginFiles($this->DirsToSearch);
56 # for each plugin file found 57 foreach ($this->PluginFiles as $PluginName => $PluginFileName)
61 # attempt to load plugin 62 $Result = $this->LoadPlugin($PluginName, $PluginFileName);
64 # add plugin to list of loaded plugins 65 $this->Plugins[$PluginName] = $Result;
67 catch (Exception $Exception)
70 $ErrMsgs[$PluginName][] = $Exception->getMessage();
74 # check dependencies and drop any plugins with failed dependencies 75 $DepErrMsgs = $this->CheckDependencies($this->Plugins);
76 $DisabledPlugins = array();
77 foreach ($DepErrMsgs as $PluginName => $Msgs)
79 $DisabledPlugins[] = $PluginName;
80 foreach ($Msgs as $Msg)
82 $ErrMsgs[$PluginName][] = $Msg;
86 # sort plugins according to any loading order requests 87 $this->Plugins = $this->SortPluginsByInitializationPrecedence(
91 foreach ($this->Plugins as $PluginName => $Plugin)
93 # if plugin is loaded and enabled 94 if (!in_array($PluginName, $DisabledPlugins)
95 && $Plugin->IsEnabled())
97 # attempt to make plugin ready 100 $Result = $this->ReadyPlugin($Plugin);
102 catch (Exception $Except)
104 $Result = array(
"Uncaught Exception: ".$Except->getMessage());
107 # if making plugin ready failed 108 if ($Result !== NULL)
110 # save error messages 111 foreach ($Result as $Msg)
113 $ErrMsgs[$PluginName][] = $Msg;
118 # mark plugin as ready 119 $Plugin->IsReady(TRUE);
124 # check plugin dependencies again in case an install or upgrade failed 125 $DepErrMsgs = $this->CheckDependencies($this->Plugins, TRUE);
127 # for any plugins that were disabled because of dependencies 128 foreach ($DepErrMsgs as $PluginName => $Msgs)
130 # make sure all plugin hooks are undone 131 $this->UnhookPlugin($this->Plugins[$PluginName]);
133 # mark the plugin as unready 134 $this->Plugins[$PluginName]->IsReady(FALSE);
136 # record any errors that were reported 137 foreach ($Msgs as $Msg)
139 $ErrMsgs[$PluginName][] = $Msg;
143 # save any error messages for later use 144 $this->ErrMsgs = $ErrMsgs;
146 # report to caller whether any problems were encountered 147 return count($ErrMsgs) ? FALSE : TRUE;
157 return $this->ErrMsgs;
168 public function GetPlugin($PluginName, $EvenIfNotReady = FALSE)
170 if (!$EvenIfNotReady && array_key_exists($PluginName, $this->Plugins)
171 && !$this->Plugins[$PluginName]->IsReady())
173 $Trace = debug_backtrace();
174 $Caller = basename($Trace[0][
"file"]).
":".$Trace[0][
"line"];
175 throw new Exception(
"Attempt to access uninitialized plugin " 176 .$PluginName.
" from ".$Caller);
178 return isset($this->Plugins[$PluginName])
179 ? $this->Plugins[$PluginName] : NULL;
188 return $this->Plugins;
200 return $this->
GetPlugin($this->PageFilePlugin);
210 # for each loaded plugin 212 foreach ($this->Plugins as $PluginName => $Plugin)
214 # retrieve plugin attributes 215 $Info[$PluginName] = $Plugin->GetAttributes();
217 # add in other values to attributes 218 $Info[$PluginName][
"Enabled"] = $Plugin->IsEnabled();
219 $Info[$PluginName][
"Installed"] = $Plugin->IsInstalled();
220 $Info[$PluginName][
"ClassFile"] = $this->PluginFiles[$PluginName];
223 # sort plugins by name 224 uasort($Info,
function ($A, $B) {
225 $AName = strtoupper($A[
"Name"]);
226 $BName = strtoupper($B[
"Name"]);
227 return ($AName == $BName) ? 0
228 : ($AName < $BName) ? -1 : 1;
231 # return plugin info to caller 242 $Dependents = array();
244 foreach ($AllAttribs as $Name => $Attribs)
246 if (array_key_exists($PluginName, $Attribs[
"Requires"]))
248 $Dependents[] = $Name;
250 $Dependents = array_merge($Dependents, $SubDependents);
262 $ActivePluginNames = array();
263 foreach ($this->Plugins as $PluginName => $Plugin)
265 if ($Plugin->IsReady())
267 $ActivePluginNames[] = $PluginName;
270 return $ActivePluginNames;
281 return !isset($this->Plugins[$PluginName]) ? FALSE
282 : $this->Plugins[$PluginName]->IsEnabled($NewValue);
295 # if plugin is installed 296 if ($this->Plugins[$PluginName]->IsInstalled())
298 # call uninstall method for plugin 299 $Result = $this->Plugins[$PluginName]->Uninstall();
301 # if plugin uninstall method succeeded 302 if ($Result === NULL)
304 # remove plugin info from database 305 $this->DB->Query(
"DELETE FROM PluginInfo" 306 .
" WHERE BaseName = '".addslashes($PluginName).
"'");
308 # drop our data for the plugin 309 unset($this->Plugins[$PluginName]);
310 unset($this->PluginFiles[$PluginName]);
314 # report results (if any) to caller 325 if (!is_callable($Func))
327 throw new InvalidArgumentException(
328 "Invalid configuration value loading function supplied.");
330 self::$CfgValueLoader = $Func;
334 # ---- PRIVATE INTERFACE ------------------------------------------------- 338 private $DirsToSearch;
339 private $ErrMsgs = array();
340 private $PageFilePlugin = NULL;
341 private $Plugins = array();
342 private $PluginFiles = array();
343 private $PluginHasDir = array();
345 static private $CfgValueLoader;
356 private function FindPluginFiles($DirsToSearch)
359 $PluginFiles = array();
360 foreach ($DirsToSearch as $Dir)
362 # if directory exists 365 # for each file in directory 366 # (plugin directories will be in the list before 367 # similarly-named (single-file) plugin files, 368 # so directory versions will be preferred over 369 # single-file versions) 370 $FileNames = scandir($Dir);
371 foreach ($FileNames as $FileName)
373 # if file looks like base plugin file 374 if (preg_match(
"/^[a-zA-Z_][a-zA-Z0-9_]*\.php$/", $FileName))
376 # if we do not already have a plugin with that name 377 $PluginName = substr($FileName, 0, -4);
378 if (!isset($PluginFiles[$PluginName]))
381 $PluginFiles[$PluginName] = $Dir.
"/".$FileName;
384 # else if file looks like plugin directory 385 elseif (is_dir($Dir.
"/".$FileName)
386 && preg_match(
"/^[a-zA-Z_][a-zA-Z0-9_]*/", $FileName))
388 # if there is a base plugin file in the directory 389 $PluginName = $FileName;
390 $PluginFile = $Dir.
"/".$PluginName.
"/".$PluginName.
".php";
391 if (file_exists($PluginFile))
394 $PluginFiles[$PluginName] = $PluginFile;
399 $this->ErrMsgs[$PluginName][] =
400 "Expected plugin file <i>".$PluginName.
".php</i> not" 401 .
" found in plugin subdirectory <i>" 402 .$Dir.
"/".$PluginName.
"</i>";
409 # return info about found plugins to caller 422 private function LoadPlugin($PluginName, $PluginFileName)
424 # bring in plugin class file 425 include_once($PluginFileName);
427 # check to make sure plugin class is defined by file 428 if (!class_exists($PluginName))
430 throw new Exception(
"Expected class <i>".$PluginName
431 .
"</i> not found in plugin file <i>" 432 .$PluginFileName.
"</i>");
435 # check that plugin class is a valid descendant of base plugin class 436 if (!is_subclass_of($PluginName,
"Plugin"))
438 throw new Exception(
"Plugin <b>".$PluginName.
"</b>" 439 .
" could not be loaded because <i>".$PluginName.
"</i> class" 440 .
" was not a subclass of base <i>Plugin</i> class");
443 # instantiate and register the plugin 444 $Plugin =
new $PluginName($PluginName);
446 # check required plugin attributes 447 $RequiredAttribs = array(
"Name",
"Version");
448 $Attribs = $Plugin->GetAttributes();
449 foreach ($RequiredAttribs as $AttribName)
451 if (!strlen($Attribs[$AttribName]))
453 throw new Exception(
"Plugin <b>".$PluginName.
"</b>" 454 .
" could not be loaded because it" 455 .
" did not have a <i>" 456 .$AttribName.
"</i> attribute set.");
460 # return loaded plugin 469 private function ReadyPlugin(&$Plugin)
471 # tell system to recognize any plugin subdirectories 472 $this->RecognizePluginDirectories($Plugin->GetBaseName());
474 # install or upgrade plugin if needed 475 $PluginInstalled = $this->InstallPlugin($Plugin);
477 # if install/upgrade failed 478 if (is_string($PluginInstalled))
480 # report errors to caller 481 return array($PluginInstalled);
484 # set up plugin configuration options 485 $ErrMsgs = $Plugin->SetUpConfigOptions();
487 # if plugin configuration setup failed 488 if ($ErrMsgs !== NULL)
490 # report errors to caller 491 return is_array($ErrMsgs) ? $ErrMsgs : array($ErrMsgs);
494 # set default configuration values if necessary 495 if ($PluginInstalled)
497 $this->SetPluginDefaultConfigValues($Plugin);
500 # initialize the plugin 501 $ErrMsgs = $Plugin->Initialize();
503 # if initialization failed 504 if ($ErrMsgs !== NULL)
506 # report errors to caller 507 return is_array($ErrMsgs) ? $ErrMsgs : array($ErrMsgs);
510 # register and hook any events for plugin 511 $ErrMsgs = $this->HookPlugin($Plugin);
513 # make sure all hooks are undone if hooking failed 514 if ($ErrMsgs !== NULL)
516 $this->UnhookPlugin($Plugin);
519 # report result to caller 528 private function HookPlugin(&$Plugin)
530 # register any events declared by plugin 531 $Events = $Plugin->DeclareEvents();
532 if (count($Events)) { $this->AF->RegisterEvent($Events); }
534 # if plugin has events that need to be hooked 535 $EventsToHook = $Plugin->HookEvents();
536 if (count($EventsToHook))
540 foreach ($EventsToHook as $EventName => $PluginMethods)
542 # for each method to hook for the event 543 if (!is_array($PluginMethods))
544 { $PluginMethods = array($PluginMethods); }
545 foreach ($PluginMethods as $PluginMethod)
547 # if the event only allows static callbacks 548 if ($this->AF->IsStaticOnlyEvent($EventName))
550 # hook event with shell for static callback 551 $Caller =
new PluginCaller(
552 $Plugin->GetBaseName(), $PluginMethod);
553 $Result = $this->AF->HookEvent(
555 array($Caller,
"CallPluginMethod"));
560 $Result = $this->AF->HookEvent(
561 $EventName, array($Plugin, $PluginMethod));
565 if ($Result === FALSE)
567 $ErrMsgs[] =
"Unable to hook requested event <i>" 568 .$EventName.
"</i> for plugin <b>" 569 .$Plugin->GetBaseName().
"</b>";
574 # if event hook setup failed 577 # report errors to caller 582 # report success to caller 590 private function UnhookPlugin(&$Plugin)
592 # if plugin had events to hook 593 $EventsToHook = $Plugin->HookEvents();
594 if (count($EventsToHook))
598 foreach ($EventsToHook as $EventName => $PluginMethods)
600 # for each method to hook for the event 601 if (!is_array($PluginMethods))
602 { $PluginMethods = array($PluginMethods); }
603 foreach ($PluginMethods as $PluginMethod)
605 # if the event only allows static callbacks 606 if ($this->AF->IsStaticOnlyEvent($EventName))
608 # unhook event with shell for static callback 609 $Caller =
new PluginCaller(
610 $Plugin->GetBaseName(), $PluginMethod);
611 $this->AF->UnhookEvent($EventName,
612 array($Caller,
"CallPluginMethod"));
617 $this->AF->UnhookEvent(
618 $EventName, array($Plugin, $PluginMethod));
632 private function InstallPlugin(&$Plugin)
634 # if plugin has not been installed 635 $InstallOrUpgradePerformed = FALSE;
636 $PluginName = $Plugin->GetBaseName();
637 $Attribs = $Plugin->GetAttributes();
638 $LockName = __CLASS__.
":Install:".$PluginName;
639 if (!$Plugin->IsInstalled())
641 # set default values if present 642 $this->SetPluginDefaultConfigValues($Plugin, TRUE);
644 # try to get lock to prevent anyone else from trying to run 645 # install or upgrade at the same time 646 $GotLock = $this->AF->GetLock($LockName, FALSE);
648 # if could not get lock 652 return "Installation of plugin <b>" 653 .$PluginName.
"</b> in progress.";
657 $ErrMsg = $Plugin->Install();
658 $InstallOrUpgradePerformed = TRUE;
660 # if install succeeded 663 # mark plugin as installed 664 $Plugin->IsInstalled(TRUE);
667 $this->AF->ReleaseLock($LockName);
672 $this->AF->ReleaseLock($LockName);
674 # return error message about installation failure 675 return "Installation of plugin <b>" 676 .$PluginName.
"</b> failed: <i>".$ErrMsg.
"</i>";
681 # if plugin version is newer than version in database 682 if (version_compare($Attribs[
"Version"],
683 $Plugin->InstalledVersion()) == 1)
685 # set default values for any new configuration settings 686 $this->SetPluginDefaultConfigValues($Plugin);
688 # try to get lock to prevent anyone else from trying to run 689 # upgrade or install at the same time 690 $GotLock = $this->AF->GetLock($LockName, FALSE);
692 # if could not get lock 696 return "Upgrade of plugin <b>" 697 .$PluginName.
"</b> in progress.";
701 $ErrMsg = $Plugin->Upgrade($Plugin->InstalledVersion());
702 $InstallOrUpgradePerformed = TRUE;
704 # if upgrade succeeded 705 if ($ErrMsg === NULL)
707 # update plugin version in database 708 $Plugin->InstalledVersion($Attribs[
"Version"]);
711 $this->AF->ReleaseLock($LockName);
716 $this->AF->ReleaseLock($LockName);
718 # report error message about upgrade failure 719 return "Upgrade of plugin <b>" 720 .$PluginName.
"</b> from version <i>" 721 .addslashes($Plugin->InstalledVersion())
722 .
"</i> to version <i>" 723 .addslashes($Attribs[
"Version"]).
"</i> failed: <i>" 727 # else if plugin version is older than version in database 728 elseif (version_compare($Attribs[
"Version"],
729 $Plugin->InstalledVersion()) == -1)
731 # return error message about version conflict 733 .$PluginName.
"</b> is older (<i>" 734 .addslashes($Attribs[
"Version"])
735 .
"</i>) than previously-installed version (<i>" 736 .addslashes($Plugin->InstalledVersion())
741 # report result to caller 742 return $InstallOrUpgradePerformed;
750 private function RecognizePluginDirectories($PluginName)
752 # if plugin has its own subdirectory 753 $PluginFileName = $this->PluginFiles[$PluginName];
754 $this->PluginHasDir[$PluginName] = preg_match(
755 "%/".$PluginName.
"/".$PluginName.
".php\$%",
756 $PluginFileName) ? TRUE : FALSE;
757 if ($this->PluginHasDir[$PluginName])
759 # if plugin has its own object directory 760 $Dir = dirname($PluginFileName);
761 if (is_dir($Dir.
"/objects"))
763 # add object directory to class autoloading list 768 # add plugin directory to class autoloading list 772 # if plugin has its own interface directory 773 $InterfaceDir = $Dir.
"/interface";
774 if (is_dir($InterfaceDir))
776 # add interface directory to AF search lists 777 $this->AF->AddInterfaceDirectories(
778 [ $InterfaceDir.
"/%ACTIVEUI%/",
779 $InterfaceDir.
"/%DEFAULTUI%/" ]);
781 # add interface object directories if any found 782 if (count(glob($InterfaceDir.
"/*/objects")))
784 $this->AF->AddObjectDirectory(
785 $InterfaceDir.
"/%ACTIVEUI%/objects");
786 $this->AF->AddObjectDirectory(
787 $InterfaceDir.
"/%DEFAULTUI%/objects");
790 # add interface include directories if any found 791 if (count(glob($InterfaceDir.
"/*/include")))
793 $this->AF->AddIncludeDirectories(
794 [ $InterfaceDir.
"/%ACTIVEUI%/include",
795 $InterfaceDir.
"/%DEFAULTUI%/include" ]);
798 # add image directories if any found 799 if (count(glob($InterfaceDir.
"/*/images")))
801 $this->AF->AddImageDirectories(
802 [ $InterfaceDir.
"/%ACTIVEUI%/images",
803 $InterfaceDir.
"/%DEFAULTUI%/images" ]);
816 private function SetPluginDefaultConfigValues($Plugin, $Overwrite = FALSE)
818 # if plugin has configuration info 819 $Attribs = $Plugin->GetAttributes();
820 if (isset($Attribs[
"CfgSetup"]))
822 foreach ($Attribs[
"CfgSetup"] as $CfgValName => $CfgSetup)
824 if (isset($CfgSetup[
"Default"]) && ($Overwrite
825 || ($Plugin->ConfigSetting($CfgValName) === NULL)))
827 if (isset(self::$CfgValueLoader))
829 $Plugin->ConfigSetting($CfgValName,
830 call_user_func(self::$CfgValueLoader,
831 $CfgSetup[
"Type"], $CfgSetup[
"Default"]));
835 $Plugin->ConfigSetting($CfgValName, $CfgSetup[
"Default"]);
849 private function CheckDependencies($Plugins, $CheckReady = FALSE)
851 # look until all enabled plugins check out okay 855 # start out assuming all plugins are okay 859 foreach ($Plugins as $PluginName => $Plugin)
861 # if plugin is enabled and not checking for ready 863 if ($Plugin->IsEnabled() && (!$CheckReady || $Plugin->IsReady()))
865 # load plugin attributes 866 if (!isset($Attribs[$PluginName]))
868 $Attribs[$PluginName] = $Plugin->GetAttributes();
871 # for each dependency for this plugin 872 foreach ($Attribs[$PluginName][
"Requires"]
873 as $ReqName => $ReqVersion)
875 # handle PHP version requirements 876 if ($ReqName ==
"PHP")
878 if (version_compare($ReqVersion, phpversion(),
">"))
880 $ErrMsgs[$PluginName][] =
"PHP version " 881 .
"<i>".$ReqVersion.
"</i>" 882 .
" required by <b>".$PluginName.
"</b>" 883 .
" was not available. (Current PHP version" 884 .
" is <i>".phpversion().
"</i>.)";
887 # handle PHP extension requirements 888 elseif (preg_match(
"/^PHPX_/", $ReqName))
890 list($Dummy, $ExtensionName) = explode(
"_", $ReqName, 2);
891 if (!extension_loaded($ExtensionName))
893 $ErrMsgs[$PluginName][] =
"PHP extension " 894 .
"<i>".$ExtensionName.
"</i>" 895 .
" required by <b>".$PluginName.
"</b>" 896 .
" was not available.";
898 elseif (($ReqVersion !== TRUE)
899 && (phpversion($ExtensionName) !== FALSE)
900 && version_compare($ReqVersion,
901 phpversion($ExtensionName),
">"))
903 $ErrMsgs[$PluginName][] =
"PHP extension " 904 .
"<i>".$ExtensionName.
"</i>" 905 .
" version <i>".$ReqVersion.
"</i>" 906 .
" required by <b>".$PluginName.
"</b>" 907 .
" was not available. (Current version" 908 .
" of extension <i>".$ExtensionName.
"</i>" 909 .
" is <i>".phpversion($ExtensionName).
"</i>.)";
912 # handle dependencies on other plugins 915 # load plugin attributes if not already loaded 916 if (isset($Plugins[$ReqName])
917 && !isset($Attribs[$ReqName]))
920 $Plugins[$ReqName]->GetAttributes();
923 # if target plugin is not present or is too old 925 # or (if appropriate) is not ready 926 if (!isset($Plugins[$ReqName])
927 || version_compare($ReqVersion,
928 $Attribs[$ReqName][
"Version"],
">")
929 || !$Plugins[$ReqName]->IsEnabled()
931 && !$Plugins[$ReqName]->IsReady()))
934 $ErrMsgs[$PluginName][] =
"Plugin <i>" 935 .$ReqName.
" ".$ReqVersion.
"</i>" 936 .
" required by <b>".$PluginName.
"</b>" 937 .
" was not available.";
941 # if problem was found with plugin 942 if (isset($ErrMsgs[$PluginName]))
944 # remove plugin from our list 945 unset($Plugins[$PluginName]);
947 # set flag to indicate a plugin had to be dropped 953 }
while ($AllOkay == FALSE);
955 # return messages about any dropped plugins back to caller 967 private function SortPluginsByInitializationPrecedence($Plugins)
969 # load plugin attributes 970 foreach ($Plugins as $PluginName => $Plugin)
972 $PluginAttribs[$PluginName] = $Plugin->GetAttributes();
975 # determine initialization order 976 $PluginsAfterUs = array();
977 foreach ($PluginAttribs as $PluginName => $Attribs)
979 foreach ($Attribs[
"InitializeBefore"] as $OtherPluginName)
981 $PluginsAfterUs[$PluginName][] = $OtherPluginName;
983 foreach ($Attribs[
"InitializeAfter"] as $OtherPluginName)
985 $PluginsAfterUs[$OtherPluginName][] = $PluginName;
989 # infer other initialization order cues from lists of required plugins 990 foreach ($PluginAttribs as $PluginName => $Attribs)
992 # for each required plugin 993 foreach ($Attribs[
"Requires"]
994 as $RequiredPluginName => $RequiredPluginVersion)
996 # skip the requirement if it it not for another known plugin 997 if (!isset($PluginAttribs[$RequiredPluginName]))
1002 # if there is not a requirement in the opposite direction 1003 if (!array_key_exists($PluginName,
1004 $PluginAttribs[$RequiredPluginName][
"Requires"]))
1006 # if the required plugin is not scheduled to be after us 1007 if (!array_key_exists($PluginName, $PluginsAfterUs)
1008 || !in_array($RequiredPluginName,
1009 $PluginsAfterUs[$PluginName]))
1011 # if we are not already scheduled to be after the required plugin 1012 if (!array_key_exists($PluginName, $PluginsAfterUs)
1013 || !in_array($RequiredPluginName,
1014 $PluginsAfterUs[$PluginName]))
1016 # schedule us to be after the required plugin 1017 $PluginsAfterUs[$RequiredPluginName][] =
1025 # keep track of those plugins we have yet to do and those that are done 1026 $UnsortedPlugins = array_keys($Plugins);
1027 $PluginsProcessed = array();
1029 # limit the number of iterations of the plugin ordering loop 1030 # to 10 times the number of plugins we have 1031 $MaxIterations = 10 * count($UnsortedPlugins);
1032 $IterationCount = 0;
1034 # iterate through all the plugins that need processing 1035 while (($NextPlugin = array_shift($UnsortedPlugins)) !== NULL)
1037 # check to be sure that we're not looping forever 1039 if ($IterationCount > $MaxIterations)
1041 throw new Exception(
1042 "Max iteration count exceeded trying to determine plugin" 1043 .
" loading order. Is there a dependency loop?");
1046 # if no plugins require this one, it can go last 1047 if (!isset($PluginsAfterUs[$NextPlugin]))
1049 $PluginsProcessed[$NextPlugin] = $MaxIterations;
1053 # for plugins that are required by others 1054 $Index = $MaxIterations;
1055 foreach ($PluginsAfterUs[$NextPlugin] as $GoBefore)
1057 if (!isset($PluginsProcessed[$GoBefore]))
1059 # if there is something that requires us which hasn't 1060 # yet been assigned an order, then we can't determine 1061 # our own place on this iteration 1062 array_push($UnsortedPlugins, $NextPlugin);
1067 # otherwise, make sure that we're loaded 1068 # before the earliest of the things that require us 1069 $Index = min($Index, $PluginsProcessed[$GoBefore] - 1);
1072 $PluginsProcessed[$NextPlugin] = $Index;
1076 # arrange plugins according to our ordering 1077 asort($PluginsProcessed, SORT_NUMERIC);
1078 $SortedPlugins = array();
1079 foreach ($PluginsProcessed as $PluginName => $SortOrder)
1081 $SortedPlugins[$PluginName] = $Plugins[$PluginName];
1084 # return sorted list to caller 1085 return $SortedPlugins;
1096 public function FindPluginPhpFile($PageName)
1098 # build list of possible locations for file 1100 "local/plugins/%PLUGIN%/pages/%PAGE%.php",
1101 "plugins/%PLUGIN%/pages/%PAGE%.php",
1102 "local/plugins/%PLUGIN%/%PAGE%.php",
1103 "plugins/%PLUGIN%/%PAGE%.php",
1106 # look for file and return (possibly) updated page to caller 1107 return $this->FindPluginPageFile($PageName, $Locations);
1119 public function FindPluginHtmlFile($PageName)
1121 # build list of possible locations for file 1123 "local/plugins/%PLUGIN%/interface/%ACTIVEUI%/%PAGE%.html",
1124 "plugins/%PLUGIN%/interface/%ACTIVEUI%/%PAGE%.html",
1125 "local/plugins/%PLUGIN%/interface/%DEFAULTUI%/%PAGE%.html",
1126 "plugins/%PLUGIN%/interface/%DEFAULTUI%/%PAGE%.html",
1127 "local/plugins/%PLUGIN%/%PAGE%.html",
1128 "plugins/%PLUGIN%/%PAGE%.html",
1132 $Params = $this->FindPluginPageFile($PageName, $Locations);
1134 # if plugin HTML file was found 1135 if ($Params[
"PageName"] != $PageName)
1137 # add subdirectories for plugin to search paths 1138 $Dir = preg_replace(
"%^local/%",
"", dirname($Params[
"PageName"]));
1139 $this->AF->AddImageDirectories(array(
1140 "local/".$Dir.
"/images",
1143 $this->AF->AddIncludeDirectories(array(
1144 "local/".$Dir.
"/include",
1147 $this->AF->AddFunctionDirectories(array(
1148 "local/".$Dir.
"/include",
1153 # return possibly revised HTML file name to caller 1168 private function FindPluginPageFile($PageName, $Locations)
1170 # set up return value assuming we will not find plugin page file 1171 $ReturnValue[
"PageName"] = $PageName;
1173 # look for plugin name and plugin page name in base page name 1174 preg_match(
"/P_([A-Za-z].[A-Za-z0-9]*)_([A-Za-z0-9_-]+)/", $PageName, $Matches);
1176 # if plugin name and plugin page name were found and plugin name is valid 1177 if (count($Matches) == 3)
1179 # if plugin is valid and enabled and has its own subdirectory 1180 $PluginName = $Matches[1];
1181 if (isset($this->Plugins[$PluginName])
1182 && $this->PluginHasDir[$PluginName]
1183 && $this->Plugins[$PluginName]->IsEnabled())
1185 # for each possible location 1186 $PageName = $Matches[2];
1187 $ActiveUI = $this->AF->ActiveUserInterface();
1188 $DefaultUI = $this->AF->DefaultUserInterface();
1189 foreach ($Locations as $Loc)
1191 # make any needed substitutions into path 1192 $FileName = str_replace(
1193 array(
"%DEFAULTUI%",
"%ACTIVEUI%",
"%PLUGIN%",
"%PAGE%"),
1194 array($DefaultUI, $ActiveUI, $PluginName, $PageName),
1197 # if file exists in this location 1198 if (file_exists($FileName))
1200 # set return value to contain full plugin page file name 1201 $ReturnValue[
"PageName"] = $FileName;
1203 # save plugin name as home of current page 1204 $this->PageFilePlugin = $PluginName;
1206 # set G_Plugin to plugin associated with current page 1216 # return array containing page name or page file name to caller 1217 return $ReturnValue;
1241 public function __construct($PluginName, $MethodName)
1243 $this->PluginName = $PluginName;
1244 $this->MethodName = $MethodName;
1252 public function CallPluginMethod()
1254 $Args = func_get_args();
1255 $Plugin = self::$Manager->GetPlugin($this->PluginName);
1256 return call_user_func_array(array($Plugin, $this->MethodName), $Args);
1263 public function GetCallbackAsText()
1265 return $this->PluginName.
"::".$this->MethodName;
1273 public function __sleep()
1275 return array(
"PluginName",
"MethodName");
1279 static public $Manager;
1281 private $PluginName;
1282 private $MethodName;
GetErrorMessages()
Retrieve any error messages generated during plugin loading.
Manager to load and invoke plugins.
GetPlugin($PluginName, $EvenIfNotReady=FALSE)
Retrieve specified plugin.
SQL database abstraction object with smart query caching.
UninstallPlugin($PluginName)
Uninstall plugin and (optionally) delete any associated data.
GetDependents($PluginName)
Returns a list of plugins dependent on the specified plugin.
GetActivePluginList()
Get list of active (i.e.
GetPluginAttributes()
Retrieve info about currently loaded plugins.
PluginEnabled($PluginName, $NewValue=NULL)
Get/set whether specified plugin is enabled.
__construct($AppFramework, $PluginDirectories)
PluginManager class constructor.
GetPluginForCurrentPage()
Retrieve plugin for current page (if any).
GetPlugins()
Retrieve all loaded plugins.
const ORDER_LAST
Handle item last (i.e.
static SetApplicationFramework($AF)
Set the application framework to be referenced within plugins.
static SetConfigValueLoader($Func)
Set function to load plugin configuration values from data.
LoadPlugins()
Load and initialize plugins.
static AddObjectDirectory($Dir, $NamespacePrefixes=array(), $Callback=NULL)
Add directory to be searched for object files when autoloading.