ProxyFactory::generateMethods()   C
last analyzed

Complexity

Conditions 14
Paths 53

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 56
rs 6.2666
c 0
b 0
f 0
cc 14
nc 53
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Doctrine\ODM\CouchDB\Proxy;
4
5
use Doctrine\ODM\CouchDB\DocumentManager;
6
use Doctrine\ODM\CouchDB\Mapping\ClassMetadata;
7
use Doctrine\Common\Util\ClassUtils;
8
9
/**
10
 * This factory is used to create proxy objects for entities at runtime.
11
 *
12
 * @author Roman Borschel <[email protected]>
13
 * @author Giorgio Sironi <[email protected]>
14
 * @author Nils Adermann <[email protected]>
15
 *
16
 * This whole thing is copy & pasted from ORM - should really be slightly
17
 * refactored to generate
18
 */
19
class ProxyFactory
20
{
21
    /** The DocumentManager this factory is bound to. */
22
    private $dm;
23
    /** Whether to automatically (re)generate proxy classes. */
24
    private $autoGenerate;
25
    /** The namespace that contains all proxy classes. */
26
    private $proxyNamespace;
27
    /** The directory that contains all proxy classes. */
28
    private $proxyDir;
29
30
    /**
31
     * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
32
     * connected to the given <tt>DocumentManager</tt>.
33
     *
34
     * @param DocumentManager $dm The DocumentManager the new factory works for.
35
     * @param string $proxyDir The directory to use for the proxy classes. It must exist.
36
     * @param string $proxyNs The namespace to use for the proxy classes.
37
     * @param boolean $autoGenerate Whether to automatically generate proxy classes.
38
     * @throws ProxyException
39
     */
40
    public function __construct(DocumentManager $dm, $proxyDir, $proxyNs, $autoGenerate = false)
41
    {
42
        if ( ! $proxyDir) {
43
            throw ProxyException::proxyDirectoryRequired();
44
        }
45
        if ( ! $proxyNs) {
46
            throw ProxyException::proxyNamespaceRequired();
47
        }
48
        $this->dm = $dm;
49
        $this->proxyDir = $proxyDir;
50
        $this->autoGenerate = $autoGenerate;
51
        $this->proxyNamespace = $proxyNs;
52
    }
53
54
    /**
55
     * Gets a reference proxy instance for the entity of the given type and identified by
56
     * the given identifier.
57
     *
58
     * @param string $className
59
     * @param mixed $identifier
60
     * @return object
61
     */
62
    public function getProxy($className, $identifier)
63
    {
64
        $fqn = ClassUtils::generateProxyClassName($className, $this->proxyNamespace);
65
66
        if ( ! class_exists($fqn, false)) {
67
            $fileName = $this->getProxyFileName($className);
68
            if ($this->autoGenerate) {
69
                $this->generateProxyClass($this->dm->getClassMetadata($className), $fileName, self::$proxyClassTemplate);
70
            }
71
            require $fileName;
72
        }
73
74
        if ( ! $this->dm->getMetadataFactory()->hasMetadataFor($fqn)) {
75
            $this->dm->getMetadataFactory()->setMetadataFor($fqn, $this->dm->getClassMetadata($className));
76
        }
77
78
        return new $fqn($this->dm, $identifier);
79
    }
80
81
    /**
82
     * Generate the Proxy file name
83
     *
84
     * @param string $className
85
     * @param string $baseDir Optional base directory for proxy file name generation.
86
     *                        If not specified, the directory configured on the Configuration of the
87
     *                        EntityManager will be used by this factory.
88
     * @return string
89
     */
90
    private function getProxyFileName($className, $baseDir = null)
91
    {
92
        $proxyDir = $baseDir ?: $this->proxyDir;
93
94
        return $proxyDir . DIRECTORY_SEPARATOR . '__CG__' . str_replace('\\', '', $className) . '.php';
95
    }
96
97
    /**
98
     * Generates proxy classes for all given classes.
99
     *
100
     * @param array $classes The classes (ClassMetadata instances) for which to generate proxies.
101
     * @param string $toDir The target directory of the proxy classes. If not specified, the
102
     *                      directory configured on the Configuration of the DocumentManager used
103
     *                      by this factory is used.
104
     */
105
    public function generateProxyClasses(array $classes, $toDir = null)
106
    {
107
        $proxyDir = $toDir ?: $this->proxyDir;
108
        $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
0 ignored issues
show
Unused Code introduced by
$proxyDir is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
109
        foreach ($classes as $class) {
110
            /* @var $class ClassMetadata */
111
            if ($class->isMappedSuperclass) {
112
                continue;
113
            }
114
115
            $proxyFileName = $this->getProxyFileName($class->name, $toDir);
116
            $this->generateProxyClass($class, $proxyFileName, self::$proxyClassTemplate);
117
        }
118
    }
119
120
    /**
121
     * Generates a proxy class file.
122
     *
123
     * @param $class
124
     * @param $fileName
125
     * @param $template
126
     */
127
    private function generateProxyClass($class, $fileName, $template)
128
    {
129
        $methods = $this->generateMethods($class);
130
        $sleepImpl = $this->generateSleep($class);
131
132
        $placeholders = array(
133
            '<namespace>',
134
            '<proxyClassName>', '<className>',
135
            '<methods>', '<sleepImpl>'
136
        );
137
138
        $className = ltrim($class->name, '\\');
139
        $proxyClassName = ClassUtils::generateProxyClassName($class->name, $this->proxyNamespace);
140
        $parts = explode('\\', strrev($proxyClassName), 2);
141
        $proxyClassNamespace = strrev($parts[1]);
142
        $proxyClassName = strrev($parts[0]);
143
144
        $replacements = array(
145
            $proxyClassNamespace,
146
            $proxyClassName,
147
            $className,
148
            $methods,
149
            $sleepImpl
150
        );
151
152
        $template = str_replace($placeholders, $replacements, $template);
153
154
        file_put_contents($fileName, $template, LOCK_EX);
155
    }
156
157
    /**
158
     * Generates the methods of a proxy class.
159
     *
160
     * @param ClassMetadata $class
161
     * @return string The code of the generated methods.
162
     */
163
    private function generateMethods(ClassMetadata $class)
164
    {
165
        $methods = '';
166
167
        foreach ($class->reflClass->getMethods() as $method) {
168
            /* @var $method \ReflectionMethod */
169
            if ($method->isConstructor() || strtolower($method->getName()) == "__sleep") {
170
                continue;
171
            }
172
173
            if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) {
174
                $methods .= PHP_EOL . '    public function ';
175
                if ($method->returnsReference()) {
176
                    $methods .= '&';
177
                }
178
                $methods .= $method->getName() . '(';
179
                $firstParam = true;
180
                $parameterString = $argumentString = '';
181
182
                foreach ($method->getParameters() as $param) {
183
                    if ($firstParam) {
184
                        $firstParam = false;
185
                    } else {
186
                        $parameterString .= ', ';
187
                        $argumentString  .= ', ';
188
                    }
189
190
                    // We need to pick the type hint class too
191
                    if (($paramClass = $param->getClass()) !== null) {
192
                        $parameterString .= '\\' . $paramClass->getName() . ' ';
193
                    } else if ($param->isArray()) {
194
                        $parameterString .= 'array ';
195
                    }
196
197
                    if ($param->isPassedByReference()) {
198
                        $parameterString .= '&';
199
                    }
200
201
                    $parameterString .= '$' . $param->getName();
202
                    $argumentString  .= '$' . $param->getName();
203
204
                    if ($param->isDefaultValueAvailable()) {
205
                        $parameterString .= ' = ' . var_export($param->getDefaultValue(), true);
206
                    }
207
                }
208
209
                $methods .= $parameterString . ')';
210
                $methods .= PHP_EOL . '    {' . PHP_EOL;
211
                $methods .= '        $this->__load();' . PHP_EOL;
212
                $methods .= '        return parent::' . $method->getName() . '(' . $argumentString . ');';
213
                $methods .= PHP_EOL . '    }' . PHP_EOL;
214
            }
215
        }
216
217
        return $methods;
218
    }
