DependencyInjector   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 99
Duplicated Lines 42.42 %

Coupling/Cohesion

Components 1
Dependencies 0
Metric Value
wmc 13
lcom 1
cbo 0
dl 42
loc 99
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A instance() 0 6 2
A init() 0 4 1
A injectIntoMethod() 19 19 4
B injectIntoConstructor() 23 23 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 *
4
 * © 2015 Tolan Blundell.  All rights reserved.
5
 * <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 */
11
12
namespace PatternSeek\DependencyInjector;
13
14
use Pimple\Container;
15
use ReflectionException;
16
17
/**
18
 * Inject dependencies into a class method from a Pimple container
19
 * Dependency objects in Pimple must be named after the dependency FQCN
20
 * 
21
 */
22
class DependencyInjector
23
{
24
25
    /**
26
     * @var DependencyInjector
27
     */
28
    private static $singleton;
29
30
31
    /**
32
     * @var Container
33
     */
34
    private $container;
35
36
    /**
37
     * @param Container $container
38
     */
39
    private function __construct( Container $container ){
40
        $this->container = $container;
41
    }
42
43
    /**
44
     * @return DependencyInjector
45
     * @throws \Exception
46
     */
47
    public static function instance(){
48
        if( ! isset( self::$singleton->container ) ){
49
            throw new \Exception( "Can't access DependencyInjector singleton before it is initialised via DependencyInjector::init()" );
50
        }
51
        return self::$singleton;
52
    }
53
54
    /**
55
     * @param Container $container
56
     */
57
    public static function init( Container $container ){
58
        $di = new DependencyInjector( $container );
59
        self::$singleton = $di;
60
    }
61
62
    /**
63
     * Inject dependencies from, or including, the Pimple container, into a given method on a given object
64
     * @param $object
65
     * @param $methodName
66
     * @return mixed The method's return value
67
     */
68 View Code Duplication
    public function injectIntoMethod( $object, $methodName = "injectDependencies" ){
69
        $ref = new \ReflectionClass($object);
70
        try{
71
            $refMethod = $ref->getMethod( $methodName );
72
        }catch( ReflectionException  $e ){
73
            return null;
74
        }
75
        
76
        $toInject = [];
77
        foreach ($refMethod->getParameters() as $p) {
78
            $className = $p->getClass()->name;
79
            if( $className === "Pimple\\Container" ){
80
                $toInject[] = $this->container;
81
            }else{
82
                $toInject[] = $this->container[ $className ];
83
            }
84
        }
85
        return $refMethod->invoke( $object, ... $toInject );
86
    }
87
88
    /**
89
     * Inject dependencies from, or including, the Pimple container, into a a given class's constructor
90
     * Optionally providing a number of arguments to the constructor to prepend.
91
     *
92
     * @param string $classToBuildName
93
     * @param array $toInject
94
     * @return bool Whether the method was found
95
     */
96 View Code Duplication
    public function injectIntoConstructor( $classToBuildName, array $toInject=[] ){
97
        $ref = new \ReflectionClass($classToBuildName);
98
        try{
99
            $constr = $ref->getConstructor();
100
        }catch( ReflectionException  $e ){
101
            return null;
102
        }
103
104
        $numToSkip = count($toInject);
105
        foreach ($constr->getParameters() as $p) {
106
            if( $numToSkip > 0 ){
107
                $numToSkip--;
108
                continue;
109
            }
110
            $classToInjectName = $p->getClass()->name;
111
            if( $classToInjectName === "Pimple\\Container" ){
112
                $toInject[] = $this->container;
113
            }else{
114
                $toInject[] = $this->container[ $classToInjectName ];
115
            }
116
        }
117
        return new $classToBuildName( ... $toInject );
118
    }
119
120
}
121