Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @link          http://cakephp.org CakePHP(tm) Project
12
 * @package       Cake.View
13
 * @since         CakePHP(tm) v 0.2.9
14
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
15
 */
16
 
17
App::uses('Router', 'Routing');
18
App::uses('Hash', 'Utility');
19
App::uses('Inflector', 'Utility');
20
 
21
/**
22
 * Abstract base class for all other Helpers in CakePHP.
23
 * Provides common methods and features.
24
 *
25
 * @package       Cake.View
26
 */
27
class Helper extends Object {
28
 
29
/**
30
 * Settings for this helper.
31
 *
32
 * @var array
33
 */
34
	public $settings = array();
35
 
36
/**
37
 * List of helpers used by this helper
38
 *
39
 * @var array
40
 */
41
	public $helpers = array();
42
 
43
/**
44
 * A helper lookup table used to lazy load helper objects.
45
 *
46
 * @var array
47
 */
48
	protected $_helperMap = array();
49
 
50
/**
51
 * The current theme name if any.
52
 *
53
 * @var string
54
 */
55
	public $theme = null;
56
 
57
/**
58
 * Request object
59
 *
60
 * @var CakeRequest
61
 */
62
	public $request = null;
63
 
64
/**
65
 * Plugin path
66
 *
67
 * @var string
68
 */
69
	public $plugin = null;
70
 
71
/**
72
 * Holds the fields array('field_name' => array('type' => 'string', 'length' => 100),
73
 * primaryKey and validates array('field_name')
74
 *
75
 * @var array
76
 */
77
	public $fieldset = array();
78
 
79
/**
80
 * Holds tag templates.
81
 *
82
 * @var array
83
 */
84
	public $tags = array();
85
 
86
/**
87
 * Holds the content to be cleaned.
88
 *
89
 * @var mixed
90
 */
91
	protected $_tainted = null;
92
 
93
/**
94
 * Holds the cleaned content.
95
 *
96
 * @var mixed
97
 */
98
	protected $_cleaned = null;
99
 
100
/**
101
 * The View instance this helper is attached to
102
 *
103
 * @var View
104
 */
105
	protected $_View;
106
 
107
/**
108
 * A list of strings that should be treated as suffixes, or
109
 * sub inputs for a parent input. This is used for date/time
110
 * inputs primarily.
111
 *
112
 * @var array
113
 */
114
	protected $_fieldSuffixes = array(
115
		'year', 'month', 'day', 'hour', 'min', 'second', 'meridian'
116
	);
117
 
118
/**
119
 * The name of the current model entities are in scope of.
120
 *
121
 * @see Helper::setEntity()
122
 * @var string
123
 */
124
	protected $_modelScope;
125
 
126
/**
127
 * The name of the current model association entities are in scope of.
128
 *
129
 * @see Helper::setEntity()
130
 * @var string
131
 */
132
	protected $_association;
133
 
134
/**
135
 * The dot separated list of elements the current field entity is for.
136
 *
137
 * @see Helper::setEntity()
138
 * @var string
139
 */
140
	protected $_entityPath;
141
 
142
/**
143
 * Minimized attributes
144
 *
145
 * @var array
146
 */
147
	protected $_minimizedAttributes = array(
148
		'allowfullscreen',
149
		'async',
150
		'autofocus',
151
		'autoplay',
152
		'checked',
153
		'compact',
154
		'controls',
155
		'declare',
156
		'default',
157
		'defaultchecked',
158
		'defaultmuted',
159
		'defaultselected',
160
		'defer',
161
		'disabled',
162
		'enabled',
163
		'formnovalidate',
164
		'hidden',
165
		'indeterminate',
166
		'inert',
167
		'ismap',
168
		'itemscope',
169
		'loop',
170
		'multiple',
171
		'muted',
172
		'nohref',
173
		'noresize',
174
		'noshade',
175
		'novalidate',
176
		'nowrap',
177
		'open',
178
		'pauseonexit',
179
		'readonly',
180
		'required',
181
		'reversed',
182
		'scoped',
183
		'seamless',
184
		'selected',
185
		'sortable',
186
		'spellcheck',
187
		'truespeed',
188
		'typemustmatch',
189
		'visible'
190
	);
191
 
192
/**
193
 * Format to attribute
194
 *
195
 * @var string
196
 */
197
	protected $_attributeFormat = '%s="%s"';
198
 
199
/**
200
 * Format to attribute
201
 *
202
 * @var string
203
 */
204
	protected $_minimizedAttributeFormat = '%s="%s"';
205
 
206
/**
207
 * Default Constructor
208
 *
209
 * @param View $View The View this helper is being attached to.
210
 * @param array $settings Configuration settings for the helper.
211
 */
212
	public function __construct(View $View, $settings = array()) {
213
		$this->_View = $View;
214
		$this->request = $View->request;
215
		if ($settings) {
216
			$this->settings = Hash::merge($this->settings, $settings);
217
		}
218
		if (!empty($this->helpers)) {
219
			$this->_helperMap = ObjectCollection::normalizeObjectArray($this->helpers);
220
		}
221
	}
222
 
223
/**
224
 * Provide non fatal errors on missing method calls.
225
 *
226
 * @param string $method Method to invoke
227
 * @param array $params Array of params for the method.
228
 * @return void
229
 */
230
	public function __call($method, $params) {
231
		trigger_error(__d('cake_dev', 'Method %1$s::%2$s does not exist', get_class($this), $method), E_USER_WARNING);
232
	}
233
 
234
/**
235
 * Lazy loads helpers. Provides access to deprecated request properties as well.
236
 *
237
 * @param string $name Name of the property being accessed.
238
 * @return mixed Helper or property found at $name
239
 * @deprecated 3.0.0 Accessing request properties through this method is deprecated and will be removed in 3.0.
240
 */
241
	public function __get($name) {
242
		if (isset($this->_helperMap[$name]) && !isset($this->{$name})) {
243
			$settings = array('enabled' => false) + (array)$this->_helperMap[$name]['settings'];
244
			$this->{$name} = $this->_View->loadHelper($this->_helperMap[$name]['class'], $settings);
245
		}
246
		if (isset($this->{$name})) {
247
			return $this->{$name};
248
		}
249
		switch ($name) {
250
			case 'base':
251
			case 'here':
252
			case 'webroot':
253
			case 'data':
254
				return $this->request->{$name};
255
			case 'action':
256
				return isset($this->request->params['action']) ? $this->request->params['action'] : '';
257
			case 'params':
258
				return $this->request;
259
		}
260
	}
261
 
262
/**
263
 * Provides backwards compatibility access for setting values to the request object.
264
 *
265
 * @param string $name Name of the property being accessed.
266
 * @param mixed $value Value to set.
267
 * @return void
268
 * @deprecated 3.0.0 This method will be removed in 3.0
269
 */
270
	public function __set($name, $value) {
271
		switch ($name) {
272
			case 'base':
273
			case 'here':
274
			case 'webroot':
275
			case 'data':
276
				$this->request->{$name} = $value;
277
				return;
278
			case 'action':
279
				$this->request->params['action'] = $value;
280
				return;
281
		}
282
		$this->{$name} = $value;
283
	}
284
 
285
/**
286
 * Finds URL for specified action.
287
 *
288
 * Returns a URL pointing at the provided parameters.
289
 *
290
 * @param string|array $url Either a relative string url like `/products/view/23` or
291
 *    an array of URL parameters. Using an array for URLs will allow you to leverage
292
 *    the reverse routing features of CakePHP.
293
 * @param bool $full If true, the full base URL will be prepended to the result
294
 * @return string Full translated URL with base path.
295
 * @link http://book.cakephp.org/2.0/en/views/helpers.html
296
 */
297
	public function url($url = null, $full = false) {
298
		return h(Router::url($url, $full));
299
	}
300
 
301
/**
302
 * Checks if a file exists when theme is used, if no file is found default location is returned
303
 *
304
 * @param string $file The file to create a webroot path to.
305
 * @return string Web accessible path to file.
306
 */
307
	public function webroot($file) {
308
		$asset = explode('?', $file);
309
		$asset[1] = isset($asset[1]) ? '?' . $asset[1] : null;
310
		$webPath = "{$this->request->webroot}" . $asset[0];
311
		$file = $asset[0];
312
 
313
		if (!empty($this->theme)) {
314
			$file = trim($file, '/');
315
			$theme = $this->theme . '/';
316
 
317
			if (DS === '\\') {
318
				$file = str_replace('/', '\\', $file);
319
			}
320
 
321
			if (file_exists(Configure::read('App.www_root') . 'theme' . DS . $this->theme . DS . $file)) {
322
				$webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
323
			} else {
324
				$themePath = App::themePath($this->theme);
325
				$path = $themePath . 'webroot' . DS . $file;
326
				if (file_exists($path)) {
327
					$webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
328
				}
329
			}
330
		}
331
		if (strpos($webPath, '//') !== false) {
332
			return str_replace('//', '/', $webPath . $asset[1]);
333
		}
334
		return $webPath . $asset[1];
335
	}
336
 
337
/**
338
 * Generate URL for given asset file. Depending on options passed provides full URL with domain name.
339
 * Also calls Helper::assetTimestamp() to add timestamp to local files
340
 *
341
 * @param string|array $path Path string or URL array
342
 * @param array $options Options array. Possible keys:
343
 *   `fullBase` Return full URL with domain name
344
 *   `pathPrefix` Path prefix for relative URLs
345
 *   `ext` Asset extension to append
346
 *   `plugin` False value will prevent parsing path as a plugin
347
 * @return string Generated URL
348
 */
349
	public function assetUrl($path, $options = array()) {
350
		if (is_array($path)) {
351
			return $this->url($path, !empty($options['fullBase']));
352
		}
353
		if (strpos($path, '://') !== false) {
354
			return $path;
355
		}
356
		if (!array_key_exists('plugin', $options) || $options['plugin'] !== false) {
357
			list($plugin, $path) = $this->_View->pluginSplit($path, false);
358
		}
359
		if (!empty($options['pathPrefix']) && $path[0] !== '/') {
360
			$path = $options['pathPrefix'] . $path;
361
		}
362
		if (!empty($options['ext']) &&
363
			strpos($path, '?') === false &&
364
			substr($path, -strlen($options['ext'])) !== $options['ext']
365
		) {
366
			$path .= $options['ext'];
367
		}
368
		if (preg_match('|^([a-z0-9]+:)?//|', $path)) {
369
			return $path;
370
		}
371
		if (isset($plugin)) {
372
			$path = Inflector::underscore($plugin) . '/' . $path;
373
		}
374
		$path = $this->_encodeUrl($this->assetTimestamp($this->webroot($path)));
375
 
376
		if (!empty($options['fullBase'])) {
377
			$path = rtrim(Router::fullBaseUrl(), '/') . '/' . ltrim($path, '/');
378
		}
379
		return $path;
380
	}
381
 
382
/**
383
 * Encodes a URL for use in HTML attributes.
384
 *
385
 * @param string $url The URL to encode.
386
 * @return string The URL encoded for both URL & HTML contexts.
387
 */
388
	protected function _encodeUrl($url) {
389
		$path = parse_url($url, PHP_URL_PATH);
390
		$parts = array_map('rawurldecode', explode('/', $path));
391
		$parts = array_map('rawurlencode', $parts);
392
		$encoded = implode('/', $parts);
393
		return h(str_replace($path, $encoded, $url));
394
	}
395
 
396
/**
397
 * Adds a timestamp to a file based resource based on the value of `Asset.timestamp` in
398
 * Configure. If Asset.timestamp is true and debug > 0, or Asset.timestamp === 'force'
399
 * a timestamp will be added.
400
 *
401
 * @param string $path The file path to timestamp, the path must be inside WWW_ROOT
402
 * @return string Path with a timestamp added, or not.
403
 */
404
	public function assetTimestamp($path) {
405
		$stamp = Configure::read('Asset.timestamp');
406
		$timestampEnabled = $stamp === 'force' || ($stamp === true && Configure::read('debug') > 0);
407
		if ($timestampEnabled && strpos($path, '?') === false) {
408
			$filepath = preg_replace(
409
				'/^' . preg_quote($this->request->webroot, '/') . '/',
410
				'',
411
				urldecode($path)
412
			);
413
			$webrootPath = WWW_ROOT . str_replace('/', DS, $filepath);
414
			if (file_exists($webrootPath)) {
415
				//@codingStandardsIgnoreStart
416
				return $path . '?' . @filemtime($webrootPath);
417
				//@codingStandardsIgnoreEnd
418
			}
419
			$segments = explode('/', ltrim($filepath, '/'));
420
			if ($segments[0] === 'theme') {
421
				$theme = $segments[1];
422
				unset($segments[0], $segments[1]);
423
				$themePath = App::themePath($theme) . 'webroot' . DS . implode(DS, $segments);
424
				//@codingStandardsIgnoreStart
425
				return $path . '?' . @filemtime($themePath);
426
				//@codingStandardsIgnoreEnd
427
			} else {
428
				$plugin = Inflector::camelize($segments[0]);
429
				if (CakePlugin::loaded($plugin)) {
430
					unset($segments[0]);
431
					$pluginPath = CakePlugin::path($plugin) . 'webroot' . DS . implode(DS, $segments);
432
					//@codingStandardsIgnoreStart
433
					return $path . '?' . @filemtime($pluginPath);
434
					//@codingStandardsIgnoreEnd
435
				}
436
			}
437
		}
438
		return $path;
439
	}
440
 
441
/**
442
 * Used to remove harmful tags from content. Removes a number of well known XSS attacks
443
 * from content. However, is not guaranteed to remove all possibilities. Escaping
444
 * content is the best way to prevent all possible attacks.
445
 *
446
 * @param string|array $output Either an array of strings to clean or a single string to clean.
447
 * @return string|array|null Cleaned content for output
448
 * @deprecated 3.0.0 This method will be removed in 3.0
449
 */
450
	public function clean($output) {
451
		$this->_reset();
452
		if (empty($output)) {
453
			return null;
454
		}
455
		if (is_array($output)) {
456
			foreach ($output as $key => $value) {
457
				$return[$key] = $this->clean($value);
458
			}
459
			return $return;
460
		}
461
		$this->_tainted = $output;
462
		$this->_clean();
463
		return $this->_cleaned;
464
	}
465
 
466
/**
467
 * Returns a space-delimited string with items of the $options array. If a key
468
 * of $options array happens to be one of those listed in `Helper::$_minimizedAttributes`
469
 *
470
 * And its value is one of:
471
 *
472
 * - '1' (string)
473
 * - 1 (integer)
474
 * - true (boolean)
475
 * - 'true' (string)
476
 *
477
 * Then the value will be reset to be identical with key's name.
478
 * If the value is not one of these 3, the parameter is not output.
479
 *
480
 * 'escape' is a special option in that it controls the conversion of
481
 *  attributes to their html-entity encoded equivalents. Set to false to disable html-encoding.
482
 *
483
 * If value for any option key is set to `null` or `false`, that option will be excluded from output.
484
 *
485
 * @param array $options Array of options.
486
 * @param array $exclude Array of options to be excluded, the options here will not be part of the return.
487
 * @param string $insertBefore String to be inserted before options.
488
 * @param string $insertAfter String to be inserted after options.
489
 * @return string Composed attributes.
490
 * @deprecated 3.0.0 This method will be moved to HtmlHelper in 3.0
491
 */
492
	protected function _parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) {
493
		if (!is_string($options)) {
494
			$options = (array)$options + array('escape' => true);
495
 
496
			if (!is_array($exclude)) {
497
				$exclude = array();
498
			}
499
 
500
			$exclude = array('escape' => true) + array_flip($exclude);
501
			$escape = $options['escape'];
502
			$attributes = array();
503
 
504
			foreach ($options as $key => $value) {
505
				if (!isset($exclude[$key]) && $value !== false && $value !== null) {
506
					$attributes[] = $this->_formatAttribute($key, $value, $escape);
507
				}
508
			}
509
			$out = implode(' ', $attributes);
510
		} else {
511
			$out = $options;
512
		}
513
		return $out ? $insertBefore . $out . $insertAfter : '';
514
	}
