GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 1e1cfe...2af5da )
by Steevan
02:22
created

ReadOnlyHydrator::createEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 11
rs 9.4285
cc 1
eloc 6
nc 1
nop 2
1
<?php
2
3
namespace steevanb\DoctrineReadOnlyHydrator\Hydrator;
4
5
use Doctrine\Common\Proxy\AbstractProxyFactory;
6
use Doctrine\Common\Proxy\ProxyGenerator;
7
use Doctrine\ORM\Mapping\ClassMetadata;
8
use steevanb\DoctrineReadOnlyHydrator\Entity\ReadOnlyEntityInterface;
9
use steevanb\DoctrineReadOnlyHydrator\Exception\PrivateMethodShouldNotAccessPropertiesException;
10
11
class ReadOnlyHydrator extends SimpleObjectHydrator
12
{
13
    const HYDRATOR_NAME = 'readOnly';
14
15
    /**
16
     * @param ClassMetadata $classMetaData
17
     * @param array $data
18
     * @return mixed
19
     * @throws \Exception
20
     */
21
    protected function createEntity(ClassMetadata $classMetaData, array $data)
22
    {
23
        $className = $this->getEntityClassName($classMetaData, $data);
24
//        $this->generateProxyFile($classMetaData, $data);
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
25
26
        require_once($this->getProxyFilePath($className));
27
        $proxyClassName = $this->getProxyNamespace($className) . '\\' . $this->getProxyClassName($className);
28
        $entity = new $proxyClassName(array_keys($data));
29
30
        return $entity;
31
    }
32
33
    /**
34
     * @param ClassMetadata $classMetaData
35
     * @param array $data
36
     * @return $this
37
     */
38
    protected function generateProxyFile(ClassMetadata $classMetaData, array $data)
39
    {
40
        $entityClassName = $this->getEntityClassName($classMetaData, $data);
41
        $proxyMethodsCode = implode("\n\n", $this->getPhpForProxyMethods($classMetaData, $entityClassName));
42
        $proxyNamespace = $this->getProxyNamespace($entityClassName);
43
        $proxyClassName = $this->getProxyClassName($entityClassName);
44
        $generator = static::class;
45
        $readOnlyInterface = ReadOnlyEntityInterface::class;
46
47
        $php = <<<PHP
48
<?php
49
50
namespace $proxyNamespace;
51
52
/**
53
 * DO NOT EDIT THIS FILE - IT WAS CREATED BY $generator
54
 */
55
class $proxyClassName extends \\$entityClassName implements \\$readOnlyInterface
56
{
57
    protected \$loadedProperties;
58
59
    public function __construct(array \$loadedProperties)
60
    {
61
        \$this->loadedProperties = \$loadedProperties;
62
    }
63
64
$proxyMethodsCode
65
66
    protected function assertReadOnlyPropertiesAreLoaded(array \$properties)
67
    {
68
        foreach (\$properties as \$property) {
69
            if (in_array(\$property, \$this->loadedProperties) === false) {
70
                throw new \steevanb\DoctrineReadOnlyHydrator\Exception\PropertyNotLoadedException(\$this, \$property);
71
            }
72
        }
73
    }
74
}
75
PHP;
76
        file_put_contents($this->getProxyFilePath($entityClassName), $php);
77
78
        return $this;
79
    }
80
81
    /**
82
     * @param string $entityClassName
83
     * @return string
84
     */
85
    protected function getProxyFilePath($entityClassName)
86
    {
87
        $fileName = str_replace('\\', '_', $entityClassName) . '.php';
88
89
        return $this->getProxyDirectory() . DIRECTORY_SEPARATOR . $fileName;
90
    }
91
92
    /**
93
     * @param string $entityClassName
94
     * @return string
95
     */
96
    protected function getProxyNamespace($entityClassName)
97
    {
98
        return 'ReadOnlyProxies\\' . substr($entityClassName, 0, strrpos($entityClassName, '\\'));
99
    }
100
101
    /**
102
     * @param string $entityClassName
103
     * @return string
104
     */
105
    protected function getProxyClassName($entityClassName)
106
    {
107
        return substr($entityClassName, strrpos($entityClassName, '\\') + 1);
108
    }
109
110
    /**
111
     * As Doctrine\ORM\EntityManager::newHydrator() call new FooHydrator($this), we can't set parameters to Hydrator.
112
     * So, we will use proxyDirectory from Doctrine\Common\Proxy\AbstractProxyFactory.
113
     * It's directory used by Doctrine\ORM\Internal\Hydration\ObjectHydrator.
114
     *
115
     * @return string
116
     */
117
    protected function getProxyDirectory()
118
    {
119
        /** @var ProxyGenerator $proxyGenerator */
120
        $proxyGenerator = $this->getPrivatePropertyValue(
121
            AbstractProxyFactory::class,
122
            'proxyGenerator',
123
            $this->_em->getProxyFactory()
124
        );
125
126
        $directory = $this->getPrivatePropertyValue(get_class($proxyGenerator), 'proxyDirectory', $proxyGenerator);
127
        $readOnlyDirectory = $directory . DIRECTORY_SEPARATOR . 'ReadOnly';
128
        if (is_dir($readOnlyDirectory) === false) {
129
            mkdir($readOnlyDirectory);
130
        }
131
132
        return $readOnlyDirectory;
133
    }
134
135
    /**
136
     * @param \ReflectionMethod $reflectionMethod
137
     * @param array $properties
138
     * @return string|false
139
     */
140
    protected function getUsedProperties(\ReflectionMethod $reflectionMethod, $properties)
141
    {
142
        $classLines = file($reflectionMethod->getFileName());
143
        $methodLines = array_slice(
144
            $classLines,
145
            $reflectionMethod->getStartLine() - 1,
146
            $reflectionMethod->getEndLine() - $reflectionMethod->getStartLine() + 1
147
        );
148
        $code = '<?php' . "\n" . implode("\n", $methodLines) . "\n" . '?>';
149
150
        $return = array();
151
        $nextStringIsProperty = false;
152
        foreach (token_get_all($code) as $token) {
153
            if (is_array($token)) {
154
                if ($token[0] === T_VARIABLE && $token[1] === '$this') {
155
                    $nextStringIsProperty = true;
156
                } elseif ($nextStringIsProperty && $token[0] === T_STRING) {
157
                    $nextStringIsProperty = false;
158
                    if (in_array($token[1], $properties)) {
159
                        $return[$token[1]] = true;
160
                    }
161
                }
162
            }
163
        }
164
165
        return array_keys($return);
166
    }
167
168
    /**
169
     * @param ClassMetadata $classMetaData
170
     * @param string $entityClassName
171
     * @return array
172
     * @throws PrivateMethodShouldNotAccessPropertiesException
173
     */
174
    protected function getPhpForProxyMethods(ClassMetadata $classMetaData, $entityClassName)
175
    {
176
        $return = array();
177
        $reflectionClass = new \ReflectionClass($entityClassName);
178
        $properties = array_merge($classMetaData->getFieldNames(), array_keys($classMetaData->associationMappings));
179
        foreach ($reflectionClass->getMethods() as $method) {
180
            if ($method->getName() === '__construct') {
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
181
                continue;
182
            }
183
184
            $usedProperties = $this->getUsedProperties($method, $properties);
185
            if (count($usedProperties) > 0) {
186
                if ($method->isPrivate()) {
187
                    throw new PrivateMethodShouldNotAccessPropertiesException(
188
                        $entityClassName,
189
                        $method->getName(),
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
190
                        $usedProperties
191
                    );
192
                }
193
194
                $return[] = $this->getPhpForMethod($method, $usedProperties);
195
            }
196
        }
197
198
        return $return;
199
    }
200
201
    /**
202
     * @param \ReflectionMethod $reflectionMethod
203
     * @param array $properties
204
     * @return string
205
     */
206
    protected function getPhpForMethod(\ReflectionMethod $reflectionMethod, array $properties)
207
    {
208
        if ($reflectionMethod->isPublic()) {
209
            $signature = 'public';
210
        } else {
211
            $signature = 'protected';
212
        }
213
        $signature .= ' function ' . $reflectionMethod->getName() . '(';
0 ignored issues
show
Bug introduced by
Consider using $reflectionMethod->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
214
        $parameters = array();
215
        foreach ($reflectionMethod->getParameters() as $parameter) {
216
            $parameters[] = $this->getPhpForParameter($parameter);
217
        }
218
        $signature .= implode(', ', $parameters) . ')';
219
220
        $method = $reflectionMethod->getName();
0 ignored issues
show
Bug introduced by
Consider using $reflectionMethod->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
221
222
        array_walk($properties, function(&$name) {
223
            $name = "'" . $name . "'";
224
        });
225
        $propertiesToAssert = implode(', ', $properties);
226
227
        $php = <<<PHP
228
    $signature
229
    {
230
        \$this->assertReadOnlyPropertiesAreLoaded(array($propertiesToAssert));
231
232
        return call_user_func_array(array('parent', '$method'), func_get_args());
233
    }
234
PHP;
235
236
        return $php;
237
    }
238
239
    /**
240
     * @param \ReflectionParameter $parameter
241
     * @return string
242
     */
243
    protected function getPhpForParameter(\ReflectionParameter $parameter)
244
    {
245
        $php = null;
246
        if ($parameter->getClass() instanceof \ReflectionClass) {
247
            $php .= '\\' . $parameter->getClass()->getName() . ' ';
0 ignored issues
show
Bug introduced by
Consider using $parameter->getClass()->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
248
        } elseif ($parameter->isCallable()) {
249
            $php .= 'callable ';
250
        }
251
252
        if ($parameter->isPassedByReference()) {
253
            $php .= '&';
254
        }
255
        $php .= '$' . $parameter->getName();
0 ignored issues
show
Bug introduced by
Consider using $parameter->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
256
257
        if ($parameter->isDefaultValueAvailable()) {
258
            if ($parameter->isDefaultValueConstant()) {
259
                $defaultValue = $parameter->getDefaultValueConstantName();
1 ignored issue
show
Bug introduced by
The method getDefaultValueConstantName() does not exist on ReflectionParameter. Did you maybe mean getDefaultValue()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
260
            } elseif ($parameter->getDefaultValue() === null) {
261
                $defaultValue = 'null';
262
            } elseif (is_string($parameter->getDefaultValue())) {
263
                $defaultValue = '\'' . $parameter->getDefaultValue() . '\'';
264
            } else {
265
                $defaultValue = $parameter->getDefaultValue();
266
            }
267
            $php .= ' = ' . $defaultValue;
268
        }
269
270
        return $php;
271
    }
272
}
273