Repository: symfony/flex (php)

Issue:
composer req orm failing with Composer 2 RC1
```
composer create-project symfony/skeleton sf_test
cd sf_test
composer req orm
```

```
Fatal error: Uncaught TypeError: Argument 1 passed to Composer\Semver\Intervals::compactConstraint() must implement interface Composer\Semver\Constraint\ConstraintInterface, string given, called in /home/shyim/Code/sf_test/vendor/symfony/flex/src/Unpacker.php on line 146 and defined in phar:///nix/store/iwdd9qff8z6vd95z71y8n0na1pczv6wz-composer-2.0.0-RC1/libexec/composer/composer.phar/vendor/composer/semver/src/Intervals.php:139
Stack trace:
#0 /home/shyim/Code/sf_test/vendor/symfony/flex/src/Unpacker.php(146): Composer\Semver\Intervals::compactConstraint('^1.11')
#1 /home/shyim/Code/sf_test/vendor/symfony/flex/src/Command/UnpackCommand.php(79): Symfony\Flex\Unpacker->unpack(Object(Symfony\Flex\Unpack\Operation))
#2 /home/shyim/Code/sf_test/vendor/symfony/flex/src/Command/RequireCommand.php(63): Symfony\Flex\Command\UnpackCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#3 phar:///nix/store/iwdd9qff8z6vd95z71y8n0na1pczv6wz-composer-2.0.0-RC1/libexe in phar:///nix/store/iwdd9qff8z6vd95z71y8n0na1pczv6wz-composer-2.0.0-RC1/libexec/composer/composer.phar/vendor/composer/semver/src/Intervals.php on line 139
```

Pull request description:
Fix Unpacker failing on Intervals::compactConstraint()
Fix #678

Patch:
diff --git a/src/Flex.php b/src/Flex.php
index 8817131..b2b7968 100644
--- a/src/Flex.php
+++ b/src/Flex.php
@@ -120,13 +120,14 @@ class Flex implements PluginInterface, EventSubscriberInterface
         $this->config = $composer->getConfig();
         $this->options = $this->initOptions();
 
