Open Journal Systems  3.3.0
Plugin.inc.php
1 <?php
2 
47 // Define the well-known file name for filter configuration data.
48 define('PLUGIN_FILTER_DATAFILE', 'filterConfig.xml');
49 define('PLUGIN_TEMPLATE_RESOURCE_PREFIX', 'plugins');
50 
51 abstract class Plugin {
53  var $pluginPath;
54 
57 
59  var $request;
60 
64  function __construct() {
65  }
66 
67  /*
68  * Public Plugin API (Registration and Initialization)
69  */
90  function register($category, $path, $mainContextId = null) {
91  $this->pluginPath = $path;
92  $this->pluginCategory = $category;
93  if ($this->getInstallSchemaFile() || $this->getInstallMigration()) {
94  HookRegistry::register ('Installer::postInstall', array($this, 'updateSchema'));
95  }
96  if ($this->getInstallSitePluginSettingsFile()) {
97  HookRegistry::register ('Installer::postInstall', array($this, 'installSiteSettings'));
98  }
100  HookRegistry::register ('Installer::postInstall', array($this, 'installControlledVocabs'));
101  }
102  if ($this->getInstallEmailTemplatesFile()) {
103  HookRegistry::register ('Installer::postInstall', array($this, 'installEmailTemplates'));
104  HookRegistry::register ('PKPLocale::installLocale', array($this, 'installLocale'));
105  }
106  if ($this->getInstallEmailTemplateDataFile()) {
107  HookRegistry::register ('Installer::postInstall', array($this, 'installEmailTemplateData'));
108  }
109  if ($this->getInstallDataFile()) {
110  HookRegistry::register ('Installer::postInstall', array($this, 'installData'));
111  }
113  HookRegistry::register ('Context::add', array($this, 'installContextSpecificSettings'));
114  }
115 
116  HookRegistry::register ('Installer::postInstall', array($this, 'installFilters'));
117 
118  $this->_registerTemplateResource();
119  return true;
120  }
121 
126  //
127  // Plugin Display
128  //
129 
137  abstract function getName();
138 
144  abstract function getDisplayName();
145 
151  abstract function getDescription();
152 
153  //
154  // Plugin Behavior and Management
155  //
156 
164  function getSeq() {
165  return 0;
166  }
167 
173  function isSitePlugin() {
174  return false;
175  }
176 
183  function manage($args, $request) {
184  throw new Exception('Unhandled management action!');
185  }
186 
194  function getHideManagement() {
195  return false;
196  }
197 
198  //
199  // Plugin Installation
200  //
201 
208  function getInstallSchemaFile() {
209  return null;
210  }
211 
216  function getInstallMigration() {
217  return null;
218  }
219 
226  function getInstallDataFile() {
227  return null;
228  }
229 
238  return null;
239  }
240 
247  return array();
248  }
249 
260  return null;
261  }
262 
269  function getInstallEmailTemplatesFile() {
270  return null;
271  }
272 
282  return null;
283  }
284 
295  function getInstallFilterConfigFiles() {
296  // Construct the well-known filter configuration file names.
297  $filterConfigFile = $this->getPluginPath().'/filter/'.PLUGIN_FILTER_DATAFILE;
298  $filterConfigFiles = array(
299  './lib/pkp/'.$filterConfigFile,
300  './'.$filterConfigFile
301  );
302  return $filterConfigFiles;
303  }
304 
305  /*
306  * Protected helper methods (can be used by custom plugins but
307  * should not be overridden by custom plugins)
308  */
313  function getCategory() {
314  return $this->pluginCategory;
315  }
316 
321  function getPluginPath() {
323  }
324 
329  function getDirName() {
330  return basename($this->pluginPath);
331  }
332 
340  public function getTemplateResource($template = null, $inCore = false) {
341  $pluginPath = $this->getPluginPath();
342  if ($inCore) {
343  $pluginPath = PKP_LIB_PATH . DIRECTORY_SEPARATOR . $pluginPath;
344  }
345  $plugin = basename($pluginPath);
346  $category = basename(dirname($pluginPath));
347  // Slash characters (/) are not allowed in resource names, so use dashes (-) instead.
348  $resourceName = strtr(join('/', array(PLUGIN_TEMPLATE_RESOURCE_PREFIX, $pluginPath, $category, $plugin)),'/','-');
349  return $resourceName . ($template!==null?":$template":'');
350  }
351 
357  function getTemplatePath($inCore = false) {
358  $templatePath = ($inCore?PKP_LIB_PATH . DIRECTORY_SEPARATOR:'') . $this->getPluginPath() . DIRECTORY_SEPARATOR . 'templates';
359  if (is_dir($templatePath)) return $templatePath;
360  return null;
361  }
362 
367  protected function _registerTemplateResource($inCore = false) {
368  if ($templatePath = $this->getTemplatePath($inCore)) {
369  $templateMgr = TemplateManager::getManager();
370  $pluginTemplateResource = new PKPTemplateResource($templatePath);
371  $templateMgr->registerResource($this->getTemplateResource(null, $inCore), $pluginTemplateResource);
372  }
373  }
374 
389  public function _overridePluginTemplates($hookName, $args) {
390  $filePath =& $args[0];
391  $template = $args[1];
392  $checkFilePath = $filePath;
393 
394  // If there's a templates/ prefix on the template, clean up the test path.
395  if (strpos($filePath, 'plugins/') === 0) $checkFilePath = 'templates/' . $checkFilePath;
396 
397  // If there's a lib/pkp/ prefix on the template, test without it.
398  $libPkpPrefix = 'lib' . DIRECTORY_SEPARATOR . 'pkp' . DIRECTORY_SEPARATOR;
399  if (strpos($checkFilePath, $libPkpPrefix) === 0) $checkFilePath = substr($filePath, strlen($libPkpPrefix));
400 
401  // Check if an overriding plugin exists in the plugin path.
402  if ($overriddenFilePath = $this->_findOverriddenTemplate($checkFilePath)) {
403  $filePath = $overriddenFilePath;
404  }
405 
406  return false;
407  }
408 
414  private function _findOverriddenTemplate($path) {
415  $fullPath = sprintf('%s/%s', $this->getPluginPath(), $path);
416 
417  if (file_exists($fullPath)) {
418  return $fullPath;
419  }
420 
421  // Backward compatibility for OJS prior to 3.1.2; changed path to templates for plugins.
422  if (($fullPath = preg_replace("/templates\/(?!.*templates\/)/", "", $fullPath)) && file_exists($fullPath)) {
423  if (Config::getVar('debug', 'deprecation_warnings')) {
424  trigger_error('Deprecated: The template at ' . $fullPath . ' has moved and will not be found in the future.');
425  }
426  return $fullPath;
427  }
428 
429  // Recursive check for templates in ancestors of a current theme plugin
430  if (is_a($this, 'ThemePlugin')
431  && $this->parent
432  && $fullPath = $this->parent->_findOverriddenTemplate($path)) {
433  return $fullPath;
434  }
435 
436  return null;
437  }
438 
445  function addLocaleData($locale = null) {
446  if ($locale == '') $locale = AppLocale::getLocale();
447  $localeFilenames = $this->getLocaleFilename($locale);
448  if ($localeFilenames) {
449  if (is_scalar($localeFilenames)) $localeFilenames = array($localeFilenames);
450  foreach($localeFilenames as $localeFilename) {
451  AppLocale::registerLocaleFile($locale, $localeFilename);
452  }
453  return true;
454  }
455  return false;
456  }
457 
464  function getSetting($contextId, $name) {
465  if (!defined('RUNNING_UPGRADE') && !Config::getVar('general', 'installed')) return null;
466 
467  // Construct the argument list and call the plug-in settings DAO
468  $arguments = array(
469  $contextId,
470  $this->getName(),
471  $name,
472  );
473 
474  $pluginSettingsDao = DAORegistry::getDAO('PluginSettingsDAO'); /* @var $pluginSettingsDao PluginSettingsDAO */
475  return call_user_func_array(array(&$pluginSettingsDao, 'getSetting'), $arguments);
476  }
477 
486  function updateSetting($contextId, $name, $value, $type = null) {
487 
488  // Construct the argument list and call the plug-in settings DAO
489  $arguments = array(
490  $contextId,
491  $this->getName(),
492  $name,
493  $value,
494  $type,
495  );
496 
497  $pluginSettingsDao = DAORegistry::getDAO('PluginSettingsDAO'); /* @var $pluginSettingsDao PluginSettingsDAO */
498  call_user_func_array(array(&$pluginSettingsDao, 'updateSetting'), $arguments);
499  }
500 
506  function import($class) {
507  require_once($this->getPluginPath() . '/' . str_replace('.', '/', $class) . '.inc.php');
508  }
509 
510  /*
511  * Protected helper methods (for internal use only, should not
512  * be used by custom plug-ins)
513  *
514  * NB: These methods may change without notice in the future!
515  */
522  function getLocaleFilename($locale) {
523  $masterLocale = MASTER_LOCALE;
524  $baseLocaleFilename = $this->getPluginPath() . "/locale/$locale/locale.po";
525  $baseMasterLocaleFilename = $this->getPluginPath() . "/locale/$masterLocale/locale.po";
526  $libPkpFilename = "lib/pkp/$baseLocaleFilename";
527  $masterLibPkpFilename = "lib/pkp/$baseMasterLocaleFilename";
528  $filenames = array();
529  if (file_exists($baseMasterLocaleFilename)) $filenames[] = $baseLocaleFilename;
530  if (file_exists($masterLibPkpFilename)) $filenames[] = $libPkpFilename;
531 
532  // This compatibility code for XML file fallback will eventually be removed.
533  // See https://github.com/pkp/pkp-lib/issues/5090.
534  $baseMasterXmlLocaleFilename = preg_replace('/\.po$/', '.xml', $baseMasterLocaleFilename);
535  if (file_exists($baseMasterXmlLocaleFilename)) $filenames[] = preg_replace('/\.po$/', '.xml', $baseLocaleFilename);
536  $masterXmlLibPkpLocaleFilename = preg_replace('/\.po$/', '.xml', $baseMasterLocaleFilename);
537  if (file_exists($masterXmlLibPkpLocaleFilename)) $filenames[] = preg_replace('/\.po$/', '.xml', $libPkpFilename);
538 
539  return $filenames;
540  }
541 
549  function installData($hookName, $args) {
550  $installer =& $args[0];
551  $result =& $args[1];
552 
553  // Treat single and multiple data files uniformly.
554  $dataFiles = $this->getInstallDataFile();
555  if (is_scalar($dataFiles)) $dataFiles = array($dataFiles);
556 
557  // Install all data files.
558  foreach($dataFiles as $dataFile) {
559  $sql = $installer->dataXMLParser->parseData($dataFile);
560  if ($sql) {
561  $result = $installer->executeSQL($sql);
562  } else {
563  AppLocale::requireComponents(LOCALE_COMPONENT_PKP_INSTALLER);
564  $installer->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $this->getInstallDataFile(), __('installer.installParseDBFileError')));
565  $result = false;
566  }
567  if (!$result) return false;
568  }
569  return false;
570  }
571 
579  function installSiteSettings($hookName, $args) {
580  // All contexts are set to zero for site-wide plug-in settings
582  $contextDepth = $application->getContextDepth();
583  if ($contextDepth >0) {
584  $arguments = array_fill(0, $contextDepth, 0);
585  } else {
586  $arguments = array();
587  }
588  $arguments[] = $this->getName();
589  $arguments[] = $this->getInstallSitePluginSettingsFile();
590  $pluginSettingsDao = DAORegistry::getDAO('PluginSettingsDAO'); /* @var $pluginSettingsDao PluginSettingsDAO */
591  call_user_func_array(array(&$pluginSettingsDao, 'installSettings'), $arguments);
592 
593  return false;
594  }
595 
602  function installControlledVocabs($hookName, $args) {
603  // All contexts are set to zero for site-wide plug-in settings
604  $controlledVocabDao = DAORegistry::getDAO('ControlledVocabDAO'); /* @var $controlledVocabDao ControlledVocabDAO */
605  foreach ($this->getInstallControlledVocabFiles() as $file) {
606  $controlledVocabDao->installXML($file);
607  }
608  return false;
609  }
618  function installContextSpecificSettings($hookName, $args) {
619  $context = $args[0];
620  $pluginSettingsDao = DAORegistry::getDAO('PluginSettingsDAO'); /* @var $pluginSettingsDao PluginSettingsDAO */
621  $pluginSettingsDao->installSettings($context->getId(), $this->getName(), $this->getContextSpecificPluginSettingsFile());
622  return false;
623  }
624 
632  function installEmailTemplates($hookName, $args) {
633  $installer =& $args[0]; /* @var $installer Installer */
634  $result =& $args[1];
635 
636  // Load email template data as required from the locale files.
637  $emailTemplateDao = DAORegistry::getDAO('EmailTemplateDAO'); /* @var $emailTemplateDao EmailTemplateDAO */
638  $emailTemplateLocales = [];
639  foreach ($installer->installedLocales as $locale) {
640  $emailFile = $this->getPluginPath() . "/locale/$locale/emails.po";
641  if (!file_exists($emailFile)) continue;
642  AppLocale::registerLocaleFile($locale, $emailFile);
643  $emailTemplateLocales[] = $locale;
644  }
645  $sql = $emailTemplateDao->installEmailTemplates($this->getInstallEmailTemplatesFile(), $emailTemplateLocales, true, null, true);
646 
647  if ($sql === false) {
648  // The template file seems to be invalid.
649  $installer->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $this->getInstallEmailTemplatesFile(), __('installer.installParseEmailTemplatesFileError')));
650  $result = false;
651  } else {
652  // Are there any yet uninstalled email templates?
653  assert(is_array($sql));
654  if (!empty($sql)) {
655  // Install templates.
656  $result = $installer->executeSQL($sql);
657  }
658  }
659  return false;
660  }
661 
670  function installEmailTemplateData($hookName, $args) {
671  $installer =& $args[0];
672  $result =& $args[1];
673 
674  $emailTemplateDao = DAORegistry::getDAO('EmailTemplateDAO'); /* @var $emailTemplateDao EmailTemplateDAO */
675  foreach ($installer->installedLocales as $locale) {
676  $filename = str_replace('{$installedLocale}', $locale, $this->getInstallEmailTemplateDataFile());
677  if (!file_exists($filename)) continue;
678  $sql = $emailTemplateDao->installEmailTemplateData($filename, $locale, true);
679  if ($sql) {
680  $result = $installer->executeSQL($sql);
681  } else {
682  $installer->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $this->getInstallDataFile(), __('installer.installParseEmailTemplatesFileError')));
683  $result = false;
684  }
685  }
686  return false;
687  }
688 
696  function installLocale($hookName, $args) {
697  $locale =& $args[0];
698  $filename = str_replace('{$installedLocale}', $locale, $this->getInstallEmailTemplateDataFile());
699  $emailTemplateDao = DAORegistry::getDAO('EmailTemplateDAO'); /* @var $emailTemplateDao EmailTemplateDAO */
700 
701  // Since pkp/pkp-lib#5461, there are two ways to specify localized email data in plugins.
702  // Install locale data specified in the old form. (Deprecated!)
703  if ($this->getInstallEmailTemplateDataFile()) $emailTemplateDao->installEmailTemplateData($filename, $locale);
704 
705  // Install locale data specified in the new form.
706  if (file_exists($emailFile = $this->getPluginPath() . "/locale/$locale/emails.po")) {
707  AppLocale::registerLocaleFile($locale, $emailFile);
708  $emailTemplateDao->installEmailTemplateLocaleData($this->getInstallEmailTemplatesFile(), [$locale]);
709  }
710  return false;
711  }
712 
718  function installFilters($hookName, $args) {
719  $installer =& $args[0]; /* @var $installer Installer */
720  $result =& $args[1]; /* @var $result boolean */
721 
722  // Get the filter configuration file name(s).
723  $filterConfigFiles = $this->getInstallFilterConfigFiles();
724  if (is_scalar($filterConfigFiles)) $filterConfigFiles = array($filterConfigFiles);
725 
726  // Run through the config file positions and see
727  // whether one of these exists and needs to be installed.
728  foreach($filterConfigFiles as $filterConfigFile) {
729  // Is there a filter configuration?
730  if (!file_exists($filterConfigFile)) continue;
731 
732  // Install the filter configuration.
733  $result = $installer->installFilterConfig($filterConfigFile);
734  if (!$result) {
735  // The filter configuration file seems to be invalid.
736  $installer->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $filterConfigFile, __('installer.installParseFilterConfigFileError')));
737  }
738  }
739 
740  // Do not stop installation.
741  return false;
742  }
743 
752  function updateSchema($hookName, $args) {
753  $installer =& $args[0];
754  $result =& $args[1];
755 
756  // Deprecated: Create schema using ADODB XML Schema
757  if ($schemaFile = $this->getInstallSchemaFile()) {
758  $schemaXMLParser = new adoSchema($installer->dbconn);
759  $sql = $schemaXMLParser->parseSchema($schemaFile);
760  if ($sql) {
761  $result = $installer->executeSQL($sql);
762  } else {
763  $installer->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $this->getInstallSchemaFile(), __('installer.installParseDBFileError')));
764  $result = false;
765  }
766  }
767  // Preferred: Create schema using Migrations
768  if ($migration = $this->getInstallMigration()) try {
769  $migration->up();
770  } catch (Exception $e) {
771  $installer->setError(INSTALLER_ERROR_DB, __('installer.installMigrationError', ['class' => get_class($migration)]));
772  $result = false;
773  }
774  return false;
775  }
776 
784  function smartyPluginUrl($params, $smarty) {
785  $path = array($this->getCategory(), $this->getName());
786  if (is_array($params['path'])) {
787  $params['path'] = array_merge($path, $params['path']);
788  } elseif (!empty($params['path'])) {
789  $params['path'] = array_merge($path, array($params['path']));
790  } else {
791  $params['path'] = $path;
792  }
793  return $smarty->smartyUrl($params, $smarty);
794  }
795 
801  function getCurrentVersion() {
802  $versionDao = DAORegistry::getDAO('VersionDAO'); /* @var $versionDao VersionDAO */
803  $pluginPath = $this->getPluginPath();
804  $product = basename($pluginPath);
805  $category = basename(dirname($pluginPath));
806  $installedPlugin = $versionDao->getCurrentVersion('plugins.'.$category, $product, true);
807 
808  if ($installedPlugin) {
809  return $installedPlugin;
810  } else {
811  return false;
812  }
813  }
814 
819  function &getRequest() {
820  if (!$this->request) {
821  $this->request =& Registry::get('request');
822  }
823  return $this->request;
824  }
825 
826  /*
827  * Private helper methods
828  */
835  function getActions($request, $actionArgs) {
836  return array();
837  }
838 
843  function getCanEnable() {
844  return false;
845  }
846 
851  function getCanDisable() {
852  return false;
853  }
854 
859  function getEnabled() {
860  return true;
861  }
862 }
Plugin\getDisplayName
getDisplayName()
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
Plugin\getInstallSchemaFile
getInstallSchemaFile()
Definition: Plugin.inc.php:217
Plugin\updateSchema
updateSchema($hookName, $args)
Definition: Plugin.inc.php:761
Plugin\getCategory
getCategory()
Definition: Plugin.inc.php:322
Plugin\updateSetting
updateSetting($contextId, $name, $value, $type=null)
Definition: Plugin.inc.php:495
Plugin\getCanDisable
getCanDisable()
Definition: Plugin.inc.php:860
$application
$application
Definition: index.php:65
Plugin\getActions
getActions($request, $actionArgs)
Definition: Plugin.inc.php:844
Plugin\getDirName
getDirName()
Definition: Plugin.inc.php:338
Plugin\getDescription
getDescription()
Plugin\getName
getName()
Plugin\getRequest
& getRequest()
Definition: Plugin.inc.php:828
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
Plugin\getInstallFilterConfigFiles
getInstallFilterConfigFiles()
Definition: Plugin.inc.php:304
Plugin\installControlledVocabs
installControlledVocabs($hookName, $args)
Definition: Plugin.inc.php:611
AppLocale\registerLocaleFile
static registerLocaleFile($locale, $filename, $addToTop=false)
Definition: env1/MockAppLocale.inc.php:48
Plugin\__construct
__construct()
Definition: Plugin.inc.php:73
Plugin\getInstallMigration
getInstallMigration()
Definition: Plugin.inc.php:225
Plugin\getCurrentVersion
getCurrentVersion()
Definition: Plugin.inc.php:810
Plugin\isSitePlugin
isSitePlugin()
Definition: Plugin.inc.php:182
Plugin\getInstallSitePluginSettingsFile
getInstallSitePluginSettingsFile()
Definition: Plugin.inc.php:246
Plugin\installEmailTemplateData
installEmailTemplateData($hookName, $args)
Definition: Plugin.inc.php:679
Plugin\installFilters
installFilters($hookName, $args)
Definition: Plugin.inc.php:727
Plugin\$pluginCategory
$pluginCategory
Definition: Plugin.inc.php:62
Plugin\installContextSpecificSettings
installContextSpecificSettings($hookName, $args)
Definition: Plugin.inc.php:627
PKPTemplateResource
Representation for a PKP template resource (template directory).
Definition: PKPTemplateResource.inc.php:16
Plugin\getHideManagement
getHideManagement()
Definition: Plugin.inc.php:203
Plugin\getInstallEmailTemplateDataFile
getInstallEmailTemplateDataFile()
Definition: Plugin.inc.php:290
Plugin\getEnabled
getEnabled()
Definition: Plugin.inc.php:868
Plugin\getInstallDataFile
getInstallDataFile()
Definition: Plugin.inc.php:235
Registry\get
static & get($key, $createIfEmpty=false, $createWithDefault=null)
Definition: Registry.inc.php:35
Plugin\getSetting
getSetting($contextId, $name)
Definition: Plugin.inc.php:473
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
Plugin\getInstallControlledVocabFiles
getInstallControlledVocabFiles()
Definition: Plugin.inc.php:255
PKPTemplateManager\getManager
static & getManager($request=null)
Definition: PKPTemplateManager.inc.php:1239
Plugin\smartyPluginUrl
smartyPluginUrl($params, $smarty)
Definition: Plugin.inc.php:793
Plugin\$pluginPath
$pluginPath
Definition: Plugin.inc.php:56
Plugin\_registerTemplateResource
_registerTemplateResource($inCore=false)
Definition: Plugin.inc.php:376
Plugin\getCanEnable
getCanEnable()
Definition: Plugin.inc.php:852
Plugin
Abstract class for plugins.
Definition: Plugin.inc.php:51
Plugin\installLocale
installLocale($hookName, $args)
Definition: Plugin.inc.php:705
Plugin\getTemplateResource
getTemplateResource($template=null, $inCore=false)
Definition: Plugin.inc.php:349
Plugin\getPluginPath
getPluginPath()
Definition: Plugin.inc.php:330
Plugin\$request
$request
Definition: Plugin.inc.php:68
Plugin\getTemplatePath
getTemplatePath($inCore=false)
Definition: Plugin.inc.php:366
Plugin\addLocaleData
addLocaleData($locale=null)
Definition: Plugin.inc.php:454
HookRegistry\register
static register($hookName, $callback, $hookSequence=HOOK_SEQUENCE_NORMAL)
Definition: HookRegistry.inc.php:70
Plugin\installEmailTemplates
installEmailTemplates($hookName, $args)
Definition: Plugin.inc.php:641
Plugin\getSeq
getSeq()
Definition: Plugin.inc.php:173
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
Plugin\getLocaleFilename
getLocaleFilename($locale)
Definition: Plugin.inc.php:531
Plugin\getContextSpecificPluginSettingsFile
getContextSpecificPluginSettingsFile()
Definition: Plugin.inc.php:268
AppLocale\getLocale
static getLocale()
Definition: env1/MockAppLocale.inc.php:40
Plugin\_overridePluginTemplates
_overridePluginTemplates($hookName, $args)
Definition: Plugin.inc.php:398
Plugin\getInstallEmailTemplatesFile
getInstallEmailTemplatesFile()
Definition: Plugin.inc.php:278
Plugin\installSiteSettings
installSiteSettings($hookName, $args)
Definition: Plugin.inc.php:588
Plugin\installData
installData($hookName, $args)
Definition: Plugin.inc.php:558
Plugin\manage
manage($args, $request)
Definition: Plugin.inc.php:192