Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • CachingIterator
  • FilterExecutor
  • FilterInfo
  • Filters
  • Html
  • SnippetDriver
  • Template

Interfaces

  • IHtmlString
  • ISnippetBridge
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Latte (https://latte.nette.org)
  5:  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Latte\Runtime;
  9: 
 10: use Latte\Engine;
 11: use Latte\Helpers;
 12: 
 13: 
 14: /**
 15:  * Filter executor.
 16:  * @internal
 17:  */
 18: class FilterExecutor
 19: {
 20:     /** @var array */
 21:     private $_dynamic = [];
 22: 
 23:     /** @var array [name => [callback, FilterInfo aware] */
 24:     private $_static = [
 25:         'breaklines' => ['Latte\Runtime\Filters::breaklines', false],
 26:         'bytes' => ['Latte\Runtime\Filters::bytes', false],
 27:         'capitalize' => ['Latte\Runtime\Filters::capitalize', false],
 28:         'datastream' => ['Latte\Runtime\Filters::dataStream', false],
 29:         'date' => ['Latte\Runtime\Filters::date', false],
 30:         'escapecss' => ['Latte\Runtime\Filters::escapeCss', false],
 31:         'escapehtml' => ['Latte\Runtime\Filters::escapeHtml', false],
 32:         'escapehtmlcomment' => ['Latte\Runtime\Filters::escapeHtmlComment', false],
 33:         'escapeical' => ['Latte\Runtime\Filters::escapeICal', false],
 34:         'escapejs' => ['Latte\Runtime\Filters::escapeJs', false],
 35:         'escapeurl' => ['rawurlencode', false],
 36:         'escapexml' => ['Latte\Runtime\Filters::escapeXml', false],
 37:         'firstupper' => ['Latte\Runtime\Filters::firstUpper', false],
 38:         'checkurl' => ['Latte\Runtime\Filters::safeUrl', false],
 39:         'implode' => ['implode', false],
 40:         'indent' => ['Latte\Runtime\Filters::indent', true],
 41:         'length' => ['Latte\Runtime\Filters::length', false],
 42:         'lower' => ['Latte\Runtime\Filters::lower', false],
 43:         'nl2br' => ['Latte\Runtime\Filters::nl2br', false],
 44:         'number' => ['number_format', false],
 45:         'padleft' => ['Latte\Runtime\Filters::padLeft', false],
 46:         'padright' => ['Latte\Runtime\Filters::padRight', false],
 47:         'repeat' => ['Latte\Runtime\Filters::repeat', true],
 48:         'replace' => ['Latte\Runtime\Filters::replace', true],
 49:         'replacere' => ['Latte\Runtime\Filters::replaceRe', false],
 50:         'reverse' => ['Latte\Runtime\Filters::reverse', false],
 51:         'safeurl' => ['Latte\Runtime\Filters::safeUrl', false],
 52:         'strip' => ['Latte\Runtime\Filters::strip', true],
 53:         'striphtml' => ['Latte\Runtime\Filters::stripHtml', true],
 54:         'striptags' => ['Latte\Runtime\Filters::stripTags', true],
 55:         'substr' => ['Latte\Runtime\Filters::substring', false],
 56:         'trim' => ['Latte\Runtime\Filters::trim', true],
 57:         'truncate' => ['Latte\Runtime\Filters::truncate', false],
 58:         'upper' => ['Latte\Runtime\Filters::upper', false],
 59:         'webalize' => ['Nette\Utils\Strings::webalize', false],
 60:     ];
 61: 
 62: 
 63:     /**
 64:      * Registers run-time filter.
 65:      * @param  string|null
 66:      * @param  callable
 67:      * @return static
 68:      */
 69:     public function add($name, $callback)
 70:     {
 71:         if ($name == null) { // intentionally ==
 72:             array_unshift($this->_dynamic, $callback);
 73:         } else {
 74:             $name = strtolower($name);
 75:             $this->_static[$name] = [$callback, null];
 76:             unset($this->$name);
 77:         }
 78:         return $this;
 79:     }
 80: 
 81: 
 82:     /**
 83:      * Returns all run-time filters.
 84:      * @return string[]
 85:      */
 86:     public function getAll()
 87:     {
 88:         return array_combine($tmp = array_keys($this->_static), $tmp);
 89:     }
 90: 
 91: 
 92:     /**
 93:      * Returns filter for classic calling.
 94:      * @return callable
 95:      */
 96:     public function __get($name)
 97:     {
 98:         $lname = strtolower($name);
 99:         if (isset($this->$lname)) { // case mismatch
100:             return $this->$lname;
101: 
102:         } elseif (isset($this->_static[$lname])) {
103:             list($callback, $aware) = $this->prepareFilter($lname);
104:             if ($aware) { // FilterInfo aware filter
105:                 return $this->$lname = function ($arg) use ($callback) {
106:                     $args = func_get_args();
107:                     array_unshift($args, $info = new FilterInfo);
108:                     if ($arg instanceof IHtmlString) {
109:                         $args[1] = $arg->__toString();
110:                         $info->contentType = Engine::CONTENT_HTML;
111:                     }
112:                     $res = call_user_func_array($callback, $args);
113:                     return $info->contentType === Engine::CONTENT_HTML
114:                         ? new Html($res)
115:                         : $res;
116:                 };
117:             } else { // classic filter
118:                 return $this->$lname = $callback;
119:             }
120:         }
121: 
122:         return $this->$lname = function ($arg) use ($lname, $name) { // dynamic filter
123:             $args = func_get_args();
124:             array_unshift($args, $lname);
125:             foreach ($this->_dynamic as $filter) {
126:                 $res = call_user_func_array(Helpers::checkCallback($filter), $args);
127:                 if ($res !== null) {
128:                     return $res;
129:                 } elseif (isset($this->_static[$lname])) { // dynamic converted to classic
130:                     $this->$name = Helpers::checkCallback($this->_static[$lname][0]);
131:                     return call_user_func_array($this->$name, func_get_args());
132:                 }
133:             }
134:             $hint = ($t = Helpers::getSuggestion(array_keys($this->_static), $name)) ? ", did you mean '$t'?" : '.';
135:             throw new \LogicException("Filter '$name' is not defined$hint");
136:         };
137:     }
138: 
139: 
140:     /**
141:      * Calls filter with FilterInfo.
142:      * @return mixed
143:      */
144:     public function filterContent($name, FilterInfo $info, $arg)
145:     {
146:         $lname = strtolower($name);
147:         $args = func_get_args();
148:         array_shift($args);
149: 
150:         if (!isset($this->_static[$lname])) {
151:             $hint = ($t = Helpers::getSuggestion(array_keys($this->_static), $name)) ? ", did you mean '$t'?" : '.';
152:             throw new \LogicException("Filter |$name is not defined$hint");
153:         }
154: 
155:         list($callback, $aware) = $this->prepareFilter($lname);
156:         if ($aware) { // FilterInfo aware filter
157:             return call_user_func_array($callback, $args);
158: 
159:         } else { // classic filter
160:             array_shift($args);
161:             if ($info->contentType !== Engine::CONTENT_TEXT) {
162:                 trigger_error("Filter |$name is called with incompatible content type " . strtoupper($info->contentType)
163:                     . ($info->contentType === Engine::CONTENT_HTML ? ', try to prepend |stripHtml.' : '.'), E_USER_WARNING);
164:             }
165:             $res = call_user_func_array($this->$name, $args);
166:             if ($res instanceof IHtmlString) {
167:                 trigger_error("Filter |$name should be changed to content-aware filter.");
168:                 $info->contentType = Engine::CONTENT_HTML;
169:                 $res = $res->__toString();
170:             }
171:             return $res;
172:         }
173:     }
174: 
175: 
176:     private function prepareFilter($name)
177:     {
178:         if (!isset($this->_static[$name][1])) {
179:             $callback = Helpers::checkCallback($this->_static[$name][0]);
180:             if (is_string($callback) && strpos($callback, '::')) {
181:                 $callback = explode('::', $callback);
182:             } elseif (is_object($callback)) {
183:                 $callback = [$callback, '__invoke'];
184:             }
185:             $ref = is_array($callback)
186:                 ? new \ReflectionMethod($callback[0], $callback[1])
187:                 : new \ReflectionFunction($callback);
188:             $this->_static[$name][1] = ($tmp = $ref->getParameters())
189:                 && $tmp[0]->getClass() && $tmp[0]->getClass()->getName() === 'Latte\Runtime\FilterInfo';
190:         }
191:         return $this->_static[$name];
192:     }
193: }
194: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0