Skip to content

PHPMD version 3.x compatibility #273

Description

@EduardoMorales-mrm

phpmd 3.x introduced a new CLI structure based on Symfony Console with an analyze subcommand. The current command generation in src/Tools/Analyzer/Phpmd.php produces a phpmd 2.x-style command that is incompatible with phpmd 3.x.

Current behavior

phpqa generates:

vendor/bin/phpmd "web/modules/custom","web/themes/custom" xml "/path/to/phpmd.xml.dist" --exclude /vendor/,/node_modules/,/tests/src/ --suffixes php,module,install,theme --reportfile "reports/codereview/phpmd.xml"

This fails with phpmd 3.x:

Command "web/modules/custom,web/themes/custom" is not defined.

phpmd 3.x interprets the first positional argument as a subcommand name.

Expected behavior

phpqa should generate a phpmd 3.x-compatible command:

vendor/bin/phpmd analyze
--exclude 'vendor/' --exclude 'node_modules/' --exclude 'tests/src/'
--suffixes php --suffixes module --suffixes install --suffixes theme
--ruleset "/path/to/phpmd.xml.dist"
--format xml
--reportfile-xml "reports/codereview/phpmd.xml"
-- "web/modules/custom" "web/themes/custom"

Breaking changes in phpmd 3.x CLI

Area phpmd 2.x phpmd 3.x
Subcommand none (positional source dirs first) analyze required as first arg
Source dirs first positional arg (comma-separated) trailing args after -- separator
Format second positional arg (xml/text) --format xml
Ruleset third positional arg --ruleset /path/to/ruleset.xml
Exclude --exclude /vendor/,/node_modules/ (comma-separated, slash-delimited) --exclude '*vendor/*' (one flag per pattern, glob-style with asterisks)
Suffixes --suffixes php,module,install (comma-separated, single flag) --suffixes php --suffixes module (one flag per extension)
Report file --reportfile file.xml --reportfile-xml file.xml

Proposed fix

Two files need updating:

src/IgnoredPaths.php — add a phpmd3() method that generates glob-style --exclude patterns:

public function phpmd3()
{
$parts = [];
foreach ($this->ignoreDirs as $dir) {
$dir = trim($dir, '/');
$parts[] = '--exclude ' . escapeshellarg('*' . $dir . '/*');
}
foreach ($this->ignoreFiles as $file) {
$file = ltrim($file, '/');
$parts[] = '--exclude ' . escapeshellarg('*' . $file);
}
return $parts ? ' ' . implode(' ', $parts) : '';
}

src/Tools/Analyzer/Phpmd.php — rewrite __invoke() to use the phpmd 3.x command structure. Version detection via $this->toolVersionIs('>=', '3.0.0') can be used to maintain backward compatibility with phpmd 2.x if needed:

public function __invoke()
{
$this->tool->errorsType = $this->config->value('phpmd.ignoreParsingErrors') === true;
$rulesets = $this->config->pathsOrValues('phpmd.standard');

$extensions = array_filter(array_map('trim', explode(',', $this->config->csv('phpqa.extensions'))));
$suffixArgs = ' ' . implode(' ', array_map(function ($ext) {
return '--suffixes ' . $ext;
}, $extensions));

$args = [];
$args[] = 'analyze';
$args[] = $this->options->ignore->phpmd3();
$args[] = $suffixArgs;
$args['ruleset'] = \Edge\QA\escapePath(implode(',', $rulesets));
$args['format'] = $this->options->isSavedToFiles ? 'xml' : 'text';
if ($this->options->isSavedToFiles) {
$args['reportfile-xml'] = $this->tool->getEscapedXmlFile();
}
$args[] = '-- ' . $this->options->getAnalyzedDirs(' ');
return $args;
}

Environment

  • phpmd/phpmd: 3.x
  • edgedesign/phpqa: dev-master
  • PHP: 8.4

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions