Packages that ship a lot of versions can have a lot of sets to apply. For, twig/twig has 6 sets in Rector, a couple for v1 and a couple for v2. What about v3? We must always check for our locally installed version and then keep rector.php
up to date.
This could lead to errors as we run sets with new features from v3 that we don't have yet.
At the moment, we have to add sets manually one by one to rector.php
:
return RectorConfig::configure()
->withSets([
\Rector\Symfony\Set\TwigSetList::TWIG_112,
\Rector\Symfony\Set\TwigSetList::TWIG_127,
\Rector\Symfony\Set\TwigSetList::TWIG_134,
\Rector\Symfony\Set\TwigSetList::TWIG_20,
\Rector\Symfony\Set\TwigSetList::TWIG_24,
])
This doesn't seem right for a couple of reasons:
composer.json
version of twig/twig
If we upgrade to Twig 3 later on, Rector should pick up sets for Twig 3 for us. So, we don't maintain the rector.php
at all.
withComposerBased()
return RectorConfig::configure()
->withComposerBased(twig: true);
You can drop all sets from above and use this single parameter. Currently, we support Twig, PHPUnit, and Doctrine. Support for Symfony and Laravel is coming soon.
Rector will go through all Twig sets and check our installed version in vendor/composer/installed.json
. Then, it finds all sets relevant to our specific version.
If you're writing your custom extension for your community, you'll want to create your own SetProvider
to handle complexity for your users.
Let's look at a real example for TwigSetProvider
from the rector-symfony
package:
namespace Rector\Symfony\Set\SetProvider;
use Rector\Set\Contract\SetInterface;
use Rector\Set\Contract\SetProviderInterface;
use Rector\Set\ValueObject\ComposerTriggeredSet;
use Rector\Set\ValueObject\Set;
final class TwigSetProvider implements SetProviderInterface
{
/**
* @return SetInterface[]
*/
public function provide(): array
{
return [
new ComposerTriggeredSet(
'twig',
'twig/twig',
'1.27',
__DIR__ . '/../../../config/sets/twig/twig127.php'
),
new ComposerTriggeredSet(
'twig',
'twig/twig',
'2.0',
__DIR__ . '/../../../config/sets/twig/twig20.php'
),
// ...
];
}
}
Setup is straightforward - define the version and path to the set:
namespace Rector\Set\ValueObject;
final class ComposerTriggeredSet
{
public function __construct(
private string $groupName,
private string $packageName,
private string $version,
private string $setFilePath
) {
}
// ...
}
$groupName
is key in ->withComposerBased()
:$packageName
is the composer package name.$version
is the minimal version to trigger the set$setFilePath
is the path to the Rector config with rules as we know itIn the near future, community packages like Laravel will have their own SetProvider
classes. To get their latest upgrade sets, all you'll have to do is add one param:
return RectorConfig::configure()
->withComposerBased(laravel: true);
Happy coding!