/home/edulekha/studygroup.edulekha.com/ow_system_plugins/base/bol/plugin_service.php
<?php
/**
* EXHIBIT A. Common Public Attribution License Version 1.0
* The contents of this file are subject to the Common Public Attribution License Version 1.0 (the “License”);
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://www.oxwall.org/license. The License is based on the Mozilla Public License Version 1.1
* but Sections 14 and 15 have been added to cover use of software over a computer network and provide for
* limited attribution for the Original Developer. In addition, Exhibit A has been modified to be consistent
* with Exhibit B. Software distributed under the License is distributed on an “AS IS” basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language
* governing rights and limitations under the License. The Original Code is Oxwall software.
* The Initial Developer of the Original Code is Oxwall Foundation (http://www.oxwall.org/foundation).
* All portions of the code written by Oxwall Foundation are Copyright (c) 2011. All Rights Reserved.
* EXHIBIT B. Attribution Information
* Attribution Copyright Notice: Copyright 2011 Oxwall Foundation. All rights reserved.
* Attribution Phrase (not exceeding 10 words): Powered by Oxwall community software
* Attribution URL: http://www.oxwall.org/
* Graphic Image as provided in the Covered Code.
* Display of Attribution Information is required in Larger Works which are defined in the CPAL as a work
* which combines Covered Code or portions thereof with code not governed by the terms of the CPAL.
*/
/**
* @author Sardar Madumarov <madumarov@gmail.com>
* @package ow_system_plugins.base.bol
* @since 1.0
*/
class BOL_PluginService
{
/**
* @deprecated since version 1.8.1
*/
const UPDATE_SERVER = BOL_StorageService::UPDATE_SERVER;
/* list of plugin scripts */
const SCRIPT_INIT = "init.php";
const SCRIPT_INSTALL = "install.php";
const SCRIPT_UNINSTALL = "uninstall.php";
const SCRIPT_ACTIVATE = "activate.php";
const SCRIPT_DEACTIVATE = "deactivate.php";
const PLUGIN_INFO_XML = "plugin.xml";
/* ---------------------------------------------------------------------- */
const PLUGIN_STATUS_UP_TO_DATE = BOL_PluginDao::UPDATE_VAL_UP_TO_DATE;
const PLUGIN_STATUS_UPDATE = BOL_PluginDao::UPDATE_VAL_UPDATE;
const PLUGIN_STATUS_MANUAL_UPDATE = BOL_PluginDao::UPDATE_VAL_MANUAL_UPDATE;
const MANUAL_UPDATES_CHECK_INTERVAL_IN_SECONDS = 30;
/**
* @var BOL_PluginDao
*/
private $pluginDao;
/**
* @var array
*/
private $pluginListCache;
/**
* Singleton instance.
*
* @var BOL_PluginService
*/
private static $classInstance;
/**
* Returns an instance of class (singleton pattern implementation).
*
* @return BOL_PluginService
*/
public static function getInstance()
{
if ( self::$classInstance === null )
{
self::$classInstance = new self();
}
return self::$classInstance;
}
/**
* Constructor.
*/
private function __construct()
{
$this->pluginDao = BOL_PluginDao::getInstance();
}
/**
* Saves and updates plugin items.
*
* @param BOL_Plugin $pluginItem
*/
public function savePlugin( BOL_Plugin $pluginItem )
{
$this->pluginDao->save($pluginItem);
$this->updatePluginListCache();
}
/**
* Removes plugin entry in DB.
*
* @param integer $id
*/
public function deletePluginById( $id )
{
$this->pluginDao->deleteById($id);
$this->updatePluginListCache();
}
/**
* Returns all installed plugins.
*
* @return array<BOL_Plugin>
*/
public function findAllPlugins()
{
return $this->getPluginListCache();
}
/**
* Finds plugin item for provided key.
*
* @param string $key
* @return BOL_Plugin
*/
public function findPluginByKey( $key, $developerKey = null )
{
$key = strtolower($key);
$pluginList = $this->getPluginListCache();
if ( !array_key_exists($key, $pluginList) || ( $developerKey !== null && $pluginList[$key]->getDeveloperKey() != strtolower($developerKey) ) )
{
return null;
}
return $pluginList[$key];
}
/**
* Returns list of active plugins.
*
* @return array
*/
public function findActivePlugins()
{
$activePlugins = array();
$pluginList = $this->getPluginListCache();
/* @var $plugin BOL_Plugin */
foreach ( $pluginList as $plugin )
{
if ( $plugin->isActive() )
{
$activePlugins[] = $plugin;
}
}
return $activePlugins;
}
/**
* Returns list of plugins available for installation.
*
* @return array
*/
public function getAvailablePluginsList()
{
$availPlugins = array();
$dbPluginsArray = array_keys($this->getPluginListCache());
$xmlPlugins = $this->getPluginsXmlInfo();
foreach ( $xmlPlugins as $key => $plugin )
{
if ( !in_array($plugin["key"], $dbPluginsArray) )
{
$availPlugins[$key] = $plugin;
}
}
return $availPlugins;
}
/**
* Returns all plugins XML info.
*/
public function getPluginsXmlInfo()
{
$resultArray = array();
$xmlFiles = UTIL_File::findFiles(OW_DIR_PLUGIN, array("xml"), 1);
foreach ( $xmlFiles as $pluginXml )
{
if ( basename($pluginXml) == self::PLUGIN_INFO_XML )
{
$pluginInfo = $this->readPluginXmlInfo($pluginXml);
if ( $pluginInfo !== null )
{
$resultArray[$pluginInfo["key"]] = $pluginInfo;
}
}
}
return $resultArray;
}
/**
* Updates plugin meta info in DB using data in plugin.xml
*/
public function updatePluginsXmlInfo()
{
$info = $this->getPluginsXmlInfo();
foreach ( $info as $key => $pluginInfo )
{
$dto = $this->pluginDao->findPluginByKey($key);
if ( $dto !== null )
{
$dto->setTitle($pluginInfo["title"]);
$dto->setDescription($pluginInfo["description"]);
$dto->setDeveloperKey($pluginInfo["developerKey"]);
$this->pluginDao->save($dto);
}
}
}
/**
* Reads provided XML file and returns plugin info array.
*
* @param string $pluginXmlPath
* @return array|null
*/
public function readPluginXmlInfo( $pluginXmlPath )
{
if ( !file_exists($pluginXmlPath) )
{
return null;
}
$propList = array("key", "name", "description", "license", "author", "build", "copyright", "licenseUrl");
$xmlInfo = (array) simplexml_load_file($pluginXmlPath);
if ( !$xmlInfo )
{
return null;
}
foreach ( $propList as $prop )
{
if ( empty($xmlInfo[$prop]) )
{
return null;
}
}
$xmlInfo["title"] = $xmlInfo["name"];
$xmlInfo["path"] = dirname($pluginXmlPath);
return $xmlInfo;
}
/**
* Returns the count of plugins with update available.
*
* @return type
*/
public function findPluginsForUpdateCount()
{
return $this->pluginDao->findPluginsForUpdateCount();
}
/**
* Returns all regular (non system) plugins.
*
* @return array
*/
public function findRegularPlugins()
{
$regularPlugins = array();
/* @var $plugin BOL_Plugin */
foreach ( $this->getPluginListCache() as $plugin )
{
if ( !$plugin->isSystem() )
{
$regularPlugins[] = $plugin;
}
}
return $regularPlugins;
}
/**
* Installs plugins.
* Installs all available system plugins
*/
public function installSystemPlugins()
{
$files = UTIL_File::findFiles(OW_DIR_SYSTEM_PLUGIN, array("xml"), 1);
$pluginData = array();
$tempPluginData = array();
// first element should be BASE plugin
foreach ( $files as $file )
{
$tempArr = $this->readPluginXmlInfo($file);
$pathArr = explode(DS, dirname($file));
$tempArr["dir_name"] = array_pop($pathArr);
if ( $tempArr["key"] == "base" )
{
$pluginData[$tempArr["key"]] = $tempArr;
}
else
{
$tempPluginData[$tempArr["key"]] = $tempArr;
}
}
foreach ( $tempPluginData as $key => $val )
{
$pluginData[$key] = $val;
}
if ( !array_key_exists("base", $pluginData) )
{
throw new LogicException("Base plugin is not found in `{$basePluginRootDir}`!");
}
// install plugins list
foreach ( $pluginData as $pluginInfo )
{
$pluginDto = new BOL_Plugin();
$pluginDto->setTitle((!empty($pluginInfo["title"]) ? trim($pluginInfo["title"]) : "No Title"));
$pluginDto->setDescription((!empty($pluginInfo["description"]) ? trim($pluginInfo["description"]) : "No Description"));
$pluginDto->setKey(trim($pluginInfo["key"]));
$pluginDto->setModule($pluginInfo["dir_name"]);
$pluginDto->setIsActive(true);
$pluginDto->setIsSystem(true);
$pluginDto->setBuild((int) $pluginInfo["build"]);
if ( !empty($pluginInfo["developerKey"]) )
{
$pluginDto->setDeveloperKey(trim($pluginInfo["developerKey"]));
}
$this->pluginListCache[$pluginDto->getKey()] = $pluginDto;
$plugin = new OW_Plugin($pluginDto);
$this->includeScript($plugin->getRootDir() . BOL_PluginService::SCRIPT_INSTALL);
$this->pluginDao->save($pluginDto);
$this->updatePluginListCache();
$this->addPluginDirs($pluginDto);
}
}
/**
* Installs plugins.
*
* @param string $key
*/
public function install( $key, $generateCache = true )
{
$availablePlugins = $this->getAvailablePluginsList();
if ( empty($key) || !array_key_exists($key, $availablePlugins) )
{
throw new LogicException("Invalid plugin key - `{$key}` provided for install!");
}
$pluginInfo = $availablePlugins[$key];
$dirArray = explode(DS, $pluginInfo["path"]);
$moduleName = array_pop($dirArray);
// add DB entry
$pluginDto = new BOL_Plugin();
$pluginDto->setTitle((!empty($pluginInfo["title"]) ? trim($pluginInfo["title"]) : "No Title"));
$pluginDto->setDescription((!empty($pluginInfo["description"]) ? trim($pluginInfo["description"]) : "No Description"));
$pluginDto->setKey(trim($pluginInfo["key"]));
$pluginDto->setModule($moduleName);
$pluginDto->setIsActive(true);
$pluginDto->setIsSystem(false);
$pluginDto->setBuild((int) $pluginInfo["build"]);
if ( !empty($pluginInfo["developerKey"]) )
{
$pluginDto->setDeveloperKey(trim($pluginInfo["developerKey"]));
}
$this->pluginDao->save($pluginDto);
$this->updatePluginListCache();
$this->addPluginDirs($pluginDto);
$plugin = new OW_Plugin($pluginDto);
$this->includeScript($plugin->getRootDir() . BOL_PluginService::SCRIPT_INSTALL);
$this->includeScript($plugin->getRootDir() . BOL_PluginService::SCRIPT_ACTIVATE);
$pluginDto = $this->findPluginByKey($pluginDto->getKey());
if ( $generateCache )
{
BOL_LanguageService::getInstance()->generateCacheForAllActiveLanguages();
}
// trigger event
OW::getEventManager()->trigger(new OW_Event(OW_EventManager::ON_AFTER_PLUGIN_INSTALL,
array("pluginKey" => $pluginDto->getKey())));
return $pluginDto;
}
/**
* Creates platform reserved dirs for plugin, copies all plugin static data
*
* @param BOL_Plugin $pluginDto
*/
public function addPluginDirs( BOL_Plugin $pluginDto )
{
$plugin = new OW_Plugin($pluginDto);
if ( file_exists($plugin->getStaticDir()) )
{
UTIL_File::copyDir($plugin->getStaticDir(), $plugin->getPublicStaticDir());
}
// create dir in pluginfiles
if( file_exists($plugin->getInnerPluginFilesDir()) )
{
UTIL_File::copyDir($plugin->getInnerPluginFilesDir(), $plugin->getPluginFilesDir());
}
else if ( !file_exists($plugin->getPluginFilesDir()) )
{
mkdir($plugin->getPluginFilesDir());
chmod($plugin->getPluginFilesDir(), 0777);
}
// create dir in userfiles
if( file_exists($plugin->getInnerUserFilesDir()) )
{
OW::getStorage()->copyDir($plugin->getInnerUserFilesDir(), $plugin->getUserFilesDir());
}
else if ( !file_exists($plugin->getUserFilesDir()) )
{
OW::getStorage()->mkdir($plugin->getUserFilesDir());
}
}
/**
* Uninstalls plugin
*
* @param string $pluginKey
*/
public function uninstall( $pluginKey )
{
if ( empty($pluginKey) )
{
throw new LogicException("Empty plugin key provided for uninstall");
}
$pluginDto = $this->findPluginByKey(trim($pluginKey));
if ( $pluginDto === null )
{
throw new LogicException("Invalid plugin key - `{$pluginKey}` provided for uninstall!");
}
$plugin = new OW_Plugin($pluginDto);
// trigger event
OW::getEventManager()->trigger(new OW_Event(OW_EventManager::ON_BEFORE_PLUGIN_UNINSTALL,
array("pluginKey" => $pluginDto->getKey())));
$this->includeScript($plugin->getRootDir() . BOL_PluginService::SCRIPT_DEACTIVATE);
$this->includeScript($plugin->getRootDir() . BOL_PluginService::SCRIPT_UNINSTALL);
// delete plugin work dirs
$dirsToRemove = array(
$plugin->getPluginFilesDir(),
$plugin->getUserFilesDir(),
$plugin->getPublicStaticDir()
);
foreach ( $dirsToRemove as $dir )
{
if ( file_exists($dir) )
{
UTIL_File::removeDir($dir);
}
}
// remove plugin configs
OW::getConfig()->deletePluginConfigs($pluginDto->getKey());
// delete language prefix
$prefixId = BOL_LanguageService::getInstance()->findPrefixId($pluginDto->getKey());
if ( !empty($prefixId) )
{
BOL_LanguageService::getInstance()->deletePrefix($prefixId, true);
}
//delete authorization stuff
BOL_AuthorizationService::getInstance()->deleteGroup($pluginDto->getKey());
// drop plugin tables
$tables = OW::getDbo()->queryForColumnList("SHOW TABLES LIKE '" . str_replace('_', '\_', OW_DB_PREFIX) . $pluginDto->getKey() . "\_%'");
if ( !empty($tables) )
{
$query = "DROP TABLE ";
foreach ( $tables as $table )
{
$query .= "`" . $table . "`,";
}
$query = substr($query, 0, -1);
OW::getDbo()->query($query);
}
//remove entry in DB
$this->deletePluginById($pluginDto->getId());
$this->updatePluginListCache();
// trigger event
OW::getEventManager()->trigger(new OW_Event(OW_EventManager::ON_AFTER_PLUGIN_UNINSTALL,
array("pluginKey" => $pluginDto->getKey())));
}
/**
* Activates plugin
*
* @param string $key
*/
public function activate( $key )
{
$pluginDto = $this->pluginDao->findPluginByKey($key);
if ( $pluginDto == null )
{
throw new LogicException("Can't activate {$key} plugin!");
}
$pluginDto->setIsActive(true);
$this->pluginDao->save($pluginDto);
OW::getPluginManager()->addPackagePointers($pluginDto);
$this->includeScript(OW_DIR_PLUGIN . $pluginDto->getModule() . DS . self::SCRIPT_ACTIVATE);
$this->updatePluginListCache();
// trigger event
$event = new OW_Event(OW_EventManager::ON_AFTER_PLUGIN_ACTIVATE, array("pluginKey" => $pluginDto->getKey()));
OW::getEventManager()->trigger($event);
}
/**
* Deactivates plugin
*
* @param sring $key
*/
public function deactivate( $key )
{
$pluginDto = $this->pluginDao->findPluginByKey($key);
if ( $pluginDto == null )
{
throw new LogicException("Can't deactivate {$key} plugin!");
}
// trigger event
$event = new OW_Event(OW_EventManager::ON_BEFORE_PLUGIN_DEACTIVATE, array("pluginKey" => $pluginDto->getKey()));
OW::getEventManager()->trigger($event);
$pluginDto->setIsActive(false);
$this->pluginDao->save($pluginDto);
$this->includeScript(OW::getPluginManager()->getPlugin($pluginDto->getKey())->getRootDir() . self::SCRIPT_DEACTIVATE);
$this->updatePluginListCache();
$event = new OW_Event(OW_EventManager::ON_AFTER_PLUGIN_DEACTIVATE, array("pluginKey" => $pluginDto->getKey()));
OW::getEventManager()->trigger($event);
}
/**
* Returns the count of plugins available for update
*
* @return int
*/
public function getPluginsToUpdateCount()
{
return $this->pluginDao->findPluginsForUpdateCount();
}
/**
* Checks if plugin source code was updated, if yes changes the update status in DB
*
* @return void
*/
public function checkManualUpdates()
{
$timestamp = OW::getConfig()->getValue("base", "check_mupdates_ts");
if ( ( time() - (int) $timestamp ) < self::MANUAL_UPDATES_CHECK_INTERVAL_IN_SECONDS )
{
return;
}
$plugins = $this->pluginDao->findAll();
$xmlInfo = $this->getPluginsXmlInfo();
/* @var $plugin BOL_Plugin */
foreach ( $plugins as $plugin )
{
if ( !empty($xmlInfo[$plugin->getKey()]) && (int) $plugin->getBuild() < (int) $xmlInfo[$plugin->getKey()]['build'] )
{
$plugin->setUpdate(BOL_PluginDao::UPDATE_VAL_MANUAL_UPDATE);
$this->pluginDao->save($plugin);
}
}
OW::getConfig()->saveConfig("base", "check_mupdates_ts", time());
}
/**
* Returns next plugin for manual update if it's available
*
* @return BOL_Plugin
*/
public function findNextManualUpdatePlugin()
{
return $this->pluginDao->findPluginForManualUpdate();
}
/**
* Returns plugins with invalid license
*
* @return array
*/
public function findPluginsWithInvalidLicense()
{
return $this->pluginDao->findPluginsWithInvalidLicense();
}
/* ---------------------------------------------------------------------- */
private function updatePluginListCache()
{
$this->pluginListCache = array();
$dbData = $this->pluginDao->findAll();
/* @var $plugin BOL_Plugin */
foreach ( $dbData as $plugin )
{
$this->pluginListCache[$plugin->getKey()] = $plugin;
}
}
private function getPluginListCache()
{
if ( !$this->pluginListCache )
{
$this->updatePluginListCache();
}
return $this->pluginListCache;
}
/**
* @param string $scriptPath
*/
public function includeScript( $scriptPath )
{
if ( file_exists($scriptPath) )
{
include_once $scriptPath;
}
}
/**
* @deprecated since version 1.8.1
*/
public function checkUpdates()
{
BOL_StorageService::getInstance()->checkUpdates();
}
}