jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/338509 )
Change subject: AutoloadGenerator: Add support for class_alias()
......................................................................
AutoloadGenerator: Add support for class_alias()
Blob, Field, DatabaseBase are now auto-detected.
Change-Id: Ib8fae2ec3fbb3f5e4aca7965f81631c5f0485ea1
---
M includes/libs/rdbms/database/Database.php
M includes/libs/rdbms/encasing/Blob.php
M includes/libs/rdbms/field/Field.php
M includes/utils/AutoloadGenerator.php
A tests/phpunit/includes/utils/ClassCollectorTest.php
M tests/phpunit/structure/AutoLoaderTest.php
6 files changed, 122 insertions(+), 13 deletions(-)
Approvals:
Aaron Schulz: Looks good to me, approved
jenkins-bot: Verified
diff --git a/includes/libs/rdbms/database/Database.php
b/includes/libs/rdbms/database/Database.php
index 9d800a2..1c5c77e 100644
--- a/includes/libs/rdbms/database/Database.php
+++ b/includes/libs/rdbms/database/Database.php
@@ -3467,4 +3467,4 @@
}
}
-class_alias( 'Database', 'DatabaseBase' );
+class_alias( Database::class, 'DatabaseBase' );
diff --git a/includes/libs/rdbms/encasing/Blob.php
b/includes/libs/rdbms/encasing/Blob.php
index d394692..db5b7e5 100644
--- a/includes/libs/rdbms/encasing/Blob.php
+++ b/includes/libs/rdbms/encasing/Blob.php
@@ -18,4 +18,4 @@
}
}
-class_alias( 'Wikimedia\Rdbms\Blob', 'Blob' );
+class_alias( Blob::class, 'Blob' );
diff --git a/includes/libs/rdbms/field/Field.php
b/includes/libs/rdbms/field/Field.php
index 7a25f03..7918f36 100644
--- a/includes/libs/rdbms/field/Field.php
+++ b/includes/libs/rdbms/field/Field.php
@@ -32,4 +32,4 @@
function isNullable();
}
-class_alias( 'Wikimedia\Rdbms\Field', 'Field' );
+class_alias( Field::class, 'Field' );
diff --git a/includes/utils/AutoloadGenerator.php
b/includes/utils/AutoloadGenerator.php
index 0bfd4a27..55e228a 100644
--- a/includes/utils/AutoloadGenerator.php
+++ b/includes/utils/AutoloadGenerator.php
@@ -291,15 +291,6 @@
foreach ( glob( $this->basepath . '/*.php' ) as $file ) {
$this->readFile( $file );
}
-
- // Legacy aliases (1.28)
- $this->forceClassPath( 'DatabaseBase',
- $this->basepath .
'/includes/libs/rdbms/database/Database.php' );
- // Legacy aliases (1.29)
- $this->forceClassPath( 'Blob',
- $this->basepath .
'/includes/libs/rdbms/encasing/Blob.php' );
- $this->forceClassPath( 'Field',
- $this->basepath .
'/includes/libs/rdbms/field/Field.php' );
}
}
@@ -329,6 +320,11 @@
protected $tokens;
/**
+ * @var array Class alias with target/name fields
+ */
+ protected $alias;
+
+ /**
* @var string $code PHP code (including <?php) to detect class names
from
* @return array List of FQCN detected within the tokens
*/
@@ -336,6 +332,7 @@
$this->namespace = '';
$this->classes = [];
$this->startToken = null;
+ $this->alias = null;
$this->tokens = [];
foreach ( token_get_all( $code ) as $token ) {
@@ -358,6 +355,8 @@
if ( is_string( $token ) ) {
return;
}
+ // Note: When changing class name discovery logic,
+ // AutoLoaderTest.php may also need to be updated.
switch ( $token[0] ) {
case T_NAMESPACE:
case T_CLASS:
@@ -365,6 +364,12 @@
case T_TRAIT:
case T_DOUBLE_COLON:
$this->startToken = $token;
+ break;
+ case T_STRING:
+ if ( $token[1] === 'class_alias' ) {
+ $this->startToken = $token;
+ $this->alias = [];
+ }
}
}
@@ -388,6 +393,49 @@
}
break;
+ case T_STRING:
+ if ( $this->alias !== null ) {
+ // Flow 1 - Two string literals:
+ // - T_STRING class_alias
+ // - '('
+ // - T_CONSTANT_ENCAPSED_STRING 'TargetClass'
+ // - ','
+ // - T_WHITESPACE
+ // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+ // - ')'
+ // Flow 2 - Use of ::class syntax for first
parameter
+ // - T_STRING class_alias
+ // - '('
+ // - T_STRING TargetClass
+ // - T_DOUBLE_COLON ::
+ // - T_CLASS class
+ // - ','
+ // - T_WHITESPACE
+ // - T_CONSTANT_ENCAPSED_STRING 'AliasName'
+ // - ')'
+ if ( $token === '(' ) {
+ // Start of a function call to
class_alias()
+ $this->alias = [ 'target' => false,
'name' => false ];
+ } elseif ( $token === ',' ) {
+ // Record that we're past the first
parameter
+ if ( $this->alias['target'] === false )
{
+ $this->alias['target'] = true;
+ }
+ } elseif ( is_array( $token ) && $token[0] ===
T_CONSTANT_ENCAPSED_STRING ) {
+ if ( $this->alias['target'] === true ) {
+ // We already saw a first
argument, this must be the second.
+ // Strip quotes from the string
literal.
+ $this->alias['name'] = substr(
$token[1], 1, -1 );
+ }
+ } elseif ( $token === ')' ) {
+ // End of function call
+ $this->classes[] = $this->alias['name'];
+ $this->alias = null;
+ $this->startToken = null;
+ }
+ }
+ break;
+
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
diff --git a/tests/phpunit/includes/utils/ClassCollectorTest.php
b/tests/phpunit/includes/utils/ClassCollectorTest.php
new file mode 100644
index 0000000..e8a228e
--- /dev/null
+++ b/tests/phpunit/includes/utils/ClassCollectorTest.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @covers ClassCollector
+ */
+class ClassCollectorTest extends PHPUnit_Framework_TestCase {
+
+ public static function provideCases() {
+ return [
+ [
+ "class Foo {}",
+ [ 'Foo' ],
+ ],
+ [
+ "namespace Example;\nclass Foo {}\nclass Bar
{}",
+ [ 'Example\Foo', 'Example\Bar' ],
+ ],
+ [
+ "class_alias( 'Foo', 'Bar' );",
+ [ 'Bar' ],
+ ],
+ [
+ "namespace Example;\nclass Foo {}\nclass_alias(
'Example\Foo', 'Foo' );",
+ [ 'Example\Foo', 'Foo' ],
+ ],
+ [
+ "namespace Example;\nclass Foo {}\nclass_alias(
'Example\Foo', 'Bar' );",
+ [ 'Example\Foo', 'Bar' ],
+ ],
+ [
+ "class_alias( Foo::class, 'Bar' );",
+ [ 'Bar' ],
+ ],
+ [
+ "namespace Example;\nclass Foo {}\nclass_alias(
Foo::class, 'Bar' );",
+ [ 'Example\Foo', 'Bar' ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideCases
+ */
+ public function testGetClasses( $code, array $classes, $message = null
) {
+ $cc = new ClassCollector();
+ $this->assertEquals( $classes, $cc->getClasses( "<?php\n$code"
), $message );
+ }
+}
diff --git a/tests/phpunit/structure/AutoLoaderTest.php
b/tests/phpunit/structure/AutoLoaderTest.php
index f36b51a..d81e8c6 100644
--- a/tests/phpunit/structure/AutoLoaderTest.php
+++ b/tests/phpunit/structure/AutoLoaderTest.php
@@ -68,6 +68,7 @@
}
// We could use token_get_all() here, but this is faster
+ // Note: Keep in sync with ClassCollector
$matches = [];
preg_match_all( '/
^ [\t ]* (?:
@@ -77,6 +78,11 @@
class_alias \s* \( \s*
([\'"]) (?P<original> [^\'"]+)
\g{-2} \s* , \s*
([\'"]) (?P<alias> [^\'"]+ )
\g{-2} \s*
+ \) \s* ;
+ |
+ class_alias \s* \( \s*
+ (?P<originalStatic>
[a-zA-Z0-9_]+)::class \s* , \s*
+ ([\'"]) (?P<aliasString>
[^\'"]+ ) \g{-2} \s*
\) \s* ;
)
/imx', $contents, $matches, PREG_SET_ORDER );
@@ -95,11 +101,18 @@
foreach ( $matches as $match ) {
if ( !empty( $match['class'] ) ) {
+ // 'class Foo {}'
$class = $fileNamespace .
$match['class'];
$actual[$class] = $file;
$classesInFile[$class] = true;
} else {
- $aliasesInFile[$match['alias']] =
$match['original'];
+ if ( !empty( $match['original'] ) ) {
+ // 'class_alias( "Foo", "Bar"
);'
+ $aliasesInFile[$match['alias']]
= $match['original'];
+ } else {
+ // 'class_alias( Foo::class,
"Bar" );'
+
$aliasesInFile[$match['aliasString']] = $fileNamespace .
$match['originalStatic'];
+ }
}
}
--
To view, visit https://gerrit.wikimedia.org/r/338509
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ib8fae2ec3fbb3f5e4aca7965f81631c5f0485ea1
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Krinkle <[email protected]>
Gerrit-Reviewer: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: Florianschmidtwelzow <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Reedy <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits