Skip to content

Commit

Permalink
2.2.1
Browse files Browse the repository at this point in the history
* [FEATURE] Add file locking utilities.

* [TASK] Optimize code.
* [TASK] Set version to 2.2.1.
* [TASK] Update manual.

* [BUGFIX] Avoid race condition while checking log files.
* [BUGFIX] Overriding of ctrl properties failed if property name did not match original TCA key.
  • Loading branch information
phantasie-schmiede authored Apr 5, 2024
1 parent 657c85d commit a2f10c9
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 33 deletions.
1 change: 1 addition & 0 deletions Classes/Attribute/TCA/Tab.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
class Tab extends AbstractTcaAttribute
{
public function __construct(
// The identifier has to be written in snake_case!
protected string $identifier = '',
protected string $label = '',
/**
Expand Down
13 changes: 7 additions & 6 deletions Classes/Service/Configuration/TcaService.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,14 +455,15 @@ protected function buildFromAttributes(string $className, bool $overrideMode): v
}

if (null !== $ctrl) {
$ctrlProperties = $ctrl->toArray();

if ($overrideMode) {
$ctrlProperties = array_filter($ctrlProperties, static function($key) use ($reflection) {
$setArguments = $reflection->getAttributes(Ctrl::class)[0]->getArguments();
$ctrlProperties = [];
$setArguments = $reflection->getAttributes(Ctrl::class)[0]->getArguments();

return in_array($key, $setArguments, true);
}, ARRAY_FILTER_USE_KEY);
foreach ($setArguments as $key => $value) {
$ctrlProperties[TcaUtility::convertKey($key)] = $value;
}
} else {
$ctrlProperties = $ctrl->toArray();
}

foreach ($ctrlProperties as $property => $value) {
Expand Down
4 changes: 2 additions & 2 deletions Classes/Utility/ContextUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
*/
class ContextUtility
{
public const DEFAULT_LANGUAGE_KEY = 'en';
public const DEFAULT_LANGUAGE_KEY = 'default';

public static function getCurrentBackendLanguage(): string
{
ValidationUtility::requiresBackendContext();
$language = $GLOBALS['BE_USER']->uc['lang'];
$language = (string)$GLOBALS['BE_USER']->user['lang'];

if ('' === $language) {
// Fallback to default language.
Expand Down
69 changes: 64 additions & 5 deletions Classes/Utility/FileUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

namespace PSB\PsbFoundation\Utility;

use DateTime;
use Exception;
use NumberFormatter;
use RuntimeException;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
Expand Down Expand Up @@ -94,20 +96,58 @@ public static function formatFileSize(
return $numberFormatter->format($bytes) . ' ' . $unitString;
}

/**
* @param string $fileName
*
* @return false|string
*/
public static function getLockFileName(string $fileName): string
{
return (self::resolveFileName($fileName) ?: $fileName) . '.lock';
}

public static function getMimeType(string $fileName): bool|string
{
$fileName = self::resolveFileName($fileName);
$fileInformation = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = $fileInformation->file($fileName);
finfo_close($fileInformation);

return $mimeType;
}

/**
* @throws Exception
*/
public static function isFileLocked(string $fileName): bool
{
$lockFileName = self::getLockFileName($fileName);

if (!file_exists($lockFileName)) {
return false;
}

$fileName = self::resolveFileName($fileName);
$content = trim(file_get_contents($lockFileName));

if (!empty($content)) {
$lifetime = new DateTime($content);
$now = new DateTime();

if ($now > $lifetime) {
return !self::unlockFile($fileName);
}
}

return true;
}

public static function lockFile(string $fileName, ?DateTime $lifetime = null): bool
{
$lockFileName = self::getLockFileName($fileName);

if ($lifetime instanceof DateTime) {
$content = $lifetime->format('Y-m-d H:i:s');
}

return self::write($lockFileName, $content ?? '');
}

/**
* Converts relative to absolute paths.
*
Expand All @@ -120,9 +160,28 @@ public static function resolveFileName(string $fileName): string
return GeneralUtility::getFileAbsFileName($fileName) ?: realpath($fileName) ?: '';
}

public static function unlockFile(string $fileName): bool
{
$lockFileName = self::getLockFileName($fileName);

if (file_exists($lockFileName)) {
return unlink($lockFileName);
}

return true;
}

/**
* @throws Exception
*/
public static function write(string $fileName, string $content, bool $append = false): bool
{
$fileName = self::resolveFileName($fileName);

if (self::isFileLocked($fileName)) {
return false;
}

$pathDetails = pathinfo($fileName);

// Directory creation is skipped if it already exists.
Expand Down
42 changes: 25 additions & 17 deletions Classes/Utility/Localization/LoggingUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

namespace PSB\PsbFoundation\Utility\Localization;

use Closure;
use DateTime;
use Doctrine\DBAL\Exception;
use JsonException;
use PSB\PsbFoundation\Data\ExtensionInformation;
Expand Down Expand Up @@ -46,21 +48,32 @@ class LoggingUtility
private static ?bool $logMissingLanguageLabels = null;

/**
* @return void
* @throws Exception
*/
public static function checkPostponedAccessLogEntries(): void
{
$logFile = FilePathUtility::getLanguageLabelLogFilesPath() . self::LOG_FILES['ACCESS'];
self::checkPostponedLogEntries(
static function($logEntry) {
self::writeAccessLogToDatabase($logEntry);
},
FilePathUtility::getLanguageLabelLogFilesPath() . self::LOG_FILES['ACCESS']
);
}

if (file_exists($logFile) && $logContent = file_get_contents($logFile)) {
$postponedKeys = StringUtility::explodeByLineBreaks($logContent);
public static function checkPostponedLogEntries(Closure $closure, string $logFile): void
{
if (file_exists($logFile) && !FileUtility::isFileLocked($logFile) && $logContent = file_get_contents(
$logFile
)) {
FileUtility::lockFile($logFile, (new DateTime())->modify('+5 seconds'));
$postponedEntries = StringUtility::explodeByLineBreaks($logContent);

foreach (array_filter($postponedKeys) as $postponedKey) {
self::writeAccessLogToDatabase($postponedKey);
foreach (array_filter($postponedEntries) as $postponedEntry) {
$closure($postponedEntry);
}

unlink($logFile);
FileUtility::unlockFile($logFile);
}
}

Expand All @@ -69,26 +82,21 @@ public static function checkPostponedAccessLogEntries(): void
*/
public static function checkPostponedMissingLogEntries(): void
{
$logFile = FilePathUtility::getLanguageLabelLogFilesPath() . self::LOG_FILES['MISSING'];

if (file_exists($logFile) && $logContent = file_get_contents($logFile)) {
$postponedEntries = StringUtility::explodeByLineBreaks($logContent);

foreach (array_filter($postponedEntries) as $postponedEntry) {
self::checkPostponedLogEntries(
static function($logEntry) {
[
$postponedKey,
$postponedKeyExists,
] = json_decode(
$postponedEntry,
$logEntry,
false,
512,
JSON_THROW_ON_ERROR
);
self::writeMissingLogToDatabase($postponedKey, $postponedKeyExists);
}

unlink($logFile);
}
},
FilePathUtility::getLanguageLabelLogFilesPath() . self::LOG_FILES['MISSING']
);
}

/**
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,6 @@ Examples (filename => icon identifier):
### Extension settings
#### Log missing language labels
If activated, missing language labels will be stored in `tx_psbfoundation_missing_language_labels`.
This is restricted to `PSB\PsbFoundation\Utility\LocalizationUtility` which is also used by `PSB\PsbFoundation\ViewHelpers\TranslateViewHelper`.
All missing default labels (e.g. plugin title or field label) will be listed this way if you didn't provide a custom label.
Fixed entries get removed on next check (every time the cache is cleared).<br>
It's recommended to check this table during extension development.
Expand Down Expand Up @@ -624,7 +623,6 @@ GlobalVariableService::get(RequestParameterProvider::class . '.formData.hiddenIn
`PSB\PsbFoundation\ViewHelpers\TranslateViewHelper` is an extended clone of the core's TranslateViewHelper.

Additional features:
- Logging of missing language labels via `\PSB\PsbFoundation\Utility\LocalizationUtility`
- Support of plural forms in language files;
<trans-unit>-tags in xlf-files can be grouped like this to define plural forms of a translation:
```xml
Expand Down
2 changes: 1 addition & 1 deletion ext_emconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
'description' => 'Configuration framework for TYPO3 extension development',
'state' => 'stable',
'title' => 'PSbits | Foundation',
'version' => '2.2.0',
'version' => '2.2.1',
];

0 comments on commit a2f10c9

Please sign in to comment.