Completed
Push — master ( c350e4...2fe906 )
by Fran
08:21
created

Singleton::__clone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
namespace PSFS\base;
4
5
use PSFS\base\config\Config;
6
use PSFS\base\types\SingletonTrait;
7
8
/**
9
 * Class Singleton
10
 * @package PSFS\base
11
 */
12
class Singleton
13
{
14
    use SingletonTrait;
15
    /**
16
     * @var bool Flag that indicated if the class is already loaded
17
     */
18
    protected $loaded = false;
19
20 2
    public function __construct()
21
    {
22 2
        Logger::log(get_class($this) . ' constructor invoked');
23 2
    }
24
25
    /**
26
     * Magic setter
27
     * @param $variable
28
     * @param $value
29
     */
30 8
    public function __set($variable, $value)
31
    {
32 8
        if (property_exists(get_class($this), $variable)) {
33 8
            $this->$variable = $value;
34 8
        }
35 8
    }
36
37
    /**
38
     * Magic getter
39
     * @param string $variable
40
     * @return $mixed
41
     */
42 1
    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...
43
    {
44 1
        return property_exists(get_class($this), $variable) ? $this->$variable : null;
45
    }
46
47
    /**
48
     * Método que devuelve si una clase está isntanciada correctamente
49
     * @return bool
50
     */
51 2
    public function isLoaded()
52
    {
53 2
        return $this->loaded;
54
    }
55
56
    /**
57
     * Método que configura como cargada una clase
58
     * @param bool $loaded
59
     */
60 2
    public function setLoaded($loaded = true)
61
    {
62 2
        $this->loaded = $loaded;
63 2
    }
64
65
    /**
66
     * HELPERS
67
     */
68
69
    /**
70
     * Método que extrae el nombre de la clase
71
     * @return string
72
     */
73 1
    public function getShortName()
74
    {
75 1
        $reflector = new \ReflectionClass(get_class($this));
76 1
        return $reflector->getShortName();
77
    }
78
79
    /**
80
     * Dependency inyector service invoker
81
     * @param string $variable
82
     * @param bool $singleton
83
     * @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...
84
     * @return $this
85
     */
86 2
    public function load($variable, $singleton = true, $classNameSpace = null)
87
    {
88 2
        $calledClass = get_called_class();
89
        try {
90 2
            $instance = $this->constructInyectableInstance($variable, $singleton, $classNameSpace, $calledClass);
91 2
            $setter = "set" . ucfirst($variable);
92 2
            if (method_exists($calledClass, $setter)) {
93 1
                $this->$setter($instance);
94 1
            } else {
95 2
                $this->$variable = $instance;
96
            }
97 2
        } catch (\Exception $e) {
98 1
            Logger::log($e->getMessage() . ': ' . $e->getFile() . ' [' . $e->getLine() . ']', LOG_ERR);
99
        }
100 2
        return $this;
101
    }
102
103
    /**
104
     * Método que inyecta automáticamente las dependencias en la clase
105
     */
106 2
    public function init()
107
    {
108 2
        if (!$this->isLoaded()) {
109 2
            $cacheFilename = "reflections" . DIRECTORY_SEPARATOR . sha1(get_class($this)) . ".json";
110
            /** @var \PSFS\base\Cache $cacheService */
111 2
            $cacheService = Cache::getInstance();
112
            /** @var \PSFS\base\config\Config $configService */
113 2
            $configService = Config::getInstance();
114 2
            $properties = $cacheService->getDataFromFile($cacheFilename, Cache::JSON);
115 2
            if (true === $configService->getDebugMode() || null === $properties) {
116 2
                $properties = $this->getClassProperties();
117 2
                $cacheService->storeData($cacheFilename, $properties, Cache::JSON);
118 2
            }
119
            /** @var \ReflectionProperty $property */
120 2
            if (!empty($properties) && is_array($properties)) foreach ($properties as $property => $class) {
121 2
                $this->load($property, true, $class);
122 2
            }
123 2
            $this->setLoaded();
124 2
        } else {
125 1
            Logger::log(get_class($this) . ' already loaded', LOG_INFO);
126
        }
127 2
    }
128
129
    /**
130
     * Método que extrae todas las propiedades inyectables de una clase
131
     * @param null $class
132
     * @return array
133
     */
134 2
    private function getClassProperties($class = null)
135
    {
136 2
        $properties = array();
137 2
        if (null === $class) {
138 2
            $class = get_class($this);
139 2
        }
140 2
        Logger::log('Extracting annotations properties from class ' . $class);
141 2
        $selfReflector = new \ReflectionClass($class);
142 2
        if (false !== $selfReflector->getParentClass()) {
143 2
            $properties = $this->getClassProperties($selfReflector->getParentClass()->getName());
144 2
        }
145 2 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...
146 2
            $doc = $property->getDocComment();
147 2
            if (preg_match('/@Inyectable/im', $doc)) {
148 2
                $instanceType = $this->extractVarType($property->getDocComment());
149 2
                if (null !== $instanceType) {
150 2
                    $properties[$property->getName()] = $instanceType;
151 2
                }
152 2
            }
153 2
        }
154 2
        return $properties;
155
    }
156
157
    /**
158
     * Método que extrae el tipo de instancia de la variable
159
     * @param $doc
160
     * @return null|string
161
     */
162 2
    private function extractVarType($doc)
163
    {
164 2
        $type = null;
165 2
        if (false !== preg_match('/@var\s+([^\s]+)/', $doc, $matches)) {
166 2
            list(, $type) = $matches;
167 2
        }
168 2
        return $type;
169
    }
170
171
    /**
172
     * Create the depecency injected
173
     * @param string $variable
174
     * @param bool $singleton
175
     * @param string $classNameSpace
176
     * @param string $calledClass
177
     * @return mixed
178
     */
179 2
    private function constructInyectableInstance($variable, $singleton, $classNameSpace, $calledClass)
180
    {
181 2
        Logger::log('Create inyectable instance for ' . $classNameSpace . ' into ' . get_class($this));
182 2
        $reflector = new \ReflectionClass($calledClass);
183 2
        $property = $reflector->getProperty($variable);
184 2
        $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...
185 2
        if (true === $singleton && method_exists($varInstanceType, "getInstance")) {
186 2
            $instance = $varInstanceType::getInstance();
187 2
        } else {
188 1
            $instance = new $varInstanceType();
189
        }
190 2
        return $instance;
191
    }
192
}
193