Passed
Push — dev ( b45126...5faaf1 )
by 世昌
02:13
created

ContentWrapper::matchWrapper()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 4
nop 1
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\framework\response;
3
4
use ReflectionException;
5
use SplFileObject;
6
use ReflectionClass;
7
use JsonSerializable;
8
use suda\framework\exception\NoWrapperFoundException;
9
use suda\framework\response\wrapper\FileContentWrapper;
10
use suda\framework\response\wrapper\HtmlContentWrapper;
11
use suda\framework\response\wrapper\JsonContentWrapper;
12
use suda\framework\response\wrapper\NullContentWrapper;
13
14
/**
15
 * 内容包装
16
 */
17
class ContentWrapper
18
{
19
    protected $types = [
20
       [ JsonContentWrapper::class , ['array', JsonSerializable::class],],
21
       [ HtmlContentWrapper::class , ['boolean', 'integer','double', 'string'],],
22
       [ NullContentWrapper::class , ['NULL'],],
23
       [ FileContentWrapper::class , [SplFileObject::class],],
24
    ];
25
26
    /**
27
     * 注册包装器
28
     *
29
     * @param string $provider
30
     * @param array $types
31
     * @return void
32
     */
33
    public function register(string $provider, array $types)
34
    {
35
        array_unshift($this->types, [$provider, $types]);
36
    }
37
38
    /**
39
     * 判断是否为某种类型
40
     *
41
     * @param mixed $data
42
     * @param string $type
43
     * @return boolean
44
     */
45
    public static function isTypeOf($data, string $type) : bool
46
    {
47
        if (is_object($data)
48
            && !in_array($type, ['boolean', 'bool', 'integer', 'int', 'float', 'double', 'string','array','NULL'])) {
49
            try {
50
                $class = new ReflectionClass($data);
51
                $typeRef = new ReflectionClass($type);
52
                if ($typeRef->isInterface()) {
53
                    return $class->implementsInterface($type);
54
                } else {
55
                    return $class->isSubclassOf($type) || $typeRef->isInstance($data);
56
                }
57
            } catch (ReflectionException $e) {
58
                return false;
59
            }
60
        } else {
61
            return gettype($data) === static::phpTypeAlias($type);
62
        }
63
    }
64
65
    protected static function phpTypeAlias(string $type):string
66
    {
67
        if ($type === 'bool') {
68
            return 'boolean';
69
        }
70
        if ($type === 'int') {
71
            return 'integer';
72
        }
73
        if ($type === 'float') {
74
            return 'double';
75
        }
76
        return $type;
77
    }
78
79
    /**
80
     * 包装
81
     *
82
     * @param mixed $content
83
     * @return ContentWrapperInterface
84
     */
85
    public function getWrapper($content): ContentWrapperInterface
86
    {
87
        if ($content instanceof ContentWrapperInterface) {
88
            return $content;
89
        }
90
        if ($wrapper = $this->matchWrapper($content)) {
91
            return $wrapper;
92
        }
93
        if (method_exists($content, '__toString')) {
94
            return new HtmlContentWrapper($content, 'string');
95
        }
96
        throw new NoWrapperFoundException(sprintf('no wrapper for type %s', get_class($content)), E_USER_ERROR);
97
    }
98
99
    /**
100
     * @param $content
101
     * @return ContentWrapperInterface|null
102
     */
103
    private function matchWrapper($content):?ContentWrapperInterface
104
    {
105
        foreach ($this->types as $typeConfig) {
106
            list($wrapper, $types) = $typeConfig;
107
            foreach ($types as $type) {
108
                if (static::isTypeOf($content, $type)) {
109
                    return new $wrapper($content, $type);
110
                }
111
            }
112
        }
113
        return null;
114
    }
115
}
116