Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ jobs:
run: |
echo "session.save_path=$PWD/var/sessions/test" > php.ini
echo "memory_limit=1012M" >> php.ini
php -c php.ini -dpcov.enabled=1 vendor/bin/phpunit --exclude-group cache-clear --exclude-group cache-clear-install --exclude-group update-schema-doctrine --coverage-cobertura=coverage1.xml --testdox
# rector グループ (AttributeArgumentsOrderRectorTest) は rector 同梱の
# nikic/php-parser を読み込み、pcov 有効時に本体の nikic/php-parser と衝突して
# fatal (Cannot redeclare PhpParser\Node\Scalar\Float_) になるため除外する。
php -c php.ini -dpcov.enabled=1 vendor/bin/phpunit --exclude-group cache-clear --exclude-group cache-clear-install --exclude-group update-schema-doctrine --exclude-group rector --coverage-cobertura=coverage1.xml --testdox
# GitHub のコードカバレッジ (Code Quality) にアップロードする。
# - PHPUnit ステップの outcome でガードする: 上記の continue-on-error により
# テストがクラッシュしてもジョブは成功扱いのままになり、coverage1.xml が
Expand Down
28 changes: 28 additions & 0 deletions src/Eccube/Rector/CodingStyle/AttributeArgumentsOrderRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@
*/
final class AttributeArgumentsOrderRector extends AbstractRector
{
/**
* 非推奨アノテーションクラス → 新しい Attribute クラスのマッピング
*
* AnnotationToAttributeRector が Sensio FrameworkExtraBundle のアノテーションを
* Attribute に変換した直後、まだ use 文が Sensio クラスを指している段階で本ルールが走ると、
* リフレクションで Sensio 側のコンストラクタ第一パラメータ(例: Template の $data)を
* 読み取ってしまい、後段の RenameClassRector がクラスだけ置換しても誤った名前付き引数
* (例: #[Template(data: '...')])が残る。
*
* これを避けるため、リフレクション対象のクラス名を「新しい Attribute クラス」へ事前に
* 差し替え、置換後のクラスの正しいパラメータ順序(例: Template の $template)を使う。
* 差し替えるのはリフレクション対象のみで、出力される Attribute 名ノードには手を加えない。
*
* @var array<string, class-string>
*
* @see https://github.com/EC-CUBE/ec-cube/issues/6540
*/
private const DEPRECATED_CLASS_MAPPING = [
'Sensio\Bundle\FrameworkExtraBundle\Configuration\Template' => \Symfony\Bridge\Twig\Attribute\Template::class,
'Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache' => \Symfony\Component\HttpKernel\Attribute\Cache::class,
'Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted' => \Symfony\Component\Security\Http\Attribute\IsGranted::class,
'Sensio\Bundle\FrameworkExtraBundle\Configuration\Security' => \Symfony\Component\Security\Http\Attribute\IsGranted::class,
];

/**
* コンストラクタパラメータ順序のキャッシュ
*
Expand Down Expand Up @@ -195,6 +219,10 @@ private function resolveAttributeClassName(Attribute $attribute): string
*/
private function getConstructorParameterOrder(string $className): array
{
// 非推奨アノテーションクラスは新しい Attribute クラスへ差し替えてからリフレクションする
// (#6540: Sensio クラスの第一パラメータ名が残ってしまう問題への対策)
$className = self::DEPRECATED_CLASS_MAPPING[$className] ?? $className;

// キャッシュをチェック
if (isset($this->constructorParameterOrderCache[$className])) {
return $this->constructorParameterOrderCache[$className];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Eccube\Tests\Rector\CodingStyle;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

/**
* Rector を実行するため rector 同梱の nikic/php-parser を読み込む。
* pcov 有効のカバレッジ実行では本体の nikic/php-parser と衝突して
* "Cannot redeclare class PhpParser\Node\Scalar\Float_" で fatal になるため、
* カバレッジ実行から除外できるよう rector グループを付与する
* (coverage.yml で --exclude-group rector)。
*/
#[Group('rector')]
final class AttributeArgumentsOrderRectorTest extends AbstractRectorTestCase
{
#[DataProvider(methodName: 'provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): \Iterator
{
return self::yieldFilesFromDirectory(__DIR__.'/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__.'/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Eccube\Tests\Rector\CodingStyle\Fixture;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DeprecatedTemplateAttribute
{
#[Template('@admin/Content/cache.twig')]
public function index()
{
}
}

?>
-----
<?php

namespace Eccube\Tests\Rector\CodingStyle\Fixture;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DeprecatedTemplateAttribute
{
#[Template(template: '@admin/Content/cache.twig')]
public function index()
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Eccube\Tests\Rector\CodingStyle\Fixture;

use Symfony\Component\Routing\Attribute\Route;

class RouteAttributeOrder
{
#[Route('/contact', requirements: ['id' => '\d+'], name: 'contact', methods: ['GET', 'POST'])]
public function contact()
{
}
}

?>
-----
<?php

namespace Eccube\Tests\Rector\CodingStyle\Fixture;

use Symfony\Component\Routing\Attribute\Route;

class RouteAttributeOrder
{
#[Route(path: '/contact', name: 'contact', requirements: ['id' => '\d+'], methods: ['GET', 'POST'])]
public function contact()
{
}
}

?>
22 changes: 22 additions & 0 deletions tests/Eccube/Tests/Rector/CodingStyle/config/configured_rule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Eccube\Rector\CodingStyle\AttributeArgumentsOrderRector;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
->withRules([
AttributeArgumentsOrderRector::class,
]);
8 changes: 8 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@
*/

use Symfony\Component\Dotenv\Dotenv;
use Symfony\Polyfill\Php84\Php84;

require dirname(__DIR__).'/vendor/autoload.php';

// symfony/polyfill-php84 の Php84 クラスをテスト実行前に確実にロードしておく。
// テスト env では Symfony の DebugClassLoader が有効で、kernel 起動後に
// グローバル関数 bcround() から Php84 を遅延 autoload すると
// Php84::bcround() が解決できず、PHP 8.2/8.3 で税計算(bcround)を通す
// 全テストが「Call to undefined method」で失敗する。事前ロードで回避する。
class_exists(Php84::class);

if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
require dirname(__DIR__).'/config/bootstrap.php';
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
Expand Down
Loading