-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove dependency on doctrine/common
We were only relying on it for functionality related to proxies, which is very little code.
- Loading branch information
Showing
6 changed files
with
183 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\ORM\Proxy; | ||
|
||
use Closure; | ||
|
||
use function file_exists; | ||
use function ltrim; | ||
use function spl_autoload_register; | ||
use function str_replace; | ||
use function strlen; | ||
use function strpos; | ||
use function substr; | ||
|
||
use const DIRECTORY_SEPARATOR; | ||
|
||
/** | ||
* Special Autoloader for Proxy classes, which are not PSR-0 compliant. | ||
*/ | ||
final class Autoloader | ||
{ | ||
/** | ||
* Resolves proxy class name to a filename based on the following pattern. | ||
* | ||
* 1. Remove Proxy namespace from class name. | ||
* 2. Remove namespace separators from remaining class name. | ||
* 3. Return PHP filename from proxy-dir with the result from 2. | ||
* | ||
* @psalm-param class-string $className | ||
* | ||
* @throws NotAProxyClass | ||
*/ | ||
public static function resolveFile(string $proxyDir, string $proxyNamespace, string $className): string | ||
{ | ||
if (strpos($className, $proxyNamespace) !== 0) { | ||
throw new NotAProxyClass($className, $proxyNamespace); | ||
} | ||
|
||
// remove proxy namespace from class name | ||
$classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace)); | ||
|
||
// remove namespace separators from remaining class name | ||
$fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace); | ||
|
||
return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php'; | ||
} | ||
|
||
/** | ||
* Registers and returns autoloader callback for the given proxy dir and namespace. | ||
* | ||
* @param Closure(string, string, class-string): void|null $notFoundCallback Invoked when the proxy file is not found. | ||
* | ||
* @return Closure(string): void | ||
*/ | ||
public static function register( | ||
string $proxyDir, | ||
string $proxyNamespace, | ||
Closure|null $notFoundCallback = null, | ||
): Closure { | ||
$proxyNamespace = ltrim($proxyNamespace, '\\'); | ||
|
||
$autoloader = /** @param class-string $className */ static function (string $className) use ($proxyDir, $proxyNamespace, $notFoundCallback): void { | ||
if ($proxyNamespace === '') { | ||
return; | ||
} | ||
|
||
if (strpos($className, $proxyNamespace) !== 0) { | ||
return; | ||
} | ||
|
||
$file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); | ||
|
||
if ($notFoundCallback && ! file_exists($file)) { | ||
$notFoundCallback($proxyDir, $proxyNamespace, $className); | ||
} | ||
|
||
require $file; | ||
}; | ||
|
||
spl_autoload_register($autoloader); | ||
|
||
return $autoloader; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\ORM\Proxy; | ||
|
||
use Doctrine\ORM\Exception\ORMException; | ||
use InvalidArgumentException; | ||
|
||
use function sprintf; | ||
|
||
final class NotAProxyClass extends InvalidArgumentException implements ORMException | ||
{ | ||
public function __construct(string $className, string $proxyNamespace) | ||
{ | ||
parent::__construct(sprintf( | ||
'The class "%s" is not part of the proxy namespace "%s"', | ||
$className, | ||
$proxyNamespace, | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\Proxy; | ||
|
||
use Doctrine\ORM\Proxy\Autoloader; | ||
use PHPUnit\Framework\Attributes\DataProvider; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
use function class_exists; | ||
use function file_exists; | ||
use function file_put_contents; | ||
use function sys_get_temp_dir; | ||
use function unlink; | ||
|
||
use const DIRECTORY_SEPARATOR; | ||
|
||
class AutoloaderTest extends TestCase | ||
{ | ||
/** @return iterable<string, array{string, string, class-string, string}> */ | ||
public static function dataResolveFile(): iterable | ||
{ | ||
return [ | ||
['/tmp', 'MyProxy', 'MyProxy\RealClass', '/tmp' . DIRECTORY_SEPARATOR . 'RealClass.php'], | ||
['/tmp', 'MyProxy', 'MyProxy\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'], | ||
['/tmp', 'MyProxy\Subdir', 'MyProxy\Subdir\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'], | ||
['/tmp', 'MyProxy', 'MyProxy\__CG__\Other\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__OtherRealClass.php'], | ||
]; | ||
} | ||
|
||
/** @param class-string $className */ | ||
#[DataProvider('dataResolveFile')] | ||
public function testResolveFile( | ||
string $proxyDir, | ||
string $proxyNamespace, | ||
string $className, | ||
string $expectedProxyFile, | ||
): void { | ||
$actualProxyFile = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); | ||
self::assertEquals($expectedProxyFile, $actualProxyFile); | ||
} | ||
|
||
public function testAutoload(): void | ||
{ | ||
if (file_exists(sys_get_temp_dir() . '/AutoloaderTestClass.php')) { | ||
unlink(sys_get_temp_dir() . '/AutoloaderTestClass.php'); | ||
} | ||
|
||
$autoloader = Autoloader::register(sys_get_temp_dir(), 'ProxyAutoloaderTest', static function ($proxyDir, $proxyNamespace, $className): void { | ||
file_put_contents(sys_get_temp_dir() . '/AutoloaderTestClass.php', '<?php namespace ProxyAutoloaderTest; class AutoloaderTestClass {} '); | ||
}); | ||
|
||
self::assertTrue(class_exists('ProxyAutoloaderTest\AutoloaderTestClass', true)); | ||
unlink(sys_get_temp_dir() . '/AutoloaderTestClass.php'); | ||
} | ||
} |