CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.7 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.7
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • BreadcrumbsHelper
  • FlashHelper
  • FormHelper
  • HtmlHelper
  • NumberHelper
  • PaginatorHelper
  • RssHelper
  • SessionHelper
  • TextHelper
  • TimeHelper
  • UrlHelper

Traits

  • IdGeneratorTrait
  • SecureFieldTokenTrait
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         0.9.1
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\View\Helper;
  16: 
  17: use Cake\Core\Configure;
  18: use Cake\Http\Response;
  19: use Cake\View\Helper;
  20: use Cake\View\StringTemplateTrait;
  21: use Cake\View\View;
  22: 
  23: /**
  24:  * Html Helper class for easy use of HTML widgets.
  25:  *
  26:  * HtmlHelper encloses all methods needed while working with HTML pages.
  27:  *
  28:  * @property \Cake\View\Helper\UrlHelper $Url
  29:  * @link https://book.cakephp.org/3.0/en/views/helpers/html.html
  30:  */
  31: class HtmlHelper extends Helper
  32: {
  33: 
  34:     use StringTemplateTrait;
  35: 
  36:     /**
  37:      * List of helpers used by this helper
  38:      *
  39:      * @var array
  40:      */
  41:     public $helpers = ['Url'];
  42: 
  43:     /**
  44:      * Reference to the Response object
  45:      *
  46:      * @var \Cake\Http\Response
  47:      */
  48:     public $response;
  49: 
  50:     /**
  51:      * Default config for this class
  52:      *
  53:      * @var array
  54:      */
  55:     protected $_defaultConfig = [
  56:         'templates' => [
  57:             'meta' => '<meta{{attrs}}/>',
  58:             'metalink' => '<link href="{{url}}"{{attrs}}/>',
  59:             'link' => '<a href="{{url}}"{{attrs}}>{{content}}</a>',
  60:             'mailto' => '<a href="mailto:{{url}}"{{attrs}}>{{content}}</a>',
  61:             'image' => '<img src="{{url}}"{{attrs}}/>',
  62:             'tableheader' => '<th{{attrs}}>{{content}}</th>',
  63:             'tableheaderrow' => '<tr{{attrs}}>{{content}}</tr>',
  64:             'tablecell' => '<td{{attrs}}>{{content}}</td>',
  65:             'tablerow' => '<tr{{attrs}}>{{content}}</tr>',
  66:             'block' => '<div{{attrs}}>{{content}}</div>',
  67:             'blockstart' => '<div{{attrs}}>',
  68:             'blockend' => '</div>',
  69:             'tag' => '<{{tag}}{{attrs}}>{{content}}</{{tag}}>',
  70:             'tagstart' => '<{{tag}}{{attrs}}>',
  71:             'tagend' => '</{{tag}}>',
  72:             'tagselfclosing' => '<{{tag}}{{attrs}}/>',
  73:             'para' => '<p{{attrs}}>{{content}}</p>',
  74:             'parastart' => '<p{{attrs}}>',
  75:             'css' => '<link rel="{{rel}}" href="{{url}}"{{attrs}}/>',
  76:             'style' => '<style{{attrs}}>{{content}}</style>',
  77:             'charset' => '<meta charset="{{charset}}"/>',
  78:             'ul' => '<ul{{attrs}}>{{content}}</ul>',
  79:             'ol' => '<ol{{attrs}}>{{content}}</ol>',
  80:             'li' => '<li{{attrs}}>{{content}}</li>',
  81:             'javascriptblock' => '<script{{attrs}}>{{content}}</script>',
  82:             'javascriptstart' => '<script>',
  83:             'javascriptlink' => '<script src="{{url}}"{{attrs}}></script>',
  84:             'javascriptend' => '</script>',
  85:             'confirmJs' => '{{confirm}}'
  86:         ]
  87:     ];
  88: 
  89:     /**
  90:      * Breadcrumbs.
  91:      *
  92:      * @var array
  93:      * @deprecated 3.3.6 Use the BreadcrumbsHelper instead
  94:      */
  95:     protected $_crumbs = [];
  96: 
  97:     /**
  98:      * Names of script & css files that have been included once
  99:      *
 100:      * @var array
 101:      */
 102:     protected $_includedAssets = [];
 103: 
 104:     /**
 105:      * Options for the currently opened script block buffer if any.
 106:      *
 107:      * @var array
 108:      */
 109:     protected $_scriptBlockOptions = [];
 110: 
 111:     /**
 112:      * Document type definitions
 113:      *
 114:      * @var array
 115:      */
 116:     protected $_docTypes = [
 117:         'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
 118:         'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
 119:         'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
 120:         'html5' => '<!DOCTYPE html>',
 121:         'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
 122:         'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
 123:         'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
 124:         'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
 125:     ];
 126: 
 127:     /**
 128:      * Constructor
 129:      *
 130:      * ### Settings
 131:      *
 132:      * - `templates` Either a filename to a config containing templates.
 133:      *   Or an array of templates to load. See Cake\View\StringTemplate for
 134:      *   template formatting.
 135:      *
 136:      * ### Customizing tag sets
 137:      *
 138:      * Using the `templates` option you can redefine the tag HtmlHelper will use.
 139:      *
 140:      * @param \Cake\View\View $View The View this helper is being attached to.
 141:      * @param array $config Configuration settings for the helper.
 142:      */
 143:     public function __construct(View $View, array $config = [])
 144:     {
 145:         parent::__construct($View, $config);
 146:         $this->response = $this->_View->getResponse() ?: new Response();
 147:     }
 148: 
 149:     /**
 150:      * Adds a link to the breadcrumbs array.
 151:      *
 152:      * @param string $name Text for link
 153:      * @param string|array|null $link URL for link (if empty it won't be a link)
 154:      * @param array $options Link attributes e.g. ['id' => 'selected']
 155:      * @return $this
 156:      * @see \Cake\View\Helper\HtmlHelper::link() for details on $options that can be used.
 157:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-breadcrumb-trails-with-htmlhelper
 158:      * @deprecated 3.3.6 Use the BreadcrumbsHelper instead
 159:      */
 160:     public function addCrumb($name, $link = null, array $options = [])
 161:     {
 162:         deprecationWarning(
 163:             'HtmlHelper::addCrumb() is deprecated. ' .
 164:             'Use the BreadcrumbsHelper instead.'
 165:         );
 166: 
 167:         $this->_crumbs[] = [$name, $link, $options];
 168: 
 169:         return $this;
 170:     }
 171: 
 172:     /**
 173:      * Returns a doctype string.
 174:      *
 175:      * Possible doctypes:
 176:      *
 177:      *  - html4-strict:  HTML4 Strict.
 178:      *  - html4-trans:  HTML4 Transitional.
 179:      *  - html4-frame:  HTML4 Frameset.
 180:      *  - html5: HTML5. Default value.
 181:      *  - xhtml-strict: XHTML1 Strict.
 182:      *  - xhtml-trans: XHTML1 Transitional.
 183:      *  - xhtml-frame: XHTML1 Frameset.
 184:      *  - xhtml11: XHTML1.1.
 185:      *
 186:      * @param string $type Doctype to use.
 187:      * @return string|null Doctype string
 188:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-doctype-tags
 189:      */
 190:     public function docType($type = 'html5')
 191:     {
 192:         if (isset($this->_docTypes[$type])) {
 193:             return $this->_docTypes[$type];
 194:         }
 195: 
 196:         return null;
 197:     }
 198: 
 199:     /**
 200:      * Creates a link to an external resource and handles basic meta tags
 201:      *
 202:      * Create a meta tag that is output inline:
 203:      *
 204:      * ```
 205:      * $this->Html->meta('icon', 'favicon.ico');
 206:      * ```
 207:      *
 208:      * Append the meta tag to custom view block "meta":
 209:      *
 210:      * ```
 211:      * $this->Html->meta('description', 'A great page', ['block' => true]);
 212:      * ```
 213:      *
 214:      * Append the meta tag to custom view block:
 215:      *
 216:      * ```
 217:      * $this->Html->meta('description', 'A great page', ['block' => 'metaTags']);
 218:      * ```
 219:      *
 220:      * Create a custom meta tag:
 221:      *
 222:      * ```
 223:      * $this->Html->meta(['property' => 'og:site_name', 'content' => 'CakePHP']);
 224:      * ```
 225:      *
 226:      * ### Options
 227:      *
 228:      * - `block` - Set to true to append output to view block "meta" or provide
 229:      *   custom block name.
 230:      *
 231:      * @param string|array $type The title of the external resource, Or an array of attributes for a
 232:      *   custom meta tag.
 233:      * @param string|array|null $content The address of the external resource or string for content attribute
 234:      * @param array $options Other attributes for the generated tag. If the type attribute is html,
 235:      *    rss, atom, or icon, the mime-type is returned.
 236:      * @return string|null A completed `<link />` element, or null if the element was sent to a block.
 237:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-meta-tags
 238:      */
 239:     public function meta($type, $content = null, array $options = [])
 240:     {
 241:         if (!is_array($type)) {
 242:             $types = [
 243:                 'rss' => ['type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $content],
 244:                 'atom' => ['type' => 'application/atom+xml', 'title' => $type, 'link' => $content],
 245:                 'icon' => ['type' => 'image/x-icon', 'rel' => 'icon', 'link' => $content],
 246:                 'keywords' => ['name' => 'keywords', 'content' => $content],
 247:                 'description' => ['name' => 'description', 'content' => $content],
 248:                 'robots' => ['name' => 'robots', 'content' => $content],
 249:                 'viewport' => ['name' => 'viewport', 'content' => $content],
 250:                 'canonical' => ['rel' => 'canonical', 'link' => $content],
 251:                 'next' => ['rel' => 'next', 'link' => $content],
 252:                 'prev' => ['rel' => 'prev', 'link' => $content],
 253:                 'first' => ['rel' => 'first', 'link' => $content],
 254:                 'last' => ['rel' => 'last', 'link' => $content]
 255:             ];
 256: 
 257:             if ($type === 'icon' && $content === null) {
 258:                 $types['icon']['link'] = 'favicon.ico';
 259:             }
 260: 
 261:             if (isset($types[$type])) {
 262:                 $type = $types[$type];
 263:             } elseif (!isset($options['type']) && $content !== null) {
 264:                 if (is_array($content) && isset($content['_ext'])) {
 265:                     $type = $types[$content['_ext']];
 266:                 } else {
 267:                     $type = ['name' => $type, 'content' => $content];
 268:                 }
 269:             } elseif (isset($options['type'], $types[$options['type']])) {
 270:                 $type = $types[$options['type']];
 271:                 unset($options['type']);
 272:             } else {
 273:                 $type = [];
 274:             }
 275:         }
 276: 
 277:         $options += $type + ['block' => null];
 278:         $out = null;
 279: 
 280:         if (isset($options['link'])) {
 281:             $options['link'] = $this->Url->assetUrl($options['link']);
 282:             if (isset($options['rel']) && $options['rel'] === 'icon') {
 283:                 $out = $this->formatTemplate('metalink', [
 284:                     'url' => $options['link'],
 285:                     'attrs' => $this->templater()->formatAttributes($options, ['block', 'link'])
 286:                 ]);
 287:                 $options['rel'] = 'shortcut icon';
 288:             }
 289:             $out .= $this->formatTemplate('metalink', [
 290:                 'url' => $options['link'],
 291:                 'attrs' => $this->templater()->formatAttributes($options, ['block', 'link'])
 292:             ]);
 293:         } else {
 294:             $out = $this->formatTemplate('meta', [
 295:                 'attrs' => $this->templater()->formatAttributes($options, ['block', 'type'])
 296:             ]);
 297:         }
 298: 
 299:         if (empty($options['block'])) {
 300:             return $out;
 301:         }
 302:         if ($options['block'] === true) {
 303:             $options['block'] = __FUNCTION__;
 304:         }
 305:         $this->_View->append($options['block'], $out);
 306:     }
 307: 
 308:     /**
 309:      * Returns a charset META-tag.
 310:      *
 311:      * @param string|null $charset The character set to be used in the meta tag. If empty,
 312:      *  The App.encoding value will be used. Example: "utf-8".
 313:      * @return string A meta tag containing the specified character set.
 314:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-charset-tags
 315:      */
 316:     public function charset($charset = null)
 317:     {
 318:         if (empty($charset)) {
 319:             $charset = strtolower(Configure::read('App.encoding'));
 320:         }
 321: 
 322:         return $this->formatTemplate('charset', [
 323:             'charset' => !empty($charset) ? $charset : 'utf-8'
 324:         ]);
 325:     }
 326: 
 327:     /**
 328:      * Creates an HTML link.
 329:      *
 330:      * If $url starts with "http://" this is treated as an external link. Else,
 331:      * it is treated as a path to controller/action and parsed with the
 332:      * UrlHelper::build() method.
 333:      *
 334:      * If the $url is empty, $title is used instead.
 335:      *
 336:      * ### Options
 337:      *
 338:      * - `escape` Set to false to disable escaping of title and attributes.
 339:      * - `escapeTitle` Set to false to disable escaping of title. Takes precedence
 340:      *   over value of `escape`)
 341:      * - `confirm` JavaScript confirmation message.
 342:      *
 343:      * @param string|array $title The content to be wrapped by `<a>` tags.
 344:      *   Can be an array if $url is null. If $url is null, $title will be used as both the URL and title.
 345:      * @param string|array|null $url Cake-relative URL or array of URL parameters, or
 346:      *   external URL (starts with http://)
 347:      * @param array $options Array of options and HTML attributes.
 348:      * @return string An `<a />` element.
 349:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-links
 350:      */
 351:     public function link($title, $url = null, array $options = [])
 352:     {
 353:         $escapeTitle = true;
 354:         if ($url !== null) {
 355:             $url = $this->Url->build($url, $options);
 356:             unset($options['fullBase']);
 357:         } else {
 358:             $url = $this->Url->build($title);
 359:             $title = htmlspecialchars_decode($url, ENT_QUOTES);
 360:             $title = h(urldecode($title));
 361:             $escapeTitle = false;
 362:         }
 363: 
 364:         if (isset($options['escapeTitle'])) {
 365:             $escapeTitle = $options['escapeTitle'];
 366:             unset($options['escapeTitle']);
 367:         } elseif (isset($options['escape'])) {
 368:             $escapeTitle = $options['escape'];
 369:         }
 370: 
 371:         if ($escapeTitle === true) {
 372:             $title = h($title);
 373:         } elseif (is_string($escapeTitle)) {
 374:             $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
 375:         }
 376: 
 377:         $templater = $this->templater();
 378:         $confirmMessage = null;
 379:         if (isset($options['confirm'])) {
 380:             $confirmMessage = $options['confirm'];
 381:             unset($options['confirm']);
 382:         }
 383:         if ($confirmMessage) {
 384:             $confirm = $this->_confirm($confirmMessage, 'return true;', 'return false;', $options);
 385:             $options['onclick'] = $templater->format('confirmJs', [
 386:                 'confirmMessage' => $this->_cleanConfirmMessage($confirmMessage),
 387:                 'confirm' => $confirm
 388:             ]);
 389:         }
 390: 
 391:         return $templater->format('link', [
 392:             'url' => $url,
 393:             'attrs' => $templater->formatAttributes($options),
 394:             'content' => $title
 395:         ]);
 396:     }
 397: 
 398:     /**
 399:      * Creates a link element for CSS stylesheets.
 400:      *
 401:      * ### Usage
 402:      *
 403:      * Include one CSS file:
 404:      *
 405:      * ```
 406:      * echo $this->Html->css('styles.css');
 407:      * ```
 408:      *
 409:      * Include multiple CSS files:
 410:      *
 411:      * ```
 412:      * echo $this->Html->css(['one.css', 'two.css']);
 413:      * ```
 414:      *
 415:      * Add the stylesheet to view block "css":
 416:      *
 417:      * ```
 418:      * $this->Html->css('styles.css', ['block' => true]);
 419:      * ```
 420:      *
 421:      * Add the stylesheet to a custom block:
 422:      *
 423:      * ```
 424:      * $this->Html->css('styles.css', ['block' => 'layoutCss']);
 425:      * ```
 426:      *
 427:      * ### Options
 428:      *
 429:      * - `block` Set to true to append output to view block "css" or provide
 430:      *   custom block name.
 431:      * - `once` Whether or not the css file should be checked for uniqueness. If true css
 432:      *   files  will only be included once, use false to allow the same
 433:      *   css to be included more than once per request.
 434:      * - `plugin` False value will prevent parsing path as a plugin
 435:      * - `rel` Defaults to 'stylesheet'. If equal to 'import' the stylesheet will be imported.
 436:      * - `fullBase` If true the URL will get a full address for the css file.
 437:      *
 438:      * @param string|array $path The name of a CSS style sheet or an array containing names of
 439:      *   CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
 440:      *   of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
 441:      * @param array $options Array of options and HTML arguments.
 442:      * @return string|null CSS `<link />` or `<style />` tag, depending on the type of link.
 443:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#linking-to-css-files
 444:      */
 445:     public function css($path, array $options = [])
 446:     {
 447:         $options += ['once' => true, 'block' => null, 'rel' => 'stylesheet'];
 448: 
 449:         if (is_array($path)) {
 450:             $out = '';
 451:             foreach ($path as $i) {
 452:                 $out .= "\n\t" . $this->css($i, $options);
 453:             }
 454:             if (empty($options['block'])) {
 455:                 return $out . "\n";
 456:             }
 457: 
 458:             return null;
 459:         }
 460: 
 461:         if (strpos($path, '//') !== false) {
 462:             $url = $path;
 463:         } else {
 464:             $url = $this->Url->css($path, $options);
 465:             $options = array_diff_key($options, ['fullBase' => null, 'pathPrefix' => null]);
 466:         }
 467: 
 468:         if ($options['once'] && isset($this->_includedAssets[__METHOD__][$path])) {
 469:             return null;
 470:         }
 471:         unset($options['once']);
 472:         $this->_includedAssets[__METHOD__][$path] = true;
 473:         $templater = $this->templater();
 474: 
 475:         if ($options['rel'] === 'import') {
 476:             $out = $templater->format('style', [
 477:                 'attrs' => $templater->formatAttributes($options, ['rel', 'block']),
 478:                 'content' => '@import url(' . $url . ');',
 479:             ]);
 480:         } else {
 481:             $out = $templater->format('css', [
 482:                 'rel' => $options['rel'],
 483:                 'url' => $url,
 484:                 'attrs' => $templater->formatAttributes($options, ['rel', 'block']),
 485:             ]);
 486:         }
 487: 
 488:         if (empty($options['block'])) {
 489:             return $out;
 490:         }
 491:         if ($options['block'] === true) {
 492:             $options['block'] = __FUNCTION__;
 493:         }
 494:         $this->_View->append($options['block'], $out);
 495:     }
 496: 
 497:     /**
 498:      * Returns one or many `<script>` tags depending on the number of scripts given.
 499:      *
 500:      * If the filename is prefixed with "/", the path will be relative to the base path of your
 501:      * application. Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
 502:      *
 503:      * ### Usage
 504:      *
 505:      * Include one script file:
 506:      *
 507:      * ```
 508:      * echo $this->Html->script('styles.js');
 509:      * ```
 510:      *
 511:      * Include multiple script files:
 512:      *
 513:      * ```
 514:      * echo $this->Html->script(['one.js', 'two.js']);
 515:      * ```
 516:      *
 517:      * Add the script file to a custom block:
 518:      *
 519:      * ```
 520:      * $this->Html->script('styles.js', ['block' => 'bodyScript']);
 521:      * ```
 522:      *
 523:      * ### Options
 524:      *
 525:      * - `block` Set to true to append output to view block "script" or provide
 526:      *   custom block name.
 527:      * - `once` Whether or not the script should be checked for uniqueness. If true scripts will only be
 528:      *   included once, use false to allow the same script to be included more than once per request.
 529:      * - `plugin` False value will prevent parsing path as a plugin
 530:      * - `fullBase` If true the url will get a full address for the script file.
 531:      *
 532:      * @param string|array $url String or array of javascript files to include
 533:      * @param array $options Array of options, and html attributes see above.
 534:      * @return string|null String of `<script />` tags or null if block is specified in options
 535:      *   or if $once is true and the file has been included before.
 536:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#linking-to-javascript-files
 537:      */
 538:     public function script($url, array $options = [])
 539:     {
 540:         $defaults = ['block' => null, 'once' => true];
 541:         $options += $defaults;
 542: 
 543:         if (is_array($url)) {
 544:             $out = '';
 545:             foreach ($url as $i) {
 546:                 $out .= "\n\t" . $this->script($i, $options);
 547:             }
 548:             if (empty($options['block'])) {
 549:                 return $out . "\n";
 550:             }
 551: 
 552:             return null;
 553:         }
 554: 
 555:         if (strpos($url, '//') === false) {
 556:             $url = $this->Url->script($url, $options);
 557:             $options = array_diff_key($options, ['fullBase' => null, 'pathPrefix' => null]);
 558:         }
 559:         if ($options['once'] && isset($this->_includedAssets[__METHOD__][$url])) {
 560:             return null;
 561:         }
 562:         $this->_includedAssets[__METHOD__][$url] = true;
 563: 
 564:         $out = $this->formatTemplate('javascriptlink', [
 565:             'url' => $url,
 566:             'attrs' => $this->templater()->formatAttributes($options, ['block', 'once']),
 567:         ]);
 568: 
 569:         if (empty($options['block'])) {
 570:             return $out;
 571:         }
 572:         if ($options['block'] === true) {
 573:             $options['block'] = __FUNCTION__;
 574:         }
 575:         $this->_View->append($options['block'], $out);
 576:     }
 577: 
 578:     /**
 579:      * Wrap $script in a script tag.
 580:      *
 581:      * ### Options
 582:      *
 583:      * - `safe` (boolean) Whether or not the $script should be wrapped in `<![CDATA[ ]]>`.
 584:      *   Defaults to `false`.
 585:      * - `block` Set to true to append output to view block "script" or provide
 586:      *   custom block name.
 587:      *
 588:      * @param string $script The script to wrap
 589:      * @param array $options The options to use. Options not listed above will be
 590:      *    treated as HTML attributes.
 591:      * @return string|null String or null depending on the value of `$options['block']`
 592:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-inline-javascript-blocks
 593:      */
 594:     public function scriptBlock($script, array $options = [])
 595:     {
 596:         $options += ['safe' => false, 'block' => null];
 597:         if ($options['safe']) {
 598:             $script = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
 599:         }
 600:         unset($options['safe']);
 601: 
 602:         $out = $this->formatTemplate('javascriptblock', [
 603:             'attrs' => $this->templater()->formatAttributes($options, ['block']),
 604:             'content' => $script
 605:         ]);
 606: 
 607:         if (empty($options['block'])) {
 608:             return $out;
 609:         }
 610:         if ($options['block'] === true) {
 611:             $options['block'] = 'script';
 612:         }
 613:         $this->_View->append($options['block'], $out);
 614:     }
 615: 
 616:     /**
 617:      * Begin a script block that captures output until HtmlHelper::scriptEnd()
 618:      * is called. This capturing block will capture all output between the methods
 619:      * and create a scriptBlock from it.
 620:      *
 621:      * ### Options
 622:      *
 623:      * - `safe` (boolean) Whether or not the $script should be wrapped in `<![CDATA[ ]]>`.
 624:      *   See scriptBlock().
 625:      * - `block` Set to true to append output to view block "script" or provide
 626:      *   custom block name.
 627:      *
 628:      * @param array $options Options for the code block.
 629:      * @return void
 630:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-inline-javascript-blocks
 631:      */
 632:     public function scriptStart(array $options = [])
 633:     {
 634:         $this->_scriptBlockOptions = $options;
 635:         ob_start();
 636:     }
 637: 
 638:     /**
 639:      * End a Buffered section of JavaScript capturing.
 640:      * Generates a script tag inline or appends to specified view block depending on
 641:      * the settings used when the scriptBlock was started
 642:      *
 643:      * @return string|null Depending on the settings of scriptStart() either a script tag or null
 644:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-inline-javascript-blocks
 645:      */
 646:     public function scriptEnd()
 647:     {
 648:         $buffer = ob_get_clean();
 649:         $options = $this->_scriptBlockOptions;
 650:         $this->_scriptBlockOptions = [];
 651: 
 652:         return $this->scriptBlock($buffer, $options);
 653:     }
 654: 
 655:     /**
 656:      * Builds CSS style data from an array of CSS properties
 657:      *
 658:      * ### Usage:
 659:      *
 660:      * ```
 661:      * echo $this->Html->style(['margin' => '10px', 'padding' => '10px'], true);
 662:      *
 663:      * // creates
 664:      * 'margin:10px;padding:10px;'
 665:      * ```
 666:      *
 667:      * @param array $data Style data array, keys will be used as property names, values as property values.
 668:      * @param bool $oneLine Whether or not the style block should be displayed on one line.
 669:      * @return string CSS styling data
 670:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-css-programatically
 671:      */
 672:     public function style(array $data, $oneLine = true)
 673:     {
 674:         $out = [];
 675:         foreach ($data as $key => $value) {
 676:             $out[] = $key . ':' . $value . ';';
 677:         }
 678:         if ($oneLine) {
 679:             return implode(' ', $out);
 680:         }
 681: 
 682:         return implode("\n", $out);
 683:     }
 684: 
 685:     /**
 686:      * Returns the breadcrumb trail as a sequence of &raquo;-separated links.
 687:      *
 688:      * If `$startText` is an array, the accepted keys are:
 689:      *
 690:      * - `text` Define the text/content for the link.
 691:      * - `url` Define the target of the created link.
 692:      *
 693:      * All other keys will be passed to HtmlHelper::link() as the `$options` parameter.
 694:      *
 695:      * @param string $separator Text to separate crumbs.
 696:      * @param string|array|bool $startText This will be the first crumb, if false it defaults to first crumb in array. Can
 697:      *   also be an array, see above for details.
 698:      * @return string|null Composed bread crumbs
 699:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-breadcrumb-trails-with-htmlhelper
 700:      * @deprecated 3.3.6 Use the BreadcrumbsHelper instead
 701:      */
 702:     public function getCrumbs($separator = '&raquo;', $startText = false)
 703:     {
 704:         deprecationWarning(
 705:             'HtmlHelper::getCrumbs() is deprecated. ' .
 706:             'Use the BreadcrumbsHelper instead.'
 707:         );
 708: 
 709:         $crumbs = $this->_prepareCrumbs($startText);
 710:         if (!empty($crumbs)) {
 711:             $out = [];
 712:             foreach ($crumbs as $crumb) {
 713:                 if (!empty($crumb[1])) {
 714:                     $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
 715:                 } else {
 716:                     $out[] = $crumb[0];
 717:                 }
 718:             }
 719: 
 720:             return implode($separator, $out);
 721:         }
 722: 
 723:         return null;
 724:     }
 725: 
 726:     /**
 727:      * Returns breadcrumbs as a (x)html list
 728:      *
 729:      * This method uses HtmlHelper::tag() to generate list and its elements. Works
 730:      * similar to HtmlHelper::getCrumbs(), so it uses options which every
 731:      * crumb was added with.
 732:      *
 733:      * ### Options
 734:      *
 735:      * - `separator` Separator content to insert in between breadcrumbs, defaults to ''
 736:      * - `firstClass` Class for wrapper tag on the first breadcrumb, defaults to 'first'
 737:      * - `lastClass` Class for wrapper tag on current active page, defaults to 'last'
 738:      *
 739:      * @param array $options Array of HTML attributes to apply to the generated list elements.
 740:      * @param string|array|bool $startText This will be the first crumb, if false it defaults to first crumb in array. Can
 741:      *   also be an array, see `HtmlHelper::getCrumbs` for details.
 742:      * @return string|null Breadcrumbs HTML list.
 743:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-breadcrumb-trails-with-htmlhelper
 744:      * @deprecated 3.3.6 Use the BreadcrumbsHelper instead
 745:      */
 746:     public function getCrumbList(array $options = [], $startText = false)
 747:     {
 748:         deprecationWarning(
 749:             'HtmlHelper::getCrumbList() is deprecated. ' .
 750:             'Use the BreadcrumbsHelper instead.'
 751:         );
 752: 
 753:         $defaults = ['firstClass' => 'first', 'lastClass' => 'last', 'separator' => '', 'escape' => true];
 754:         $options += $defaults;
 755:         $firstClass = $options['firstClass'];
 756:         $lastClass = $options['lastClass'];
 757:         $separator = $options['separator'];
 758:         $escape = $options['escape'];
 759:         unset($options['firstClass'], $options['lastClass'], $options['separator'], $options['escape']);
 760: 
 761:         $crumbs = $this->_prepareCrumbs($startText, $escape);
 762:         if (empty($crumbs)) {
 763:             return null;
 764:         }
 765: 
 766:         $result = '';
 767:         $crumbCount = count($crumbs);
 768:         $ulOptions = $options;
 769:         foreach ($crumbs as $which => $crumb) {
 770:             $options = [];
 771:             if (empty($crumb[1])) {
 772:                 $elementContent = $crumb[0];
 773:             } else {
 774:                 $elementContent = $this->link($crumb[0], $crumb[1], $crumb[2]);
 775:             }
 776:             if (!$which && $firstClass !== false) {
 777:                 $options['class'] = $firstClass;
 778:             } elseif ($which == $crumbCount - 1 && $lastClass !== false) {
 779:                 $options['class'] = $lastClass;
 780:             }
 781:             if (!empty($separator) && ($crumbCount - $which >= 2)) {
 782:                 $elementContent .= $separator;
 783:             }
 784:             $result .= $this->formatTemplate('li', [
 785:                 'content' => $elementContent,
 786:                 'attrs' => $this->templater()->formatAttributes($options)
 787:             ]);
 788:         }
 789: 
 790:         return $this->formatTemplate('ul', [
 791:             'content' => $result,
 792:             'attrs' => $this->templater()->formatAttributes($ulOptions)
 793:         ]);
 794:     }
 795: 
 796:     /**
 797:      * Prepends startText to crumbs array if set
 798:      *
 799:      * @param string|array|bool $startText Text to prepend
 800:      * @param bool $escape If the output should be escaped or not
 801:      * @return array Crumb list including startText (if provided)
 802:      * @deprecated 3.3.6 Use the BreadcrumbsHelper instead
 803:      */
 804:     protected function _prepareCrumbs($startText, $escape = true)
 805:     {
 806:         deprecationWarning(
 807:             'HtmlHelper::_prepareCrumbs() is deprecated. ' .
 808:             'Use the BreadcrumbsHelper instead.'
 809:         );
 810: 
 811:         $crumbs = $this->_crumbs;
 812:         if ($startText) {
 813:             if (!is_array($startText)) {
 814:                 $startText = [
 815:                     'url' => '/',
 816:                     'text' => $startText
 817:                 ];
 818:             }
 819:             $startText += ['url' => '/', 'text' => __d('cake', 'Home')];
 820:             list($url, $text) = [$startText['url'], $startText['text']];
 821:             unset($startText['url'], $startText['text']);
 822:             array_unshift($crumbs, [$text, $url, $startText + ['escape' => $escape]]);
 823:         }
 824: 
 825:         return $crumbs;
 826:     }
 827: 
 828:     /**
 829:      * Creates a formatted IMG element.
 830:      *
 831:      * This method will set an empty alt attribute if one is not supplied.
 832:      *
 833:      * ### Usage:
 834:      *
 835:      * Create a regular image:
 836:      *
 837:      * ```
 838:      * echo $this->Html->image('cake_icon.png', ['alt' => 'CakePHP']);
 839:      * ```
 840:      *
 841:      * Create an image link:
 842:      *
 843:      * ```
 844:      * echo $this->Html->image('cake_icon.png', ['alt' => 'CakePHP', 'url' => 'https://cakephp.org']);
 845:      * ```
 846:      *
 847:      * ### Options:
 848:      *
 849:      * - `url` If provided an image link will be generated and the link will point at
 850:      *   `$options['url']`.
 851:      * - `fullBase` If true the src attribute will get a full address for the image file.
 852:      * - `plugin` False value will prevent parsing path as a plugin
 853:      *
 854:      * @param string|array $path Path to the image file, relative to the app/webroot/img/ directory.
 855:      * @param array $options Array of HTML attributes. See above for special options.
 856:      * @return string completed img tag
 857:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#linking-to-images
 858:      */
 859:     public function image($path, array $options = [])
 860:     {
 861:         $path = $this->Url->image($path, $options);
 862:         $options = array_diff_key($options, ['fullBase' => null, 'pathPrefix' => null]);
 863: 
 864:         if (!isset($options['alt'])) {
 865:             $options['alt'] = '';
 866:         }
 867: 
 868:         $url = false;
 869:         if (!empty($options['url'])) {
 870:             $url = $options['url'];
 871:             unset($options['url']);
 872:         }
 873: 
 874:         $templater = $this->templater();
 875:         $image = $templater->format('image', [
 876:             'url' => $path,
 877:             'attrs' => $templater->formatAttributes($options),
 878:         ]);
 879: 
 880:         if ($url) {
 881:             return $templater->format('link', [
 882:                 'url' => $this->Url->build($url),
 883:                 'attrs' => null,
 884:                 'content' => $image
 885:             ]);
 886:         }
 887: 
 888:         return $image;
 889:     }
 890: 
 891:     /**
 892:      * Returns a row of formatted and named TABLE headers.
 893:      *
 894:      * @param array $names Array of tablenames. Each tablename also can be a key that points to an array with a set
 895:      *     of attributes to its specific tag
 896:      * @param array|null $trOptions HTML options for TR elements.
 897:      * @param array|null $thOptions HTML options for TH elements.
 898:      * @return string Completed table headers
 899:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-table-headings
 900:      */
 901:     public function tableHeaders(array $names, array $trOptions = null, array $thOptions = null)
 902:     {
 903:         $out = [];
 904:         foreach ($names as $arg) {
 905:             if (!is_array($arg)) {
 906:                 $out[] = $this->formatTemplate('tableheader', [
 907:                     'attrs' => $this->templater()->formatAttributes($thOptions),
 908:                     'content' => $arg
 909:                 ]);
 910:             } else {
 911:                 $out[] = $this->formatTemplate('tableheader', [
 912:                     'attrs' => $this->templater()->formatAttributes(current($arg)),
 913:                     'content' => key($arg)
 914:                 ]);
 915:             }
 916:         }
 917: 
 918:         return $this->tableRow(implode(' ', $out), (array)$trOptions);
 919:     }
 920: 
 921:     /**
 922:      * Returns a formatted string of table rows (TR's with TD's in them).
 923:      *
 924:      * @param array|string $data Array of table data
 925:      * @param array|bool|null $oddTrOptions HTML options for odd TR elements if true useCount is used
 926:      * @param array|bool|null $evenTrOptions HTML options for even TR elements
 927:      * @param bool $useCount adds class "column-$i"
 928:      * @param bool $continueOddEven If false, will use a non-static $count variable,
 929:      *    so that the odd/even count is reset to zero just for that call.
 930:      * @return string Formatted HTML
 931:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-table-cells
 932:      */
 933:     public function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true)
 934:     {
 935:         if (empty($data[0]) || !is_array($data[0])) {
 936:             $data = [$data];
 937:         }
 938: 
 939:         if ($oddTrOptions === true) {
 940:             $useCount = true;
 941:             $oddTrOptions = null;
 942:         }
 943: 
 944:         if ($evenTrOptions === false) {
 945:             $continueOddEven = false;
 946:             $evenTrOptions = null;
 947:         }
 948: 
 949:         if ($continueOddEven) {
 950:             static $count = 0;
 951:         } else {
 952:             $count = 0;
 953:         }
 954: 
 955:         $out = [];
 956:         foreach ($data as $line) {
 957:             $count++;
 958:             $cellsOut = $this->_renderCells($line, $useCount);
 959:             $opts = $count % 2 ? $oddTrOptions : $evenTrOptions;
 960:             $out[] = $this->tableRow(implode(' ', $cellsOut), (array)$opts);
 961:         }
 962: 
 963:         return implode("\n", $out);
 964:     }
 965: 
 966:     /**
 967:      * Renders cells for a row of a table.
 968:      *
 969:      * This is a helper method for tableCells(). Overload this method as you
 970:      * need to change the behavior of the cell rendering.
 971:      *
 972:      * @param array $line Line data to render.
 973:      * @param bool $useCount Renders the count into the row. Default is false.
 974:      * @return string[]
 975:      */
 976:     protected function _renderCells($line, $useCount = false)
 977:     {
 978:         $i = 0;
 979:         $cellsOut = [];
 980:         foreach ($line as $cell) {
 981:             $cellOptions = [];
 982: 
 983:             if (is_array($cell)) {
 984:                 $cellOptions = $cell[1];
 985:                 $cell = $cell[0];
 986:             }
 987: 
 988:             if ($useCount) {
 989:                 $i += 1;
 990:                 if (isset($cellOptions['class'])) {
 991:                     $cellOptions['class'] .= ' column-' . $i;
 992:                 } else {
 993:                     $cellOptions['class'] = 'column-' . $i;
 994:                 }
 995:             }
 996: 
 997:             $cellsOut[] = $this->tableCell($cell, $cellOptions);
 998:         }
 999: 
1000:         return $cellsOut;
1001:     }
1002: 
1003:     /**
1004:      * Renders a single table row (A TR with attributes).
1005:      *
1006:      * @param string $content The content of the row.
1007:      * @param array $options HTML attributes.
1008:      * @return string
1009:      */
1010:     public function tableRow($content, array $options = [])
1011:     {
1012:         return $this->formatTemplate('tablerow', [
1013:             'attrs' => $this->templater()->formatAttributes($options),
1014:             'content' => $content
1015:         ]);
1016:     }
1017: 
1018:     /**
1019:      * Renders a single table cell (A TD with attributes).
1020:      *
1021:      * @param string $content The content of the cell.
1022:      * @param array $options HTML attributes.
1023:      * @return string
1024:      */
1025:     public function tableCell($content, array $options = [])
1026:     {
1027:         return $this->formatTemplate('tablecell', [
1028:             'attrs' => $this->templater()->formatAttributes($options),
1029:             'content' => $content
1030:         ]);
1031:     }
1032: 
1033:     /**
1034:      * Returns a formatted block tag, i.e DIV, SPAN, P.
1035:      *
1036:      * ### Options
1037:      *
1038:      * - `escape` Whether or not the contents should be html_entity escaped.
1039:      *
1040:      * @param string $name Tag name.
1041:      * @param string|null $text String content that will appear inside the div element.
1042:      *   If null, only a start tag will be printed
1043:      * @param array $options Additional HTML attributes of the DIV tag, see above.
1044:      * @return string The formatted tag element
1045:      */
1046:     public function tag($name, $text = null, array $options = [])
1047:     {
1048:         if (empty($name)) {
1049:             return $text;
1050:         }
1051:         if (isset($options['escape']) && $options['escape']) {
1052:             $text = h($text);
1053:             unset($options['escape']);
1054:         }
1055:         if ($text === null) {
1056:             $tag = 'tagstart';
1057:         } else {
1058:             $tag = 'tag';
1059:         }
1060: 
1061:         return $this->formatTemplate($tag, [
1062:             'attrs' => $this->templater()->formatAttributes($options),
1063:             'tag' => $name,
1064:             'content' => $text,
1065:         ]);
1066:     }
1067: 
1068:     /**
1069:      * Returns a formatted DIV tag for HTML FORMs.
1070:      *
1071:      * ### Options
1072:      *
1073:      * - `escape` Whether or not the contents should be html_entity escaped.
1074:      *
1075:      * @param string|null $class CSS class name of the div element.
1076:      * @param string|null $text String content that will appear inside the div element.
1077:      *   If null, only a start tag will be printed
1078:      * @param array $options Additional HTML attributes of the DIV tag
1079:      * @return string The formatted DIV element
1080:      */
1081:     public function div($class = null, $text = null, array $options = [])
1082:     {
1083:         if (!empty($class)) {
1084:             $options['class'] = $class;
1085:         }
1086: 
1087:         return $this->tag('div', $text, $options);
1088:     }
1089: 
1090:     /**
1091:      * Returns a formatted P tag.
1092:      *
1093:      * ### Options
1094:      *
1095:      * - `escape` Whether or not the contents should be html_entity escaped.
1096:      *
1097:      * @param string $class CSS class name of the p element.
1098:      * @param string $text String content that will appear inside the p element.
1099:      * @param array $options Additional HTML attributes of the P tag
1100:      * @return string The formatted P element
1101:      */
1102:     public function para($class, $text, array $options = [])
1103:     {
1104:         if (!empty($options['escape'])) {
1105:             $text = h($text);
1106:         }
1107:         if ($class && !empty($class)) {
1108:             $options['class'] = $class;
1109:         }
1110:         $tag = 'para';
1111:         if ($text === null) {
1112:             $tag = 'parastart';
1113:         }
1114: 
1115:         return $this->formatTemplate($tag, [
1116:             'attrs' => $this->templater()->formatAttributes($options),
1117:             'content' => $text,
1118:         ]);
1119:     }
1120: 
1121:     /**
1122:      * Returns an audio/video element
1123:      *
1124:      * ### Usage
1125:      *
1126:      * Using an audio file:
1127:      *
1128:      * ```
1129:      * echo $this->Html->media('audio.mp3', ['fullBase' => true]);
1130:      * ```
1131:      *
1132:      * Outputs:
1133:      *
1134:      * ```
1135:      * <video src="http://www.somehost.com/files/audio.mp3">Fallback text</video>
1136:      * ```
1137:      *
1138:      * Using a video file:
1139:      *
1140:      * ```
1141:      * echo $this->Html->media('video.mp4', ['text' => 'Fallback text']);
1142:      * ```
1143:      *
1144:      * Outputs:
1145:      *
1146:      * ```
1147:      * <video src="/files/video.mp4">Fallback text</video>
1148:      * ```
1149:      *
1150:      * Using multiple video files:
1151:      *
1152:      * ```
1153:      * echo $this->Html->media(
1154:      *      ['video.mp4', ['src' => 'video.ogv', 'type' => "video/ogg; codecs='theora, vorbis'"]],
1155:      *      ['tag' => 'video', 'autoplay']
1156:      * );
1157:      * ```
1158:      *
1159:      * Outputs:
1160:      *
1161:      * ```
1162:      * <video autoplay="autoplay">
1163:      *      <source src="/files/video.mp4" type="video/mp4"/>
1164:      *      <source src="/files/video.ogv" type="video/ogv; codecs='theora, vorbis'"/>
1165:      * </video>
1166:      * ```
1167:      *
1168:      * ### Options
1169:      *
1170:      * - `tag` Type of media element to generate, either "audio" or "video".
1171:      *  If tag is not provided it's guessed based on file's mime type.
1172:      * - `text` Text to include inside the audio/video tag
1173:      * - `pathPrefix` Path prefix to use for relative URLs, defaults to 'files/'
1174:      * - `fullBase` If provided the src attribute will get a full address including domain name
1175:      *
1176:      * @param string|array $path Path to the video file, relative to the webroot/{$options['pathPrefix']} directory.
1177:      *  Or an array where each item itself can be a path string or an associate array containing keys `src` and `type`
1178:      * @param array $options Array of HTML attributes, and special options above.
1179:      * @return string Generated media element
1180:      */
1181:     public function media($path, array $options = [])
1182:     {
1183:         $options += [
1184:             'tag' => null,
1185:             'pathPrefix' => 'files/',
1186:             'text' => ''
1187:         ];
1188: 
1189:         if (!empty($options['tag'])) {
1190:             $tag = $options['tag'];
1191:         } else {
1192:             $tag = null;
1193:         }
1194: 
1195:         if (is_array($path)) {
1196:             $sourceTags = '';
1197:             foreach ($path as &$source) {
1198:                 if (is_string($source)) {
1199:                     $source = [
1200:                         'src' => $source,
1201:                     ];
1202:                 }
1203:                 if (!isset($source['type'])) {
1204:                     $ext = pathinfo($source['src'], PATHINFO_EXTENSION);
1205:                     $source['type'] = $this->response->getMimeType($ext);
1206:                 }
1207:                 $source['src'] = $this->Url->assetUrl($source['src'], $options);
1208:                 $sourceTags .= $this->formatTemplate('tagselfclosing', [
1209:                     'tag' => 'source',
1210:                     'attrs' => $this->templater()->formatAttributes($source)
1211:                 ]);
1212:             }
1213:             unset($source);
1214:             $options['text'] = $sourceTags . $options['text'];
1215:             unset($options['fullBase']);
1216:         } else {
1217:             if (empty($path) && !empty($options['src'])) {
1218:                 $path = $options['src'];
1219:             }
1220:             $options['src'] = $this->Url->assetUrl($path, $options);
1221:         }
1222: 
1223:         if ($tag === null) {
1224:             if (is_array($path)) {
1225:                 $mimeType = $path[0]['type'];
1226:             } else {
1227:                 $mimeType = $this->response->getMimeType(pathinfo($path, PATHINFO_EXTENSION));
1228:             }
1229:             if (preg_match('#^video/#', $mimeType)) {
1230:                 $tag = 'video';
1231:             } else {
1232:                 $tag = 'audio';
1233:             }
1234:         }
1235: 
1236:         if (isset($options['poster'])) {
1237:             $options['poster'] = $this->Url->assetUrl($options['poster'], ['pathPrefix' => Configure::read('App.imageBaseUrl')] + $options);
1238:         }
1239:         $text = $options['text'];
1240: 
1241:         $options = array_diff_key($options, [
1242:             'tag' => null,
1243:             'fullBase' => null,
1244:             'pathPrefix' => null,
1245:             'text' => null
1246:         ]);
1247: 
1248:         return $this->tag($tag, $text, $options);
1249:     }
1250: 
1251:     /**
1252:      * Build a nested list (UL/OL) out of an associative array.
1253:      *
1254:      * Options for $options:
1255:      *
1256:      * - `tag` - Type of list tag to use (ol/ul)
1257:      *
1258:      * Options for $itemOptions:
1259:      *
1260:      * - `even` - Class to use for even rows.
1261:      * - `odd` - Class to use for odd rows.
1262:      *
1263:      * @param array $list Set of elements to list
1264:      * @param array $options Options and additional HTML attributes of the list (ol/ul) tag.
1265:      * @param array $itemOptions Options and additional HTML attributes of the list item (LI) tag.
1266:      * @return string The nested list
1267:      * @link https://book.cakephp.org/3.0/en/views/helpers/html.html#creating-nested-lists
1268:      */
1269:     public function nestedList(array $list, array $options = [], array $itemOptions = [])
1270:     {
1271:         $options += ['tag' => 'ul'];
1272:         $items = $this->_nestedListItem($list, $options, $itemOptions);
1273: 
1274:         return $this->formatTemplate($options['tag'], [
1275:             'attrs' => $this->templater()->formatAttributes($options, ['tag']),
1276:             'content' => $items
1277:         ]);
1278:     }
1279: 
1280:     /**
1281:      * Internal function to build a nested list (UL/OL) out of an associative array.
1282:      *
1283:      * @param array $items Set of elements to list.
1284:      * @param array $options Additional HTML attributes of the list (ol/ul) tag.
1285:      * @param array $itemOptions Options and additional HTML attributes of the list item (LI) tag.
1286:      * @return string The nested list element
1287:      * @see \Cake\View\Helper\HtmlHelper::nestedList()
1288:      */
1289:     protected function _nestedListItem($items, $options, $itemOptions)
1290:     {
1291:         $out = '';
1292: 
1293:         $index = 1;
1294:         foreach ($items as $key => $item) {
1295:             if (is_array($item)) {
1296:                 $item = $key . $this->nestedList($item, $options, $itemOptions);
1297:             }
1298:             if (isset($itemOptions['even']) && $index % 2 === 0) {
1299:                 $itemOptions['class'] = $itemOptions['even'];
1300:             } elseif (isset($itemOptions['odd']) && $index % 2 !== 0) {
1301:                 $itemOptions['class'] = $itemOptions['odd'];
1302:             }
1303:             $out .= $this->formatTemplate('li', [
1304:                 'attrs' => $this->templater()->formatAttributes($itemOptions, ['even', 'odd']),
1305:                 'content' => $item
1306:             ]);
1307:             $index++;
1308:         }
1309: 
1310:         return $out;
1311:     }
1312: 
1313:     /**
1314:      * Event listeners.
1315:      *
1316:      * @return array
1317:      */
1318:     public function implementedEvents()
1319:     {
1320:         return [];
1321:     }
1322: }
1323: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs