rectorphp / rector

Instant Upgrades and Automated Refactoring of any PHP 5.3+ code
https://getrector.com
MIT License
8.55k stars 679 forks source link

Missing Documentation for Registering `SetProviderInterface` #8720

Open ghostwriter opened 1 month ago

ghostwriter commented 1 month ago

Hi,

SetListInterface was deprecated.

/**
 * @deprecated This interface needs a reflection to load and uses constant links. 
 * Now we changed to services provider architecture that can be used and registerd easily. 
 * Use @see SetProviderInterface instead
 */
interface SetListInterface
{
}
// src/Set/Contract/SetListInterface.php
interface SetProviderInterface
{
    /**
     * @return SetInterface[]
     */
    public function provide(): array;
}
// src/Set/Contract/SetProviderInterface.php

Question

Can you please provide documentation or examples on how to register a class that implements the SetProviderInterface using RectorConfigBuilder or RectorConfig.

It is unclear how to properly implement and register the new interface.

Thank you.

TomasVotruba commented 1 month ago

Hi, this feature is internal. We don't use for public yet. How do you use the deprecated interface?

ghostwriter commented 1 month ago

SetListInterface is implemented on a few SetList ValueObjects, similar to rector

Before deprecation:

After deprecation:

https://github.com/ghostwriter/mockery-rector/blob/28d60268ff72943df51c561f556d6eb5c412bcfc/src/MockerySetProvider.php

https://github.com/ghostwriter/mockery-rector/blob/28d60268ff72943df51c561f556d6eb5c412bcfc/src/MockerySetList.php

Config:

use Ghostwriter\MockeryRector\MockeryLevelSetList;
use Ghostwriter\MockeryRector\MockerySetList;
use Ghostwriter\MockeryRector\Rule\ExtendMockeryTestCaseRector;
use Ghostwriter\MockeryRector\Rule\HamcrestToPHPUnitRector;
use Ghostwriter\MockeryRector\Rule\PHPUnitToMockeryRector;
use Ghostwriter\MockeryRector\Rule\ProphecyToMockeryRector;
use Ghostwriter\MockeryRector\Rule\ShouldReceiveToAllowsRector;
use Ghostwriter\MockeryRector\Rule\ShouldReceiveToExpectsRector;
use Ghostwriter\MockeryRector\Rule\UseMockeryPHPUnitIntegrationTraitRector;

use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withRules([
        // ExtendMockeryTestCaseRector::class,
        // HamcrestToPHPUnitRector::class,
        // PHPUnitToMockeryRector::class,
        // ProphecyToMockeryRector::class,
        // ShouldReceiveToAllowsRector::class,
        // ShouldReceiveToExpectsRector::class,
        // UseMockeryPHPUnitIntegrationTraitRector::class,
    ])
    ->withSets([
         // version sets
         MockerySetList::MOCKERY_1_6, // v1.6.0
         MockerySetList::MOCKERY_2_0, // v2.0.0
         // or level sets
         MockeryLevelSetList::UP_TO_MOCKERY_1_6, // v0.1.0 - v1.6.0
         MockeryLevelSetList::UP_TO_MOCKERY_2_0, // v0.1.0 - v2.0.0
         // or migration sets
         MockerySetList::PHPUNIT_TO_MOCKERY, // PHPUnit to Mockery
         MockerySetList::PROPHECY_TO_MOCKERY, // Prophecy to Mockery
    ]);
ghostwriter commented 1 month ago

I would like to use the ComposerTriggeredSet feature.

I would like to see a withSetProviders(string ...$setProviders) method that accepts FQCN (string) of a class that implements SetProviderInterface which we can check via is_a($setProvider, SetProviderInterface::class, true).

return RectorConfig::configure()
    ->withSetProviders(
        PHPSetProvider::class,
        PHPUnitSetProvider::class,
        MockerySetProvider::class,
    );
ghostwriter commented 1 month ago

class RectorConfigBuilder
{
    /**
     * @var array<class-string<SetProviderInterface>>
     */
    private array $setProviders = [];
    /**
     * @param class-string<SetProviderInterface> ...$setProviders
     */
    public function withSetProviders(string ...$setProviders): self
    {
        foreach ($setProviders as $setProvider) {
            if (! is_a($setProvider, SetProviderInterface::class, true)) {
                throw new InvalidConfigurationException(sprintf(
                    'Set provider "%s" must implement "%s"',
                    $setProvider,
                    SetProviderInterface::class
                ));
            }

            $this->setProviders[] = $setProvider;
        }

        return $this;
    }

    public function __invoke(RectorConfig $rectorConfig): void
    {
        // @experimental 2024-07
        if ($this->setProviders !== []) {
            $setProviderCollector = new SetProviderCollector(array_map(
                static fn (string $setProvider): SetProviderInterface =>
                $rectorConfig->make($setProvider),
                $this->setProviders
            ));

            foreach ($setProviderCollector->provideSets() as $set) {
                $this->setGroups[] = $set->getGroupName();
            }
        }

        // @experimental 2024-06
        if ($this->setGroups !== []) {
            $setProviderCollector ??= $rectorConfig->make(SetProviderCollector::class);
            $setManager = new SetManager($setProviderCollector);

            $this->groupLoadedSets = $setManager->matchBySetGroups($this->setGroups);
        }
    }
}