pictcode / lib / Cake / View / Helper.php @ 3bf0e002
履歴 | 表示 | アノテート | ダウンロード (28.165 KB)
| 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("&", "<", ">"), array("&amp;", "&lt;", "&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("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $this->_cleaned); |
| 985 |
} |
| 986 |
|
| 987 |
} |