From b7ea05900e8c2e87b60f0c9bf79443a99c1a584b Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Mon, 27 Nov 2017 22:34:32 +1300 Subject: [PATCH] FIX Support self::class text collection --- src/i18n/TextCollection/i18nTextCollector.php | 25 ++++++++++++++++--- tests/php/i18n/i18nTextCollectorTest.php | 12 +++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/i18n/TextCollection/i18nTextCollector.php b/src/i18n/TextCollection/i18nTextCollector.php index e724e28a2..6d57f7ad9 100644 --- a/src/i18n/TextCollection/i18nTextCollector.php +++ b/src/i18n/TextCollection/i18nTextCollector.php @@ -558,6 +558,7 @@ class i18nTextCollector $inNamespace = false; $inClass = false; // after `class` but before `{` $inArrayClosedBy = false; // Set to the expected closing token, or false if not in array + $inSelf = false; // Tracks progress of collecting self::class $currentEntity = array(); $currentClass = []; // Class components $previousToken = null; @@ -584,10 +585,20 @@ class i18nTextCollector if ($id === T_CLASS) { // Skip if previous token was '::'. E.g. 'Object::class' if (is_array($previousToken) && $previousToken[0] === T_DOUBLE_COLON) { + if ($inSelf) { + // Handle self::class by allowing logic further down + // for __CLASS__ to handle an array of class parts + $id = T_CLASS_C; + $inSelf = false; + } else { + // Don't handle other ::class definitions. We can't determine which + // class was invoked, so parent::class is not possible at this point. + continue; + } + } else { + $inClass = true; continue; } - $inClass = true; - continue; } if ($inClass && $id === T_STRING) { $currentClass[] = $text; @@ -614,7 +625,7 @@ class i18nTextCollector // If inside this translation, some elements might be unreachable if (in_array($id, [T_VARIABLE, T_STATIC]) || - ($id === T_STRING && in_array($text, ['self', 'static', 'parent'])) + ($id === T_STRING && in_array($text, ['static', 'parent'])) ) { // Un-collectable strings such as _t(static::class.'.KEY'). // Should be provided by i18nEntityProvider instead @@ -625,6 +636,12 @@ class i18nTextCollector continue; } + // Start collecting self::class declarations + if ($id === T_STRING && $text === 'self') { + $inSelf = true; + continue; + } + // Check text if ($id == T_CONSTANT_ENCAPSED_STRING) { // Fixed quoting escapes, and remove leading/trailing quotes @@ -648,7 +665,7 @@ class i18nTextCollector throw new LogicException("Invalid string escape: " .$text); } } elseif ($id === T_CLASS_C) { - // Evaluate __CLASS__ . '.KEY' concatenation + // Evaluate __CLASS__ . '.KEY' and self::class concatenation $text = implode('\\', $currentClass); } else { continue; diff --git a/tests/php/i18n/i18nTextCollectorTest.php b/tests/php/i18n/i18nTextCollectorTest.php index ddbf43519..f02abe58e 100644 --- a/tests/php/i18n/i18nTextCollectorTest.php +++ b/tests/php/i18n/i18nTextCollectorTest.php @@ -323,13 +323,21 @@ class MyClass extends Base implements SomeService { "Slash=\\\\, Quote=\\"" ); } + public function getMagicConstantStringFromSelf() + { + return _t( + self::class . '.SELF_CLASS', + 'Self Class' + ); + } } PHP; $this->assertEquals( [ 'SilverStripe\\Framework\\Core\\MyClass.NEWLINES' => "New Lines", 'SilverStripe\\Framework\\MyClass.ANOTHER_STRING' => 'Slash=\\, Quote=\'', - 'SilverStripe\\Framework\\MyClass.DOUBLE_STRING' => 'Slash=\\, Quote="' + 'SilverStripe\\Framework\\MyClass.DOUBLE_STRING' => 'Slash=\\, Quote="', + 'SilverStripe\\Framework\\Core\\MyClass.SELF_CLASS' => 'Self Class', ], $c->collectFromCode($php, null, $mymodule) ); @@ -434,7 +442,7 @@ PHP; $php = <<