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 $PluginFiles = $this->FindPlugins($this->DirsToSearch);
56 # for each plugin found 57 foreach ($PluginFiles as $PluginName => $PluginFileName)
59 # attempt to load plugin 60 $Result = $this->LoadPlugin($PluginName, $PluginFileName);
62 # if errors were encountered during loading 63 if (is_array($Result))
66 $ErrMsgs[$PluginName][] = $Result;
70 # add plugin to list of loaded plugins 71 $this->Plugins[$PluginName] = $Result;
75 # check dependencies and drop any plugins with failed dependencies 76 $DepErrMsgs = $this->CheckDependencies($this->Plugins);
77 $DisabledPlugins = array();
78 foreach ($DepErrMsgs as $PluginName => $Msgs)
80 $DisabledPlugins[] = $PluginName;
81 foreach ($Msgs as $Msg)
83 $ErrMsgs[$PluginName][] = $Msg;
87 # sort plugins according to any loading order requests 88 $this->Plugins = $this->SortPluginsByInitializationPrecedence(
92 foreach ($this->Plugins as $PluginName => $Plugin)
94 # if plugin is loaded and enabled 95 if (!in_array($PluginName, $DisabledPlugins)
96 && $Plugin->IsEnabled())
98 # attempt to make plugin ready 99 $Result = $this->ReadyPlugin($Plugin);
101 # if making plugin ready failed 102 if ($Result !== NULL)
104 # save error messages 105 foreach ($Result as $Msg)
107 $ErrMsgs[$PluginName][] = $Msg;
112 # mark plugin as ready 113 $Plugin->IsReady(TRUE);
118 # check plugin dependencies again in case an install or upgrade failed 119 $DepErrMsgs = $this->CheckDependencies($this->Plugins, TRUE);
121 # for any plugins that were disabled because of dependencies 122 foreach ($DepErrMsgs as $PluginName => $Msgs)
124 # make sure all plugin hooks are undone 125 $this->UnhookPlugin($this->Plugins[$PluginName]);
127 # mark the plugin as unready 128 $this->Plugins[$PluginName]->IsReady(FALSE);
130 # record any errors that were reported 131 foreach ($Msgs as $Msg)
133 $ErrMsgs[$PluginName][] = $Msg;
137 # save plugin files names and any error messages for later use 138 $this->PluginFiles = $PluginFiles;
139 $this->ErrMsgs = $ErrMsgs;
141 # report to caller whether any problems were encountered 142 return count($ErrMsgs) ? FALSE : TRUE;
152 return $this->ErrMsgs;
163 public function GetPlugin($PluginName, $EvenIfNotReady = FALSE)
165 if (!$EvenIfNotReady && array_key_exists($PluginName, $this->Plugins)
166 && !$this->Plugins[$PluginName]->IsReady())
168 $Trace = debug_backtrace();
169 $Caller = basename($Trace[0][
"file"]).
":".$Trace[0][
"line"];
170 throw new Exception(
"Attempt to access uninitialized plugin " 171 .$PluginName.
" from ".$Caller);
173 return isset($this->Plugins[$PluginName])
174 ? $this->Plugins[$PluginName] : NULL;
183 return $this->Plugins;
195 return $this->
GetPlugin($this->PageFilePlugin);
205 # for each loaded plugin 207 foreach ($this->Plugins as $PluginName => $Plugin)
209 # retrieve plugin attributes 210 $Info[$PluginName] = $Plugin->GetAttributes();
212 # add in other values to attributes 213 $Info[$PluginName][
"Enabled"] = $Plugin->IsEnabled();
214 $Info[$PluginName][
"Installed"] = $Plugin->IsInstalled();
215 $Info[$PluginName][
"ClassFile"] = $this->PluginFiles[$PluginName];
218 # sort plugins by name 219 uasort($Info,
function ($A, $B) {
220 $AName = strtoupper($A[
"Name"]);
221 $BName = strtoupper($B[
"Name"]);
222 return ($AName == $BName) ? 0
223 : ($AName < $BName) ? -1 : 1;
226 # return plugin info to caller 237 $Dependents = array();
239 foreach ($AllAttribs as $Name => $Attribs)
241 if (array_key_exists($PluginName, $Attribs[
"Requires"]))
243 $Dependents[] = $Name;
245 $Dependents = array_merge($Dependents, $SubDependents);
257 $ActivePluginNames = array();
258 foreach ($this->Plugins as $PluginName => $Plugin)
260 if ($Plugin->IsReady())
262 $ActivePluginNames[] = $PluginName;
265 return $ActivePluginNames;
276 return !isset($this->Plugins[$PluginName]) ? FALSE
277 : $this->Plugins[$PluginName]->IsEnabled($NewValue);
290 # if plugin is installed 291 if ($this->Plugins[$PluginName]->IsInstalled())
293 # call uninstall method for plugin 294 $Result = $this->Plugins[$PluginName]->Uninstall();
296 # if plugin uninstall method succeeded 297 if ($Result === NULL)
299 # remove plugin info from database 300 $this->DB->Query(
"DELETE FROM PluginInfo" 301 .
" WHERE BaseName = '".addslashes($PluginName).
"'");
303 # drop our data for the plugin 304 unset($this->Plugins[$PluginName]);
305 unset($this->PluginFiles[$PluginName]);
309 # report results (if any) to caller 314 # ---- PRIVATE INTERFACE ------------------------------------------------- 318 private $DirsToSearch;
319 private $ErrMsgs = array();
320 private $PageFilePlugin = NULL;
321 private $Plugins = array();
322 private $PluginFiles = array();
323 private $PluginHasDir = array();
334 private function FindPlugins($DirsToSearch)
337 $PluginFiles = array();
338 foreach ($DirsToSearch as $Dir)
340 # if directory exists 343 # for each file in directory 344 $FileNames = scandir($Dir);
345 foreach ($FileNames as $FileName)
347 # if file looks like base plugin file 348 if (preg_match(
"/^[a-zA-Z_][a-zA-Z0-9_]*\.php$/", $FileName))
350 # if we do not already have a plugin with that name 351 $PluginName = substr($FileName, 0, -4);
352 if (!isset($PluginFiles[$PluginName]))
355 $PluginFiles[$PluginName] = $Dir.
"/".$FileName;
358 # else if file looks like plugin directory 359 elseif (is_dir($Dir.
"/".$FileName)
360 && preg_match(
"/^[a-zA-Z_][a-zA-Z0-9_]*/", $FileName))
362 # if there is a base plugin file in the directory 363 $PluginName = $FileName;
364 $PluginFile = $Dir.
"/".$PluginName.
"/".$PluginName.
".php";
365 if (file_exists($PluginFile))
368 $PluginFiles[$PluginName] = $PluginFile;
373 $this->ErrMsgs[$PluginName][] =
374 "Expected plugin file <i>".$PluginName.
".php</i> not" 375 .
" found in plugin subdirectory <i>" 376 .$Dir.
"/".$PluginName.
"</i>";
383 # return info about found plugins to caller 394 private function LoadPlugin($PluginName, $PluginFileName)
396 # bring in plugin class file 397 include_once($PluginFileName);
399 # if plugin class was not defined by file 400 if (!class_exists($PluginName))
402 $ErrMsgs[] =
"Expected class <i>".$PluginName
403 .
"</i> not found in plugin file <i>" 404 .$PluginFileName.
"</i>";
408 # if plugin class is not a valid descendant of base plugin class 409 if (!is_subclass_of($PluginName,
"Plugin"))
411 $ErrMsgs[] =
"Plugin <b>".$PluginName.
"</b>" 412 .
" could not be loaded because <i>".$PluginName.
"</i> class" 413 .
" was not a subclass of base <i>Plugin</i> class";
417 # instantiate and register the plugin 418 $Plugin =
new $PluginName($PluginName);
420 # check required plugin attributes 421 $RequiredAttribs = array(
"Name",
"Version");
422 $Attribs = $Plugin->GetAttributes();
423 foreach ($RequiredAttribs as $AttribName)
425 if (!strlen($Attribs[$AttribName]))
427 $ErrMsgs[] =
"Plugin <b>".$PluginName.
"</b>" 428 .
" could not be loaded because it" 429 .
" did not have a <i>" 430 .$AttribName.
"</i> attribute set.";
434 # if all required attributes were found 435 if (!isset($ErrMsgs))
437 # if plugin has its own subdirectory 438 $this->PluginHasDir[$PluginName] = preg_match(
439 "%/".$PluginName.
"/".$PluginName.
".php\$%",
440 $PluginFileName) ? TRUE : FALSE;
441 if ($this->PluginHasDir[$PluginName])
443 # if plugin has its own object directory 444 $Dir = dirname($PluginFileName);
445 if (is_dir($Dir.
"/objects"))
447 # add object directory to class autoloading list 452 # add plugin directory to class autoloading list 456 # if plugin has its own interface directory 457 $InterfaceDir = $Dir.
"/interface";
458 if (is_dir($InterfaceDir))
460 # scan contents of interface directory for 461 # entries other than the default default 462 $InterfaceSubdirsFound = FALSE;
463 foreach (scandir($InterfaceDir) as $Entry)
465 if (($Entry !=
"default") && ($Entry[0] !=
"."))
467 $InterfaceSubdirsFound = TRUE;
472 # if entries found other than the default default 473 if ($InterfaceSubdirsFound)
475 # add directory to those scanned for interfaces 476 $this->AF->AddInterfaceDirectories(
477 array($InterfaceDir.
"/%ACTIVEUI%/",
478 $InterfaceDir.
"/%DEFAULTUI%/"));
481 # add plugin interface object directories if present 482 $ActiveUI = $this->AF->ActiveUserInterface();
483 $DefaultUI = $this->AF->DefaultUserInterface();
484 if (is_dir($InterfaceDir.
"/".$ActiveUI.
"/objects"))
487 $InterfaceDir.
"/%ACTIVEUI%/objects");
489 if (is_dir($InterfaceDir.
"/".$DefaultUI.
"/objects"))
492 $InterfaceDir.
"/%DEFAULTUI%/objects");
495 # add plugin interface include directories if present 496 if (is_dir($InterfaceDir.
"/".$DefaultUI.
"/include"))
498 $this->AF->AddIncludeDirectories(
499 $InterfaceDir.
"/%DEFAULTUI%/include");
501 if (is_dir($InterfaceDir.
"/".$ActiveUI.
"/include"))
503 $this->AF->AddIncludeDirectories(
504 $InterfaceDir.
"/%ACTIVEUI%/include");
512 # return loaded plugin or error messages, as appropriate 513 return isset($ErrMsgs) ? $ErrMsgs : $Plugin;
521 private function ReadyPlugin(&$Plugin)
523 # install or upgrade plugin if needed 524 $PluginInstalled = $this->InstallPlugin($Plugin);
526 # if install/upgrade failed 527 if (is_string($PluginInstalled))
529 # report errors to caller 530 return array($PluginInstalled);
533 # set up plugin configuration options 534 $ErrMsgs = $Plugin->SetUpConfigOptions();
536 # if plugin configuration setup failed 537 if ($ErrMsgs !== NULL)
539 # report errors to caller 540 return is_array($ErrMsgs) ? $ErrMsgs : array($ErrMsgs);
543 # set default configuration values if necessary 544 if ($PluginInstalled)
546 $this->SetPluginDefaultConfigValues($Plugin);
549 # initialize the plugin 550 $ErrMsgs = $Plugin->Initialize();
552 # if initialization failed 553 if ($ErrMsgs !== NULL)
555 # report errors to caller 556 return is_array($ErrMsgs) ? $ErrMsgs : array($ErrMsgs);
559 # register and hook any events for plugin 560 $ErrMsgs = $this->HookPlugin($Plugin);
562 # make sure all hooks are undone if hooking failed 563 if ($ErrMsgs !== NULL)
565 $this->UnhookPlugin($Plugin);
568 # report result to caller 577 private function HookPlugin(&$Plugin)
579 # register any events declared by plugin 580 $Events = $Plugin->DeclareEvents();
581 if (count($Events)) { $this->AF->RegisterEvent($Events); }
583 # if plugin has events that need to be hooked 584 $EventsToHook = $Plugin->HookEvents();
585 if (count($EventsToHook))
589 foreach ($EventsToHook as $EventName => $PluginMethods)
591 # for each method to hook for the event 592 if (!is_array($PluginMethods))
593 { $PluginMethods = array($PluginMethods); }
594 foreach ($PluginMethods as $PluginMethod)
596 # if the event only allows static callbacks 597 if ($this->AF->IsStaticOnlyEvent($EventName))
599 # hook event with shell for static callback 600 $Caller =
new PluginCaller(
601 $Plugin->GetBaseName(), $PluginMethod);
602 $Result = $this->AF->HookEvent(
604 array($Caller,
"CallPluginMethod"));
609 $Result = $this->AF->HookEvent(
610 $EventName, array($Plugin, $PluginMethod));
614 if ($Result === FALSE)
616 $ErrMsgs[] =
"Unable to hook requested event <i>" 617 .$EventName.
"</i> for plugin <b>" 618 .$Plugin->GetBaseName().
"</b>";
623 # if event hook setup failed 626 # report errors to caller 631 # report success to caller 639 private function UnhookPlugin(&$Plugin)
641 # if plugin had events to hook 642 $EventsToHook = $Plugin->HookEvents();
643 if (count($EventsToHook))
647 foreach ($EventsToHook as $EventName => $PluginMethods)
649 # for each method to hook for the event 650 if (!is_array($PluginMethods))
651 { $PluginMethods = array($PluginMethods); }
652 foreach ($PluginMethods as $PluginMethod)
654 # if the event only allows static callbacks 655 if ($this->AF->IsStaticOnlyEvent($EventName))
657 # unhook event with shell for static callback 658 $Caller =
new PluginCaller(
659 $Plugin->GetBaseName(), $PluginMethod);
660 $this->AF->UnhookEvent($EventName,
661 array($Caller,
"CallPluginMethod"));
666 $this->AF->UnhookEvent(
667 $EventName, array($Plugin, $PluginMethod));
681 private function InstallPlugin(&$Plugin)
683 # if plugin has not been installed 684 $InstallOrUpgradePerformed = FALSE;
685 $PluginName = $Plugin->GetBaseName();
686 $Attribs = $Plugin->GetAttributes();
687 $LockName = __CLASS__.
":Install:".$PluginName;
688 if (!$Plugin->IsInstalled())
690 # set default values if present 691 $this->SetPluginDefaultConfigValues($Plugin, TRUE);
693 # try to get lock to prevent anyone else from trying to run 694 # install or upgrade at the same time 695 $GotLock = $this->AF->GetLock($LockName, FALSE);
697 # if could not get lock 701 return "Installation of plugin <b>" 702 .$PluginName.
"</b> in progress.";
706 $ErrMsg = $Plugin->Install();
707 $InstallOrUpgradePerformed = TRUE;
709 # if install succeeded 712 # mark plugin as installed 713 $Plugin->IsInstalled(TRUE);
716 $this->AF->ReleaseLock($LockName);
721 $this->AF->ReleaseLock($LockName);
723 # return error message about installation failure 724 return "Installation of plugin <b>" 725 .$PluginName.
"</b> failed: <i>".$ErrMsg.
"</i>";
730 # if plugin version is newer than version in database 731 if (version_compare($Attribs[
"Version"],
732 $Plugin->InstalledVersion()) == 1)
734 # set default values for any new configuration settings 735 $this->SetPluginDefaultConfigValues($Plugin);
737 # try to get lock to prevent anyone else from trying to run 738 # upgrade or install at the same time 739 $GotLock = $this->AF->GetLock($LockName, FALSE);
741 # if could not get lock 745 return "Upgrade of plugin <b>" 746 .$PluginName.
"</b> in progress.";
750 $ErrMsg = $Plugin->Upgrade($Plugin->InstalledVersion());
751 $InstallOrUpgradePerformed = TRUE;
753 # if upgrade succeeded 754 if ($ErrMsg === NULL)
756 # update plugin version in database 757 $Plugin->InstalledVersion($Attribs[
"Version"]);
760 $this->AF->ReleaseLock($LockName);
765 $this->AF->ReleaseLock($LockName);
767 # report error message about upgrade failure 768 return "Upgrade of plugin <b>" 769 .$PluginName.
"</b> from version <i>" 770 .addslashes($Plugin->InstalledVersion())
771 .
"</i> to version <i>" 772 .addslashes($Attribs[
"Version"]).
"</i> failed: <i>" 776 # else if plugin version is older than version in database 777 elseif (version_compare($Attribs[
"Version"],
778 $Plugin->InstalledVersion()) == -1)
780 # return error message about version conflict 782 .$PluginName.
"</b> is older (<i>" 783 .addslashes($Attribs[
"Version"])
784 .
"</i>) than previously-installed version (<i>" 785 .addslashes($Plugin->InstalledVersion())
790 # report result to caller 791 return $InstallOrUpgradePerformed;
801 private function SetPluginDefaultConfigValues($Plugin, $Overwrite = FALSE)
803 # if plugin has configuration info 804 $Attribs = $Plugin->GetAttributes();
805 if (isset($Attribs[
"CfgSetup"]))
807 foreach ($Attribs[
"CfgSetup"] as $CfgValName => $CfgSetup)
809 if (isset($CfgSetup[
"Default"]) && ($Overwrite
810 || ($Plugin->ConfigSetting($CfgValName) === NULL)))
812 $Plugin->ConfigSetting($CfgValName, $CfgSetup[
"Default"]);
825 private function CheckDependencies($Plugins, $CheckReady = FALSE)
827 # look until all enabled plugins check out okay 831 # start out assuming all plugins are okay 835 foreach ($Plugins as $PluginName => $Plugin)
837 # if plugin is enabled and not checking for ready 839 if ($Plugin->IsEnabled() && (!$CheckReady || $Plugin->IsReady()))
841 # load plugin attributes 842 if (!isset($Attribs[$PluginName]))
844 $Attribs[$PluginName] = $Plugin->GetAttributes();
847 # for each dependency for this plugin 848 foreach ($Attribs[$PluginName][
"Requires"]
849 as $ReqName => $ReqVersion)
851 # handle PHP version requirements 852 if ($ReqName ==
"PHP")
854 if (version_compare($ReqVersion, phpversion(),
">"))
856 $ErrMsgs[$PluginName][] =
"PHP version " 857 .
"<i>".$ReqVersion.
"</i>" 858 .
" required by <b>".$PluginName.
"</b>" 859 .
" was not available. (Current PHP version" 860 .
" is <i>".phpversion().
"</i>.)";
863 # handle PHP extension requirements 864 elseif (preg_match(
"/^PHPX_/", $ReqName))
866 list($Dummy, $ExtensionName) = explode(
"_", $ReqName, 2);
867 if (!extension_loaded($ExtensionName))
869 $ErrMsgs[$PluginName][] =
"PHP extension " 870 .
"<i>".$ExtensionName.
"</i>" 871 .
" required by <b>".$PluginName.
"</b>" 872 .
" was not available.";
874 elseif (($ReqVersion !== TRUE)
875 && (phpversion($ExtensionName) !== FALSE)
876 && version_compare($ReqVersion,
877 phpversion($ExtensionName),
">"))
879 $ErrMsgs[$PluginName][] =
"PHP extension " 880 .
"<i>".$ExtensionName.
"</i>" 881 .
" version <i>".$ReqVersion.
"</i>" 882 .
" required by <b>".$PluginName.
"</b>" 883 .
" was not available. (Current version" 884 .
" of extension <i>".$ExtensionName.
"</i>" 885 .
" is <i>".phpversion($ExtensionName).
"</i>.)";
888 # handle dependencies on other plugins 891 # load plugin attributes if not already loaded 892 if (isset($Plugins[$ReqName])
893 && !isset($Attribs[$ReqName]))
896 $Plugins[$ReqName]->GetAttributes();
899 # if target plugin is not present or is too old 901 # or (if appropriate) is not ready 902 if (!isset($Plugins[$ReqName])
903 || version_compare($ReqVersion,
904 $Attribs[$ReqName][
"Version"],
">")
905 || !$Plugins[$ReqName]->IsEnabled()
907 && !$Plugins[$ReqName]->IsReady()))
910 $ErrMsgs[$PluginName][] =
"Plugin <i>" 911 .$ReqName.
" ".$ReqVersion.
"</i>" 912 .
" required by <b>".$PluginName.
"</b>" 913 .
" was not available.";
917 # if problem was found with plugin 918 if (isset($ErrMsgs[$PluginName]))
920 # remove plugin from our list 921 unset($Plugins[$PluginName]);
923 # set flag to indicate a plugin had to be dropped 929 }
while ($AllOkay == FALSE);
931 # return messages about any dropped plugins back to caller 943 private function SortPluginsByInitializationPrecedence($Plugins)
945 # load plugin attributes 946 foreach ($Plugins as $PluginName => $Plugin)
948 $PluginAttribs[$PluginName] = $Plugin->GetAttributes();
951 # determine initialization order 952 $PluginsAfterUs = array();
953 foreach ($PluginAttribs as $PluginName => $Attribs)
955 foreach ($Attribs[
"InitializeBefore"] as $OtherPluginName)
957 $PluginsAfterUs[$PluginName][] = $OtherPluginName;
959 foreach ($Attribs[
"InitializeAfter"] as $OtherPluginName)
961 $PluginsAfterUs[$OtherPluginName][] = $PluginName;
965 # infer other initialization order cues from lists of required plugins 966 foreach ($PluginAttribs as $PluginName => $Attribs)
968 # for each required plugin 969 foreach ($Attribs[
"Requires"]
970 as $RequiredPluginName => $RequiredPluginVersion)
972 # skip the requirement if it it not for another known plugin 973 if (!isset($PluginAttribs[$RequiredPluginName]))
978 # if there is not a requirement in the opposite direction 979 if (!array_key_exists($PluginName,
980 $PluginAttribs[$RequiredPluginName][
"Requires"]))
982 # if the required plugin is not scheduled to be after us 983 if (!array_key_exists($PluginName, $PluginsAfterUs)
984 || !in_array($RequiredPluginName,
985 $PluginsAfterUs[$PluginName]))
987 # if we are not already scheduled to be after the required plugin 988 if (!array_key_exists($PluginName, $PluginsAfterUs)
989 || !in_array($RequiredPluginName,
990 $PluginsAfterUs[$PluginName]))
992 # schedule us to be after the required plugin 993 $PluginsAfterUs[$RequiredPluginName][] =
1001 # keep track of those plugins we have yet to do and those that are done 1002 $UnsortedPlugins = array_keys($Plugins);
1003 $PluginsProcessed = array();
1005 # limit the number of iterations of the plugin ordering loop 1006 # to 10 times the number of plugins we have 1007 $MaxIterations = 10 * count($UnsortedPlugins);
1008 $IterationCount = 0;
1010 # iterate through all the plugins that need processing 1011 while (($NextPlugin = array_shift($UnsortedPlugins)) !== NULL)
1013 # check to be sure that we're not looping forever 1015 if ($IterationCount > $MaxIterations)
1017 throw new Exception(
1018 "Max iteration count exceeded trying to determine plugin" 1019 .
" loading order. Is there a dependency loop?");
1022 # if no plugins require this one, it can go last 1023 if (!isset($PluginsAfterUs[$NextPlugin]))
1025 $PluginsProcessed[$NextPlugin] = $MaxIterations;
1029 # for plugins that are required by others 1030 $Index = $MaxIterations;
1031 foreach ($PluginsAfterUs[$NextPlugin] as $GoBefore)
1033 if (!isset($PluginsProcessed[$GoBefore]))
1035 # if there is something that requires us which hasn't 1036 # yet been assigned an order, then we can't determine 1037 # our own place on this iteration 1038 array_push($UnsortedPlugins, $NextPlugin);
1043 # otherwise, make sure that we're loaded 1044 # before the earliest of the things that require us 1045 $Index = min($Index, $PluginsProcessed[$GoBefore] - 1);
1048 $PluginsProcessed[$NextPlugin] = $Index;
1052 # arrange plugins according to our ordering 1053 asort($PluginsProcessed, SORT_NUMERIC);
1054 $SortedPlugins = array();
1055 foreach ($PluginsProcessed as $PluginName => $SortOrder)
1057 $SortedPlugins[$PluginName] = $Plugins[$PluginName];
1060 # return sorted list to caller 1061 return $SortedPlugins;
1072 public function FindPluginPhpFile($PageName)
1074 # build list of possible locations for file 1076 "local/plugins/%PLUGIN%/pages/%PAGE%.php",
1077 "plugins/%PLUGIN%/pages/%PAGE%.php",
1078 "local/plugins/%PLUGIN%/%PAGE%.php",
1079 "plugins/%PLUGIN%/%PAGE%.php",
1082 # look for file and return (possibly) updated page to caller 1083 return $this->FindPluginPageFile($PageName, $Locations);
1095 public function FindPluginHtmlFile($PageName)
1097 # build list of possible locations for file 1099 "local/plugins/%PLUGIN%/interface/%ACTIVEUI%/%PAGE%.html",
1100 "plugins/%PLUGIN%/interface/%ACTIVEUI%/%PAGE%.html",
1101 "local/plugins/%PLUGIN%/interface/%DEFAULTUI%/%PAGE%.html",
1102 "plugins/%PLUGIN%/interface/%DEFAULTUI%/%PAGE%.html",
1103 "local/plugins/%PLUGIN%/%PAGE%.html",
1104 "plugins/%PLUGIN%/%PAGE%.html",
1108 $Params = $this->FindPluginPageFile($PageName, $Locations);
1110 # if plugin HTML file was found 1111 if ($Params[
"PageName"] != $PageName)
1113 # add subdirectories for plugin to search paths 1114 $Dir = preg_replace(
"%^local/%",
"", dirname($Params[
"PageName"]));
1115 $this->AF->AddImageDirectories(array(
1116 "local/".$Dir.
"/images",
1119 $this->AF->AddIncludeDirectories(array(
1120 "local/".$Dir.
"/include",
1123 $this->AF->AddFunctionDirectories(array(
1124 "local/".$Dir.
"/include",
1129 # return possibly revised HTML file name to caller 1144 private function FindPluginPageFile($PageName, $Locations)
1146 # set up return value assuming we will not find plugin page file 1147 $ReturnValue[
"PageName"] = $PageName;
1149 # look for plugin name and plugin page name in base page name 1150 preg_match(
"/P_([A-Za-z].[A-Za-z0-9]*)_([A-Za-z0-9_-]+)/", $PageName, $Matches);
1152 # if plugin name and plugin page name were found and plugin name is valid 1153 if (count($Matches) == 3)
1155 # if plugin is valid and enabled and has its own subdirectory 1156 $PluginName = $Matches[1];
1157 if (isset($this->Plugins[$PluginName])
1158 && $this->PluginHasDir[$PluginName]
1159 && $this->Plugins[$PluginName]->IsEnabled())
1161 # for each possible location 1162 $PageName = $Matches[2];
1163 $ActiveUI = $this->AF->ActiveUserInterface();
1164 $DefaultUI = $this->AF->DefaultUserInterface();
1165 foreach ($Locations as $Loc)
1167 # make any needed substitutions into path 1168 $FileName = str_replace(
1169 array(
"%DEFAULTUI%",
"%ACTIVEUI%",
"%PLUGIN%",
"%PAGE%"),
1170 array($DefaultUI, $ActiveUI, $PluginName, $PageName),
1173 # if file exists in this location 1174 if (file_exists($FileName))
1176 # set return value to contain full plugin page file name 1177 $ReturnValue[
"PageName"] = $FileName;
1179 # save plugin name as home of current page 1180 $this->PageFilePlugin = $PluginName;
1182 # set G_Plugin to plugin associated with current page 1192 # return array containing page name or page file name to caller 1193 return $ReturnValue;
1217 public function __construct($PluginName, $MethodName)
1219 $this->PluginName = $PluginName;
1220 $this->MethodName = $MethodName;
1228 public function CallPluginMethod()
1230 $Args = func_get_args();
1231 $Plugin = self::$Manager->GetPlugin($this->PluginName);
1232 return call_user_func_array(array($Plugin, $this->MethodName), $Args);
1239 public function GetCallbackAsText()
1241 return $this->PluginName.
"::".$this->MethodName;
1249 public function __sleep()
1251 return array(
"PluginName",
"MethodName");
1255 static public $Manager;
1257 private $PluginName;
1258 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.
static AddObjectDirectory($Dir, $Prefix="", $ClassPattern=NULL, $ClassReplacement=NULL)
Add directory to be searched for object files when autoloading.
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
Run hooked function last (i.e.
static SetApplicationFramework($AF)
Set the application framework to be referenced within plugins.
LoadPlugins()
Load and initialize plugins.