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.8 Red Velvet API

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