opencart/tools/phpstan/RegistryPropertyReflectionExtension.php
2025-02-24 11:37:11 +01:00

98 lines
3.6 KiB
PHP

<?php
namespace Tools\PHPStan;
use Opencart\System\Engine\Registry;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeCombinator;
class RegistryPropertyReflectionExtension implements PropertiesClassReflectionExtension {
private const DEFAULTS = [
'config' => \Opencart\System\Engine\Config::class,
'event' => \Opencart\System\Engine\Event::class,
'factory' => \Opencart\System\Engine\Factory::class,
'load' => \Opencart\System\Engine\Loader::class,
'autoloader' => \Opencart\System\Engine\Autoloader::class,
'cache' => \Opencart\System\Library\Cache::class,
'cart' => \Opencart\System\Library\Cart\Cart::class,
'currency' => \Opencart\System\Library\Cart\Currency::class,
'customer' => \Opencart\System\Library\Cart\Customer::class,
'length' => \Opencart\System\Library\Cart\Length::class,
'tax' => \Opencart\System\Library\Cart\Tax::class,
'weight' => \Opencart\System\Library\Cart\Weight::class,
'db' => \Opencart\System\Library\DB::class,
'document' => \Opencart\System\Library\Document::class,
'language' => \Opencart\System\Library\Language::class,
'log' => \Opencart\System\Library\Log::class,
'request' => \Opencart\System\Library\Request::class,
'response' => \Opencart\System\Library\Response::class,
'session' => \Opencart\System\Library\Session::class,
'template' => \Opencart\System\Library\Template::class,
'url' => \Opencart\System\Library\Url::class,
'user' => \Opencart\System\Library\Cart\User::class,
];
public function __construct(private ReflectionProvider $reflectionProvider) {}
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool {
if (!$classReflection->is(Registry::class)) {
return false;
}
if (isset(self::DEFAULTS[$propertyName])) {
return true;
}
return preg_match('/^(controller|model)_(.+)$/', $propertyName, $matches) === 1;
}
public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection {
if (isset(self::DEFAULTS[$propertyName])) {
$type = new ObjectType(self::DEFAULTS[$propertyName]);
$writable = false;
if ($propertyName === 'user') {
$writable = true;
$type = TypeCombinator::addNull($type);
}
return new LoadedProperty($classReflection, $type, $writable);
}
preg_match('/^(controller|model)_(.+)$/', $propertyName, $matches);
$classType = $this->convertSnakeToStudly($matches[1]);
$commonName = $this->convertSnakeToStudly($matches[2]);
$type = null;
foreach (['Admin', 'Catalog', 'Install'] as $domain) {
$className1 = '\Opencart\\' . $domain . '\\' . $classType . '\\' . $commonName;
$className2 = preg_replace('/\\\(?=[^\\\]+$)/', '', $className1, 1);
foreach ([$className1, $className2] as $className) {
if ($this->reflectionProvider->hasClass($className)) {
$found = new ObjectType($className);
if ($classType === 'Model') {
$found = new GenericObjectType('\Opencart\System\Engine\Proxy', [$found]);
}
$type = $type ? TypeCombinator::union($type, $found) : $found;
}
}
}
if ($type) {
$type = TypeCombinator::addNull($type);
} else {
$type = new NullType();
}
return new LoadedProperty($classReflection, $type);
}
private function convertSnakeToStudly(string $value): string {
return str_replace(' ', '\\', ucwords(str_replace('_', ' ', $value)));
}
}