first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
+258
View File
@@ -0,0 +1,258 @@
<?php
/**
* @defgroup site Site
* Site-related concerns such as the Site object and version management.
*/
/**
* @file classes/site/Site.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Site
*
* @ingroup site
*
* @see SiteDAO
*
* @brief Describes system-wide site properties.
*/
namespace PKP\site;
use PKP\facades\Locale;
use PKP\i18n\LocaleMetadata;
class Site extends \PKP\core\DataObject
{
/**
* Return associative array of all locales supported by the site.
* These locales are used to provide a language toggle on the main site pages.
*
* @param int $langLocaleStatus The const value of one of LocaleMetadata:LANGUAGE_LOCALE_*
*/
public function getSupportedLocaleNames(int $langLocaleStatus = LocaleMetadata::LANGUAGE_LOCALE_WITHOUT): array
{
static $supportedLocales;
if (isset($supportedLocales)) {
return $supportedLocales;
}
$supportedLocales = Locale::getFormattedDisplayNames($this->getSupportedLocales(), null, $langLocaleStatus);
asort($supportedLocales);
return $supportedLocales;
}
/**
* Return associative array of all locales currently by the site.
* These locales are used to provide a language toggle on the main site pages.
*
* @param int $langLocaleStatus The const value of one of LocaleMetadata:LANGUAGE_LOCALE_*
*/
public function getInstalledLocaleNames(int $langLocaleStatus = LocaleMetadata::LANGUAGE_LOCALE_WITH): array
{
static $installedLocales;
if (isset($installedLocales)) {
return $installedLocales;
}
$installedLocales = Locale::getFormattedDisplayNames($this->getInstalledLocales(), null, $langLocaleStatus);
asort($installedLocales);
return $installedLocales;
}
//
// Get/set methods
//
/**
* Get site title.
*
* @param string $locale Locale code to return, if desired.
*/
public function getTitle($locale = null)
{
return $this->getData('title', $locale);
}
/**
* Get localized site title.
*/
public function getLocalizedTitle()
{
return $this->getLocalizedData('title');
}
/**
* Get "localized" site page title (if applicable).
*
* @return array|string
*
* @deprecated 3.3.0
*/
public function getLocalizedPageHeaderTitle()
{
if ($this->getLocalizedData('pageHeaderTitleImage')) {
return $this->getLocalizedData('pageHeaderTitleImage');
}
if ($this->getData('pageHeaderTitleImage', Locale::getPrimaryLocale())) {
return $this->getData('pageHeaderTitleImage', Locale::getPrimaryLocale());
}
if ($this->getLocalizedData('title')) {
return $this->getLocalizedData('title');
}
if ($this->getData('title', Locale::getPrimaryLocale())) {
return $this->getData('title', Locale::getPrimaryLocale());
}
return '';
}
/**
* Get redirect
*
* @return int
*/
public function getRedirect()
{
return $this->getData('redirect');
}
/**
* Set redirect
*
* @param int $redirect
*/
public function setRedirect($redirect)
{
$this->setData('redirect', (int)$redirect);
}
/**
* Get localized site about statement.
*/
public function getLocalizedAbout()
{
return $this->getLocalizedData('about');
}
/**
* Get localized site contact name.
*/
public function getLocalizedContactName()
{
return $this->getLocalizedData('contactName');
}
/**
* Get localized site contact email.
*/
public function getLocalizedContactEmail()
{
return $this->getLocalizedData('contactEmail');
}
/**
* Get minimum password length.
*
* @return int
*/
public function getMinPasswordLength()
{
return $this->getData('minPasswordLength');
}
/**
* Set minimum password length.
*
* @param int $minPasswordLength
*/
public function setMinPasswordLength($minPasswordLength)
{
$this->setData('minPasswordLength', $minPasswordLength);
}
/**
* Get primary locale.
*
* @return string
*/
public function getPrimaryLocale()
{
return $this->getData('primaryLocale');
}
/**
* Set primary locale.
*
* @param string $primaryLocale
*/
public function setPrimaryLocale($primaryLocale)
{
$this->setData('primaryLocale', $primaryLocale);
}
/**
* Get installed locales.
*
* @return array
*/
public function getInstalledLocales()
{
return $this->getData('installedLocales') ?? [];
}
/**
* Set installed locales.
*
* @param array $installedLocales
*/
public function setInstalledLocales($installedLocales)
{
$this->setData('installedLocales', $installedLocales);
}
/**
* Get array of all supported locales (for static text).
*
* @return array
*/
public function getSupportedLocales()
{
return $this->getData('supportedLocales') ?? [];
}
/**
* Set array of all supported locales (for static text).
*
* @param array $supportedLocales
*/
public function setSupportedLocales($supportedLocales)
{
$this->setData('supportedLocales', $supportedLocales);
}
/**
* Get the unique site ID.
*/
public function getUniqueSiteID(): ?string
{
return $this->getData('uniqueSiteId');
}
/**
* Set the unique site ID.
*/
public function setUniqueSiteID(string $uniqueSiteId): void
{
$this->setData('uniqueSiteId', $uniqueSiteId);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\site\Site', '\Site');
}
+199
View File
@@ -0,0 +1,199 @@
<?php
/**
* @file classes/site/SiteDAO.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class SiteDAO
*
* @ingroup site
*
* @see Site
*
* @brief Operations for retrieving and modifying the Site object.
*/
namespace PKP\site;
use APP\core\Services;
use Illuminate\Support\Facades\DB;
use PKP\services\PKPSchemaService;
class SiteDAO extends \PKP\db\DAO
{
/** @var array Maps schema properties for the primary table to their column names */
public $primaryTableColumns = [
'redirect' => 'redirect',
'primaryLocale' => 'primary_locale',
'minPasswordLength' => 'min_password_length',
'installedLocales' => 'installed_locales',
'supportedLocales' => 'supported_locales',
];
/**
* Retrieve site information.
*
* @return ?Site
*/
public function getSite()
{
$result = $this->retrieve(
'SELECT * FROM site'
);
if ($row = (array) $result->current()) {
return $this->_fromRow($row);
}
return null;
}
/**
* Instantiate and return a new DataObject.
*
* @return Site
*/
public function newDataObject()
{
return new Site();
}
/**
* @copydoc SchemaDAO::_fromRow()
*/
public function _fromRow($primaryRow, $callHook = true)
{
$schemaService = Services::get('schema');
$schema = $schemaService->get(PKPSchemaService::SCHEMA_SITE);
$site = $this->newDataObject();
foreach ($this->primaryTableColumns as $propName => $column) {
if (isset($primaryRow[$column])) {
// Backwards-compatible handling of the installedLocales and
// supportedLocales data. Before 3.2, these were stored as colon-separated
// strings (eg - en:fr_CA:ar). In 3.2, these are migrated to
// serialized arrays defined by the site.json schema. However, some of the
// older upgrade scripts use site data before the migration is performed,
// so SiteDAO must be able to return the correct array before the data
// is migrated. This code checks the format and converts the old data so
// that calls to $site->getInstalledLocales() and
// $site->getSupportedLocales() return an appropriate array.
if (in_array($column, ['installed_locales', 'supported_locales']) &&
!is_null($primaryRow[$column]) && strpos($primaryRow[$column], '{') === false && is_null(json_decode($primaryRow[$column]))) {
$site->setData($propName, explode(':', $primaryRow[$column]));
} else {
$site->setData(
$propName,
$this->convertFromDb($primaryRow[$column], $schema->properties->{$propName}->type)
);
}
}
}
$result = $this->retrieve('SELECT * FROM site_settings');
foreach ($result as $settingRow) {
$settingRow = (array) $settingRow;
if (!empty($schema->properties->{$settingRow['setting_name']})) {
$site->setData(
$settingRow['setting_name'],
$this->convertFromDB(
$settingRow['setting_value'],
$schema->properties->{$settingRow['setting_name']}->type
),
empty($settingRow['locale']) ? null : $settingRow['locale']
);
}
}
return $site;
}
/**
* Insert site information.
*
* @param Site $site
*/
public function insertSite($site)
{
$type = 'array';
$returner = $this->update(
'INSERT INTO site
(redirect, min_password_length, primary_locale, installed_locales, supported_locales)
VALUES
(?, ?, ?, ?, ?)',
[
$site->getRedirect(),
(int) $site->getMinPasswordLength(),
$site->getPrimaryLocale(),
$this->convertToDB($site->getInstalledLocales(), $type),
$this->convertToDB($site->getInstalledLocales(), $type),
]
);
return $returner;
}
/**
* @copydoc SchemaDAO::updateObject
*/
public function updateObject($site)
{
$schemaService = Services::get('schema');
$schema = $schemaService->get(PKPSchemaService::SCHEMA_SITE);
$sanitizedProps = $schemaService->sanitize(PKPSchemaService::SCHEMA_SITE, $site->_data);
$set = $params = [];
foreach ($this->primaryTableColumns as $propName => $column) {
$set[] = $column . ' = ?';
$params[] = $this->convertToDb($sanitizedProps[$propName], $schema->properties->{$propName}->type);
}
$this->update('UPDATE site SET ' . join(',', $set), $params);
$deleteSettings = [];
foreach ($schema->properties as $propName => $propSchema) {
if (array_key_exists($propName, $this->primaryTableColumns)) {
continue;
} elseif (!isset($sanitizedProps[$propName])) {
$deleteSettings[] = $propName;
continue;
}
if (!empty($propSchema->multilingual)) {
foreach ($sanitizedProps[$propName] as $localeKey => $localeValue) {
// Delete rows with a null value
if (is_null($localeValue)) {
$this->update('DELETE FROM site_settings WHERE setting_name = ? AND locale = ?', [
$propName,
$localeKey,
]);
} else {
DB::table('site_settings')->updateOrInsert(
['locale' => $localeKey, 'setting_name' => $propName],
['setting_value' => $this->convertToDB($localeValue, $schema->properties->{$propName}->type)]
);
}
}
} else {
DB::table('site_settings')->updateOrInsert(
['locale' => '', 'setting_name' => $propName],
['setting_value' => $this->convertToDB($sanitizedProps[$propName], $schema->properties->{$propName}->type)]
);
}
}
if (count($deleteSettings)) {
$deleteSettingNames = join(',', array_map(function ($settingName) {
return "'{$settingName}'";
}, $deleteSettings));
$this->update("DELETE FROM site_settings WHERE setting_name in ({$deleteSettingNames})");
}
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\site\SiteDAO', '\SiteDAO');
}
+390
View File
@@ -0,0 +1,390 @@
<?php
/**
* @file classes/site/Version.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Version
*
* @ingroup site
*
* @see VersionDAO
*
* @brief Describes system version history.
*/
namespace PKP\site;
use APP\core\Application;
use Composer\Semver\Semver;
use PKP\core\Core;
class Version extends \PKP\core\DataObject
{
/**
* Constructor.
*/
public function __construct(
$major,
$minor,
$revision,
$build,
$dateInstalled,
$current,
$productType,
$product,
$productClassName,
$lazyLoad,
$sitewide
) {
parent::__construct();
// Initialize object
$this->setMajor($major);
$this->setMinor($minor);
$this->setRevision($revision);
$this->setBuild($build);
$this->setDateInstalled($dateInstalled);
$this->setCurrent($current);
$this->setProductType($productType);
$this->setProduct($product);
$this->setProductClassName($productClassName);
$this->setLazyLoad($lazyLoad);
$this->setSitewide($sitewide);
}
/**
* Compare this version with another version.
* Returns:
* < 0 if this version is lower
* 0 if they are equal
* > 0 if this version is higher
*
* @param string|Version $version the version to compare against
*
* @return int
*/
public function compare($version)
{
if (is_object($version)) {
return $this->compare($version->getVersionString());
}
return version_compare($this->getVersionString(), $version);
}
/**
* Static method to return a new version from a version string of the form "W.X.Y.Z".
*
* @param string $versionString
* @param string $productType
* @param string $product
* @param string $productClass
* @param int $lazyLoad
* @param int $sitewide
*
* @return Version
*/
public static function fromString($versionString, $productType = null, $product = null, $productClass = '', $lazyLoad = 0, $sitewide = 1)
{
$versionArray = explode('.', $versionString);
if (!$product && !$productType) {
$application = Application::get();
$product = $application->getName();
$productType = 'core';
}
$version = new Version(
(isset($versionArray[0]) ? (int) $versionArray[0] : 0),
(isset($versionArray[1]) ? (int) $versionArray[1] : 0),
(isset($versionArray[2]) ? (int) $versionArray[2] : 0),
(isset($versionArray[3]) ? (int) $versionArray[3] : 0),
Core::getCurrentDate(),
1,
$productType,
$product,
$productClass,
$lazyLoad,
$sitewide
);
return $version;
}
//
// Get/set methods
//
/**
* Get major version.
*
* @return int
*/
public function getMajor()
{
return $this->getData('major');
}
/**
* Set major version.
*
* @param int $major
*/
public function setMajor($major)
{
$this->setData('major', $major);
}
/**
* Get minor version.
*
* @return int
*/
public function getMinor()
{
return $this->getData('minor');
}
/**
* Set minor version.
*
* @param int $minor
*/
public function setMinor($minor)
{
$this->setData('minor', $minor);
}
/**
* Get revision version.
*
* @return int
*/
public function getRevision()
{
return $this->getData('revision');
}
/**
* Set revision version.
*
* @param int $revision
*/
public function setRevision($revision)
{
$this->setData('revision', $revision);
}
/**
* Get build version.
*
* @return int
*/
public function getBuild()
{
return $this->getData('build');
}
/**
* Set build version.
*
* @param int $build
*/
public function setBuild($build)
{
$this->setData('build', $build);
}
/**
* Get date installed.
*
* @return string
*/
public function getDateInstalled()
{
return $this->getData('dateInstalled');
}
/**
* Set date installed.
*
* @param string $dateInstalled
*/
public function setDateInstalled($dateInstalled)
{
$this->setData('dateInstalled', $dateInstalled);
}
/**
* Check if current version.
*
* @return int
*/
public function getCurrent()
{
return $this->getData('current');
}
/**
* Set if current version.
*
* @param int $current
*/
public function setCurrent($current)
{
$this->setData('current', $current);
}
/**
* Get product type.
*
* @return string
*/
public function getProductType()
{
return $this->getData('productType');
}
/**
* Set product type.
*
* @param string $productType
*/
public function setProductType($productType)
{
$this->setData('productType', $productType);
}
/**
* Get product name.
*
* @return string
*/
public function getProduct()
{
return $this->getData('product');
}
/**
* Set product name.
*
* @param string $product
*/
public function setProduct($product)
{
$this->setData('product', $product);
}
/**
* Get the product's class name
*
* @return string
*/
public function getProductClassName()
{
return $this->getData('productClassName');
}
/**
* Set the product's class name
*
* @param string $productClassName
*/
public function setProductClassName($productClassName)
{
$this->setData('productClassName', $productClassName);
}
/**
* Get the lazy load flag for this product
*
* @return bool
*/
public function getLazyLoad()
{
return $this->getData('lazyLoad');
}
/**
* Set the lazy load flag for this product
*
* @param bool $lazyLoad
*/
public function setLazyLoad($lazyLoad)
{
$this->setData('lazyLoad', $lazyLoad);
}
/**
* Get the sitewide flag for this product
*
* @return bool
*/
public function getSitewide()
{
return $this->getData('sitewide');
}
/**
* Set the sitewide flag for this product
*
* @param bool $sitewide
*/
public function setSitewide($sitewide)
{
$this->setData('sitewide', $sitewide);
}
/**
* Return complete version string.
*
* @param bool True (default) iff a numeric (comparable) version is to be returned.
*
* @return string
*/
public function getVersionString($numeric = true)
{
$numericVersion = sprintf('%d.%d.%d.%d', $this->getMajor(), $this->getMinor(), $this->getRevision(), $this->getBuild());
if (!$numeric && $this->getProduct() == 'omp' && preg_match('/^0\.9\.9\./', $numericVersion)) {
return ('1.0 Beta');
}
if (!$numeric && $this->getProduct() == 'ojs2' && preg_match('/^2\.9\.0\./', $numericVersion)) {
return ('3.0 Alpha 1');
}
if (!$numeric && $this->getProduct() == 'ojs2' && preg_match('/^2\.9\.9\.0/', $numericVersion)) {
return ('3.0 Beta 1');
}
if (!$numeric && $this->getProduct() == 'ops' && preg_match('/^3\.2\.0\.0/', $numericVersion)) {
return ('3.2.0 Beta');
}
return $numericVersion;
}
/**
* Checks if the Version is compatible with the given string of constraints for the version,
* formatted per composer/semver specifications;
* c.f. https://getcomposer.org/doc/articles/versions.md#writing-version-constraints
* Returns:
* true iff the version given is compatible with this version
* false iff the version given is incompatible with this version
*
* @param string $constraints the string of constraints for the version to be checked against
*
* @return boolean
*/
public function isCompatible($constraints)
{
$semver = new semver();
$version = $this->getVersionString();
return $semver->satisfies($version, $constraints);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\site\Version', '\Version');
}
+201
View File
@@ -0,0 +1,201 @@
<?php
/**
* @file classes/site/VersionCheck.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class VersionCheck
*
* @ingroup site
*
* @see Version
*
* @brief Provides methods to check for the latest version of the application.
*/
namespace PKP\site;
use APP\core\Application;
use DateInterval;
use Exception;
use Illuminate\Support\Facades\Cache;
use PKP\config\Config;
use PKP\core\PKPString;
use PKP\db\DAORegistry;
use PKP\file\FileManager;
use SimpleXMLElement;
class VersionCheck
{
/** Max lifetime for the version cache */
protected const MAX_CACHE_LIFETIME = '1 year';
public const VERSION_CODE_PATH = 'dbscripts/xml/version.xml';
/**
* Return information about the latest available version.
*
* @return array
*/
public static function getLatestVersion()
{
$application = Application::get();
$includeId = Application::isInstalled() &&
!Application::isUpgrading() &&
Config::getVar('general', 'enable_beacon', true);
if ($includeId) {
$uniqueSiteId = Application::get()->getUUID();
} else {
$uniqueSiteId = null;
}
$request = $application->getRequest();
return self::parseVersionXML(
$application->getVersionDescriptorUrl() .
($includeId ? '?id=' . urlencode($uniqueSiteId) .
'&oai=' . urlencode($request->url('index', 'oai'))
: '')
);
}
/**
* Return the currently installed database version.
*
* @return Version
*/
public static function getCurrentDBVersion()
{
$versionDao = DAORegistry::getDAO('VersionDAO'); /** @var VersionDAO $versionDao */
return $versionDao->getCurrentVersion();
}
/**
* Return the current code version.
*/
public static function getCurrentCodeVersion(): ?Version
{
return self::parseVersionXML(self::VERSION_CODE_PATH)['version'] ?? null;
}
/**
* Parse information from a version XML file.
*/
public static function parseVersionXML(string $path): ?array
{
$isVirtual = FileManager::isVirtualPath($path);
$key = __METHOD__ . static::MAX_CACHE_LIFETIME . $path . ($isVirtual ? '' : filemtime($path));
$expiration = $isVirtual ? 0 : DateInterval::createFromDateString(static::MAX_CACHE_LIFETIME);
$version = Cache::remember($key, $expiration, function () use ($path) {
$xml = new SimpleXMLElement(FileManager::getStream($path));
$version = [];
foreach (['application', 'class', 'type', 'release', 'tag', 'date', 'info', 'package', 'lazy-load', 'sitewide'] as $name) {
if (isset($xml->$name)) {
$version[$name] = (string) $xml->$name;
}
}
$version['sitewide'] = (int) ($version['sitewide'] ?? 0);
$version['lazy-load'] = (int) ($version['lazy-load'] ?? 0);
if (isset($xml->patch)) {
$version['patch'] = [];
foreach ($xml->patch as $patch) {
$version['patch'][$patch['from']] = (string) $patch;
}
}
return $version;
});
// Built outside of the cache section to avoid serializing the Version (which would need a __set_state implementation)
if (isset($version['release']) && isset($version['application'])) {
$version['version'] = Version::fromString(
$version['release'] ?? '',
$version['type'] ?? '',
$version['application'] ?? '',
$version['class'] ?? '',
$version['lazy-load'],
$version['sitewide']
);
}
return $version;
}
/**
* Find the applicable patch for the current code version (if available).
*
* @param array $versionInfo as returned by parseVersionXML()
* @param Version $codeVersion as returned by getCurrentCodeVersion()
*
* @return string
*/
public static function getPatch($versionInfo, $codeVersion = null)
{
if (!isset($codeVersion)) {
$codeVersion = self::getCurrentCodeVersion();
}
if (isset($versionInfo['patch'][$codeVersion->getVersionString()])) {
return $versionInfo['patch'][$codeVersion->getVersionString()];
}
return null;
}
/**
* Checks whether the given version file exists and whether it
* contains valid data. Returns a Version object if everything
* is ok, otherwise throws an Exception.
*
* @param string $versionFile
*
* @return Version
*/
public static function getValidPluginVersionInfo($versionFile)
{
$fileManager = new FileManager();
if ($fileManager->fileExists($versionFile)) {
$versionInfo = self::parseVersionXML($versionFile);
} else {
throw new Exception(__('manager.plugins.versionFileNotFound'));
}
// Validate plugin name and type to avoid abuse
$productType = explode('.', $versionInfo['type']);
if (count($productType) != 2 || $productType[0] != 'plugins') {
throw new Exception(__('manager.plugins.versionFileInvalid'));
}
$pluginVersion = $versionInfo['version'];
$namesToValidate = [$pluginVersion->getProduct(), $productType[1]];
foreach ($namesToValidate as $nameToValidate) {
if (!PKPString::regexp_match('/[a-z][a-zA-Z0-9]+/', $nameToValidate)) {
throw new Exception(__('manager.plugins.versionFileInvalid'));
}
}
return $pluginVersion;
}
/**
* Checks the application's version against the latest version
* on the PKP servers.
*
* @return string|false Version description or false if no newer version
*/
public static function checkIfNewVersionExists()
{
$versionInfo = self::getLatestVersion();
$latestVersion = $versionInfo['release'];
$currentVersion = self::getCurrentDBVersion();
if ($currentVersion->compare($latestVersion) < 0) {
return $latestVersion;
}
return false;
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\site\VersionCheck', '\VersionCheck');
define('VERSION_CODE_PATH', VersionCheck::VERSION_CODE_PATH);
}
+242
View File
@@ -0,0 +1,242 @@
<?php
/**
* @file classes/site/VersionDAO.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class VersionDAO
*
* @ingroup site
*
* @see Version
*
* @brief Operations for retrieving and modifying Version objects.
*/
namespace PKP\site;
use APP\core\Application;
use Illuminate\Support\Facades\DB;
use PKP\core\Core;
use PKP\plugins\Hook;
class VersionDAO extends \PKP\db\DAO
{
/**
* Retrieve the current version.
*/
public function getCurrentVersion(?string $productType = null, ?string $product = null): ?Version
{
if (!$productType || !$product) {
$application = Application::get();
$productType = 'core';
$product = $application->getName();
}
$result = $this->retrieve(
'SELECT * FROM versions WHERE current = 1 AND product_type = ? AND product = ?',
[$productType, $product]
);
$row = (array) $result->current();
return $row ? $this->_returnVersionFromRow($row) : null;
}
/**
* Retrieve the complete version history, ordered by date (most recent first).
*
* @return Version[] Versions
*/
public function getVersionHistory(?string $productType = null, ?string $product = null): array
{
$versions = [];
if (!$productType || !$product) {
$application = Application::get();
$productType = 'core';
$product = $application->getName();
}
$result = $this->retrieve(
'SELECT * FROM versions WHERE product_type = ? AND product = ? ORDER BY date_installed DESC',
[$productType, $product]
);
foreach ($result as $row) {
$versions[] = $this->_returnVersionFromRow((array) $row);
}
return $versions;
}
/**
* Internal function to return a Version object from a row.
*/
public function _returnVersionFromRow($row): Version
{
$version = new Version(
$row['major'],
$row['minor'],
$row['revision'],
$row['build'],
$this->datetimeFromDB($row['date_installed']),
$row['current'],
($row['product_type'] ?? null),
($row['product'] ?? null),
($row['product_class_name'] ?? ''),
($row['lazy_load'] ?? 0),
($row['sitewide'] ?? 0)
);
Hook::call('VersionDAO::_returnVersionFromRow', [&$version, &$row]);
return $version;
}
/**
* Insert a new version.
*/
public function insertVersion(Version $version, bool $isPlugin = false): int
{
$isNewVersion = true;
if ($version->getCurrent()) {
// Find out whether the last installed version is the same as the
// one to be inserted.
$versionHistory = $this->getVersionHistory($version->getProductType(), $version->getProduct());
$oldVersion = array_shift($versionHistory);
if ($oldVersion) {
if ($version->compare($oldVersion) == 0) {
// The old and the new current versions are the same so we need
// to update the existing version entry.
$isNewVersion = false;
} elseif ($version->compare($oldVersion) == 1) {
// Version to insert is newer than the existing version entry.
// We reset existing entry.
$this->update('UPDATE versions SET current = 0 WHERE current = 1 AND product = ?', [$version->getProduct()]);
} else {
// We do not support downgrades.
fatalError('You are trying to downgrade the product "' . $version->getProduct() . '" from version [' . $oldVersion->getVersionString(false) . '] to version [' . $version->getVersionString(false) . ']. Downgrades are not supported.');
}
}
}
if ($isNewVersion) {
// We only change the install date when we insert new
// version entries.
if ($version->getDateInstalled() == null) {
$version->setDateInstalled(Core::getCurrentDate());
}
// Insert new version entry
return $this->update(
sprintf(
'INSERT INTO versions
(major, minor, revision, build, date_installed, current, product_type, product, product_class_name, lazy_load, sitewide)
VALUES
(?, ?, ?, ?, %s, ?, ?, ?, ?, ?, ?)',
$this->datetimeToDB($version->getDateInstalled())
),
[
(int) $version->getMajor(),
(int) $version->getMinor(),
(int) $version->getRevision(),
(int) $version->getBuild(),
(int) $version->getCurrent(),
$version->getProductType(),
$version->getProduct(),
$version->getProductClassName(),
($version->getLazyLoad() ? 1 : 0),
($version->getSitewide() ? 1 : 0)
]
);
} else {
// Update existing version entry
return $this->update(
'UPDATE versions SET current = ?, product_class_name = ?, lazy_load = ?, sitewide = ?
WHERE product_type = ? AND product = ? AND major = ? AND minor = ? AND revision = ? AND build = ?',
[
(int) $version->getCurrent(),
$version->getProductClassName(),
($version->getLazyLoad() ? 1 : 0),
($version->getSitewide() ? 1 : 0),
$version->getProductType(),
$version->getProduct(),
(int) $version->getMajor(),
(int) $version->getMinor(),
(int) $version->getRevision(),
(int) $version->getBuild()
]
);
}
}
/**
* Retrieve all currently enabled products within the
* given context as a two dimensional array with the
* first key representing the product type, the second
* key the product name and the value the product version.
*/
public function getCurrentProducts(?int $contextId): array
{
$result = $this->retrieve(
'SELECT v.*
FROM versions v
LEFT JOIN plugin_settings ps
ON LOWER(v.product_class_name) = ps.plugin_name
AND ps.setting_name = \'enabled\'
' . ($contextId !== null ? ' AND (context_id = ? OR v.sitewide = 1) ' : '') . '
WHERE v.current = 1 AND (ps.setting_value = \'1\' OR v.lazy_load <> 1)',
$contextId !== null ? [$contextId] : [],
false
);
$productArray = [];
foreach ($result as $row) {
$productArray[$row->product_type][$row->product] = $this->_returnVersionFromRow((array) $row);
}
return $productArray;
}
/**
* Disable a product by setting its 'current' column to 0
*
* @param string $productType
* @param string $product
*/
public function disableVersion($productType, $product): void
{
$this->update(
'UPDATE versions SET current = 0 WHERE current = 1 AND product_type = ? AND product = ?',
[$productType, $product]
);
}
/**
* Get installation date of the given version or the first version used after that
*
* @param int $version Version number, without '.' as separator, i.e. in the form major*1000+minor*100+revision*10+build
*/
public function getInstallationDate(int $version): string
{
$product = Application::get()->getName();
$dateInstalledArray = DB::select(
"SELECT date_installed
FROM versions
WHERE major*1000+minor*100+revision*10+build IN
(SELECT MIN(major*1000+minor*100+revision*10+build)
FROM versions vt
WHERE vt.product_type = 'core' AND vt.product = ? AND vt.major*1000+vt.minor*100+vt.revision*10+vt.build >= ?)
AND product_type = 'core' AND product = ?
",
[$product, $version, $product]
);
return current($dateInstalledArray)->date_installed;
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\site\VersionDAO', '\VersionDAO');
}