515
 
516
/**
517
 * Formats an individual attribute, and returns the string value of the composed attribute.
518
 * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
519
 *
520
 * @param string $key The name of the attribute to create
521
 * @param string $value The value of the attribute to create.
522
 * @param bool $escape Define if the value must be escaped
523
 * @return string The composed attribute.
524
 * @deprecated 3.0.0 This method will be moved to HtmlHelper in 3.0
525
 */
526
	protected function _formatAttribute($key, $value, $escape = true) {
527
		if (is_array($value)) {
528
			$value = implode(' ', $value);
529
		}
530
		if (is_numeric($key)) {
531
			return sprintf($this->_minimizedAttributeFormat, $value, $value);
532
		}
533
		$truthy = array(1, '1', true, 'true', $key);
534
		$isMinimized = in_array($key, $this->_minimizedAttributes);
535
		if ($isMinimized && in_array($value, $truthy, true)) {
536
			return sprintf($this->_minimizedAttributeFormat, $key, $key);
537
		}
538
		if ($isMinimized) {
539
			return '';
540
		}
541
		return sprintf($this->_attributeFormat, $key, ($escape ? h($value) : $value));
542
	}
543
 
544
/**
545
 * Returns a string to be used as onclick handler for confirm dialogs.
546
 *
547
 * @param string $message Message to be displayed
548
 * @param string $okCode Code to be executed after user chose 'OK'
549
 * @param string $cancelCode Code to be executed after user chose 'Cancel'
550
 * @param array $options Array of options
551
 * @return string onclick JS code
552
 */
