Completed
Push — master ( 799a4d...888ea9 )
by Tony
07:03
created

ClassConfig::createDirectories()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace ClassConfig;
4
5
use ClassConfig\Annotation\Config;
6
use ClassConfig\Annotation\ConfigArray;
7
use ClassConfig\Annotation\ConfigBoolean;
8
use ClassConfig\Annotation\ConfigEntryInterface;
9
use ClassConfig\Annotation\ConfigFloat;
10
use ClassConfig\Annotation\ConfigInteger;
11
use ClassConfig\Annotation\ConfigObject;
12
use ClassConfig\Annotation\ConfigString;
13
use ClassConfig\Exceptions\MissingCachePathException;
14
use Doctrine\Common\Annotations\AnnotationReader;
15
16
/**
17
 * Class ClassConfig
18
 * @package ClassConfig
19
 */
20
class ClassConfig
21
{
22
    /**
23
     * @var AnnotationReader
24
     */
25
    protected static $annotationReader;
26
27
    /**
28
     * @var string
29
     */
30
    protected static $cachePath;
31
32
    /**
33
     * @var string
34
     */
35
    protected static $classNamespace = 'ClassConfig\Cache';
36
37
    /**
38
     * @param string $path
39
     */
40
    protected static function createDirectories(string $path)
41
    {
42
        if (!is_dir($path)) {
43
            static::createDirectories(dirname($path));
44
            mkdir($path);
45
        }
46
    }
47
48
    /**
49
     * @return AnnotationReader
50
     * @throws \Doctrine\Common\Annotations\AnnotationException
51
     */
52
    protected static function getAnnotationReader(): AnnotationReader
53
    {
54
        if (!isset(static::$annotationReader)) {
55
            static::$annotationReader = new AnnotationReader();
56
        }
57
        return static::$annotationReader;
58
    }
59
60
    /**
61
     * @param Config $annotation
62
     * @param string $className
63
     * @param string $classNamespace
64
     * @param int $subClassIteration
65
     * @return string
66
     */
67
    protected static function generate(
68
        Config $annotation,
69
        string $className,
70
        string $classNamespace,
71
        int &$subClassIteration = 0
72
    ): string {
73
        $canonicalClassName = $classNamespace . '\\' . $className;
74
75
        $effectiveClassName = $className . (0 < $subClassIteration ? '_' . $subClassIteration : '');
76
        $effectiveCanonicalClassName = $canonicalClassName . (0 < $subClassIteration ? '_' . $subClassIteration : '');
77
78
        $generator = new ClassGenerator($annotation, $effectiveClassName, $classNamespace);
79
80
        /**
81
         * @var string $key
82
         * @var ConfigEntryInterface $entry
83
         */
84
        foreach ($annotation->value as $key => $entry) {
85
            switch (true) {
86
                case $entry instanceof ConfigString:
87
                case $entry instanceof ConfigInteger:
88
                case $entry instanceof ConfigFloat:
89
                case $entry instanceof ConfigBoolean:
90
                case $entry instanceof ConfigObject:
91
                    $generator
92
                        ->generateProperty($key, $entry->getType(), isset($entry->default) ? $entry->default : null)
93
                        ->generateGet($key, $entry->getType())
94
                        ->generateSet($key, $entry->getType())
95
                        ->generateIsset($key)
96
                        ->generateUnset($key);
97
                    break;
98
99
                case $entry instanceof ConfigArray:
100
                    $generator
101
                        ->generateProperty($key, $entry->value->getType() . '[]')
102
                        ->generateArrayGet($key, $entry->value->getType() . '[]')
103
                        ->generateArraySet($key, $entry->value->getType() . '[]')
104
                        ->generateArrayGetAt($key, $entry->value->getType())
105
                        ->generateArraySetAt($key, $entry->value->getType())
106
                        ->generateArrayClear($key)
107
                        ->generateArrayPush($key, $entry->value->getType())
108
                        ->generateArrayUnshift($key, $entry->value->getType())
109
                        ->generateArrayPop($key, $entry->value->getType())
110
                        ->generateArrayShift($key, $entry->value->getType())
111
                        ->generateIsset($key)
112
                        ->generateUnset($key);
113
                    break;
114
115
                case $entry instanceof Config:
116
                    $subClassIteration++;
117
                    $entryCanonicalClassName = static::generate(
118
                        $entry,
119
                        $className,
120
                        $classNamespace,
121
                        $subClassIteration
122
                    );
123
                    $generator
124
                        ->generateProperty($key, $entryCanonicalClassName)
125
                        ->generateConfigGet($key, $entryCanonicalClassName)
126
                        ->generateConfigSet($key)
127
                        ->generateConfigIsset($key)
128
                        ->generateConfigUnset($key);
129
                    break;
130
131
                default:
132
                    throw new \RuntimeException(sprintf(
133
                        'Invalid or unsupported configuration entry type: "%s".',
134
                        get_class($entry)
135
                    ));
136
            }
137
        }
138
139
        $generator
140
            ->generateMagicGet()
141
            ->generateMagicSet()
142
            ->generateMagicIsset()
143
            ->generateMagicUnset();
144
145
        file_put_contents(
146
            static::getCachePath(true) . '/' . $effectiveClassName . '.php',
147
            (string) $generator
148
        );
149
150
        return $effectiveCanonicalClassName;
151
    }
152
153
    /**
154
     * @param string $path
155
     */
156
    public static function setCachePath(string $path)
157
    {
158
        static::$cachePath = $path;
159
    }
160
161
    /**
162
     * @param bool $create
163
     * @return string
164
     * @throws MissingCachePathException
165
     */
166
    public static function getCachePath(bool $create = false): string
167
    {
168
        if (!isset(static::$cachePath)) {
169
            throw new MissingCachePathException();
170
        }
171
        if ($create) {
172
            static::createDirectories(static::$cachePath);
173
        }
174
        return static::$cachePath;
175
    }
176
177
    /**
178
     * @return string
179
     */
180
    public static function getClassNamespace(): string
181
    {
182
        return self::$classNamespace;
183
    }
184
185
    /**
186
     * @param string $classNamespace
187
     */
188
    public static function setClassNamespace(string $classNamespace)
189
    {
190
        static::$classNamespace = $classNamespace;
191
    }
192
193
    /**
194
     * @param string $class
195
     * @return string
196
     * @throws \Doctrine\Common\Annotations\AnnotationException
197
     * @throws \ReflectionException
198
     * @throws MissingCachePathException
199
     */
200
    public static function createClass(string $class): string
201
    {
202
        $class = new \ReflectionClass($class);
203
204
        $className = 'CC__' . hash('crc32', $class->getName() . ':' . filemtime($class->getFileName()));;
0 ignored issues
show
Bug introduced by
Consider using $class->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
205
        $classNamespace = static::getClassNamespace();
206
        $canonicalClassName = $classNamespace . '\\' . $className;
207
208
        $path = static::getCachePath() . DIRECTORY_SEPARATOR . $className . '.php';
209
        if (is_file($path)) {
210
            return $canonicalClassName;
211
        }
212
213
        /** @var Config $annotation */
214
        $annotation = static::getAnnotationReader()->getClassAnnotation($class, Config::class);
215
        static::generate($annotation, $className, $classNamespace);
216
217
        return $canonicalClassName;
218
    }
219
220
    /**
221
     * @param string $class
222
     * @return AbstractConfig
223
     * @throws \Doctrine\Common\Annotations\AnnotationException
224
     * @throws \ReflectionException
225
     * @throws MissingCachePathException
226
     */
227
    public static function createInstance(string $class): AbstractConfig
228
    {
229
        $canonicalClassName = static::createClass($class);
230
        return new $canonicalClassName;
231
    }
232
}