Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Provide detailed error messages for ext_emconf.php validation #78

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading