• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitExpert / phpstan-magento / 13551485180

26 Feb 2025 07:06PM UTC coverage: 87.989% (-0.3%) from 88.269%
13551485180

push

github

web-flow
Merge pull request #337 from shochdoerfer/fix/ci_pipeline

Fix CI pipeline issues

630 of 716 relevant lines covered (87.99%)

1.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.57
/src/bitExpert/PHPStan/Magento/Autoload/ProxyAutoloader.php
1
<?php
2

3
/*
4
 * This file is part of the phpstan-magento package.
5
 *
6
 * (c) bitExpert AG
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
declare(strict_types=1);
12

13
namespace bitExpert\PHPStan\Magento\Autoload;
14

15
use bitExpert\PHPStan\Magento\Autoload\DataProvider\ClassLoaderProvider;
16
use PHPStan\Cache\Cache;
17

18
class ProxyAutoloader implements Autoloader
19
{
20
    /**
21
     * @var Cache
22
     */
23
    private $cache;
24
    /**
25
     * @var ClassLoaderProvider
26
     */
27
    private $classLoaderProvider;
28

29
    /**
30
     * ProxyAutoloader constructor.
31
     *
32
     * @param Cache $cache
33
     * @param ClassLoaderProvider $classLoaderProvider
34
     */
35
    public function __construct(Cache $cache, ClassLoaderProvider $classLoaderProvider)
36
    {
37
        $this->cache = $cache;
4✔
38
        $this->classLoaderProvider = $classLoaderProvider;
4✔
39
    }
40

41
    public function autoload(string $class): void
42
    {
43
        if (preg_match('#\\\Proxy#', $class) !== 1) {
4✔
44
            return;
1✔
45
        }
46

47
        // fix for PHPStan 1.7.5 and later: Classes generated by autoloaders are supposed to "win" against
48
        // local classes in your project. We need to check first if classes exists locally before generating them!
49
        $pathToLocalClass = $this->classLoaderProvider->findFile($class);
3✔
50
        if ($pathToLocalClass === false) {
3✔
51
            $pathToLocalClass = $this->cache->load($class, '');
2✔
52
            if ($pathToLocalClass === null) {
2✔
53
                $this->cache->save($class, '', $this->getFileContents($class));
1✔
54
                $pathToLocalClass = $this->cache->load($class, '');
1✔
55
            }
56
        }
57

58
        require_once($pathToLocalClass);
3✔
59
    }
60

61
    /**
62
     * Generate the proxy file content as Magento would.
63
     *
64
     * @param string $class
65
     * @return string
66
     * @throws \ReflectionException
67
     */
68
    protected function getFileContents(string $class): string
69
    {
70
        $namespace = explode('\\', ltrim($class, '\\'));
1✔
71
        $proxyClassname = array_pop($namespace);
1✔
72
        $proxyBaseClass = '';
1✔
73
        $originalClassname = implode('\\', $namespace);
1✔
74
        $namespace = implode('\\', $namespace);
1✔
75
        $proxyInterface = ['\Magento\Framework\ObjectManager\NoninterceptableInterface'];
1✔
76
        $methods = '';
1✔
77

78
        /** @var class-string $originalClassname */
79
        $reflectionClass = new \ReflectionClass($originalClassname);
1✔
80
        if ($reflectionClass->isInterface()) {
1✔
81
            $proxyInterface[] = '\\' . $originalClassname;
×
82
            foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
×
83
                $returnType = $method->getReturnType();
×
84
                if ($returnType instanceof \ReflectionNamedType) {
×
85
                    $returnType = ': ' . $returnType->getName();
×
86
                } else {
87
                    $returnType = '';
×
88
                }
89

90
                $params = [];
×
91
                foreach ($method->getParameters() as $parameter) {
×
92
                    $paramType = $parameter->getType();
×
93
                    if ($paramType instanceof \ReflectionNamedType) {
×
94
                        if ($paramType->isBuiltin()) {
×
95
                            $paramType = $paramType->getName() . ' ';
×
96
                        } else {
97
                            $paramType = '\\' . $paramType->getName() . ' ';
×
98
                        }
99
                    } else {
100
                        $paramType = '';
×
101
                    }
102

103
                    $defaultValue = '';
×
104
                    if ($parameter->isDefaultValueAvailable()) {
×
105
                        switch ($parameter->getDefaultValue()) {
×
106
                            case null:
107
                                $defaultValue = ' = NULL';
×
108
                                break;
×
109
                            case false:
×
110
                                $defaultValue = ' = false';
×
111
                                break;
×
112
                            default:
113
                                if (is_string($parameter->getDefaultValue())) {
×
114
                                    $defaultValue = ' = ' . $parameter->getDefaultValue();
×
115
                                }
116
                                break;
×
117
                        }
118
                    }
119

120
                    $params[] = $paramType . '$' . $parameter->getName() . $defaultValue;
×
121
                }
122

123
                $methods .= '    public function ' . $method->getName() . '(' . implode(', ', $params) . ')' .
×
124
                    $returnType . " {}\n\n";
×
125
            }
126
        } else {
127
            $proxyBaseClass = ' extends \\' . $originalClassname;
1✔
128
        }
129

130
        $template = "<?php\n";
1✔
131

132
        if ($namespace !== '') {
1✔
133
            $template .= "namespace {NAMESPACE};\n\n";
1✔
134
        }
135

136
        $template .= "/**\n";
1✔
137
        $template .= " * Proxy class for @see {CLASSNAME}\n";
1✔
138
        $template .= " */\n";
1✔
139
        $template .= "class {PROXY_CLASSNAME}{PROXY_BASE_CLASSNAME} implements {PROXY_INTERFACE}\n";
1✔
140
        $template .= "{\n";
1✔
141
        $template .= "    /**\n";
1✔
142
        $template .= "     * @return array\n";
1✔
143
        $template .= "     */\n";
1✔
144
        $template .= "    public function __sleep() {}\n";
1✔
145
        $template .= "    /**\n";
1✔
146
        $template .= "     * Retrieve ObjectManager from global scope\n";
1✔
147
        $template .= "     */\n";
1✔
148
        $template .= "    public function __wakeup() {}\n";
1✔
149
        $template .= "    /**\n";
1✔
150
        $template .= "     * Clone proxied instance\n";
1✔
151
        $template .= "     */\n";
1✔
152
        $template .= "    public function __clone() {}\n";
1✔
153
        $template .= "{METHODS}";
1✔
154
        $template .= "}\n";
1✔
155

156
        return str_replace(
1✔
157
            [
1✔
158
                '{NAMESPACE}',
1✔
159
                '{CLASSNAME}',
1✔
160
                '{PROXY_BASE_CLASSNAME}',
1✔
161
                '{PROXY_CLASSNAME}',
1✔
162
                '{PROXY_INTERFACE}',
1✔
163
                '{METHODS}'
1✔
164
            ],
1✔
165
            [
1✔
166
                $namespace,
1✔
167
                $originalClassname,
1✔
168
                $proxyBaseClass,
1✔
169
                $proxyClassname,
1✔
170
                implode(', ', $proxyInterface),
1✔
171
                $methods
1✔
172
            ],
1✔
173
            $template
1✔
174
        );
1✔
175
    }
176

177
    public function register(): void
178
    {
179
        \spl_autoload_register([$this, 'autoload'], true, false);
1✔
180
    }
181

182
    public function unregister(): void
183
    {
184
        \spl_autoload_unregister([$this, 'autoload']);
1✔
185
    }
186
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc