1 <?php
2 3 4 5 6 7
8
9 namespace Cross\Core;
10
11 use Closure;
12
13 14 15 16 17
18 class Annotate
19 {
20 21 22
23 private $delegate;
24
25 26 27 28 29
30 private $prefix = 'cp_';
31
32 33 34
35 private static $instance;
36
37 38 39 40 41
42 private function __construct(Delegate &$delegate)
43 {
44 $this->delegate = $delegate;
45 stream_register_wrapper('annotate', 'Cross\Lib\StringToPHPStream');
46 }
47
48 49 50 51 52 53
54 public static function getInstance(Delegate &$delegate)
55 {
56 if (!self::$instance) {
57 self::$instance = new Annotate($delegate);
58 }
59
60 return self::$instance;
61 }
62
63 64 65 66 67 68
69 function setPrefix($prefix)
70 {
71 $this->prefix = $prefix;
72 return $this;
73 }
74
75 76 77 78 79 80
81 public function parse($annotate = '')
82 {
83 if (empty($annotate)) {
84 return array();
85 }
86
87 $flag = preg_match_all("/@{$this->prefix}(.*?)\s+(.*)/", $annotate, $content);
88 if (!$flag) {
89 return array();
90 }
91
92 $configs = array_combine($content[1], $content[2]);
93 return $this->parseAnnotate($configs);
94 }
95
96 97 98 99 100 101
102 public function bindToClosure($params)
103 {
104 return function ($self) use ($params) {
105 return include("annotate://{$params}");
106 };
107 }
108
109 110 111 112 113 114
115 public function toCode($params)
116 {
117 return include("annotate://{$params}");
118 }
119
120 121 122 123 124 125 126 127 128 129 130 131 132 133
134 public function toArray($params)
135 {
136 $result = array();
137 $conf = array_map('trim', explode(',', $params));
138 foreach ($conf as $c) {
139 if (false !== strpos($c, '=')) {
140 $c = explode('=', $c);
141 $result[trim($c[0])] = isset($c[1]) ? trim($c[1]) : '';
142 } else {
143 $result[$c] = '';
144 }
145 }
146 unset($conf);
147
148 return $result;
149 }
150
151 152 153 154 155 156
157 private function parseAnnotate(array $annotateConfigs)
158 {
159 $result = array();
160 foreach ($annotateConfigs as $conf => $params) {
161 switch ($conf) {
162 case 'params':
163 $result['params'] = $this->toArray($params);
164 break;
165
166 case 'cache':
167 case 'response':
168 case 'basicAuth':
169 $result[$conf] = $this->toCode($params);
170 break;
171
172 case 'after':
173 case 'before':
174 $result[$conf] = $this->bindToClosure($params);
175 break;
176
177 default:
178 $params = trim($params);
179 $closureContainer = $this->delegate->getClosureContainer();
180 $hasClosure = $closureContainer->has('parseAnnotate');
181 if ($hasClosure) {
182 $closureContainer->run('parseAnnotate', array($conf, &$params, $this));
183 }
184
185 $result[$conf] = $params;
186 }
187 }
188
189 return $result;
190 }
191 }
192