Passed
Push — master ( 70f98a...9ce8e2 )
by Fran
05:26
created

Singleton::getClassProperties()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 1
dl 0
loc 14
ccs 12
cts 12
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
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
     * @param \ReflectionClass $reflector
131
     * @param array $properties
132
     * @param integer $type
133
     */
134 2
    public static function extractProperties(\ReflectionClass $reflector, array &$properties, $type = \ReflectionProperty::IS_PROTECTED)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 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...
135
    {
136 2
        foreach ($reflector->getProperties($type) as $property) {
137 2
            $doc = $property->getDocComment();
138 2
            if (preg_match('/@Inyectable/im', $doc)) {
139 2
                $instanceType = self::extractVarType($property->getDocComment());
140 2
                if (null !== $instanceType) {
141 2
                    $properties[$property->getName()] = $instanceType;
142 2
                }
143 2
            }
144 2
        }
145 2
    }
146
147
    /**
148
     * Método que extrae todas las propiedades inyectables de una clase
149
     * @param null $class
150
     * @return array
151
     */
152 2
    private function getClassProperties($class = null)
153
    {
154 2
        $properties = array();
155 2
        if (null === $class) {
156 2
            $class = get_class($this);
157 2
        }
158 2
        Logger::log('Extracting annotations properties from class ' . $class);
159 2
        $selfReflector = new \ReflectionClass($class);
160 2
        if (false !== $selfReflector->getParentClass()) {
161 2
            $properties = $this->getClassProperties($selfReflector->getParentClass()->getName());
162 2
        }
163 2
        Singleton::extractProperties($selfReflector, $properties);
164 2
        return $properties;
165
    }
166
167
    /**
168
     * Método que extrae el tipo de instancia de la variable
169
     * @param $doc
170
     * @return null|string
171
     */
172 2
    public static function extractVarType($doc)
173
    {
174 2
        $type = null;
175 2
        if (false !== preg_match('/@var\s+([^\s]+)/', $doc, $matches)) {
176 2
            list(, $type) = $matches;
177 2
        }
178 2
        return $type;
179
    }
180
181
    /**
182
     * Create the depecency injected
183
     * @param string $variable
184
     * @param bool $singleton
185
     * @param string $classNameSpace
186
     * @param string $calledClass
187
     * @return mixed
188
     */
189 2
    private function constructInyectableInstance($variable, $singleton, $classNameSpace, $calledClass)
190
    {
191 2
        Logger::log('Create inyectable instance for ' . $classNameSpace . ' into ' . get_class($this));
192 2
        $reflector = new \ReflectionClass($calledClass);
193 2
        $property = $reflector->getProperty($variable);
194 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...
195 2
        if (true === $singleton && method_exists($varInstanceType, "getInstance")) {
196 2
            $instance = $varInstanceType::getInstance();
197 2
        } else {
198 1
            $instance = new $varInstanceType();
199
        }
200 2
        return $instance;
201
    }
202
}
203