Completed
Push — master ( 04bd65...4036d4 )
by Fran
09:06
created

Singleton   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 186
Duplicated Lines 4.84 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 89.02%

Importance

Changes 10
Bugs 2 Features 0
Metric Value
c 10
b 2
f 0
dl 9
loc 186
ccs 73
cts 82
cp 0.8902
rs 9.6
wmc 32
lcom 1
cbo 4

13 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 15 3
A __construct() 0 4 1
A __clone() 0 1 1
A __wakeup() 0 1 1
A __set() 0 5 2
A __get() 0 3 2
A isLoaded() 0 3 1
A setLoaded() 0 3 1
A getShortName() 0 4 1
B init() 0 21 7
B getClassProperties() 9 21 6
A extractVarType() 0 7 2
A constructInyectableInstance() 0 13 4

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
namespace PSFS\base;
4
use PSFS\base\config\Config;
5
use PSFS\base\types\SingletonTrait;
6
7
/**
8
 * Class Singleton
9
 * @package PSFS\base
10
 */
11
class Singleton
12
{
13
    use SingletonTrait;
14
    /**
15
     * @var bool Flag that indicated if the class is already loaded
16
     */
17
    protected $loaded = false;
18
19 1
    public function __construct()
20
    {
21 1
        Logger::log(get_class($this) . ' constructor invoked');
22 1
    }
23
24
    /**
25
     * prevent the instance from being cloned
26
     *
27
     * @return void
28
     */
29
    private function __clone() {}
30
31
    /**
32
     * prevent from being unserialized
33
     *
34
     * @return void
35
     */
36
    private function __wakeup() {}
37
38
    /**
39
     * Magic setter
40
     * @param $variable
41
     * @param $value
42
     */
43 7
    public function __set($variable, $value) {
44 7
        if(property_exists(get_class($this), $variable)) {
45 7
            $this->$variable = $value;
46 7
        }
47 7
    }
48
49
    /**
50
     * Magic getter
51
     * @param string $variable
52
     * @return $mixed
53
     */
54
    public function __get($variable) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
55
        return property_exists(get_class($this), $variable) ? $this->$variable : null;
56
    }
57
58
    /**
59
     * Método que devuelve si una clase está isntanciada correctamente
60
     * @return bool
61
     */
62 1
    public function isLoaded() {
63 1
        return $this->loaded;
64
    }
65
66
    /**
67
     * Método que configura como cargada una clase
68
     * @param bool $loaded
69
     */
70 1
    public function setLoaded($loaded = true) {
71 1
        $this->loaded = $loaded;
72 1
    }
73
74
    /**
75
     * HELPERS
76
     */
77
78
    /**
79
     * Método que extrae el nombre de la clase
80
     * @return string
81
     */
82
    public function getShortName() {
83
        $reflector = new \ReflectionClass(get_class($this));
84
        return $reflector->getShortName();
85
    }
86
87
    /**
88
     * Dependency inyector service invoker
89
     * @param string $variable
90
     * @param bool $singleton
91
     * @param string $classNameSpace
0 ignored issues
show
Documentation introduced by
Should the type for parameter $classNameSpace not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
92
     * @return $this
93
     */
94 1
    public function load($variable, $singleton = true, $classNameSpace = null) {
95 1
        $calledClass = get_called_class();
96
        try {
97 1
            $instance = $this->constructInyectableInstance($variable, $singleton, $classNameSpace, $calledClass);
98 1
            $setter = "set".ucfirst($variable);
99 1
            if (method_exists($calledClass, $setter)) {
100
                $this->$setter($instance);
101
            } else {
102 1
                $this->$variable = $instance;
103
            }
104 1
        } catch (\Exception $e) {
105 1
            Logger::log($e->getMessage() . ': ' . $e->getFile() . ' ['  . $e->getLine() . ']', LOG_ERR);
106
        }
107 1
        return $this;
108
    }
109
110
    /**
111
     * Método que inyecta automáticamente las dependencias en la clase
112
     */
113 1
    public function init() {
114 1
        if (!$this->isLoaded()) {
115 1
            $cacheFilename = "reflections".DIRECTORY_SEPARATOR.sha1(get_class($this)).".json";
116
            /** @var \PSFS\base\Cache $cacheService */
117 1
            $cacheService = Cache::getInstance();
118
            /** @var \PSFS\base\config\Config $configService */
119 1
            $configService = Config::getInstance();
120 1
            $properties = $cacheService->getDataFromFile($cacheFilename, Cache::JSON);
121 1
            if (true === $configService->getDebugMode() || null === $properties) {
122 1
                $properties = $this->getClassProperties();
123 1
                $cacheService->storeData($cacheFilename, $properties, Cache::JSON);
124 1
            }
125
            /** @var \ReflectionProperty $property */
126 1
            if (!empty($properties) && is_array($properties)) foreach ($properties as $property => $class) {
127 1
                $this->load($property, true, $class);
128 1
            }
129 1
            $this->setLoaded();
130 1
        }else {
131
            Logger::log(get_class($this) . ' already loaded', LOG_INFO);
132
        }
133 1
    }
134
135
    /**
136
     * Método que extrae todas las propiedades inyectables de una clase
137
     * @param null $class
138
     * @return array
139
     */
140 1
    private function getClassProperties($class = null) {
141 1
        $properties = array();
142 1
        if (null === $class) {
143 1
            $class = get_class($this);
144 1
        }
145 1
        Logger::log('Extracting annotations properties from class ' . $class);
146 1
        $selfReflector = new \ReflectionClass($class);
147 1
        if (false !== $selfReflector->getParentClass()) {
148 1
            $properties = $this->getClassProperties($selfReflector->getParentClass()->getName());
149 1
        }
150 1 View Code Duplication
        foreach ($selfReflector->getProperties(\ReflectionProperty::IS_PROTECTED) as $property) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
151 1
            $doc = $property->getDocComment();
152 1
            if (preg_match('/@Inyectable/im', $doc)) {
153 1
                $instanceType = $this->extractVarType($property->getDocComment());
154 1
                if (null !== $instanceType) {
155 1
                    $properties[$property->getName()] = $instanceType;
156 1
                }
157 1
            }
158 1
        }
159 1
        return $properties;
160
    }
161
162
    /**
163
     * Método que extrae el tipo de instancia de la variable
164
     * @param $doc
165
     * @return null|string
166
     */
167 1
    private function extractVarType($doc) {
168 1
        $type = null;
169 1
        if (false !== preg_match('/@var\s+([^\s]+)/', $doc, $matches)) {
170 1
            list(, $type) = $matches;
171 1
        }
172 1
        return $type;
173
    }
174
175
    /**
176
     * Create the depecency injected
177
     * @param string $variable
178
     * @param bool $singleton
179
     * @param string $classNameSpace
180
     * @param string $calledClass
181
     * @return mixed
182
     */
183 1
    private function constructInyectableInstance($variable, $singleton, $classNameSpace, $calledClass)
184
    {
185 1
        Logger::log('Create inyectable instance for ' . $classNameSpace . ' into ' . get_class($this));
186 1
        $reflector = new \ReflectionClass($calledClass);
187 1
        $property = $reflector->getProperty($variable);
188 1
        $varInstanceType = (null === $classNameSpace) ? $this->extractVarType($property->getDocComment()) : $classNameSpace;
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
189 1
        if (true === $singleton && method_exists($varInstanceType, "getInstance")) {
190 1
            $instance = $varInstanceType::getInstance();
191 1
        } else {
192
            $instance = new $varInstanceType();
193
        }
194 1
        return $instance;
195
    }
196
}
197