Completed
Push — master ( b33915...6b6777 )
by Hong
02:32
created

ReferenceTrait::hasReference()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 12
rs 9.2
cc 4
eloc 8
nc 2
nop 2
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Shared
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Shared\Reference;
16
17
/**
18
 * ReferenceTrait
19
 *
20
 * Provides reference & dereference methods
21
 *
22
 * @package Phossa2\Shared
23
 * @author  Hong Zhang <[email protected]>
24
 * @see     ReferenceInterface
25
 * @version 2.0.4
26
 * @since   2.0.4 added
27
 */
28
trait ReferenceTrait
29
{
30
    /**
31
     * refernece start chars
32
     *
33
     * @var    string
34
     * @access protected
35
     */
36
    protected $ref_start = '${';
37
38
    /**
39
     * reference ending chars
40
     *
41
     * @var    string
42
     * @access protected
43
     */
44
    protected $ref_end = '}';
45
46
    /**
47
     * cached pattern to match
48
     *
49
     * @var    string
50
     * @access protected
51
     */
52
    protected $ref_pattern = '~(\$\{((?:(?!\$\{|\}).)+?)\})~';
53
54
    /**
55
     * unresolved reference
56
     *
57
     * @var    array
58
     * @access protected
59
     */
60
    protected $unresolved = [];
61
62
    /**
63
     * {@inheritDoc}
64
     */
65
    public function setReference(
66
        /*# string */ $start,
67
        /*# string */ $end
68
    ) {
69
        $this->ref_start = $start;
70
        $this->ref_end = $end;
71
72
        // build pattern
73
        $s = preg_quote($start);
74
        $e = preg_quote($end);
75
        $this->ref_pattern = sprintf(
76
            "~(%s((?:(?!%s|%s).)+?)%s)~", $s, $s, $e, $e
77
        );
78
79
        return $this;
80
    }
81
82
    /**
83
     * {@inheritDoc}
84
     */
85
    public function hasReference(
86
        /*# string */ $subject,
87
        array &$matched
88
    )/*# : bool */ {
89
        if (is_string($subject) &&
90
            false !== strpos($subject, $this->ref_start) &&
91
            preg_match($this->ref_pattern, $subject, $matched)
92
        ) {
93
            return true;
94
        }
95
        return false;
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     */
101
    public function deReference(/*# string */ $subject)
102
    {
103
        $matched = [];
104
        $count = 0;
105
        while ($this->hasReference($subject, $matched)) {
106
            $val = $this->resolveReference($matched[2]);
107
            if (is_string($val) && ++$count < 15) {
108
                $subject = str_replace($matched[1], $val, $subject);
109
            } elseif ($count == 15) {
110
                return $val;
111
            } else {
112
                return $val;
113
            }
114
        }
115
        return $subject;
116
    }
117
118
    /**
119
     * {@inheritDoc}
120
     */
121
    public function deReferenceArray(&$dataArray)
122
    {
123
        if (!is_array($dataArray)) {
124
            return;
125
        }
126
127
        foreach ($dataArray as &$data) {
128
            if (is_string($data)) {
129
                $data = $this->deReference($data);
130
            }
131
            $this->dereferenceArray($data);
132
        }
133
    }
134
135
    /**
136
     * Resolve the reference $name
137
     *
138
     * @param  string $name
139
     * @return mixed
140
     * @access protected
141
     */
142
    protected function resolveReference(/*# string */ $name)
143
    {
144
        // unresolved found
145
        if (isset($this->unresolved[$name])) {
146
            return $this->unresolved[$name];
147
        }
148
149
        // get the referenced value
150
        $val = $this->getReference($name);
151
152
        // not found
153
        if (is_null($val)) {
154
            $this->unresolved[$name] = $this->resolveUnknown($name);
155
            return $this->unresolved[$name];
156
157
        // found it
158
        } else {
159
            return $val;
160
        }
161
    }
162
163
    /**
164
     * For unknown reference $name
165
     *
166
     * @param  string $name
167
     * @return mixed
168
     * @access protected
169
     */
170
    abstract protected function resolveUnknown(/*# string */ $name);
171
172
    /**
173
     * The real resolving method. return NULL for unknown reference
174
     *
175
     * @param  string $name
176
     * @return mixed
177
     * @access protected
178
     */
179
    abstract protected function getReference(/*# string */ $name);
180
}
181