Factory::create()   B
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 17
nc 4
nop 2
1
<?php
2
/**
3
 * The base Class and super public Interface of this Library
4
 *
5
 * LICENSE: Free for all
6
 *
7
 * @category   Dependency Injection
8
 * @package    Puice
9
 * @copyright  Copyright (c) 2014 Alwin Mark
10
 * @license    Free
11
 * @link       https://github.com/CansaSCityShuffle/Puice
12
 */
13
14
namespace Puice;
15
16
use Puice\Config;
17
use Puice\Type\String;
18
19
/**
20
 * The generic Factory.
21
 *
22
 * This class is the Heart of Puice. It uses Reflection so it can creates
23
 * every Instance where the Dependencies are Defined in the Application, so
24
 * you never have to write a Factory on your own :-)
25
 *
26
 * But you still shouldn't use it in every Class. The best would be to use
27
 * it only in the Entrypoints of your Application, such as Controller,
28
 * Services or Modules.
29
 *
30
 * But you still could use it for Clientimplementations as well, to make
31
 * Application Dependencies configurable, without passing it threw every
32
 * class.
33
 *
34
 * @category   Dependency Injection
35
 * @package    Puice
36
 * @copyright  Copyright (c) 2014 Alwin Mark
37
 */
38
class Factory
39
{
40
    private $_config = null;
41
42
    /**
43
     * Yes, even this Class has dependecies, but once you have a
44
     * Configuration, you can create this Factory by its own.
45
     * Just take a look at the Specs
46
     *
47
     * @param Puice\Config $config Configuration Object holding all
48
     *                             Application Dependencies, which will be
49
     *                             passed to all objects created by this
50
     *                             class. If you only want to use this
51
     *                             Class, you have to implement your own
52
     *                             Config Class and pass it here.
53
     */
54
    public function __construct(Config $config)
55
    {
56
        $this->_config = $config;
57
    }
58
59
    /**
60
     * This is the method doing the magic. You can create every Instance
61
     * with it, as long as the Dependencies were allready defined.
62
     *
63
     * @param string $classType Type of the Dependency as $Namespace.$Classname
64
     * @param string $name Name of the Dpenedency
0 ignored issues
show
Bug introduced by
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
65
     *
66
     * @throws \Exception if some required dependencies could not be found.
67
     */
68
    public function create($classType, $className = 'default')
0 ignored issues
show
Unused Code introduced by
The parameter $className is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
    {
70
        $reflection = new \ReflectionClass($classType);
71
72
        $constructorReflection = $reflection->getConstructor();
73
74
        if ($constructorReflection == null) {
75
            return new $classType();
76
        }
77
78
        $constructorParameters = $constructorReflection->getParameters();
79
        $arguments = array();
80
81
        foreach ($constructorParameters as $parameter) {
82
            $type = null;
0 ignored issues
show
Unused Code introduced by
$type 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...
83
            $name = $parameter->name;
84
            $isOptional = $parameter->isOptional();
85
86
            if (! is_null($typeClass = @$parameter->getClass())) {
87
                $type = $typeClass->name;
88
            } else {
89
                $type = 'string';
90
            }
91
92
            $arguments[] = $this->getDependency($type, $name, $isOptional);
93
        }
94
95
        return $reflection->newInstanceArgs($arguments);
96
    }
97
98
    /**
99
     * use multiple fetching Strategies for Dependencies
100
     */
101
    private function getDependency($type, $name, $isOptional = false)
102
    {
103
        $dependency = $this->getDependencyFromConfig($type, $name);
104
105
        if (!is_null($dependency)) {
106
            return $dependency;
107
        }
108
109
        $dependency = $this->getDependencyFromType($type);
110
111
        if (!is_null($dependency)) {
112
            return $dependency;
113
        }
114
115
        $dependency = $this->getDefaultDependencyFromInterface($type);
116
117
        if (!is_null($dependency)) {
118
            return $dependency;
119
        }
120
121
        $dependency = $this->getDependencyFromInterface($type);
122
123
        if (!is_null($dependency)) {
124
            return $dependency;
125
        }
126
127
        if ($isOptional) {
128
            return null;
129
        }
130
131
        throw new \Exception(
132
            "Couldn't find Dependency for type: $type and name: $name"
133
        );
134
    }
135
136
    /**
137
     * Just try to get an Instance from the known type
138
     */
139
    private function getDependencyFromType($type)
140
    {
141
        if (class_exists($type)) {
142
            return $this->create($type, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
143
        }
144
145
        return null;
146
    }
147
148
    /**
149
     * Prepend Default to the class and try to find the class
150
     */
151 View Code Duplication
    private function getDefaultDependencyFromInterface($type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
    {
153
        $defaultDependency = preg_replace(
154
            '/(.*\\\\)(\w+)/i', '\1\2\Default\2', $type
155
        );
156
157
        if (class_exists($defaultDependency)) {
158
            return $this->create($defaultDependency, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
159
        }
160
161
        return null;
162
    }
163
164
    /**
165
     * remove Interface suffix or prefix (or middlefix) and try to find the
166
     * class
167
     */
168 View Code Duplication
    private function getDependencyFromInterface($type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
169
    {
170
        $defaultDependency = preg_replace(
171
            '/Interface/i', '', $type
172
        );
173
174
        if (class_exists($defaultDependency)) {
175
            return $this->create($defaultDependency, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
176
        }
177
178
        return null;
179
    }
180
181
    /**
182
     * scan the config object for dependencies
183
     */
184
    private function getDependencyFromConfig($type, $name)
185
    {
186
        $dependency = $this->_config->get($type, $name);
187
188
        if (is_object($dependency) || $type == 'string') {
189
            return $dependency;
190
        }
191
192
        if ($type != "string" && is_string($dependency)
193
                && class_exists($dependency)
194
        ) {
195
            return $this->create($dependency, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
196
        }
197
198
        return null;
199
    }
200
}
201