看板初始化提交
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
/**
|
||||
* Plugin Base class
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
abstract class Base extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Method called for each request
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
*/
|
||||
abstract public function initialize();
|
||||
|
||||
/**
|
||||
* Override default CSP rules
|
||||
*
|
||||
* @access public
|
||||
* @param array $rules
|
||||
*/
|
||||
public function setContentSecurityPolicy(array $rules)
|
||||
{
|
||||
$this->container['cspRules'] = $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all classes that needs to be stored in the DI container
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getClasses()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all helper classes that needs to be stored in the DI container
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getHelpers()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen on internal events
|
||||
*
|
||||
* @access public
|
||||
* @param string $event
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function on($event, $callback)
|
||||
{
|
||||
$container = $this->container;
|
||||
|
||||
$this->dispatcher->addListener($event, function () use ($container, $callback) {
|
||||
call_user_func($callback, $container);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin name
|
||||
*
|
||||
* This method should be overridden by your Plugin class
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName()
|
||||
{
|
||||
return ucfirst(substr(get_called_class(), 16, -7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin description
|
||||
*
|
||||
* This method should be overridden by your Plugin class
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginDescription()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin author
|
||||
*
|
||||
* This method should be overridden by your Plugin class
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginAuthor()
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin version
|
||||
*
|
||||
* This method should be overridden by your Plugin class
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginVersion()
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin homepage
|
||||
*
|
||||
* This method should be overridden by your Plugin class
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginHomepage()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application compatibility version
|
||||
*
|
||||
* Examples: >=1.0.36, 1.0.37, APP_VERSION
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getCompatibleVersion()
|
||||
{
|
||||
return APP_VERSION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Kanboard\Core\Base as BaseCore;
|
||||
|
||||
/**
|
||||
* Class Directory
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Directory extends BaseCore
|
||||
{
|
||||
/**
|
||||
* Get all plugins available
|
||||
*
|
||||
* @access public
|
||||
* @param string $url
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailablePlugins($url = PLUGIN_API_URL)
|
||||
{
|
||||
$plugins = $this->httpClient->getJson($url);
|
||||
$plugins = array_filter($plugins, array($this, 'isCompatible'));
|
||||
$plugins = array_filter($plugins, array($this, 'isInstallable'));
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter plugins
|
||||
*
|
||||
* @param array $plugin
|
||||
* @param string $appVersion
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompatible(array $plugin, $appVersion = APP_VERSION)
|
||||
{
|
||||
return Version::isCompatible($plugin['compatible_version'], $appVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter plugins
|
||||
*
|
||||
* @param array $plugin
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstallable(array $plugin)
|
||||
{
|
||||
return $plugin['remote_install'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
/**
|
||||
* Plugin Hooks Handler
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Hook
|
||||
{
|
||||
/**
|
||||
* List of hooks
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $hooks = array();
|
||||
|
||||
/**
|
||||
* Bind something on a hook
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function on($hook, $value)
|
||||
{
|
||||
if (! isset($this->hooks[$hook])) {
|
||||
$this->hooks[$hook] = array();
|
||||
}
|
||||
|
||||
$this->hooks[$hook][] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bindings for a hook
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @return array
|
||||
*/
|
||||
public function getListeners($hook)
|
||||
{
|
||||
return isset($this->hooks[$hook]) ? $this->hooks[$hook] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the hook is used
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($hook)
|
||||
{
|
||||
return isset($this->hooks[$hook]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge listener results with input array
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param array $values
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function merge($hook, array &$values, array $params = array())
|
||||
{
|
||||
foreach ($this->getListeners($hook) as $listener) {
|
||||
$result = call_user_func_array($listener, $params);
|
||||
|
||||
if (is_array($result) && ! empty($result)) {
|
||||
$values = array_merge($values, $result);
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute only first listener
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function first($hook, array $params = array())
|
||||
{
|
||||
foreach ($this->getListeners($hook) as $listener) {
|
||||
return call_user_func_array($listener, $params);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook with reference
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param mixed $param
|
||||
* @return mixed
|
||||
*/
|
||||
public function reference($hook, &$param)
|
||||
{
|
||||
foreach ($this->getListeners($hook) as $listener) {
|
||||
$listener($param);
|
||||
}
|
||||
|
||||
return $param;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use ZipArchive;
|
||||
use Kanboard\Core\Tool;
|
||||
|
||||
/**
|
||||
* Class Installer
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Installer extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Return true if Kanboard is configured to install plugins
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public static function isConfigured()
|
||||
{
|
||||
return PLUGIN_INSTALLER && is_writable(PLUGINS_DIR) && extension_loaded('zip');
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $archiveUrl
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function install($archiveUrl)
|
||||
{
|
||||
$zip = $this->downloadPluginArchive($archiveUrl);
|
||||
|
||||
if (! $zip->extractTo(PLUGINS_DIR)) {
|
||||
$this->cleanupArchive($zip);
|
||||
throw new PluginInstallerException(t('Unable to extract plugin archive.'));
|
||||
}
|
||||
|
||||
$this->cleanupArchive($zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginId
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function uninstall($pluginId)
|
||||
{
|
||||
$pluginFolder = PLUGINS_DIR.DIRECTORY_SEPARATOR.basename($pluginId);
|
||||
|
||||
if (! file_exists($pluginFolder)) {
|
||||
throw new PluginInstallerException(t('Plugin not found.'));
|
||||
}
|
||||
|
||||
if (! is_writable($pluginFolder)) {
|
||||
throw new PluginInstallerException(e('You don\'t have the permission to remove this plugin.'));
|
||||
}
|
||||
|
||||
Tool::removeAllFiles($pluginFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $archiveUrl
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
public function update($archiveUrl)
|
||||
{
|
||||
$zip = $this->downloadPluginArchive($archiveUrl);
|
||||
|
||||
$firstEntry = $zip->statIndex(0);
|
||||
$this->uninstall($firstEntry['name']);
|
||||
|
||||
if (! $zip->extractTo(PLUGINS_DIR)) {
|
||||
$this->cleanupArchive($zip);
|
||||
throw new PluginInstallerException(t('Unable to extract plugin archive.'));
|
||||
}
|
||||
|
||||
$this->cleanupArchive($zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download archive from URL
|
||||
*
|
||||
* @access protected
|
||||
* @param string $archiveUrl
|
||||
* @return ZipArchive
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
protected function downloadPluginArchive($archiveUrl)
|
||||
{
|
||||
if (!preg_match('/^https?:\/\//', $archiveUrl) || !filter_var($archiveUrl, FILTER_VALIDATE_URL)) {
|
||||
throw new PluginInstallerException(t('This URL is invalid'));
|
||||
}
|
||||
|
||||
$archiveData = $this->httpClient->get($archiveUrl);
|
||||
$archiveFile = tempnam(ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(), 'kb_plugin');
|
||||
|
||||
if (empty($archiveData)) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to download plugin archive.'));
|
||||
}
|
||||
|
||||
if (file_put_contents($archiveFile, $archiveData) === false) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to write temporary file for plugin.'));
|
||||
}
|
||||
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($archiveFile) !== true) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('Unable to open plugin archive.'));
|
||||
}
|
||||
|
||||
if ($zip->numFiles === 0) {
|
||||
unlink($archiveFile);
|
||||
throw new PluginInstallerException(t('There is no file in the plugin archive.'));
|
||||
}
|
||||
|
||||
return $zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove archive file
|
||||
*
|
||||
* @access protected
|
||||
* @param ZipArchive $zip
|
||||
*/
|
||||
protected function cleanupArchive(ZipArchive $zip)
|
||||
{
|
||||
$filename = $zip->filename;
|
||||
$zip->close();
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use Kanboard\Core\Tool;
|
||||
|
||||
/**
|
||||
* Plugin Loader
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Loader extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Plugin instances
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $plugins = array();
|
||||
protected $incompatiblePlugins = array();
|
||||
|
||||
/**
|
||||
* Get list of loaded plugins
|
||||
*
|
||||
* @access public
|
||||
* @return Base[]
|
||||
*/
|
||||
public function getPlugins()
|
||||
{
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of not compatible plugins
|
||||
*
|
||||
* @access public
|
||||
* @return Base[]
|
||||
*/
|
||||
public function getIncompatiblePlugins()
|
||||
{
|
||||
return $this->incompatiblePlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan plugin folder and load plugins
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function scan()
|
||||
{
|
||||
if (file_exists(PLUGINS_DIR)) {
|
||||
$loader = new ClassLoader();
|
||||
$loader->addPsr4('Kanboard\Plugin\\', PLUGINS_DIR);
|
||||
$loader->register();
|
||||
|
||||
$dir = new DirectoryIterator(PLUGINS_DIR);
|
||||
|
||||
foreach ($dir as $fileInfo) {
|
||||
if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
|
||||
$pluginName = $fileInfo->getFilename();
|
||||
$this->initializePlugin($pluginName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin schema
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
*/
|
||||
public function loadSchema($pluginName)
|
||||
{
|
||||
if (SchemaHandler::hasSchema($pluginName)) {
|
||||
$schemaHandler = new SchemaHandler($this->container);
|
||||
$schemaHandler->loadSchema($pluginName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin
|
||||
*
|
||||
* @access public
|
||||
* @throws LogicException
|
||||
* @param string $pluginName
|
||||
* @return Base
|
||||
*/
|
||||
public function loadPlugin($pluginName)
|
||||
{
|
||||
$className = '\Kanboard\Plugin\\'.$pluginName.'\\Plugin';
|
||||
|
||||
if (! class_exists($className)) {
|
||||
throw new LogicException('Unable to load this plugin class: '.$className);
|
||||
}
|
||||
|
||||
return new $className($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize plugin
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
*/
|
||||
public function initializePlugin($pluginName)
|
||||
{
|
||||
try {
|
||||
$plugin = $this->loadPlugin($pluginName);
|
||||
|
||||
if (Version::isCompatible($plugin->getCompatibleVersion(), APP_VERSION)) {
|
||||
$this->loadSchema($pluginName);
|
||||
|
||||
if (method_exists($plugin, 'onStartup')) {
|
||||
$this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
|
||||
}
|
||||
|
||||
Tool::buildDIC($this->container, $plugin->getClasses());
|
||||
Tool::buildDICHelpers($this->container, $plugin->getHelpers());
|
||||
|
||||
$plugin->initialize();
|
||||
$this->plugins[$pluginName] = $plugin;
|
||||
} else {
|
||||
$this->incompatiblePlugins[$pluginName] = $plugin;
|
||||
$this->logger->error($pluginName.' is not compatible with this version');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->logger->critical($pluginName.': '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class PluginException
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
/**
|
||||
* Class PluginInstallerException
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginInstallerException extends PluginException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use PDOException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class SchemaHandler
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class SchemaHandler extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Schema version table for plugins
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE_SCHEMA = 'plugin_schema_versions';
|
||||
|
||||
/**
|
||||
* Get schema filename
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
* @return string
|
||||
*/
|
||||
public static function getSchemaFilename($pluginName)
|
||||
{
|
||||
return PLUGINS_DIR.'/'.$pluginName.'/Schema/'.ucfirst(DB_DRIVER).'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the plugin has schema
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
* @return boolean
|
||||
*/
|
||||
public static function hasSchema($pluginName)
|
||||
{
|
||||
return file_exists(self::getSchemaFilename($pluginName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin schema
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
*/
|
||||
public function loadSchema($pluginName)
|
||||
{
|
||||
require_once self::getSchemaFilename($pluginName);
|
||||
$this->migrateSchema($pluginName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute plugin schema migrations
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
*/
|
||||
public function migrateSchema($pluginName)
|
||||
{
|
||||
$lastVersion = constant('\Kanboard\Plugin\\'.$pluginName.'\Schema\VERSION');
|
||||
$currentVersion = $this->getSchemaVersion($pluginName);
|
||||
|
||||
try {
|
||||
$this->db->startTransaction();
|
||||
$this->db->getDriver()->disableForeignKeys();
|
||||
|
||||
for ($i = $currentVersion + 1; $i <= $lastVersion; $i++) {
|
||||
$functionName = '\Kanboard\Plugin\\'.$pluginName.'\Schema\version_'.$i;
|
||||
|
||||
if (function_exists($functionName)) {
|
||||
call_user_func($functionName, $this->db->getConnection());
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->getDriver()->enableForeignKeys();
|
||||
$this->db->closeTransaction();
|
||||
$this->setSchemaVersion($pluginName, $i - 1);
|
||||
} catch (PDOException $e) {
|
||||
$this->db->cancelTransaction();
|
||||
$this->db->getDriver()->enableForeignKeys();
|
||||
throw new RuntimeException('Unable to migrate schema for the plugin: '.$pluginName.' => '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current plugin schema version
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
* @return integer
|
||||
*/
|
||||
public function getSchemaVersion($plugin)
|
||||
{
|
||||
return (int) $this->db->table(self::TABLE_SCHEMA)->eq('plugin', strtolower($plugin))->findOneColumn('version');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save last plugin schema version
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
* @param integer $version
|
||||
* @return boolean
|
||||
*/
|
||||
public function setSchemaVersion($plugin, $version)
|
||||
{
|
||||
$dictionary = array(
|
||||
strtolower($plugin) => $version
|
||||
);
|
||||
|
||||
return $this->db->getDriver()->upsert(self::TABLE_SCHEMA, 'plugin', 'version', $dictionary);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
/**
|
||||
* Class Version
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* Check plugin version compatibility with application version
|
||||
*
|
||||
* @param string $pluginCompatibleVersion
|
||||
* @param string $appVersion
|
||||
* @return bool
|
||||
*/
|
||||
public static function isCompatible($pluginCompatibleVersion, $appVersion = APP_VERSION)
|
||||
{
|
||||
if (strpos($appVersion, 'master') !== false || strpos($appVersion, 'main') !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$appVersion = str_replace('v', '', $appVersion);
|
||||
$pluginCompatibleVersion = str_replace('v', '', $pluginCompatibleVersion);
|
||||
|
||||
foreach (array('>=', '>', '<=', '<') as $operator) {
|
||||
if (strpos($pluginCompatibleVersion, $operator) === 0) {
|
||||
$pluginVersion = substr($pluginCompatibleVersion, strlen($operator));
|
||||
return version_compare($appVersion, $pluginVersion, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
return $pluginCompatibleVersion === $appVersion;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user