*/ protected array $_defaultConfig = [ 'activeClass' => 'active', ]; /** * List of helpers used by this helper * * @var string[] */ protected array $helpers = [ 'Html', 'Url', ]; /** * @param array|string $title * @param array|string|null $url * @param array $options * * @return string */ public function link(array|string $title, array|string|null $url = null, array $options = []): string { $currentUrl = $options['current'] ?? Router::parseRequest($this->getView()->getRequest()); if (!array_key_exists('target', $options) || !$currentUrl) { return $this->Html->link($title, $url, $options); } $target = $options['target']; $activeClass = $options['activeClass'] ?? $this->getConfig('activeClass'); unset($options['target']); unset($options['activeClass']); if (is_string($target)) { return $this->_linkFromStringTarget($currentUrl, $target, $title, $url, $activeClass, $options); } if (!is_array($target)) { return $this->Html->link($title, $url, $options); } if (!array_key_exists('plugin', $currentUrl)) { $currentUrl['plugin'] = false; } if (!array_key_exists('prefix', $currentUrl)) { $currentUrl['prefix'] = false; } if (isset($target['or']) && $target['or']) { foreach ($target['or'] as $singleTargetToMatch) { if ($this->_matchesUrlFromArrayTarget($currentUrl, $singleTargetToMatch)) { $options['class'] = $this->_addClass($options, $activeClass); return $this->Html->link($title, $url, $options); } } return $this->Html->link($title, $url, $options); } if (!$this->doesUrlMatchTarget($target, $currentUrl)) { return $this->Html->link($title, $url, $options); } $options['class'] = $this->_addClass($options, $activeClass); return $this->Html->link($title, $url, $options); } /** * @param array|string $targetUrl * @param array|null $current |null current url * * @return bool */ public function doesUrlMatchTarget(array|string $targetUrl, array|null $current = null) { if (!isset($current)) { $current = Router::parseRequest($this->getView()->getRequest()); } if (is_string($targetUrl) && Router::normalize($current) == Router::normalize($targetUrl)) { return true; } if (is_array($targetUrl)) { if (isset($targetUrl['or']) && $targetUrl['or']) { foreach ($targetUrl['or'] as $singleTargetToMatch) { $matched = $this->_matchesUrlFromArrayTarget($current, $singleTargetToMatch); if ($matched) { return true; } } } return $this->_matchesUrlFromArrayTarget($current, $targetUrl); } return false; } /** * @param array $providedOptions * * @return string */ protected function _addClass(array $providedOptions, string $toAdd): string { return array_key_exists('class', $providedOptions) ? $providedOptions['class'] . ' ' . $toAdd : $toAdd; } /** * @param array $current * @param string $targetString * @param string $title * @param array|string|null $url * @param array $options * * @return string */ protected function _linkFromStringTarget(array $current, string $targetString, string $title, array|string|null $url, string $activeClass, array $options) { if (Router::normalize($current) == Router::normalize($targetString)) { $options['class'] = $this->_addClass($options, $activeClass); return $this->Html->link($title, $url, $options); } return $this->Html->link($title, $url, $options); } /** * @param array $current * @param array $targetUrl * * @return bool */ protected function _matchesUrlFromArrayTarget(array $current, array $targetUrl) { foreach ($targetUrl as $targetKey => $targetValue) { if (is_array($targetValue)) { if (!in_array($current[$targetKey], $targetValue)) { return false; } continue; } if (!array_key_exists($targetKey, $current) || $targetValue != $current[$targetKey]) { return false; } } return true; } }