Total Complexity | 42 |
Total Lines | 328 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like JavaScript often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use JavaScript, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Blok\JavaScript; |
||
13 | class JavaScript |
||
14 | { |
||
15 | /** |
||
16 | * @var string |
||
17 | */ |
||
18 | private static $globalNamespace = 'JavaScript'; |
||
19 | |||
20 | /** |
||
21 | * Globals namespace |
||
22 | * @var string |
||
23 | */ |
||
24 | private $namespace = '__app'; |
||
25 | |||
26 | private static $_instances = []; |
||
27 | |||
28 | /** |
||
29 | * Selected data |
||
30 | * @var null |
||
31 | */ |
||
32 | private $activeData = null; |
||
33 | |||
34 | /** |
||
35 | * JavaScript constructor. |
||
36 | * @param null $namespace |
||
|
|||
37 | * |
||
38 | * @example |
||
39 | * $js = new JavaScript('__globals'); |
||
40 | * $js->set('foo', 'bar'); |
||
41 | */ |
||
42 | public function __construct($namespace = null) |
||
43 | { |
||
44 | if (!is_string($namespace)) { |
||
45 | $namespace = null; |
||
46 | } |
||
47 | |||
48 | if ($namespace) { |
||
49 | $this->namespace = $namespace; |
||
50 | } |
||
51 | |||
52 | if (!isset($GLOBALS[static::$globalNamespace])) { |
||
53 | $GLOBALS[static::$globalNamespace] = []; |
||
54 | } |
||
55 | |||
56 | if (!isset($GLOBALS[static::$globalNamespace][$this->namespace])) { |
||
57 | $GLOBALS[static::$globalNamespace][$this->namespace] = []; |
||
58 | } |
||
59 | |||
60 | self::$_instances[$this->namespace] = $this; |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * Calling methods statically |
||
65 | * @param $name |
||
66 | * @param $arguments |
||
67 | * @return mixed |
||
68 | * @throws \Exception |
||
69 | */ |
||
70 | public static function __callStatic($name, $arguments) |
||
71 | { |
||
72 | $instance = new self(); |
||
73 | |||
74 | if (method_exists($instance, $name)) { |
||
75 | return call_user_func_array([$instance, $name], $arguments); |
||
76 | } |
||
77 | |||
78 | throw new \Exception('[' . static::class . '::' . $name . '] method is not implemented'); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Magic getter |
||
83 | * @param $name |
||
84 | * @return mixed |
||
85 | */ |
||
86 | public function __get($name) |
||
87 | { |
||
88 | return $this->get($name); |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Magic setter |
||
93 | * @param $name |
||
94 | * @param $value |
||
95 | * @return JavaScript |
||
96 | */ |
||
97 | public function __set($name, $value) |
||
98 | { |
||
99 | return $this->set($name, $value); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Remove one or many array items from a given array using "dot" notation. |
||
104 | * @param array|string $keys |
||
105 | * @return $this |
||
106 | */ |
||
107 | public function forget($keys) |
||
108 | { |
||
109 | $data = $this->getActiveData(); |
||
110 | $this->setActiveData(Arr::forget($data, $keys), false); |
||
111 | |||
112 | return $this; |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Check if an item or items exist in an array using "dot" notation. |
||
117 | * |
||
118 | * @param string|array $keys |
||
119 | * @return bool |
||
120 | */ |
||
121 | public function has($keys) |
||
122 | { |
||
123 | return Arr::has($GLOBALS[static::$globalNamespace][$this->namespace], $keys); |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Get an item from an array using "dot" notation. |
||
128 | * |
||
129 | * @param string $key |
||
130 | * @param mixed $default |
||
131 | * @return mixed |
||
132 | */ |
||
133 | public function get($key = null, $default = null) |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Set an array item to a given value using "dot" notation. |
||
146 | * |
||
147 | * @param string $key |
||
148 | * @param mixed $value |
||
149 | * @return $this |
||
150 | */ |
||
151 | public function set($key, $value = null) |
||
152 | { |
||
153 | if (is_null($value)) { |
||
154 | $key = Arr::wrap($key); |
||
155 | |||
156 | $this->merge($key); |
||
157 | |||
158 | return $this; |
||
159 | } elseif (isset($GLOBALS[static::$globalNamespace][$this->namespace][$key]) && is_array($value)) { |
||
160 | foreach ($value as $item) { |
||
161 | if (!in_array($item, $GLOBALS[static::$globalNamespace][$this->namespace][$key])) { |
||
162 | $GLOBALS[static::$globalNamespace][$this->namespace][$key][] = $item; |
||
163 | } |
||
164 | } |
||
165 | } else { |
||
166 | Arr::set($GLOBALS[static::$globalNamespace][$this->namespace], $key, $value); |
||
167 | } |
||
168 | |||
169 | return $this; |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * @alias Javascript::set() |
||
174 | * @param $key |
||
175 | * @param $value |
||
176 | * @return JavaScript |
||
177 | */ |
||
178 | public function add($key, $value = null){ |
||
179 | return $this->set($key, $value); |
||
180 | } |
||
181 | |||
182 | /** |
||
183 | * Set the namespace |
||
184 | * @param $namespace |
||
185 | * @return $this |
||
186 | */ |
||
187 | public static function namespace($namespace) |
||
188 | { |
||
189 | if (!isset(self::$_instances[$namespace])) { |
||
190 | self::$_instances[$namespace] = new static($namespace); |
||
191 | } |
||
192 | |||
193 | return self::$_instances[$namespace]; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Flatten a multi-dimensional associative array with dots. |
||
198 | * |
||
199 | * @param string $prepend |
||
200 | * @return $this |
||
201 | */ |
||
202 | public function dot($prepend = '') |
||
203 | { |
||
204 | $data = $this->getActiveData(); |
||
205 | $this->setActiveData(Arr::dot($data, $prepend)); |
||
206 | |||
207 | return $this; |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * Get a subset of the items from the given array. |
||
212 | * |
||
213 | * @param array|string $keys |
||
214 | * @return $this |
||
215 | */ |
||
216 | public function only($keys) |
||
217 | { |
||
218 | $data = $this->getActiveData(); |
||
219 | $this->setActiveData(Arr::only($data, $keys)); |
||
220 | |||
221 | return $this; |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * Pluck an array of values from an array. |
||
226 | * |
||
227 | * @param string|array|null $value |
||
228 | * @param null $key |
||
229 | * @return $this |
||
230 | */ |
||
231 | public function pluck($value, $key = null) |
||
232 | { |
||
233 | $data = $this->getActiveData(); |
||
234 | $this->setActiveData(Arr::pluck($data, $value, $key)); |
||
235 | |||
236 | return $this; |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * Filter the array using the given callback. |
||
241 | * |
||
242 | * @param callable $callback |
||
243 | * @return $this |
||
244 | */ |
||
245 | public function where(callable $callback) |
||
246 | { |
||
247 | $data = $this->getActiveData(); |
||
248 | $this->setActiveData(Arr::where($data, $callback)); |
||
249 | |||
250 | return $this; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * Merge the given arrays |
||
255 | * |
||
256 | * @param array * $arrays |
||
257 | * @return $this |
||
258 | * @throws \Exception |
||
259 | */ |
||
260 | public function merge() |
||
261 | { |
||
262 | $arrays = func_get_args(); |
||
263 | |||
264 | foreach ($arrays as $array) { |
||
265 | if (!is_array($array)) { |
||
266 | throw new \Exception('[Hook::merge] all arguments must be Array.'); |
||
267 | } |
||
268 | |||
269 | foreach ($array as $key => $value) { |
||
270 | if ($this->has($key)) { |
||
271 | $tmp = $this->get($key); |
||
272 | |||
273 | if (is_array($tmp)) { |
||
274 | $value = Arr::wrap($value); |
||
275 | $value = array_merge_recursive($tmp, $value); |
||
276 | } |
||
277 | } |
||
278 | |||
279 | $this->set($key, $value); |
||
280 | } |
||
281 | } |
||
282 | |||
283 | return $this; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * JSON encode |
||
288 | * @return string |
||
289 | */ |
||
290 | public function toJson() |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Render as Script tag |
||
297 | * @param null $varName |
||
298 | * @param array $variables |
||
299 | * @param bool $scriptTag |
||
300 | * @return string |
||
301 | * @internal param null $namespace |
||
302 | */ |
||
303 | public function render($varName = null, $variables = [], $scriptTag = true) |
||
304 | { |
||
305 | if (is_null($varName)) { |
||
306 | $varName = $this->namespace; |
||
307 | } |
||
308 | |||
309 | $this->merge($variables); |
||
310 | |||
311 | return ($scriptTag?'<script>':'').'window.' . $varName . ' = ' . $this->toJson() . ';'.($scriptTag?'</script>':''); |
||
312 | } |
||
313 | |||
314 | public function renderVar($namespace = null, $variables = []){ |
||
315 | return $this->render($namespace, $variables, false); |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Retrieve selected data |
||
320 | * @return mixed|null |
||
321 | */ |
||
322 | private function getActiveData() |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * Set selected data |
||
333 | * @param $data |
||
334 | */ |
||
335 | private function setActiveData($data, $force = true) |
||
341 | } |
||
342 | } |
||
343 | } |