diff --git a/phpstan.neon.dist b/phpstan.neon.dist index d23694b6cb..c3abccc042 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -5,6 +5,8 @@ parameters: level: 5 bootstrapFiles: - src/Faker/ORM/Doctrine/backward-compatibility.php + excludes_analyse: + - src/Faker/Rector/ paths: - src tmpDir: .build/phpstan/ diff --git a/psalm.xml b/psalm.xml index a10904b5b7..9063647944 100644 --- a/psalm.xml +++ b/psalm.xml @@ -13,6 +13,7 @@ + diff --git a/rector-migrate.php b/rector-migrate.php index 7d99b570ba..e15c880c65 100644 --- a/rector-migrate.php +++ b/rector-migrate.php @@ -2,160 +2,9 @@ declare(strict_types=1); -use Faker\Generator; +use Faker\Rector; use Rector\Config; -use Rector\Transform; -// This file configures rector/rector to replace all deprecated property usages with their equivalent functions. return static function (Config\RectorConfig $rectorConfig): void { - $properties = [ - 'address', - 'amPm', - 'asciify', - 'biasedNumberBetween', - 'boolean', - 'bothify', - 'buildingNumber', - 'century', - 'chrome', - 'city', - 'citySuffix', - 'colorName', - 'company', - 'companyEmail', - 'companySuffix', - 'country', - 'countryCode', - 'countryISOAlpha3', - 'creditCardDetails', - 'creditCardExpirationDate', - 'creditCardExpirationDateString', - 'creditCardNumber', - 'creditCardType', - 'currencyCode', - 'date', - 'dateTime', - 'dateTimeAD', - 'dateTimeBetween', - 'dateTimeInInterval', - 'dateTimeThisCentury', - 'dateTimeThisDecade', - 'dateTimeThisMonth', - 'dateTimeThisYear', - 'dayOfMonth', - 'dayOfWeek', - 'domainName', - 'domainWord', - 'e164PhoneNumber', - 'email', - 'emoji', - 'file', - 'firefox', - 'firstName', - 'firstNameFemale', - 'firstNameMale', - 'freeEmail', - 'freeEmailDomain', - 'getDefaultTimezone', - 'hexColor', - 'hslColor', - 'hslColorAsArray', - 'iban', - 'image', - 'imageUrl', - 'imei', - 'internetExplorer', - 'iosMobileToken', - 'ipv4', - 'ipv6', - 'iso8601', - 'jobTitle', - 'languageCode', - 'lastName', - 'latitude', - 'lexify', - 'linuxPlatformToken', - 'linuxProcessor', - 'localCoordinates', - 'localIpv4', - 'locale', - 'longitude', - 'macAddress', - 'macPlatformToken', - 'macProcessor', - 'md5', - 'month', - 'monthName', - 'msedge', - 'name', - 'numerify', - 'opera', - 'paragraph', - 'paragraphs', - 'passthrough', - 'password', - 'phoneNumber', - 'postcode', - 'randomAscii', - 'randomDigitNotNull', - 'randomElement', - 'randomElements', - 'randomHtml', - 'randomKey', - 'randomLetter', - 'realText', - 'realTextBetween', - 'regexify', - 'rgbColor', - 'rgbColorAsArray', - 'rgbCssColor', - 'rgbaCssColor', - 'safari', - 'safeColorName', - 'safeEmail', - 'safeEmailDomain', - 'safeHexColor', - 'sentence', - 'sentences', - 'setDefaultTimezone', - 'sha1', - 'sha256', - 'shuffle', - 'shuffleArray', - 'shuffleString', - 'slug', - 'streetAddress', - 'streetName', - 'streetSuffix', - 'swiftBicNumber', - 'text', - 'time', - 'timezone', - 'title', - 'titleFemale', - 'titleMale', - 'tld', - 'toLower', - 'toUpper', - 'unixTime', - 'url', - 'userAgent', - 'userName', - 'uuid', - 'windowsPlatformToken', - 'word', - 'words', - 'year', - ]; - - $rectorConfig->ruleWithConfiguration( - Transform\Rector\Assign\PropertyFetchToMethodCallRector::class, - array_map(static function (string $property): Transform\ValueObject\PropertyFetchToMethodCall { - return new Transform\ValueObject\PropertyFetchToMethodCall( - Generator::class, - $property, - $property, - ); - }, $properties), - ); + $rectorConfig->rule(Rector\GeneratorPropertyFetchToMethodCallRector::class); }; diff --git a/src/Faker/Rector/GeneratorPropertyFetchToMethodCallRector.php b/src/Faker/Rector/GeneratorPropertyFetchToMethodCallRector.php new file mode 100644 index 0000000000..d7d35106d7 --- /dev/null +++ b/src/Faker/Rector/GeneratorPropertyFetchToMethodCallRector.php @@ -0,0 +1,216 @@ + + */ + private array $deprecatedPropertyNames = [ + 'address', + 'amPm', + 'asciify', + 'biasedNumberBetween', + 'boolean', + 'bothify', + 'buildingNumber', + 'century', + 'chrome', + 'city', + 'citySuffix', + 'colorName', + 'company', + 'companyEmail', + 'companySuffix', + 'country', + 'countryCode', + 'countryISOAlpha3', + 'creditCardDetails', + 'creditCardExpirationDate', + 'creditCardExpirationDateString', + 'creditCardNumber', + 'creditCardType', + 'currencyCode', + 'date', + 'dateTime', + 'dateTimeAD', + 'dateTimeBetween', + 'dateTimeInInterval', + 'dateTimeThisCentury', + 'dateTimeThisDecade', + 'dateTimeThisMonth', + 'dateTimeThisYear', + 'dayOfMonth', + 'dayOfWeek', + 'domainName', + 'domainWord', + 'e164PhoneNumber', + 'email', + 'emoji', + 'file', + 'firefox', + 'firstName', + 'firstNameFemale', + 'firstNameMale', + 'freeEmail', + 'freeEmailDomain', + 'getDefaultTimezone', + 'hexColor', + 'hslColor', + 'hslColorAsArray', + 'iban', + 'image', + 'imageUrl', + 'imei', + 'internetExplorer', + 'iosMobileToken', + 'ipv4', + 'ipv6', + 'iso8601', + 'jobTitle', + 'languageCode', + 'lastName', + 'latitude', + 'lexify', + 'linuxPlatformToken', + 'linuxProcessor', + 'localCoordinates', + 'localIpv4', + 'locale', + 'longitude', + 'macAddress', + 'macPlatformToken', + 'macProcessor', + 'md5', + 'month', + 'monthName', + 'msedge', + 'name', + 'numerify', + 'opera', + 'paragraph', + 'paragraphs', + 'passthrough', + 'password', + 'phoneNumber', + 'postcode', + 'randomAscii', + 'randomDigitNotNull', + 'randomElement', + 'randomElements', + 'randomHtml', + 'randomKey', + 'randomLetter', + 'realText', + 'realTextBetween', + 'regexify', + 'rgbColor', + 'rgbColorAsArray', + 'rgbCssColor', + 'rgbaCssColor', + 'safari', + 'safeColorName', + 'safeEmail', + 'safeEmailDomain', + 'safeHexColor', + 'sentence', + 'sentences', + 'setDefaultTimezone', + 'sha1', + 'sha256', + 'shuffle', + 'shuffleArray', + 'shuffleString', + 'slug', + 'streetAddress', + 'streetName', + 'streetSuffix', + 'swiftBicNumber', + 'text', + 'time', + 'timezone', + 'title', + 'titleFemale', + 'titleMale', + 'tld', + 'toLower', + 'toUpper', + 'unixTime', + 'url', + 'userAgent', + 'userName', + 'uuid', + 'windowsPlatformToken', + 'word', + 'words', + 'year', + ]; + + public function getNodeTypes(): array + { + return [ + Node\Expr\PropertyFetch::class, + ]; + } + + public function getRuleDefinition(): RuleDocGenerator\ValueObject\RuleDefinition + { + return new RuleDocGenerator\ValueObject\RuleDefinition( + sprintf( + 'Replaces references to deprecated properties of %s with method calls', + Generator::class, + ), + [ + new RuleDocGenerator\ValueObject\CodeSample\CodeSample( + <<<'CODE_SAMPLE' +$faker->address; +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +$faker->address(); +CODE_SAMPLE + ), + ], + ); + } + + /** + * @param Node\Expr\PropertyFetch $node + */ + public function refactor(Node $node): ?Node + { + $callerType = $this->getType($node->var); + + if (!$callerType instanceof Type\ObjectType) { + return null; + } + + if (!$callerType->isInstanceOf(Generator::class)->yes()) { + return null; + } + + if (!$node->name instanceof Node\Identifier) { + return null; + } + + $propertyName = $node->name->name; + + if (!in_array($propertyName, $this->deprecatedPropertyNames, true)) { + return null; + } + + return new Node\Expr\MethodCall( + $node->var, + new Node\Identifier($propertyName), + ); + } +}