Commit 99038b21 authored by Benni Mack's avatar Benni Mack
Browse files

[TASK] Reduce usage to tx_ter_extensions

This patch changes
- the extensions.xml generator
- various logic regarding checks if a version exists
to not query the tx_ter_extensions database table anymore.

Now the only place where tx_ter_extensions is actually used
is the SOAP API Upload and the Migration to tx_terfe2_* db structure
which will be migrated in the next patch.
parent c6816027
Pipeline #9365 failed with stages
in 3 minutes and 23 seconds
......@@ -229,16 +229,20 @@ class ExtensionKey
throw new UnauthorizedException('Access denied.', ResultCodes::ERROR_DELETEEXTENSIONKEY_ACCESSDENIED);
}
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensions');
$items = $conn->select(['*'], 'tx_ter_extensions', ['extensionkey' => $this->extensionKey])->fetchAll();
if (!empty($items)) {
if ($this->hasUploadedVersions()) {
throw new VersionExistsException('Cannot delete an extension, versions still exist', ResultCodes::ERROR_DELETEEXTENSIONKEY_CANTDELETEBECAUSEVERSIONSEXIST);
}
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$conn->delete('tx_terfe2_domain_model_extension', ['ext_key' => $this->extensionKey]);
}
public function hasUploadedVersions(): bool
{
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensions');
$items = $conn->select(['*'], 'tx_ter_extensions', ['extensionkey' => $this->extensionKey])->fetchAll();
return !empty($items);
}
/**
* Check if a user with such a name exists, and return the username from the DB (= with proper lowercase etc)
* or null, if the user does not exist.
......
......@@ -19,7 +19,6 @@ use T3o\Ter\Api\ExtensionKey;
use T3o\Ter\Api\ExtensionVersion;
use T3o\TerFe2\Provider\FileProvider;
use T3o\TerFe2\Validation\Validator\ComposerNameValidator;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
......@@ -492,7 +491,10 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
if (!$this->userIsAllowedToUploadExtension($extensionKey)) {
$this->forwardWithError($this->translate('msg.createVersionUploadNotAllowed'), 'uploadVersion');
}
if (!$this->versionIsPossibleForExtension($extensionKey, $extensionInfo->version)) {
$extensionKeyObject = new ExtensionKey($extensionKey);
$extensionVersion = new ExtensionVersion($extensionKeyObject, $extensionInfo->version);
if ($extensionVersion->doesExtensionVersionExist()) {
$this->forwardWithError($this->translate('msg.createVersionVersionExists'), 'uploadVersion');
}
$extensionInfo->extensionKey = $extensionKey;
......@@ -502,8 +504,6 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
// This code will be reworked into a full-blown API
$uploader = new ApiUser($this->frontendUser['username']);
$uploader->authenticate();
$extensionKeyObject = new ExtensionKey($extensionKey);
$extensionVersion = new ExtensionVersion($extensionKeyObject, $extensionInfo->version);
$extensionVersion->upload($uploader, $extensionInfo, $files);
$this->redirect('index', 'Registerkey', null, ['uploaded' => true], $this->settings['pages']['manageKeysPID']);
} catch (\Exception $exception) {
......@@ -607,36 +607,6 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
return null;
}
/**
* Check if an version does not exist for extension
*
* There is no better (and faster) way to do this at the moment.
*
* @param string $extensionKey The extension key
* @param string $versionString The extension version
* @return bool TRUE if version already exists
*
* TODO: Discuss with Thomas, logic looks incorrect with naming and return value.
*/
protected function versionIsPossibleForExtension($extensionKey, $versionString)
{
if (empty($extensionKey) || empty($versionString)) {
return false;
}
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensions');
$versionExistsForExtension = $connection->count(
'uid',
'tx_ter_extensions',
[
'extensionkey' => $extensionKey,
'version' => $versionString
]
);
return !$versionExistsForExtension;
}
/**
* sets SYS_LASTCHANGED to this date if it is newer than the currently set
* @param int $dateTime
......
......@@ -13,13 +13,12 @@ namespace T3o\TerFe2\Domain\Repository;
use T3o\TerFe2\Service\DocumentationService;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* This class combines all data of an extension and all versions from various database tables
*
* tx_ter_extensions -> contains all versions of all extensions
* tx_terfe2_domain_model_version -> contains all versions of all extensions
* tx_terfe2_domain_model_extension -> contains all registered extension keys and meta data (even if there was no version uploaded)
*
* Currently this class is used as a wrapper, but should vanish once we migrated the database structures properly
......@@ -36,65 +35,56 @@ class CombinedExtensionRepository
$this->documentationService = $documentationService ?? GeneralUtility::makeInstance(DocumentationService::class);
}
/**
* Fetches all information about a given list of extension keys that is not version-specific.
*
* @param array $extensionKeys
* @return array
*/
protected function getBasicExtensionInformation(array $extensionKeys): array
{
$basicExtensionInformation = [];
foreach ($extensionKeys as $extensionKey) {
$keysQueryBuilder = $this->getQueryBuilder('tx_terfe2_domain_model_extension');
$extensionKeyRow = $keysQueryBuilder
->select('uid', 'frontend_user', 'downloads', 'external_manual')
->from('tx_terfe2_domain_model_extension')
->where(
$keysQueryBuilder->expr()->eq('ext_key', $keysQueryBuilder->createNamedParameter($extensionKey))
)
->execute()
->fetch();
$basicExtensionInformation[$extensionKey] = [
'extensionuid' => $extensionKeyRow['uid'],
'ownerusername' => $extensionKeyRow['frontend_user'],
'downloads' => $extensionKeyRow['downloads'],
'external_manual' => $extensionKeyRow['external_manual'] ?: ''
];
}
return $basicExtensionInformation;
}
public function getExtensionDetailsWithVersionsAndDownloadNumbers(): array
{
$groupedVersionsByExtension = [];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_terfe2_domain_model_version');
$queryBuilder->getRestrictions()->removeAll();
$stmt = $queryBuilder
->select(
'v.uid',
'v.tstamp',
'v.extension',
'e.ext_key as extensionkey',
'e.downloads AS totaldownloads',
'e.frontend_user',
'e.external_manual',
'v.version_string AS version',
'v.title',
'v.description',
'v.state',
'v.review_state',
'v.em_category',
'v.download_counter',
'v.file_hash',
'v.upload_date',
'v.upload_comment',
'v.dependencies',
'v.composer_info',
'v.authorname',
'v.authoremail',
'v.authorcompany',
)
->from('tx_terfe2_domain_model_version', 'v')
->leftJoin(
'v',
'tx_terfe2_domain_model_extension',
'e',
$queryBuilder->expr()->eq('v.extension', $queryBuilder->quoteIdentifier('e.uid'))
)
->where(
$queryBuilder->expr()->eq('v.hidden', 0),
$queryBuilder->expr()->eq('v.deleted', 0)
)
->execute();
$queryBuilder = $this->getQueryBuilder('tx_ter_extensions');
$versions = $queryBuilder
->select('uid', 'tstamp', 'extensionkey', 'version', 'title', 'description', 'state', 'reviewstate', 'category', 'downloadcounter', 't3xfilemd5', 'lastuploaddate', 'uploadcomment', 'dependencies', 'composerinfo', 'authorname', 'authoremail', 'authorcompany')
->from('tx_ter_extensions')
->execute()
->fetchAll();
$usedExtensionKeys = array_column($versions, 'extensionkey');
$usedExtensionKeys = array_unique($usedExtensionKeys);
$basicExtensionInformation = $this->getBasicExtensionInformation($usedExtensionKeys);
foreach ($versions as $row) {
while ($row = $stmt->fetch()) {
$extensionKey = $row['extensionkey'];
$versionNumber = $row['version'];
$genericExtensionInformation = $basicExtensionInformation[$extensionKey];
$groupedVersionsByExtension[$extensionKey]['ownerusername'] = $genericExtensionInformation['ownerusername'];
$groupedVersionsByExtension[$extensionKey]['downloads'] = $genericExtensionInformation['downloads'];
$groupedVersionsByExtension[$extensionKey]['frontend_user'] = $row['frontend_user'];
$groupedVersionsByExtension[$extensionKey]['downloads'] = $row['downloads'];
$versionInformation = $this->getVersionInformation($basicExtensionInformation[$extensionKey]['extensionuid'], $versionNumber);
$row['reviewstate'] = $versionInformation['review_state'];
if (!empty($genericExtensionInformation['external_manual'])) {
$row['external_manual'] = $genericExtensionInformation['external_manual'];
} else {
if (empty($row['external_manual'])) {
try {
$row['external_manual'] = $this->documentationService->getDocumentationLink($extensionKey, $versionNumber, true);
} catch (\Exception $e) {
......@@ -106,30 +96,4 @@ class CombinedExtensionRepository
return $groupedVersionsByExtension;
}
protected function getVersionInformation(int $extensionUid, string $versionNumber)
{
$queryBuilder = $this->getQueryBuilder('tx_terfe2_domain_model_version');
$queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction::class));
$version = $queryBuilder
->select('*')
->from('tx_terfe2_domain_model_version')
->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('extension', $queryBuilder->createNamedParameter($extensionUid)),
$queryBuilder->expr()->eq('version_string', $queryBuilder->createNamedParameter($versionNumber, \PDO::PARAM_STR))
)
)
->execute()
->fetch();
return $version;
}
protected function getQueryBuilder(string $table): QueryBuilder
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
$queryBuilder->getRestrictions()->removeAll();
return $queryBuilder;
}
}
......@@ -135,8 +135,8 @@ class ExtensionIndexService implements LoggerAwareInterface
$versionObj->appendChild(new \DOMElement('title', $this->xmlentities((string)$extensionVersionArr['title'])));
$versionObj->appendChild(new \DOMElement('description', $this->xmlentities((string)$extensionVersionArr['description'])));
$versionObj->appendChild(new \DOMElement('state', $this->xmlentities((string)$extensionVersionArr['state'])));
$versionObj->appendChild(new \DOMElement('reviewstate', (string)$extensionVersionArr['reviewstate']));
$versionObj->appendChild(new \DOMElement('category', $this->xmlentities((string)$extensionVersionArr['category'])));
$versionObj->appendChild(new \DOMElement('reviewstate', (string)$extensionVersionArr['review_state']));
$versionObj->appendChild(new \DOMElement('category', $this->xmlentities((string)$extensionVersionArr['em_category'])));
if ($extensionVersionArr['category'] === 'distribution') {
$prefixDistributionFilePath = $extensionKey[0] . '/' . $extensionKey[1] . '/' . $extensionKey . '_' . $versionNumber . '_';
$distributionImage = $prefixDistributionFilePath . 'Distribution.png';
......@@ -151,18 +151,18 @@ class ExtensionIndexService implements LoggerAwareInterface
$versionObj->appendChild(
new \DOMElement(
'downloadcounter',
$this->xmlentities((string)$extensionVersionArr['downloadcounter'])
$this->xmlentities((string)$extensionVersionArr['download_counter'])
)
);
$versionObj->appendChild(new \DOMElement('lastuploaddate', (string)$extensionVersionArr['lastuploaddate']));
$versionObj->appendChild(new \DOMElement('lastuploaddate', (string)$extensionVersionArr['upload_date']));
$versionObj->appendChild(
new \DOMElement(
'uploadcomment',
$this->xmlentities((string)$extensionVersionArr['uploadcomment'])
$this->xmlentities((string)$extensionVersionArr['upload_comment'])
)
);
$versionObj->appendChild(new \DOMElement('dependencies', (string)$extensionVersionArr['dependencies']));
$versionObj->appendChild(new \DOMElement('composerinfo', (string)$extensionVersionArr['composerinfo']));
$versionObj->appendChild(new \DOMElement('composerinfo', (string)$extensionVersionArr['composer_info']));
$versionObj->appendChild(new \DOMElement('authorname', $this->xmlentities((string)$extensionVersionArr['authorname'])));
$versionObj->appendChild(new \DOMElement('authoremail', $this->xmlentities((string)$extensionVersionArr['authoremail'])));
$versionObj->appendChild(
......@@ -174,10 +174,10 @@ class ExtensionIndexService implements LoggerAwareInterface
$versionObj->appendChild(
new \DOMElement(
'ownerusername',
$this->xmlentities((string)$extensionVersionsArr['ownerusername'])
$this->xmlentities((string)$extensionVersionsArr['frontend_user'])
)
);
$versionObj->appendChild(new \DOMElement('t3xfilemd5', (string)$extensionVersionArr['t3xfilemd5']));
$versionObj->appendChild(new \DOMElement('t3xfilemd5', (string)$extensionVersionArr['file_hash']));
$versionObj->appendChild(new \DOMElement('documentation_link', (string)$extensionVersionArr['external_manual'] ?: ''));
}
}
......
......@@ -15,6 +15,7 @@ namespace T3o\TerFe2\Task;
*/
use Psr\Log\LoggerInterface;
use T3o\Ter\Api\ExtensionKey;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Mail\MailMessage;
......@@ -205,8 +206,8 @@ class CheckForExpiredExtensions extends Task
$uidsToDelete = [];
while ($expiredExtension = $expiredExtensions->fetch(\PDO::FETCH_ASSOC)) {
// Deleted in ter, then delete the key in the ter_fe2 extension table
if ($expiredExtension['ext_key'] && $this->deleteExtensionKeyInTer($expiredExtension['ext_key'])) {
$extensionKey = new ExtensionKey($expiredExtension['ext_key']);
if (!$extensionKey->hasUploadedVersions()) {
$uidsToDelete[] = $expiredExtension['uid'];
}
}
......@@ -225,31 +226,4 @@ class CheckForExpiredExtensions extends Task
));
}
}
/**
* This method can be removed as soon as tx_ter_extensions is not in use anymore.
* @param $extensionKey
* @return bool|resource
*/
protected function deleteExtensionKeyInTer($extensionKey)
{
// check if there are extension versions
$extensionsConnection = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('tx_ter_extensions');
$versionCount = $extensionsConnection->count(
'extensionkey',
'tx_ter_extensions',
[
'extensionkey' => $extensionKey
]
);
if (!$versionCount || $versionCount === 0) {
$this->logger->info(sprintf('Deleted extension key %s as it did not have versions.', $extensionKey));
return true;
}
return false;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment