API
6 years ago
Access
6 years ago
Application
6 years ago
Archive
6 years ago
ArchiveProcessor
6 years ago
Archiver
6 years ago
AssetManager
6 years ago
Auth
6 years ago
Category
6 years ago
CliMulti
6 years ago
Columns
6 years ago
Composer
6 years ago
Concurrency
6 years ago
Config
6 years ago
Container
6 years ago
CronArchive
6 years ago
DataAccess
5 years ago
DataFiles
6 years ago
DataTable
6 years ago
Db
6 years ago
DeviceDetector
5 years ago
Email
6 years ago
Exception
6 years ago
Http
6 years ago
Intl
6 years ago
Mail
6 years ago
Measurable
6 years ago
Menu
6 years ago
Metrics
6 years ago
Notification
6 years ago
Period
6 years ago
Plugin
6 years ago
ProfessionalServices
6 years ago
Report
6 years ago
ReportRenderer
6 years ago
Scheduler
6 years ago
Segment
6 years ago
Session
6 years ago
Settings
6 years ago
Tracker
5 years ago
Translation
6 years ago
UpdateCheck
6 years ago
Updater
6 years ago
Updates
6 years ago
Validators
6 years ago
View
6 years ago
ViewDataTable
6 years ago
Visualization
6 years ago
Widget
6 years ago
.htaccess
6 years ago
Access.php
6 years ago
Archive.php
6 years ago
ArchiveProcessor.php
6 years ago
AssetManager.php
6 years ago
Auth.php
6 years ago
BaseFactory.php
6 years ago
Cache.php
6 years ago
CacheId.php
6 years ago
CliMulti.php
6 years ago
Common.php
6 years ago
Config.php
6 years ago
Console.php
6 years ago
Context.php
6 years ago
Cookie.php
5 years ago
CronArchive.php
5 years ago
DataArray.php
6 years ago
DataTable.php
6 years ago
Date.php
6 years ago
Db.php
6 years ago
DbHelper.php
6 years ago
Development.php
6 years ago
DeviceDetectorFactory.php
6 years ago
ErrorHandler.php
6 years ago
EventDispatcher.php
6 years ago
ExceptionHandler.php
6 years ago
FileIntegrity.php
6 years ago
Filechecks.php
6 years ago
Filesystem.php
6 years ago
FrontController.php
6 years ago
Http.php
6 years ago
IP.php
6 years ago
Log.php
6 years ago
LogDeleter.php
6 years ago
Mail.php
6 years ago
Metrics.php
6 years ago
MetricsFormatter.php
6 years ago
Nonce.php
5 years ago
Notification.php
6 years ago
NumberFormatter.php
6 years ago
Option.php
5 years ago
Period.php
6 years ago
Piwik.php
6 years ago
Plugin.php
6 years ago
Profiler.php
6 years ago
ProxyHeaders.php
6 years ago
ProxyHttp.php
6 years ago
QuickForm2.php
6 years ago
RankingQuery.php
6 years ago
Registry.php
6 years ago
ReportRenderer.php
6 years ago
ScheduledTask.php
6 years ago
Segment.php
6 years ago
Sequence.php
6 years ago
Session.php
6 years ago
SettingsPiwik.php
6 years ago
SettingsServer.php
6 years ago
Singleton.php
6 years ago
Site.php
6 years ago
TCPDF.php
6 years ago
TaskScheduler.php
6 years ago
Theme.php
6 years ago
Timer.php
6 years ago
Tracker.php
6 years ago
Translate.php
6 years ago
Twig.php
6 years ago
Unzip.php
6 years ago
UpdateCheck.php
6 years ago
Updater.php
6 years ago
Updates.php
6 years ago
Url.php
6 years ago
UrlHelper.php
6 years ago
Version.php
5 years ago
View.php
6 years ago
bootstrap.php
6 years ago
dispatch.php
6 years ago
testMinimumPhpVersion.php
6 years ago
Twig.php
591 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Piwik - free/libre analytics platform |
| 4 | * |
| 5 | * @link https://matomo.org |
| 6 | * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later |
| 7 | * |
| 8 | */ |
| 9 | namespace Piwik; |
| 10 | |
| 11 | use Exception; |
| 12 | use Piwik\Container\StaticContainer; |
| 13 | use Piwik\DataTable\Filter\SafeDecodeLabel; |
| 14 | use Piwik\Metrics\Formatter; |
| 15 | use Piwik\Plugin\Manager; |
| 16 | use Piwik\Tracker\GoalManager; |
| 17 | use Piwik\View\RenderTokenParser; |
| 18 | use Piwik\Visualization\Sparkline; |
| 19 | use Twig_Environment; |
| 20 | use Twig_Extension_Debug; |
| 21 | use Twig_Loader_Chain; |
| 22 | use Twig_Loader_Filesystem; |
| 23 | use Twig_SimpleFilter; |
| 24 | use Twig_SimpleFunction; |
| 25 | use Twig_SimpleTest; |
| 26 | |
| 27 | function piwik_filter_truncate($string, $size) |
| 28 | { |
| 29 | if (Common::mb_strlen(html_entity_decode($string)) <= $size) { |
| 30 | return $string; |
| 31 | } else { |
| 32 | preg_match('/^(&(?:[a-z\d]+|#\d+|#x[a-f\d]+);|.){'.$size.'}/i', $string, $shortenString); |
| 33 | return reset($shortenString) . "..."; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | function piwik_format_number($string, $minFractionDigits, $maxFractionDigits) |
| 38 | { |
| 39 | $formatter = NumberFormatter::getInstance(); |
| 40 | return $formatter->format($string, $minFractionDigits, $maxFractionDigits); |
| 41 | } |
| 42 | |
| 43 | function piwik_fix_lbrace($string) |
| 44 | { |
| 45 | $chars = array('{', '{', '{', '{', '{', '{'); |
| 46 | |
| 47 | static $search; |
| 48 | static $replace; |
| 49 | |
| 50 | if (!isset($search)) { |
| 51 | $search = array_map(function ($val) { return $val . $val; }, $chars); |
| 52 | } |
| 53 | if (!isset($replace)) { |
| 54 | $replace = array_map(function ($val) { return $val . '⁣' . $val; }, $chars); |
| 55 | } |
| 56 | |
| 57 | $replacedString = str_replace($search, $replace, $string); |
| 58 | |
| 59 | // try to replace characters until there are no changes |
| 60 | if ($string !== $replacedString) { |
| 61 | return piwik_fix_lbrace($replacedString); |
| 62 | } |
| 63 | |
| 64 | return $string; |
| 65 | } |
| 66 | |
| 67 | function piwik_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) { |
| 68 | |
| 69 | $string = twig_escape_filter($env, $string, $strategy, $charset, $autoescape); |
| 70 | |
| 71 | switch ($strategy) { |
| 72 | case 'html': |
| 73 | case 'html_attr': |
| 74 | return piwik_fix_lbrace($string); |
| 75 | case 'url': |
| 76 | $encoded = rawurlencode('{'); |
| 77 | return str_replace('{{', $encoded . $encoded, $string); |
| 78 | case 'css': |
| 79 | case 'js': |
| 80 | default: |
| 81 | return $string; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | function piwik_format_money($amount, $idSite) |
| 86 | { |
| 87 | $currencySymbol = Site::getCurrencySymbolFor($idSite); |
| 88 | $numberFormatter = NumberFormatter::getInstance(); |
| 89 | return $numberFormatter->formatCurrency($amount, $currencySymbol, GoalManager::REVENUE_PRECISION); |
| 90 | } |
| 91 | |
| 92 | class PiwikTwigFilterExtension extends \Twig_Extension |
| 93 | { |
| 94 | public function getFilters() |
| 95 | { |
| 96 | return array( |
| 97 | new Twig_SimpleFilter('e', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), |
| 98 | new Twig_SimpleFilter('escape', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')) |
| 99 | ); |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Returns the name of the extension. |
| 104 | * |
| 105 | * @return string The extension name |
| 106 | */ |
| 107 | public function getName() |
| 108 | { |
| 109 | return 'escaper2'; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | /** |
| 114 | * Twig class |
| 115 | * |
| 116 | */ |
| 117 | class Twig |
| 118 | { |
| 119 | const SPARKLINE_TEMPLATE = '<img alt="" data-src="%s" width="%d" height="%d" /> |
| 120 | <script type="text/javascript">$(function() { piwik.initSparklines(); });</script>'; |
| 121 | |
| 122 | /** |
| 123 | * @var Twig_Environment |
| 124 | */ |
| 125 | private $twig; |
| 126 | |
| 127 | private $formatter; |
| 128 | |
| 129 | public function __construct() |
| 130 | { |
| 131 | $loader = $this->getDefaultThemeLoader(); |
| 132 | $this->addPluginNamespaces($loader); |
| 133 | |
| 134 | //get current theme |
| 135 | $manager = Plugin\Manager::getInstance(); |
| 136 | $theme = $manager->getThemeEnabled(); |
| 137 | $loaders = array(); |
| 138 | |
| 139 | $this->formatter = new Formatter(); |
| 140 | |
| 141 | //create loader for custom theme to overwrite twig templates |
| 142 | if ($theme && $theme->getPluginName() != \Piwik\Plugin\Manager::DEFAULT_THEME) { |
| 143 | $customLoader = $this->getCustomThemeLoader($theme); |
| 144 | if ($customLoader) { |
| 145 | //make it possible to overwrite plugin templates |
| 146 | $this->addCustomPluginNamespaces($customLoader, $theme->getPluginName()); |
| 147 | $loaders[] = $customLoader; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | $loaders[] = $loader; |
| 152 | |
| 153 | $chainLoader = new Twig_Loader_Chain($loaders); |
| 154 | |
| 155 | // Create new Twig Environment and set cache dir |
| 156 | $templatesCompiledPath = StaticContainer::get('path.tmp') . '/templates_c'; |
| 157 | |
| 158 | $this->twig = new Twig_Environment($chainLoader, |
| 159 | array( |
| 160 | 'debug' => true, // to use {{ dump(var) }} in twig templates |
| 161 | 'strict_variables' => true, // throw an exception if variables are invalid |
| 162 | 'cache' => $templatesCompiledPath, |
| 163 | ) |
| 164 | ); |
| 165 | $this->twig->addExtension(new Twig_Extension_Debug()); |
| 166 | $this->twig->clearTemplateCache(); |
| 167 | |
| 168 | $this->addFilter_translate(); |
| 169 | $this->addFilter_urlRewriteWithParameters(); |
| 170 | $this->addFilter_sumTime(); |
| 171 | $this->addFilter_money(); |
| 172 | $this->addFilter_truncate(); |
| 173 | $this->addFilter_notification(); |
| 174 | $this->addFilter_percent(); |
| 175 | $this->addFilter_percentage(); |
| 176 | $this->addFilter_percentEvolution(); |
| 177 | $this->addFilter_prettyDate(); |
| 178 | $this->addFilter_safeDecodeRaw(); |
| 179 | $this->addFilter_number(); |
| 180 | $this->addFilter_nonce(); |
| 181 | $this->addFilter_md5(); |
| 182 | $this->addFilter_onlyDomain(); |
| 183 | $this->addFilter_safelink(); |
| 184 | $this->twig->addFilter(new Twig_SimpleFilter('implode', 'implode')); |
| 185 | $this->twig->addFilter(new Twig_SimpleFilter('ucwords', 'ucwords')); |
| 186 | $this->twig->addFilter(new Twig_SimpleFilter('lcfirst', 'lcfirst')); |
| 187 | $this->twig->addFilter(new Twig_SimpleFilter('ucfirst', 'ucfirst')); |
| 188 | |
| 189 | $this->addFunction_includeAssets(); |
| 190 | $this->addFunction_linkTo(); |
| 191 | $this->addFunction_sparkline(); |
| 192 | $this->addFunction_postEvent(); |
| 193 | $this->addFunction_isPluginLoaded(); |
| 194 | $this->addFunction_getJavascriptTranslations(); |
| 195 | |
| 196 | $this->twig->addTokenParser(new RenderTokenParser()); |
| 197 | |
| 198 | $this->addTest_false(); |
| 199 | $this->addTest_true(); |
| 200 | $this->addTest_emptyString(); |
| 201 | $this->addTest_isNumeric(); |
| 202 | |
| 203 | $this->twig->addExtension(new PiwikTwigFilterExtension()); |
| 204 | } |
| 205 | |
| 206 | private function addTest_false() |
| 207 | { |
| 208 | $test = new Twig_SimpleTest( |
| 209 | 'false', |
| 210 | function ($value) { |
| 211 | return false === $value; |
| 212 | } |
| 213 | ); |
| 214 | $this->twig->addTest($test); |
| 215 | } |
| 216 | |
| 217 | private function addTest_true() |
| 218 | { |
| 219 | $test = new Twig_SimpleTest( |
| 220 | 'true', |
| 221 | function ($value) { |
| 222 | return true === $value; |
| 223 | } |
| 224 | ); |
| 225 | $this->twig->addTest($test); |
| 226 | } |
| 227 | |
| 228 | private function addTest_emptyString() |
| 229 | { |
| 230 | $test = new Twig_SimpleTest( |
| 231 | 'emptyString', |
| 232 | function ($value) { |
| 233 | return '' === $value; |
| 234 | } |
| 235 | ); |
| 236 | $this->twig->addTest($test); |
| 237 | } |
| 238 | |
| 239 | protected function addFunction_getJavascriptTranslations() |
| 240 | { |
| 241 | $getJavascriptTranslations = new Twig_SimpleFunction( |
| 242 | 'getJavascriptTranslations', |
| 243 | array('Piwik\\Translate', 'getJavascriptTranslations') |
| 244 | ); |
| 245 | $this->twig->addFunction($getJavascriptTranslations); |
| 246 | } |
| 247 | |
| 248 | protected function addFunction_isPluginLoaded() |
| 249 | { |
| 250 | $isPluginLoadedFunction = new Twig_SimpleFunction('isPluginLoaded', function ($pluginName) { |
| 251 | return \Piwik\Plugin\Manager::getInstance()->isPluginLoaded($pluginName); |
| 252 | }); |
| 253 | $this->twig->addFunction($isPluginLoadedFunction); |
| 254 | } |
| 255 | |
| 256 | protected function addFunction_includeAssets() |
| 257 | { |
| 258 | $includeAssetsFunction = new Twig_SimpleFunction('includeAssets', function ($params) { |
| 259 | if (!isset($params['type'])) { |
| 260 | throw new Exception("The function includeAssets needs a 'type' parameter."); |
| 261 | } |
| 262 | |
| 263 | $assetType = strtolower($params['type']); |
| 264 | switch ($assetType) { |
| 265 | case 'css': |
| 266 | return AssetManager::getInstance()->getCssInclusionDirective(); |
| 267 | case 'js': |
| 268 | return AssetManager::getInstance()->getJsInclusionDirective(); |
| 269 | default: |
| 270 | throw new Exception("The twig function includeAssets 'type' parameter needs to be either 'css' or 'js'."); |
| 271 | } |
| 272 | }); |
| 273 | $this->twig->addFunction($includeAssetsFunction); |
| 274 | } |
| 275 | |
| 276 | protected function addFunction_postEvent() |
| 277 | { |
| 278 | $postEventFunction = new Twig_SimpleFunction('postEvent', function ($eventName) { |
| 279 | // get parameters to twig function |
| 280 | $params = func_get_args(); |
| 281 | // remove the first value (event name) |
| 282 | array_shift($params); |
| 283 | |
| 284 | // make the first value the string that will get output in the template |
| 285 | // plugins can modify this string |
| 286 | $str = ''; |
| 287 | $params = array_merge(array( &$str ), $params); |
| 288 | |
| 289 | Piwik::postEvent($eventName, $params); |
| 290 | return $str; |
| 291 | }, array('is_safe' => array('html'))); |
| 292 | $this->twig->addFunction($postEventFunction); |
| 293 | } |
| 294 | |
| 295 | protected function addFunction_sparkline() |
| 296 | { |
| 297 | $sparklineFunction = new Twig_SimpleFunction('sparkline', function ($src) { |
| 298 | $width = Sparkline::DEFAULT_WIDTH; |
| 299 | $height = Sparkline::DEFAULT_HEIGHT; |
| 300 | return sprintf(Twig::SPARKLINE_TEMPLATE, $src, $width, $height); |
| 301 | }, array('is_safe' => array('html'))); |
| 302 | $this->twig->addFunction($sparklineFunction); |
| 303 | } |
| 304 | |
| 305 | protected function addFunction_linkTo() |
| 306 | { |
| 307 | $urlFunction = new Twig_SimpleFunction('linkTo', function ($params) { |
| 308 | return 'index.php' . Url::getCurrentQueryStringWithParametersModified($params); |
| 309 | }); |
| 310 | $this->twig->addFunction($urlFunction); |
| 311 | } |
| 312 | |
| 313 | /** |
| 314 | * @return Twig_Loader_Filesystem |
| 315 | */ |
| 316 | private function getDefaultThemeLoader() |
| 317 | { |
| 318 | $themeDir = Manager::getPluginDirectory(\Piwik\Plugin\Manager::DEFAULT_THEME) . '/templates/'; |
| 319 | $themeLoader = new Twig_Loader_Filesystem(array($themeDir), PIWIK_DOCUMENT_ROOT.DIRECTORY_SEPARATOR); |
| 320 | |
| 321 | return $themeLoader; |
| 322 | } |
| 323 | |
| 324 | /** |
| 325 | * create template loader for a custom theme |
| 326 | * @param \Piwik\Plugin $theme |
| 327 | * @return \Twig_Loader_Filesystem |
| 328 | */ |
| 329 | protected function getCustomThemeLoader(Plugin $theme) |
| 330 | { |
| 331 | $pluginsDir = Manager::getPluginDirectory($theme->getPluginName()); |
| 332 | $themeDir = $pluginsDir . '/templates/'; |
| 333 | |
| 334 | if (!file_exists($themeDir)) { |
| 335 | return false; |
| 336 | } |
| 337 | $themeLoader = new Twig_Loader_Filesystem(array($themeDir), PIWIK_DOCUMENT_ROOT.DIRECTORY_SEPARATOR); |
| 338 | |
| 339 | return $themeLoader; |
| 340 | } |
| 341 | |
| 342 | public function getTwigEnvironment() |
| 343 | { |
| 344 | return $this->twig; |
| 345 | } |
| 346 | |
| 347 | protected function addFilter_notification() |
| 348 | { |
| 349 | $twigEnv = $this->getTwigEnvironment(); |
| 350 | $notificationFunction = new Twig_SimpleFilter('notification', function ($message, $options) use ($twigEnv) { |
| 351 | |
| 352 | $template = '<div style="display:none" data-role="notification" '; |
| 353 | |
| 354 | foreach ($options as $key => $value) { |
| 355 | if (ctype_alpha($key)) { |
| 356 | $template .= sprintf('data-%s="%s" ', $key, twig_escape_filter($twigEnv, $value, 'html_attr')); |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | $template .= '>'; |
| 361 | |
| 362 | if (!empty($options['raw'])) { |
| 363 | $template .= piwik_fix_lbrace($message); |
| 364 | } else { |
| 365 | $template .= piwik_escape_filter($twigEnv, $message, 'html'); |
| 366 | } |
| 367 | |
| 368 | $template .= '</div>'; |
| 369 | |
| 370 | return $template; |
| 371 | |
| 372 | }, array('is_safe' => array('html'))); |
| 373 | $this->twig->addFilter($notificationFunction); |
| 374 | } |
| 375 | |
| 376 | protected function addFilter_safeDecodeRaw() |
| 377 | { |
| 378 | $rawSafeDecoded = new Twig_SimpleFilter('rawSafeDecoded', function ($string) { |
| 379 | $string = str_replace('+', '%2B', $string); |
| 380 | $string = str_replace(' ', html_entity_decode(' ', ENT_COMPAT | ENT_HTML401, 'UTF-8'), $string); |
| 381 | |
| 382 | $string = SafeDecodeLabel::decodeLabelSafe($string); |
| 383 | |
| 384 | return piwik_fix_lbrace($string); |
| 385 | |
| 386 | }, array('is_safe' => array('all'))); |
| 387 | $this->twig->addFilter($rawSafeDecoded); |
| 388 | } |
| 389 | |
| 390 | protected function addFilter_prettyDate() |
| 391 | { |
| 392 | $prettyDate = new Twig_SimpleFilter('prettyDate', function ($dateString, $period) { |
| 393 | return Period\Factory::build($period, $dateString)->getLocalizedShortString(); |
| 394 | }); |
| 395 | $this->twig->addFilter($prettyDate); |
| 396 | } |
| 397 | |
| 398 | protected function addFilter_percentage() |
| 399 | { |
| 400 | $percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) { |
| 401 | $formatter = NumberFormatter::getInstance(); |
| 402 | return $formatter->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision); |
| 403 | }); |
| 404 | $this->twig->addFilter($percentage); |
| 405 | } |
| 406 | |
| 407 | protected function addFilter_percent() |
| 408 | { |
| 409 | $percentage = new Twig_SimpleFilter('percent', function ($string, $precision = 1) { |
| 410 | $formatter = NumberFormatter::getInstance(); |
| 411 | return $formatter->formatPercent($string, $precision); |
| 412 | }); |
| 413 | $this->twig->addFilter($percentage); |
| 414 | } |
| 415 | |
| 416 | protected function addFilter_percentEvolution() |
| 417 | { |
| 418 | $percentage = new Twig_SimpleFilter('percentEvolution', function ($string) { |
| 419 | $formatter = NumberFormatter::getInstance(); |
| 420 | return $formatter->formatPercentEvolution($string); |
| 421 | }); |
| 422 | $this->twig->addFilter($percentage); |
| 423 | } |
| 424 | |
| 425 | private function getProfessionalServicesAdvertising() |
| 426 | { |
| 427 | return StaticContainer::get('Piwik\ProfessionalServices\Advertising'); |
| 428 | } |
| 429 | |
| 430 | protected function addFilter_number() |
| 431 | { |
| 432 | $formatter = new Twig_SimpleFilter('number', function ($string, $minFractionDigits = 0, $maxFractionDigits = 0) { |
| 433 | return piwik_format_number($string, $minFractionDigits, $maxFractionDigits); |
| 434 | }); |
| 435 | $this->twig->addFilter($formatter); |
| 436 | } |
| 437 | |
| 438 | protected function addFilter_nonce() |
| 439 | { |
| 440 | $nonce = new Twig_SimpleFilter('nonce', array('Piwik\\Nonce', 'getNonce')); |
| 441 | $this->twig->addFilter($nonce); |
| 442 | } |
| 443 | |
| 444 | private function addFilter_md5() |
| 445 | { |
| 446 | $md5 = new \Twig_SimpleFilter('md5', function ($value) { |
| 447 | return md5($value); |
| 448 | }); |
| 449 | $this->twig->addFilter($md5); |
| 450 | } |
| 451 | |
| 452 | private function addFilter_onlyDomain() |
| 453 | { |
| 454 | $domainOnly = new \Twig_SimpleFilter('domainOnly', function ($url) { |
| 455 | $parsed = parse_url($url); |
| 456 | return $parsed['scheme'] . '://' . $parsed['host']; |
| 457 | }); |
| 458 | $this->twig->addFilter($domainOnly); |
| 459 | } |
| 460 | |
| 461 | protected function addFilter_truncate() |
| 462 | { |
| 463 | $truncateFilter = new Twig_SimpleFilter('truncate', function ($string, $size) { |
| 464 | return piwik_filter_truncate($string, $size); |
| 465 | }); |
| 466 | $this->twig->addFilter($truncateFilter); |
| 467 | } |
| 468 | |
| 469 | protected function addFilter_money() |
| 470 | { |
| 471 | $moneyFilter = new Twig_SimpleFilter('money', function ($amount) { |
| 472 | if (func_num_args() != 2) { |
| 473 | throw new Exception('the money modifier expects one parameter: the idSite.'); |
| 474 | } |
| 475 | $idSite = func_get_args(); |
| 476 | $idSite = $idSite[1]; |
| 477 | return piwik_format_money($amount, $idSite); |
| 478 | }); |
| 479 | $this->twig->addFilter($moneyFilter); |
| 480 | } |
| 481 | |
| 482 | protected function addFilter_sumTime() |
| 483 | { |
| 484 | $formatter = $this->formatter; |
| 485 | $sumtimeFilter = new Twig_SimpleFilter('sumtime', function ($numberOfSeconds) use ($formatter) { |
| 486 | return $formatter->getPrettyTimeFromSeconds($numberOfSeconds, true); |
| 487 | }); |
| 488 | $this->twig->addFilter($sumtimeFilter); |
| 489 | } |
| 490 | |
| 491 | protected function addFilter_urlRewriteWithParameters() |
| 492 | { |
| 493 | $urlRewriteFilter = new Twig_SimpleFilter('urlRewriteWithParameters', function ($parameters) { |
| 494 | $parameters['updated'] = null; |
| 495 | $url = Url::getCurrentQueryStringWithParametersModified($parameters); |
| 496 | return $url; |
| 497 | }); |
| 498 | $this->twig->addFilter($urlRewriteFilter); |
| 499 | } |
| 500 | |
| 501 | protected function addFilter_translate() |
| 502 | { |
| 503 | $translateFilter = new Twig_SimpleFilter('translate', function ($stringToken) { |
| 504 | if (func_num_args() <= 1) { |
| 505 | $aValues = array(); |
| 506 | } else { |
| 507 | $aValues = func_get_args(); |
| 508 | array_shift($aValues); |
| 509 | } |
| 510 | |
| 511 | try { |
| 512 | $stringTranslated = Piwik::translate($stringToken, $aValues); |
| 513 | } catch (Exception $e) { |
| 514 | $stringTranslated = $stringToken; |
| 515 | } |
| 516 | return $stringTranslated; |
| 517 | }); |
| 518 | $this->twig->addFilter($translateFilter); |
| 519 | } |
| 520 | |
| 521 | private function addPluginNamespaces(Twig_Loader_Filesystem $loader) |
| 522 | { |
| 523 | $pluginManager = \Piwik\Plugin\Manager::getInstance(); |
| 524 | $plugins = $pluginManager->getAllPluginsNames(); |
| 525 | |
| 526 | foreach ($plugins as $name) { |
| 527 | $pluginsDir = Manager::getPluginDirectory($name); |
| 528 | $path = sprintf("%s/templates/", $pluginsDir); |
| 529 | if (is_dir($path)) { |
| 530 | $loader->addPath(rtrim($path, '/'), $name); |
| 531 | } |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | /** |
| 536 | * |
| 537 | * Plugin-Templates can be overwritten by putting identically named templates in plugins/[theme]/templates/plugins/[plugin]/ |
| 538 | * |
| 539 | */ |
| 540 | private function addCustomPluginNamespaces(Twig_Loader_Filesystem $loader, $pluginName) |
| 541 | { |
| 542 | $pluginManager = \Piwik\Plugin\Manager::getInstance(); |
| 543 | $plugins = $pluginManager->getAllPluginsNames(); |
| 544 | |
| 545 | $pluginsDir = Manager::getPluginDirectory($pluginName); |
| 546 | |
| 547 | foreach ($plugins as $name) { |
| 548 | $path = sprintf("%s/templates/plugins/%s/", $pluginsDir, $name); |
| 549 | if (is_dir($path)) { |
| 550 | $loader->addPath(rtrim($path, '/'), $name); |
| 551 | } |
| 552 | } |
| 553 | } |
| 554 | |
| 555 | /** |
| 556 | * Prepend relative paths with absolute Piwik path |
| 557 | * |
| 558 | * @param string $value relative path (pass by reference) |
| 559 | * @param int $key (don't care) |
| 560 | * @param string $path Piwik root |
| 561 | */ |
| 562 | public static function addPiwikPath(&$value, $key, $path) |
| 563 | { |
| 564 | if ($value[0] != '/' && $value[0] != DIRECTORY_SEPARATOR) { |
| 565 | $value = $path . "/$value"; |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | private function addFilter_safelink() |
| 570 | { |
| 571 | $safelink = new Twig_SimpleFilter('safelink', function ($url) { |
| 572 | if (!UrlHelper::isLookLikeSafeUrl($url)) { |
| 573 | return ''; |
| 574 | } |
| 575 | return $url; |
| 576 | }); |
| 577 | $this->twig->addFilter($safelink); |
| 578 | } |
| 579 | |
| 580 | private function addTest_isNumeric() |
| 581 | { |
| 582 | $test = new Twig_SimpleTest( |
| 583 | 'numeric', |
| 584 | function ($value) { |
| 585 | return is_numeric($value); |
| 586 | } |
| 587 | ); |
| 588 | $this->twig->addTest($test); |
| 589 | } |
| 590 | } |
| 591 |