219
220
    /**
221
     * Generates the code for the __sleep method for a proxy class.
222
     *
223
     * @param $class
224
     * @return string
225
     */
226
    private function generateSleep(ClassMetadata $class)
227
    {
228
        $sleepImpl = '';
229
230
        if ($class->reflClass->hasMethod('__sleep')) {
231
            $sleepImpl .= "return array_merge(array('__isInitialized__'), parent::__sleep());";
232
        } else {
233
            $sleepImpl .= "return array('__isInitialized__', ";
234
235
            $properties = array();
236
            foreach ($class->fieldMappings as $name => $prop) {
237
                $properties[] = "'$name'";
238
            }
239
240
            $sleepImpl .= implode(',', $properties) . ');';
241
        }
242
243
        return $sleepImpl;
244
    }
245
246
    /** Proxy class code template */
247
    private static $proxyClassTemplate = <<<'PHP'
248
<?php
249
250
namespace <namespace>;
251
252
/**
253
 * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
254
 */
255
class <proxyClassName> extends \<className> implements \Doctrine\ODM\CouchDB\Proxy\Proxy
256
{
257
    private $__doctrineDocumentManager__;
258
    private $__doctrineIdentifier__;
259
    public $__isInitialized__ = false;
260
    public function __construct($documentManager, $identifier)
261
    {
262
        $this->__doctrineDocumentManager__ = $documentManager;
263
        $this->__doctrineIdentifier__ = $identifier;
264
    }
265
    public function __load()
266
    {
267
        if (!$this->__isInitialized__ && $this->__doctrineDocumentManager__) {
268
            $this->__isInitialized__ = true;
269
            $this->__doctrineDocumentManager__->refresh($this);
270
            unset($this->__doctrineDocumentManager__, $this->__doctrineIdentifier__);
271
        }
272
    }
273
274
    public function __isInitialized()
275
    {
276
        return $this->__isInitialized__;
277
    }
278
279
    <methods>
280
281
    public function __sleep()
282
    {
283
        <sleepImpl>
284
    }
285
}
286
PHP;
287
}
288
289