+        $symfonyRequire = preg_replace('/\.x$/', '.x-dev', getenv('SYMFONY_REQUIRE') ?: ($composer->getPackage()->getExtra()['symfony']['require'] ?? null));
+
         if ($composer2 = version_compare('2.0.0', PluginInterface::PLUGIN_API_VERSION, '<=')) {
             $rfs = Factory::createHttpDownloader($this->io, $this->config);
 
             $this->downloader = $downloader = new Downloader($composer, $io, $rfs);
             $this->downloader->setFlexId($this->getFlexId());
 
-            $symfonyRequire = getenv('SYMFONY_REQUIRE') ?: ($composer->getPackage()->getExtra()['symfony']['require'] ?? null);
             if ($symfonyRequire) {
                 $this->filter = new PackageFilter($io, $symfonyRequire, $this->downloader);
             }
@@ -136,7 +137,6 @@ class Flex implements PluginInterface, EventSubscriberInterface
             $rfs = Factory::createRemoteFilesystem($this->io, $this->config);
             $this->rfs = $rfs = new ParallelDownloader($this->io, $this->config, $rfs->getOptions(), $rfs->isTlsDisabled());
 
-            $symfonyRequire = getenv('SYMFONY_REQUIRE') ?: ($composer->getPackage()->getExtra()['symfony']['require'] ?? null);
             $this->downloader = $downloader = new Downloader($composer, $io, $this->rfs);
             $this->downloader->setFlexId($this->getFlexId());
 
diff --git a/src/Unpacker.php b/src/Unpacker.php
index d6c3130..e4d30a2 100644
--- a/src/Unpacker.php
+++ b/src/Unpacker.php
@@ -25,6 +25,7 @@ use Composer\Repository\CompositeRepository;
 use Composer\Repository\RepositorySet;
 use Composer\Semver\Constraint\MultiConstraint;
 use Composer\Semver\Intervals;
+use Composer\Semver\VersionParser;
 use Symfony\Flex\Unpack\Operation;
 use Symfony\Flex\Unpack\Result;
 
@@ -33,12 +34,14 @@ class Unpacker
     private $composer;
     private $resolver;
     private $dryRun;
+    private $versionParser;
 
     public function __construct(Composer $composer, PackageResolver $resolver, bool $dryRun)
     {
         $this->composer = $composer;
         $this->resolver = $resolver;
         $this->dryRun = $dryRun;
+        $this->versionParser = new VersionParser();
     }
 
     public function unpack(Operation $op, Result $result = null, &$links = []): Result
@@ -101,7 +104,7 @@ class Unpacker
                 $linkType = $package['dev'] ? 'require-dev' : 'require';
 
                 if (isset($links[$linkName])) {
-                    $links[$linkName]['constraints'][] = $constraint;
+                    $links[$linkName]['constraints'][] = $this->versionParser->parseConstraints($constraint);
                     if ('require' === $linkType) {
                         $links[$linkName]['type'] = 'require';
                     }
@@ -138,16 +141,16 @@ class Unpacker
 
                 // removes package from "require-dev", because it will be moved to "require"
                 // save stored constraint
-                $link['constraints'][] = $jsonStored['require-dev'][$link['name']];
+                $link['constraints'][] = $this->versionParser->parseConstraints($jsonStored['require-dev'][$link['name']]);
                 $jsonManipulator->removeSubNode('require-dev', $link['name']);
             }
 
             $constraint = class_exists(Intervals::class, false)
-                ? Intervals::compactConstraint(MultiConstraint::create($link['constraints']))->getPrettyString()
+                ? Intervals::compactConstraint(MultiConstraint::create($link['constraints']))
                 : end($link['constraints'])
             ;
 
-            if (!$jsonManipulator->addLink($link['type'], $link['name'], $constraint, $op->shouldSort())) {
+            if (!$jsonManipulator->addLink($link['type'], $link['name'], $constraint->getPrettyString(), $op->shouldSort())) {
                 throw new \RuntimeException(sprintf('Unable to unpack package "%s".', $link['name']));
             }
         }


Test patch:
diff --git a/tests/FlexTest.php b/tests/FlexTest.php
index 5bfa719..2313d4a 100644
--- a/tests/FlexTest.php
+++ b/tests/FlexTest.php
@@ -25,6 +25,7 @@ use Composer\Plugin\PluginInterface;
 use Composer\Repository\RepositoryManager;
 use Composer\Repository\WritableRepositoryInterface;
 use Composer\Script\Event;
+use Composer\Semver\Constraint\MatchAllConstraint;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Flex\Configurator;
@@ -99,7 +100,7 @@ EOF
         $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE);
 
         $package = $this->mockRootPackage(['symfony' => ['allow-contrib' => true]]);
-        $package->method('getRequires')->willReturn([new Link('dummy', 'symfony/flex')]);
+        $package->method('getRequires')->willReturn([new Link('dummy', 'symfony/flex', class_exists(MatchAllConstraint::class) ? new MatchAllConstraint() : null)]);
 
         $composer = $this->mockComposer($this->mockLocker(), $package, Factory::createConfig($io));
         if (version_compare('2.0.0', PluginInterface::PLUGIN_API_VERSION, '>')) {
diff --git a/tests/UnpackerTest.php b/tests/UnpackerTest.php
index 269203f..f9e9e4e 100644
--- a/tests/UnpackerTest.php
+++ b/tests/UnpackerTest.php
@@ -7,6 +7,7 @@ use Composer\Package\Link;
 use Composer\Package\Package;
 use Composer\Repository\InstalledArrayRepository;
 use Composer\Repository\RepositoryManager;
+use Composer\Semver\Constraint\MatchAllConstraint;
 use PHPUnit\Framework\TestCase;
 use Symfony\Flex\PackageResolver;
 use Symfony\Flex\Unpack\Operation;
@@ -44,7 +45,7 @@ class UnpackerTest extends TestCase
         // Setup packages
 
         $realPkg = new Package('real', '1.0.0', '1.0.0');
-        $realPkgLink = new Link('lorem', 'real', null, 'wraps', '1.0.0');
+        $realPkgLink = new Link('lorem', 'real', class_exists(MatchAllConstraint::class) ? new MatchAllConstraint() : null, 'wraps', '1.0.0');
 
         $virtualPkgFoo = new Package('pack_foo', '1.0.0', '1.0.0');
         $virtualPkgFoo->setType('symfony-pack');