Skip to content

Commit

Permalink
[FEATURE] Provide detailed error messages for ext_emconf.php validation
Browse files Browse the repository at this point in the history
  • Loading branch information
eliashaeussler committed Nov 17, 2024
1 parent 2685258 commit a55f966
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 15 deletions.
23 changes: 19 additions & 4 deletions src/Service/VersionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use TYPO3\Tailor\Environment\Variables;
use TYPO3\Tailor\Exception\FormDataProcessingException;
use TYPO3\Tailor\Exception\RequiredConfigurationMissing;
use TYPO3\Tailor\Validation\EmConfValidationError;
use TYPO3\Tailor\Validation\EmConfVersionValidator;
use ZipArchive;

Expand Down Expand Up @@ -63,7 +64,7 @@ public function createZipArchiveFromPath(string $path): string
$zipArchive = new \ZipArchive();
$zipArchive->open($this->getVersionFilename(), \ZipArchive::CREATE | \ZipArchive::OVERWRITE);

$emConfValid = false;
$emConfValidationErrors = [EmConfValidationError::NOT_FOUND];

$iterator = new \RecursiveDirectoryIterator($fullPath, \FilesystemIterator::SKIP_DOTS);
$files = new \RecursiveIteratorIterator(
Expand Down Expand Up @@ -110,15 +111,15 @@ public function createZipArchiveFromPath(string $path): string
}

if ($filename === 'ext_emconf.php') {
$emConfValid = (new EmConfVersionValidator($fileRealPath))->isValid($this->version);
$emConfValidationErrors = (new EmConfVersionValidator($fileRealPath))->collectErrors($this->version);
}

// Add the files including their directories
$zipArchive->addFile($fileRealPath, substr($fileRealPath, strlen($fullPath) + 1));
}

if (!$emConfValid) {
throw new FormDataProcessingException('No or invalid ext_emconf.php found in the folder.', 1605563410);
if ($emConfValidationErrors !== []) {
throw new FormDataProcessingException($this->formatEmConfValidationErrors($emConfValidationErrors), 1605563410);
}

$zipArchive->close();
Expand Down Expand Up @@ -233,4 +234,18 @@ protected function getExcludeConfiguration(): array

return $configuration;
}

/**
* @param list<EmConfValidationError::*> $errors
*/
private function formatEmConfValidationErrors(array $errors): string
{
$messageParts = ['Validation of `ext_emconf.php` file failed due to the following errors:'];

foreach ($errors as $error) {
$messageParts[] = ' * ' . EmConfValidationError::getErrorMessage($error);
}

return implode(PHP_EOL, $messageParts);
}
}
49 changes: 49 additions & 0 deletions src/Validation/EmConfValidationError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 project - inspiring people to share!
* (c) 2020 Oliver Bartsch & Benni Mack
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace TYPO3\Tailor\Validation;

/**
* Enum with validation errors of ext_emconf.php files.
*
* @todo Convert to native enum once support for PHP < 8.1 is dropped.
*/
abstract class EmConfValidationError
{
public const EXTENSION_VERSION_MISMATCH = 'extension-version-mismatch';
public const MISSING_CONFIGURATION = 'missing-configuration';
public const MISSING_EXTENSION_VERSION = 'missing-version';
public const MISSING_TYPO3_VERSION_CONSTRAINT = 'missing-typo3-version-constraint';
public const NOT_FOUND = 'not-found';
public const UNSUPPORTED_TYPE = 'unsupported-type';

public static function getErrorMessage(string $error): string
{
switch ($error) {
case self::EXTENSION_VERSION_MISMATCH:
return 'The configured version in `ext_emconf.php` file does not match the given version for release.';
case self::MISSING_CONFIGURATION:
return 'The `ext_emconf.php` file is missing an $EM_CONF configuration array.';
case self::MISSING_EXTENSION_VERSION:
return 'No version configured in `ext_emconf.php` file.';
case self::MISSING_TYPO3_VERSION_CONSTRAINT:
return 'No TYPO3 version constraint configured in `ext_emconf.php` file.';
case self::NOT_FOUND:
return 'No `ext_emconf.php` file found in the folder.';
case self::UNSUPPORTED_TYPE:
return 'The $EM_CONF variable in `ext_emconf.php` file contains an unsupported type (should be an array).';
default:
// @todo Can be removed once this class is converted to a native enum.
return 'An unexpected error occurred while reading the `ext_emconf.php` file.';
}
}
}
41 changes: 31 additions & 10 deletions src/Validation/EmConfVersionValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,47 @@ public function __construct(string $filePath)
}

/**
* @param string $givenVersion
* @return bool TRUE if the ext_emconf is valid, FALSE otherwise
* @return list<EmConfValidationError::*> List of validation errors. If list is empty, ext_emconf.php file is valid.
*/
public function isValid(string $givenVersion): bool
public function collectErrors(string $givenVersion): array
{
if (!file_exists($this->emConfFilePath)) {
return [EmConfValidationError::NOT_FOUND];
}

$_EXTKEY = 'dummy';
@include $this->emConfFilePath;

if (!isset($EM_CONF)) {
return false;
return [EmConfValidationError::MISSING_CONFIGURATION];
}

$emConfDetails = reset($EM_CONF);

if (!is_array($emConfDetails)) {
return false;
return [EmConfValidationError::UNSUPPORTED_TYPE];
}
if (!isset($emConfDetails['version'], $emConfDetails['constraints']['depends']['typo3'])) {
return false;

$errors = [];

if (!isset($emConfDetails['version'])) {
$errors[] = EmConfValidationError::MISSING_EXTENSION_VERSION;
} elseif ((string)$emConfDetails['version'] !== $givenVersion) {
$errors[] = EmConfValidationError::EXTENSION_VERSION_MISMATCH;
}
if ((string)$emConfDetails['version'] !== $givenVersion) {
return false;
if (!isset($emConfDetails['constraints']['depends']['typo3'])) {
$errors[] = EmConfValidationError::MISSING_TYPO3_VERSION_CONSTRAINT;
}
return true;

return $errors;
}

/**
* @param string $givenVersion
* @return bool TRUE if the ext_emconf is valid, FALSE otherwise
*/
public function isValid(string $givenVersion): bool
{
return $this->collectErrors($givenVersion) === [];
}
}
2 changes: 1 addition & 1 deletion tests/Unit/Fixtures/EmConf/emconf_no_version.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php

$EM_CONF = [
$EM_CONF[$_EXTKEY] = [
'nothing' => 'YES',
];
63 changes: 63 additions & 0 deletions tests/Unit/Validation/EmConfVersionValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,73 @@
namespace TYPO3\Tailor\Tests\Unit\Validation;

use PHPUnit\Framework\TestCase;
use TYPO3\Tailor\Validation\EmConfValidationError;
use TYPO3\Tailor\Validation\EmConfVersionValidator;

class EmConfVersionValidatorTest extends TestCase
{
/**
* @test
*/
public function collectErrorsReturnsErrorIfFileDoesNotExist(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/no-file');
$expected = [EmConfValidationError::NOT_FOUND];
self::assertSame($expected, $subject->collectErrors('1.2.0'));
}

/**
* @test
*/
public function collectErrorsReturnsErrorIfConfigurationIsMissing(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/../Fixtures/EmConf/emconf_invalid.php');
$expected = [EmConfValidationError::MISSING_CONFIGURATION];
self::assertSame($expected, $subject->collectErrors('1.0.0'));
}

/**
* @test
*/
public function collectErrorsReturnsErrorIfFileDoesNotMatchEmConfStructure(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/../Fixtures/EmConf/emconf_no_structure.php');
$expected = [EmConfValidationError::UNSUPPORTED_TYPE];
self::assertSame($expected, $subject->collectErrors('1.0.0'));
}

/**
* @test
*/
public function collectErrorsReturnsErrorsIfNoVersionGiven(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/../Fixtures/EmConf/emconf_no_version.php');
$expected = [
EmConfValidationError::MISSING_EXTENSION_VERSION,
EmConfValidationError::MISSING_TYPO3_VERSION_CONSTRAINT,
];
self::assertSame($expected, $subject->collectErrors('1.0.0'));
}

/**
* @test
*/
public function collectErrorsReturnsErrorIfVersionsDoNotMatch(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/../Fixtures/EmConf/emconf_valid.php');
$expected = [EmConfValidationError::EXTENSION_VERSION_MISMATCH];
self::assertSame($expected, $subject->collectErrors('2.0.0'));
}

/**
* @test
*/
public function collectErrorsReturnsEmptyArrayIfFileIsValid(): void
{
$subject = new EmConfVersionValidator(__DIR__ . '/../Fixtures/EmConf/emconf_valid.php');
self::assertSame([], $subject->collectErrors('1.0.0'));
}

/**
* @test
*/
Expand Down

0 comments on commit a55f966

Please sign in to comment.