553
	protected function _confirm($message, $okCode, $cancelCode = '', $options = array()) {
554
		$message = json_encode($message);
555
		$confirm = "if (confirm({$message})) { {$okCode} } {$cancelCode}";
556
		if (isset($options['escape']) && $options['escape'] === false) {
557
			$confirm = h($confirm);
558
		}
559
		return $confirm;
560
	}
561
 
562
/**
563
 * Sets this helper's model and field properties to the dot-separated value-pair in $entity.
564
 *
565
 * @param string $entity A field name, like "ModelName.fieldName" or "ModelName.ID.fieldName"
566
 * @param bool $setScope Sets the view scope to the model specified in $tagValue
567
 * @return void
568
 */
569
	public function setEntity($entity, $setScope = false) {
570
		if ($entity === null) {
571
			$this->_modelScope = false;
572
		}
573
		if ($setScope === true) {
574
			$this->_modelScope = $entity;
575
		}
576
		$parts = array_values(Hash::filter(explode('.', $entity)));
577
		if (empty($parts)) {
578
			return;
579
		}
580
		$count = count($parts);
581
		$lastPart = isset($parts[$count - 1]) ? $parts[$count - 1] : null;
582
 
583
		// Either 'body' or 'date.month' type inputs.
584
		if (($count === 1 && $this->_modelScope && !$setScope) ||
585
			(
586
				$count === 2 &&
587
				in_array($lastPart, $this->_fieldSuffixes) &&
588
				$this->_modelScope &&
589
				$parts[0] !== $this->_modelScope
590
			)
591
		) {
592
			$entity = $this->_modelScope . '.' . $entity;
593
		}
594
 
595
		// 0.name, 0.created.month style inputs. Excludes inputs with the modelScope in them.
596
		if ($count >= 2 &&
597
			is_numeric($parts[0]) &&
598
			!is_numeric($parts[1]) &&
599
			$this->_modelScope &&
600
			strpos($entity, $this->_modelScope) === false
601
		) {
602
			$entity = $this->_modelScope . '.' . $entity;
603
		}
604
 
605
		$this->_association = null;
606
 
607
		$isHabtm = (
608
			isset($this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type']) &&
609
			$this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type'] === 'multiple'
610
		);
611
 
612
		// habtm models are special
613
		if ($count === 1 && $isHabtm) {
614
			$this->_association = $parts[0];
615
			$entity = $parts[0] . '.' . $parts[0];
616
		} else {
617
			// check for associated model.
618
			$reversed = array_reverse($parts);
619
			foreach ($reversed as $i => $part) {
620
				if ($i > 0 && preg_match('/^[A-Z]/', $part)) {
621
					$this->_association = $part;
622
					break;
623
				}
624
			}
625
		}
626
		$this->_entityPath = $entity;
627
	}
628
 
629
/**
630
 * Returns the entity reference of the current context as an array of identity parts
631
 *
632
 * @return array An array containing the identity elements of an entity
633
 */
634
	public function entity() {
635
		return explode('.', $this->_entityPath);
636
	}
637
 
638
/**
639
 * Gets the currently-used model of the rendering context.
640
 *
641
 * @return string
642
 */
643
	public function model() {
644
		if ($this->_association) {
645
			return $this->_association;
646
		}
647
		return $this->_modelScope;
648
	}
649
 
650
/**
651
 * Gets the currently-used model field of the rendering context.
652
 * Strips off field suffixes such as year, month, day, hour, min, meridian
653
 * when the current entity is longer than 2 elements.
654
 *
655
 * @return string
656
 */
657
	public function field() {
658
		$entity = $this->entity();
659
		$count = count($entity);
660
		$last = $entity[$count - 1];
661
		if ($count > 2 && in_array($last, $this->_fieldSuffixes)) {
662
			$last = isset($entity[$count - 2]) ? $entity[$count - 2] : null;
663
		}
664
		return $last;
665
	}
666
 
667
/**
668
 * Generates a DOM ID for the selected element, if one is not set.
669
 * Uses the current View::entity() settings to generate a CamelCased id attribute.
670
 *
671
 * @param array|string $options Either an array of html attributes to add $id into, or a string
672
 *   with a view entity path to get a domId for.
673
 * @param string $id The name of the 'id' attribute.
674
 * @return mixed If $options was an array, an array will be returned with $id set. If a string
675
 *   was supplied, a string will be returned.
676
 */
677
	public function domId($options = null, $id = 'id') {
678
		if (is_array($options) && array_key_exists($id, $options) && $options[$id] === null) {
679
			unset($options[$id]);
680
			return $options;
681
		} elseif (!is_array($options) && $options !== null) {
682
			$this->setEntity($options);
683
			return $this->domId();
684
		}
685
 
686
		$entity = $this->entity();
687
		$model = array_shift($entity);
688
		$dom = $model . implode('', array_map(array('Inflector', 'camelize'), $entity));
689
 
690
		if (is_array($options) && !array_key_exists($id, $options)) {
691
			$options[$id] = $dom;
692
		} elseif ($options === null) {
693
			return $dom;
694
		}
695
		return $options;
696
	}
697
 
698
/**
699
 * Gets the input field name for the current tag. Creates input name attributes
700
 * using CakePHP's data[Model][field] formatting.
701
 *
702
 * @param array|string $options If an array, should be an array of attributes that $key needs to be added to.
703
 *   If a string or null, will be used as the View entity.
704
 * @param string $field Field name.
705
 * @param string $key The name of the attribute to be set, defaults to 'name'
706
 * @return mixed If an array was given for $options, an array with $key set will be returned.
707
 *   If a string was supplied a string will be returned.
708
 */
709
	protected function _name($options = array(), $field = null, $key = 'name') {
710
		if ($options === null) {
711
			$options = array();
712
		} elseif (is_string($options)) {
713
			$field = $options;
714
			$options = 0;
715
		}
716
 
717
		if (!empty($field)) {
718
			$this->setEntity($field);
719
		}
720
 
721
		if (is_array($options) && array_key_exists($key, $options)) {
722
			return $options;
723
		}
724
 
725
		switch ($field) {
726
			case '_method':
727
				$name = $field;
728
				break;
729
			default:
730
				$name = 'data[' . implode('][', $this->entity()) . ']';
731
		}
732
 
733
		if (is_array($options)) {
734
			$options[$key] = $name;
735
			return $options;
736
		}
737
		return $name;
738
	}
739
 
740
/**
741
 * Gets the data for the current tag
742
 *
743
 * @param array|string $options If an array, should be an array of attributes that $key needs to be added to.
744
 *   If a string or null, will be used as the View entity.
745
 * @param string $field Field name.
746
 * @param string $key The name of the attribute to be set, defaults to 'value'
747
 * @return mixed If an array was given for $options, an array with $key set will be returned.
748
 *   If a string was supplied a string will be returned.
749
 */
750
	public function value($options = array(), $field = null, $key = 'value') {
751
		if ($options === null) {
752
			$options = array();
753
		} elseif (is_string($options)) {
754
			$field = $options;
755
			$options = 0;
756
		}
757
 
758
		if (is_array($options) && isset($options[$key])) {
759
			return $options;
760
		}
761
 
762
		if (!empty($field)) {
763
			$this->setEntity($field);
764
		}
765
		$result = null;
766
		$data = $this->request->data;
767
 
768
		$entity = $this->entity();
769
		if (!empty($data) && is_array($data) && !empty($entity)) {
770
			$result = Hash::get($data, implode('.', $entity));
771
		}
772
 
773
		$habtmKey = $this->field();
774
		if (empty($result) && isset($data[$habtmKey][$habtmKey]) && is_array($data[$habtmKey])) {
775
			$result = $data[$habtmKey][$habtmKey];
776
		} elseif (empty($result) && isset($data[$habtmKey]) && is_array($data[$habtmKey])) {
777
			if (ClassRegistry::isKeySet($habtmKey)) {
778
				$model = ClassRegistry::getObject($habtmKey);
779
				$result = $this->_selectedArray($data[$habtmKey], $model->primaryKey);
780
			}
781
		}
782
 
783
		if (is_array($options)) {
784
			if ($result === null && isset($options['default'])) {
785
				$result = $options['default'];
786
			}
787
			unset($options['default']);
788
		}
789
 
790
		if (is_array($options)) {
791
			$options[$key] = $result;
792
			return $options;
793
		}
794
		return $result;
795
	}
796
 
797
/**
798
 * Sets the defaults for an input tag. Will set the
799
 * name, value, and id attributes for an array of html attributes.
800
 *
801
 * @param string $field The field name to initialize.
802
 * @param array $options Array of options to use while initializing an input field.
803
 * @return array Array options for the form input.
804
 */
805
	protected function _initInputField($field, $options = array()) {
806
		if ($field !== null) {
807
			$this->setEntity($field);
808
		}
809
		$options = (array)$options;
810
		$options = $this->_name($options);
811
		$options = $this->value($options);
812
		$options = $this->domId($options);
813
		return $options;
814
	}
815
 
816
/**
817
 * Adds the given class to the element options
818
 *
819
 * @param array $options Array options/attributes to add a class to
820
 * @param string $class The class name being added.
821
 * @param string $key the key to use for class.
822
 * @return array Array of options with $key set.
823
 */
824
	public function addClass($options = array(), $class = null, $key = 'class') {
825
		if (isset($options[$key]) && trim($options[$key])) {
826
			$options[$key] .= ' ' . $class;
827
		} else {
828
			$options[$key] = $class;
829
		}
830
		return $options;
831
	}
832
 
833
/**
834
 * Returns a string generated by a helper method
835
 *
836
 * This method can be overridden in subclasses to do generalized output post-processing
837
 *
838
 * @param string $str String to be output.
839
 * @return string
840
 * @deprecated 3.0.0 This method will be removed in future versions.
841
 */
842
	public function output($str) {
843
		return $str;
844
	}
845
 
846
/**
847
 * Before render callback. beforeRender is called before the view file is rendered.
848
 *
849
 * Overridden in subclasses.
850
 *
851
 * @param string $viewFile The view file that is going to be rendered
852
 * @return void
853
 */
854
	public function beforeRender($viewFile) {
855
	}
856
 
857
/**
858
 * After render callback. afterRender is called after the view file is rendered
859
 * but before the layout has been rendered.
860
 *
861
 * Overridden in subclasses.
862
 *
863
 * @param string $viewFile The view file that was rendered.
864
 * @return void
865
 */
866
	public function afterRender($viewFile) {
867
	}
868
 
869
/**
870
 * Before layout callback. beforeLayout is called before the layout is rendered.
871
 *
872
 * Overridden in subclasses.
873
 *
874
 * @param string $layoutFile The layout about to be rendered.
875
 * @return void
876
 */
877
	public function beforeLayout($layoutFile) {
878
	}
879
 
880
/**
881
 * After layout callback. afterLayout is called after the layout has rendered.
882
 *
883
 * Overridden in subclasses.
884
 *
885
 * @param string $layoutFile The layout file that was rendered.
886
 * @return void
887
 */
888
	public function afterLayout($layoutFile) {
889
	}
890
 
891
/**
892
 * Before render file callback.
893
 * Called before any view fragment is rendered.
894
 *
895
 * Overridden in subclasses.
896
 *
897
 * @param string $viewFile The file about to be rendered.
898
 * @return void
899
 */
900
	public function beforeRenderFile($viewFile) {
901
	}
902
 
903
/**
904
 * After render file callback.
905
 * Called after any view fragment is rendered.
906
 *
907
 * Overridden in subclasses.
908
 *
909
 * @param string $viewFile The file just be rendered.
910
 * @param string $content The content that was rendered.
911
 * @return void
912
 */
913
	public function afterRenderFile($viewFile, $content) {
914
	}
915
 
916
/**
917
 * Transforms a recordset from a hasAndBelongsToMany association to a list of selected
918
 * options for a multiple select element
919
 *
920
 * @param string|array $data Data array or model name.
921
 * @param string $key Field name.
922
 * @return array
923
 */
924
	protected function _selectedArray($data, $key = 'id') {
925
		if (!is_array($data)) {
926
			$model = $data;
927
			if (!empty($this->request->data[$model][$model])) {
928
				return $this->request->data[$model][$model];
929
			}
930
			if (!empty($this->request->data[$model])) {
931
				$data = $this->request->data[$model];
932
			}
933
		}
934
		$array = array();
935
		if (!empty($data)) {
936
			foreach ($data as $row) {
937
				if (isset($row[$key])) {
938
					$array[$row[$key]] = $row[$key];
939
				}
940
			}
941
		}
942
		return empty($array) ? null : $array;
943
	}
944
 
945
/**
946
 * Resets the vars used by Helper::clean() to null
947
 *
948
 * @return void
949
 */
950
	protected function _reset() {
951
		$this->_tainted = null;
952
		$this->_cleaned = null;
953
	}
954
 
955
/**
956
 * Removes harmful content from output
957
 *
958
 * @return void
959
 */
960
	protected function _clean() {
961
		if (get_magic_quotes_gpc()) {
962
			$this->_cleaned = stripslashes($this->_tainted);
963
		} else {
964
			$this->_cleaned = $this->_tainted;
965
		}
966
 
967
		$this->_cleaned = str_replace(array("&amp;", "&lt;", "&gt;"), array("&amp;amp;", "&amp;lt;", "&amp;gt;"), $this->_cleaned);
968
		$this->_cleaned = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $this->_cleaned);
969
		$this->_cleaned = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $this->_cleaned);
970
		$this->_cleaned = html_entity_decode($this->_cleaned, ENT_COMPAT, "UTF-8");
971
		$this->_cleaned = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $this->_cleaned);
972
		$this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $this->_cleaned);
973
		$this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $this->_cleaned);
974
		$this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=*([\'\"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#iUu', '$1=$2nomozbinding...', $this->_cleaned);
975
		$this->_cleaned = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $this->_cleaned);
976
		$this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*expression[\x00-\x20]*\([^>]*>#iU', "$1>", $this->_cleaned);
977
		$this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*behaviour[\x00-\x20]*\([^>]*>#iU', "$1>", $this->_cleaned);
978
		$this->_cleaned = preg_replace('#(<[^>]+)style[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*).*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*>#iUu', "$1>", $this->_cleaned);
979
		$this->_cleaned = preg_replace('#</*\w+:\w[^>]*>#i', "", $this->_cleaned);
980
		do {
981
			$oldstring = $this->_cleaned;
982
			$this->_cleaned = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $this->_cleaned);
983
		} while ($oldstring !== $this->_cleaned);
984
		$this->_cleaned = str_replace(array("&amp;", "&lt;", "&gt;"), array("&amp;amp;", "&amp;lt;", "&amp;gt;"), $this->_cleaned);
985
	}
986
 
987
}