diff -Nru php-nette-2.3.10/client-side/netteForms.js php-nette-2.4-20160731/client-side/netteForms.js --- php-nette-2.3.10/client-side/netteForms.js 2016-04-13 18:50:54.000000000 +0000 +++ php-nette-2.4-20160731/client-side/netteForms.js 2016-07-31 17:46:56.000000000 +0000 @@ -6,6 +6,10 @@ */ (function(global, factory) { + if (!global.JSON) { + return; + } + if (typeof define === 'function' && define.amd) { define(function() { return factory(global); @@ -13,8 +17,11 @@ } else if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = factory(global); } else { + var init = !global.Nette || !global.Nette.noInit; global.Nette = factory(global); - global.Nette.initOnLoad(); + if (init) { + global.Nette.initOnLoad(); + } } }(typeof window !== 'undefined' ? window : this, function(window) { @@ -23,20 +30,35 @@ var Nette = {}; +Nette.formErrors = []; +Nette.version = '2.4'; + + /** * Attaches a handler to an event for the element. */ Nette.addEvent = function(element, on, callback) { - var original = element['on' + on]; - element['on' + on] = function() { - if (typeof original === 'function' && original.apply(element, arguments) === false) { - return false; - } - return callback.apply(element, arguments); - }; + if (element.addEventListener) { + element.addEventListener(on, callback); + } else if (on === 'DOMContentLoaded') { + element.attachEvent('onreadystatechange', function() { + if (element.readyState === 'complete') { + callback.call(this); + } + }); + } else { + element.attachEvent('on' + on, getHandler(callback)); + } }; +function getHandler(callback) { + return function(e) { + return callback.call(this, e); + }; +} + + /** * Returns the value of form element. */ @@ -116,7 +138,7 @@ /** * Validates form element against given rules. */ -Nette.validateControl = function(elem, rules, onlyCheck, value) { +Nette.validateControl = function(elem, rules, onlyCheck, value, emptyOptional) { elem = elem.tagName ? elem : elem[0]; // RadioNodeList rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules')); value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value; @@ -126,15 +148,20 @@ op = rule.op.match(/(~)?([^?]+)/), curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem; + rule.neg = op[1]; + rule.op = op[2]; + rule.condition = !!rule.rules; + if (!curElem) { continue; + } else if (rule.op === 'optional') { + emptyOptional = !Nette.validateRule(elem, ':filled', null, value); + continue; + } else if (emptyOptional && !rule.condition && rule.op !== ':filled') { + return true; } - rule.neg = op[1]; - rule.op = op[2]; - rule.condition = !!rule.rules; curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList - var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)}, success = Nette.validateRule(curElem, rule.op, rule.arg, curValue); @@ -145,7 +172,7 @@ } if (rule.condition && success) { - if (!Nette.validateControl(elem, rule.rules, onlyCheck, value)) { + if (!Nette.validateControl(elem, rule.rules, onlyCheck, value, rule.op === ':blank' ? false : emptyOptional)) { return false; } } else if (!rule.condition && !success) { @@ -162,6 +189,12 @@ return false; } } + + if (!onlyCheck && elem.type === 'number' && !elem.validity.valid) { + Nette.addError(elem, 'Please enter a valid value.'); + return false; + } + return true; }; @@ -173,11 +206,14 @@ var form = sender.form || sender, scope = false; + Nette.formErrors = []; + if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) { var scopeArr = Nette.parseJSON(form['nette-submittedBy'].getAttribute('data-nette-validation-scope')); if (scopeArr.length) { scope = new RegExp('^(' + scopeArr.join('-|') + '-)'); } else { + Nette.showFormErrors(form, []); return true; } } @@ -201,11 +237,13 @@ continue; } - if (!Nette.validateControl(elem)) { + if (!Nette.validateControl(elem) && !Nette.formErrors.length) { return false; } } - return true; + var success = !Nette.formErrors.length; + Nette.showFormErrors(form, Nette.formErrors); + return success; }; @@ -226,14 +264,42 @@ /** - * Display error message. + * Adds error message to the queue. */ Nette.addError = function(elem, message) { - if (message) { - alert(message); + Nette.formErrors.push({ + element: elem, + message: message + }); +}; + + +/** + * Display error messages. + */ +Nette.showFormErrors = function(form, errors) { + var messages = [], + focusElem; + + for (var i in errors) { + var elem = errors[i].element, + message = errors[i].message; + + if (!Nette.inArray(messages, message)) { + messages.push(message); + + if (!focusElem && elem.focus) { + focusElem = elem; + } + } } - if (elem.focus) { - elem.focus(); + + if (messages.length) { + alert(messages.join('\n')); + + if (focusElem) { + focusElem.focus(); + } } }; @@ -243,7 +309,10 @@ */ Nette.expandRuleArgument = function(form, arg) { if (arg && arg.control) { - arg = Nette.getEffectiveValue(form.elements.namedItem(arg.control)); + var control = form.elements.namedItem(arg.control), + value = {value: Nette.getEffectiveValue(control)}; + Nette.validateControl(control, null, true, value); + arg = value.value; } return arg; }; @@ -273,6 +342,9 @@ Nette.validators = { filled: function(elem, arg, val) { + if (elem.type === 'number' && elem.validity.badInput) { + return true; + } return val !== '' && val !== false && val !== null && (!Nette.isArray(val) || !!val.length) && (!window.FileList || !(val instanceof window.FileList) || val.length); @@ -318,14 +390,35 @@ }, minLength: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.tooShort) { + return false + } else if (elem.validity.badInput) { + return null; + } + } return val.length >= arg; }, maxLength: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.tooLong) { + return false + } else if (elem.validity.badInput) { + return null; + } + } return val.length <= arg; }, length: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.tooShort || elem.validity.tooLong) { + return false + } else if (elem.validity.badInput) { + return null; + } + } arg = Nette.isArray(arg) ? arg : [arg, arg]; return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]); }, @@ -359,10 +452,16 @@ }, integer: function(elem, arg, val) { + if (elem.type === 'number' && elem.validity.badInput) { + return false; + } return (/^-?[0-9]+$/).test(val); }, 'float': function(elem, arg, val, value) { + if (elem.type === 'number' && elem.validity.badInput) { + return false; + } val = val.replace(' ', '').replace(',', '.'); if ((/^-?[0-9]*[.,]?[0-9]+$/).test(val)) { value.value = val; @@ -372,14 +471,35 @@ }, min: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.rangeUnderflow) { + return false + } else if (elem.validity.badInput) { + return null; + } + } return Nette.validators.range(elem, [arg, null], val); }, max: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.rangeOverflow) { + return false + } else if (elem.validity.badInput) { + return null; + } + } return Nette.validators.range(elem, [null, arg], val); }, range: function(elem, arg, val) { + if (elem.type === 'number') { + if (elem.validity.rangeUnderflow || elem.validity.rangeOverflow) { + return false + } else if (elem.validity.badInput) { + return null; + } + } return Nette.isArray(arg) ? ((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null; }, @@ -497,11 +617,9 @@ Nette.parseJSON = function(s) { - s = s || '[]'; - if (s.substr(0, 3) === '{op') { - return eval('[' + s + ']'); // backward compatibility - } - return window.JSON && window.JSON.parse ? JSON.parse(s) : eval(s); + return (s || '').substr(0, 3) === '{op' + ? eval('[' + s + ']') // backward compatibility with Nette 2.0.x + : JSON.parse(s || '[]'); }; @@ -526,19 +644,14 @@ if (!Nette.validateForm(form)) { if (e && e.stopPropagation) { e.stopPropagation(); + e.preventDefault(); } else if (window.event) { event.cancelBubble = true; + event.returnValue = false; } - return false; } }); - Nette.addEvent(form, 'click', function(e) { - e = e || event; - var target = e.target || e.srcElement; - form['nette-submittedBy'] = (target.type in {submit: 1, image: 1}) ? target : null; - }); - Nette.toggleForm(form); }; @@ -547,7 +660,7 @@ * @private */ Nette.initOnLoad = function() { - Nette.addEvent(window, 'load', function() { + Nette.addEvent(document, 'DOMContentLoaded', function() { for (var i = 0; i < document.forms.length; i++) { var form = document.forms[i]; for (var j = 0; j < form.elements.length; j++) { @@ -557,6 +670,13 @@ } } } + + Nette.addEvent(document.body, 'click', function(e) { + var target = e.target || e.srcElement; + if (target.form && target.type in {submit: 1, image: 1}) { + target.form['nette-submittedBy'] = target; + } + }); }); }; diff -Nru php-nette-2.3.10/debian/changelog php-nette-2.4-20160731/debian/changelog --- php-nette-2.3.10/debian/changelog 2016-04-25 20:47:23.000000000 +0000 +++ php-nette-2.4-20160731/debian/changelog 2016-09-23 07:37:58.000000000 +0000 @@ -1,3 +1,20 @@ +php-nette (2.4-20160731-1) unstable; urgency=medium + + * Update debian/watch to accommodate the new date-based ZIP releases + * Import Upstream version v2.4.0 (20160731) + * Update upstream-changelog + * Refresh 0001-Fix-path-in-examples.patch + * Remove deleted files from debian/copyright + * Add uncompressed sources to debian/missing-sources (from Tracy Github repo) + + -- Florian Schlichting Fri, 23 Sep 2016 09:37:58 +0200 + +php-nette (2.3.10-2) unstable; urgency=medium + + * Add missing dependency on php-xml + + -- Florian Schlichting Thu, 15 Sep 2016 21:50:41 +0200 + php-nette (2.3.10-1) unstable; urgency=medium * Import Upstream version 2.3.10 diff -Nru php-nette-2.3.10/debian/control php-nette-2.4-20160731/debian/control --- php-nette-2.3.10/debian/control 2016-04-25 20:43:31.000000000 +0000 +++ php-nette-2.4-20160731/debian/control 2016-09-15 19:50:15.000000000 +0000 @@ -11,7 +11,7 @@ Package: php-nette Architecture: all -Depends: php-common, php-intl, php-json, ${misc:Depends} +Depends: php-common, php-intl, php-json, php-xml, ${misc:Depends} Recommends: php-gd, php-memcache Breaks: php-apigen (<< 2.8.0+dfsg-3+) Description: Nette Framework diff -Nru php-nette-2.3.10/debian/copyright php-nette-2.4-20160731/debian/copyright --- php-nette-2.3.10/debian/copyright 2016-04-25 20:20:35.000000000 +0000 +++ php-nette-2.4-20160731/debian/copyright 2016-09-23 07:37:50.000000000 +0000 @@ -10,7 +10,6 @@ Files: examples/Forms/assets/logo.png examples/Tracy/assets/arrow.png - tools/Requirements-Checker/assets/logo.png Copyright: 2008, 2014, Nette Foundation License: CC-BY-SA-3.0 @@ -42,7 +41,6 @@ Nette/Tracy/assets/Bar/bar.css Nette/Tracy/assets/Bar/bar.phtml Nette/Tracy/assets/BlueScreen/bluescreen.css - Nette/Tracy/assets/BlueScreen/bluescreen.phtml Copyright: 2004, David Grudl 2008, 2014, Nette Foundation License: BSD-3-clause or GPL-2 or GPL-3, and CC-BY-SA-3.0 diff -Nru php-nette-2.3.10/debian/missing-sources/bar.js php-nette-2.4-20160731/debian/missing-sources/bar.js --- php-nette-2.3.10/debian/missing-sources/bar.js 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/debian/missing-sources/bar.js 2016-09-23 07:37:50.000000000 +0000 @@ -0,0 +1,554 @@ +/** + * This file is part of the Tracy (https://tracy.nette.org) + */ + +(function(){ + Tracy = window.Tracy || {}; + + var layer = document.getElementById('tracy-debug'); + + Tracy.getAjaxHeader = function() { + return layer.dataset.id; + }; + + var Panel = Tracy.DebugPanel = function(id) { + this.id = id; + this.elem = document.getElementById(this.id); + this.elem.Tracy = this.elem.Tracy || {}; + }; + + Panel.PEEK = 'tracy-mode-peek'; + Panel.FLOAT = 'tracy-mode-float'; + Panel.WINDOW = 'tracy-mode-window'; + Panel.FOCUSED = 'tracy-focused'; + Panel.zIndex = 20000; + + Panel.prototype.init = function() { + var _this = this, elem = this.elem; + + elem.innerHTML = elem.dataset.tracyContent; + Tracy.Dumper.init(this.dumps, elem); + delete elem.dataset.tracyContent; + delete this.dumps; + evalScripts(elem); + + draggable(elem, { + handle: elem.querySelector('h1'), + stop: function() { + _this.toFloat(); + } + }); + + elem.addEventListener('mouseover', function(e) { + if (isTargetChanged(e.relatedTarget, this)) { + _this.focus(); + } + }); + + elem.addEventListener('mouseout', function(e) { + if (isTargetChanged(e.relatedTarget, this)) { + _this.blur(); + } + }); + + elem.addEventListener('click', function() { + _this.oldPosition = getPosition(elem); + }); + + elem.addEventListener('tracy-toggle', function() { + if (_this.oldPosition) { + var pos = getPosition(elem); + setPosition(elem, { + right: pos.right - pos.width + _this.oldPosition.width, + bottom: pos.bottom - pos.height + _this.oldPosition.height + }); + _this.oldPosition = null; + } + }); + + forEach(elem.querySelectorAll('.tracy-icons a'), function(a) { + a.addEventListener('click', function(e) { + if (this.rel === 'close') { + _this.toPeek(); + } else { + _this.toWindow(); + } + e.preventDefault(); + }); + }); + + if (!this.is('tracy-ajax')) { + Tracy.Toggle.persist(elem); + } + }; + + Panel.prototype.is = function(mode) { + return this.elem.classList.contains(mode); + }; + + Panel.prototype.focus = function(callback) { + var elem = this.elem; + if (this.is(Panel.WINDOW)) { + elem.Tracy.window.focus(); + } else { + clearTimeout(elem.Tracy.displayTimeout); + elem.Tracy.displayTimeout = setTimeout(function() { + elem.classList.add(Panel.FOCUSED); + elem.style.display = 'block'; + elem.style.zIndex = Panel.zIndex++; + if (callback) { + callback(); + } + }, 50); + } + }; + + Panel.prototype.blur = function() { + var elem = this.elem; + elem.classList.remove(Panel.FOCUSED); + if (this.is(Panel.PEEK)) { + clearTimeout(elem.Tracy.displayTimeout); + elem.Tracy.displayTimeout = setTimeout(function() { + elem.style.display = 'none'; + }, 50); + } + }; + + Panel.prototype.toFloat = function() { + this.elem.classList.remove(Panel.WINDOW); + this.elem.classList.remove(Panel.PEEK); + this.elem.classList.add(Panel.FLOAT); + this.elem.style.display = 'block'; + this.reposition(); + }; + + Panel.prototype.toPeek = function() { + this.elem.classList.remove(Panel.WINDOW); + this.elem.classList.remove(Panel.FLOAT); + this.elem.classList.add(Panel.PEEK); + this.elem.style.display = 'none'; + }; + + Panel.prototype.toWindow = function() { + var offset = getOffset(this.elem); + offset.left += typeof window.screenLeft === 'number' ? window.screenLeft : (window.screenX + 10); + offset.top += typeof window.screenTop === 'number' ? window.screenTop : (window.screenY + 50); + + var win = window.open('', this.id.replace(/-/g, '_'), 'left=' + offset.left + ',top=' + offset.top + + ',width=' + this.elem.offsetWidth + ',height=' + this.elem.offsetHeight + ',resizable=yes,scrollbars=yes'); + if (!win) { + return false; + } + + function escape(s) { + return s.replace(/&/g, '&').replace(/' + + '' + + ' + + + + +

Nette Forms live validation example

+ + + + diff -Nru php-nette-2.3.10/examples/Forms/localization.php php-nette-2.4-20160731/examples/Forms/localization.php --- php-nette-2.3.10/examples/Forms/localization.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Forms/localization.php 2016-07-31 17:46:44.000000000 +0000 @@ -48,16 +48,16 @@ $form->addText('age', 'Your age:') ->setRequired('Enter your age') ->addRule($form::INTEGER, 'Age must be numeric value') - ->addRule($form::RANGE, 'Age must be in range from %d to %d', array(10, 100)); + ->addRule($form::RANGE, 'Age must be in range from %d to %d', [10, 100]); -$countries = array( - 'World' => array( +$countries = [ + 'World' => [ 'bu' => 'Buranda', 'qu' => 'Qumran', 'st' => 'Saint Georges Island', - ), + ], '?' => 'other', -); +]; $form->addSelect('country', 'Country:', $countries) ->setPrompt('Select your country'); diff -Nru php-nette-2.3.10/examples/Forms/manual-rendering.php php-nette-2.4-20160731/examples/Forms/manual-rendering.php --- php-nette-2.3.10/examples/Forms/manual-rendering.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Forms/manual-rendering.php 2016-07-31 17:46:44.000000000 +0000 @@ -23,14 +23,14 @@ $form->addText('age') ->setRequired('Enter your age'); -$form->addRadioList('gender', NULL, array( +$form->addRadioList('gender', NULL, [ 'm' => 'male', 'f' => 'female', -)); +]); $form->addText('email') - ->addCondition($form::FILLED) - ->addRule($form::EMAIL, 'Incorrect email address'); + ->setRequired(FALSE) + ->addRule($form::EMAIL, 'Incorrect email address'); $form->addSubmit('submit'); diff -Nru php-nette-2.3.10/examples/Micro-blog/composer.json php-nette-2.4-20160731/examples/Micro-blog/composer.json --- php-nette-2.3.10/examples/Micro-blog/composer.json 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/Micro-blog/composer.json 2016-07-31 17:46:20.000000000 +0000 @@ -14,9 +14,15 @@ } ], "require": { - "php": ">=5.3.0", - "nette/nette": "~2.3.0" + "php": ">=5.4", + "nette/application": "~2.3", + "nette/bootstrap": "~2.3", + "nette/database": "~2.3", + "nette/robot-loader": "~2.3", + "latte/latte": "~2.3", + "tracy/tracy": "~2.3" }, + "minimum-stability": "dev", "config": { "vendor-dir": "www/data/vendor" } diff -Nru php-nette-2.3.10/examples/Micro-blog/www/data/TemplateRouter.php php-nette-2.4-20160731/examples/Micro-blog/www/data/TemplateRouter.php --- php-nette-2.3.10/examples/Micro-blog/www/data/TemplateRouter.php 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/Micro-blog/www/data/TemplateRouter.php 2016-07-31 17:46:20.000000000 +0000 @@ -24,7 +24,7 @@ $latte = new Latte\Engine; $latte->setTempDirectory($cachePath . '/cache'); $macroSet = new Latte\Macros\MacroSet($latte->getCompiler()); - $macroSet->addMacro('url', function () {}); // ignore + $macroSet->addMacro('url', function () {}, NULL, NULL, $macroSet::ALLOWED_IN_HEAD); // ignore return $latte; })->setFile($file); }); @@ -34,12 +34,12 @@ public function scanRoutes($path) { - $routes = array(); + $routes = []; $latte = new Latte\Engine; $macroSet = new Latte\Macros\MacroSet($latte->getCompiler()); $macroSet->addMacro('url', function ($node) use (&$routes, &$file) { $routes[$node->args] = (string) $file; - }); + }, NULL, NULL, $macroSet::ALLOWED_IN_HEAD); foreach (Nette\Utils\Finder::findFiles('*.latte')->from($path) as $file) { $latte->compile($file); } diff -Nru php-nette-2.3.10/examples/Micro-blog/www/data/templates/@layout.latte php-nette-2.4-20160731/examples/Micro-blog/www/data/templates/@layout.latte --- php-nette-2.3.10/examples/Micro-blog/www/data/templates/@layout.latte 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/Micro-blog/www/data/templates/@layout.latte 2016-07-31 17:46:20.000000000 +0000 @@ -2,7 +2,7 @@ - {block title|striptags|trim}Homepage{/block} | Nette Framework Micro-blog example + {block title|stripHtml|trim}Homepage{/block} | Nette Framework Micro-blog example diff -Nru php-nette-2.3.10/examples/Micro-blog/www/index.php php-nette-2.4-20160731/examples/Micro-blog/www/index.php --- php-nette-2.3.10/examples/Micro-blog/www/index.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Micro-blog/www/index.php 2016-07-31 17:46:44.000000000 +0000 @@ -24,4 +24,5 @@ $container->addService('router', new TemplateRouter('data/templates', __DIR__ . '/data/temp')); // Run the application! -$container->getService('application')->run(); +$container->getByType(Nette\Application\Application::class) + ->run(); diff -Nru php-nette-2.3.10/examples/Modules-Usage/app/bootstrap.php php-nette-2.4-20160731/examples/Modules-Usage/app/bootstrap.php --- php-nette-2.3.10/examples/Modules-Usage/app/bootstrap.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Modules-Usage/app/bootstrap.php 2016-07-31 17:46:46.000000000 +0000 @@ -28,7 +28,7 @@ // Setup router using mod_rewrite detection if (function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) { - $router = $container->getService('router'); + $router = $container->getByType(Nette\Application\IRouter::class); $router[] = new Route('index.php', 'Front:Default:default', Route::ONE_WAY); $router[] = $adminRouter = new RouteList('Admin'); diff -Nru php-nette-2.3.10/examples/Modules-Usage/app/modules/Admin/templates/@layout.latte php-nette-2.4-20160731/examples/Modules-Usage/app/modules/Admin/templates/@layout.latte --- php-nette-2.3.10/examples/Modules-Usage/app/modules/Admin/templates/@layout.latte 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/Modules-Usage/app/modules/Admin/templates/@layout.latte 2016-07-31 17:46:20.000000000 +0000 @@ -14,10 +14,10 @@
- This is layout template {$template->getName() |replace:$root} + This is layout template {$this->getParentName() |replace:$root}
- This is content block template {$presenter->template->getFile() |replace:$root} + This is content block template {$this->getName() |replace:$root} {include content}
diff -Nru php-nette-2.3.10/examples/Modules-Usage/app/modules/Front/templates/@layout.latte php-nette-2.4-20160731/examples/Modules-Usage/app/modules/Front/templates/@layout.latte --- php-nette-2.3.10/examples/Modules-Usage/app/modules/Front/templates/@layout.latte 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/Modules-Usage/app/modules/Front/templates/@layout.latte 2016-07-31 17:46:20.000000000 +0000 @@ -14,10 +14,10 @@
- This is layout template {$template->getName() |replace:$root} + This is layout template {$this->getParentName() |replace:$root}
- This is content block template {$presenter->template->getFile() |replace:$root} + This is content block template {$this->getName() |replace:$root} {include content}
diff -Nru php-nette-2.3.10/examples/Modules-Usage/composer.json php-nette-2.4-20160731/examples/Modules-Usage/composer.json --- php-nette-2.3.10/examples/Modules-Usage/composer.json 2016-04-13 18:50:24.000000000 +0000 +++ php-nette-2.4-20160731/examples/Modules-Usage/composer.json 2016-07-31 17:46:20.000000000 +0000 @@ -14,7 +14,12 @@ } ], "require": { - "php": ">=5.3.0", - "nette/nette": "~2.3.0" - } + "php": ">=5.4", + "nette/application": "~2.3", + "nette/bootstrap": "~2.3", + "nette/robot-loader": "~2.3", + "latte/latte": "~2.3", + "tracy/tracy": "~2.3" + }, + "minimum-stability": "dev" } diff -Nru php-nette-2.3.10/examples/Modules-Usage/www/index.php php-nette-2.4-20160731/examples/Modules-Usage/www/index.php --- php-nette-2.3.10/examples/Modules-Usage/www/index.php 2016-04-13 18:50:24.000000000 +0000 +++ php-nette-2.4-20160731/examples/Modules-Usage/www/index.php 2016-07-31 17:46:20.000000000 +0000 @@ -4,4 +4,5 @@ $container = require __DIR__ . '/../app/bootstrap.php'; // run application -$container->getService('application')->run(); +$container->getByType(Nette\Application\Application::class) + ->run(); diff -Nru php-nette-2.3.10/examples/Tracy/ajax.php php-nette-2.4-20160731/examples/Tracy/ajax.php --- php-nette-2.3.10/examples/Tracy/ajax.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/examples/Tracy/ajax.php 2016-07-31 17:46:46.000000000 +0000 @@ -0,0 +1,64 @@ + + + +

Tracy: AJAX demo

+ +

+ see Debug Bar in the bottom right corner +

+ +

+ use ESC to toggle BlueScreen +

+ + + + diff -Nru php-nette-2.3.10/examples/Tracy/assets/style.css php-nette-2.4-20160731/examples/Tracy/assets/style.css --- php-nette-2.3.10/examples/Tracy/assets/style.css 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Tracy/assets/style.css 2016-07-31 17:46:44.000000000 +0000 @@ -1,11 +1,16 @@ -body { +html { font: 15px/1.5 Tahoma, sans-serif; color: #333; background: #fff; - margin: 1.6em; + margin: 0 1.6em; padding: 0; } +html.arrow { + background: #fff url(arrow.png) no-repeat bottom right; + height: 100%; +} + h1 { font-size: 210%; font-weight: normal; diff -Nru php-nette-2.3.10/examples/Tracy/barDump.php php-nette-2.4-20160731/examples/Tracy/barDump.php --- php-nette-2.3.10/examples/Tracy/barDump.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Tracy/barDump.php 2016-07-31 17:46:46.000000000 +0000 @@ -1,11 +1,3 @@ - - - - -

Tracy Debug Bar demo

- -

You can dump variables to bar in rightmost bottom egde.

- + +

Tracy: bar dump demo

+ +

You can dump variables to bar in rightmost bottom egde.

+ +test', 'String'); +bdump('test', 'String'); diff -Nru php-nette-2.3.10/examples/Tracy/dump.php php-nette-2.4-20160731/examples/Tracy/dump.php --- php-nette-2.3.10/examples/Tracy/dump.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/examples/Tracy/dump.php 2016-07-31 17:46:46.000000000 +0000 @@ -1,26 +1,28 @@ - - -

Tracy Dumper demo

- + + +

Tracy: Dumper demo

+ + - -

Tracy Exception demo

- + + +

Tracy: exception demo

+ + - -

Tracy Fatal Error demo

- + + +

Tracy: fatal error demo

+ 'val1', 'key2' => TRUE)); +$arr = [10, 20, ['key1' => 'val1', 'key2' => TRUE]]; // will show in FireLogger Debugger::fireLog('Hello World'); @@ -18,7 +18,7 @@ function second($arg1, $arg2) { - third(array(1, 2, 3)); + third([1, 2, 3]); } function third($arg1) diff -Nru php-nette-2.3.10/examples/Tracy/redirect.php php-nette-2.4-20160731/examples/Tracy/redirect.php --- php-nette-2.3.10/examples/Tracy/redirect.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/examples/Tracy/redirect.php 2016-07-31 17:46:46.000000000 +0000 @@ -0,0 +1,22 @@ + + + +

Tracy: redirect demo

diff -Nru php-nette-2.3.10/examples/.travis.yml php-nette-2.4-20160731/examples/.travis.yml --- php-nette-2.3.10/examples/.travis.yml 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/examples/.travis.yml 2016-07-31 17:46:20.000000000 +0000 @@ -1,6 +1,6 @@ language: php php: - - 5.3.3 + - 5.4 script: - php code-checker/src/code-checker.php diff -Nru php-nette-2.3.10/Nette/Application/Application.php php-nette-2.4-20160731/Nette/Application/Application.php --- php-nette-2.3.10/Nette/Application/Application.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Application.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * Front Controller. */ -class Application extends Nette\Object +class Application { + use Nette\SmartObject; + /** @var int */ public static $maxLoop = 20; @@ -27,7 +29,7 @@ /** @var callable[] function (Application $sender); Occurs before the application loads presenter */ public $onStartup; - /** @var callable[] function (Application $sender, \Exception $e = NULL); Occurs before the application shuts down */ + /** @var callable[] function (Application $sender, \Exception|\Throwable $e = NULL); Occurs before the application shuts down */ public $onShutdown; /** @var callable[] function (Application $sender, Request $request); Occurs when a new request is received */ @@ -39,11 +41,11 @@ /** @var callable[] function (Application $sender, IResponse $response); Occurs when a new response is ready for dispatch */ public $onResponse; - /** @var callable[] function (Application $sender, \Exception $e); Occurs when an unhandled exception occurs in the application */ + /** @var callable[] function (Application $sender, \Exception|\Throwable $e); Occurs when an unhandled exception occurs in the application */ public $onError; /** @var Request[] */ - private $requests = array(); + private $requests = []; /** @var IPresenter */ private $presenter; @@ -81,7 +83,10 @@ $this->processRequest($this->createInitialRequest()); $this->onShutdown($this); + } catch (\Throwable $e) { } catch (\Exception $e) { + } + if (isset($e)) { $this->onError($this, $e); if ($this->catchExceptions && $this->errorPresenter) { try { @@ -89,6 +94,8 @@ $this->onShutdown($this, $e); return; + } catch (\Throwable $e) { + $this->onError($this, $e); } catch (\Exception $e) { $this->onError($this, $e); } @@ -129,6 +136,7 @@ */ public function processRequest(Request $request) { + process: if (count($this->requests) > self::$maxLoop) { throw new ApplicationException('Too many loops detected in application life cycle.'); } @@ -138,10 +146,11 @@ $this->presenter = $this->presenterFactory->createPresenter($request->getPresenterName()); $this->onPresenter($this, $this->presenter); - $response = $this->presenter->run($request); + $response = $this->presenter->run(clone $request); if ($response instanceof Responses\ForwardResponse) { - $this->processRequest($response->getRequest()); + $request = $response->getRequest(); + goto process; } elseif ($response) { $this->onResponse($this, $response); @@ -151,9 +160,10 @@ /** + * @param \Exception|\Throwable * @return void */ - public function processException(\Exception $e) + public function processException($e) { if (!$e instanceof BadRequestException && $this->httpResponse instanceof Nette\Http\Response) { $this->httpResponse->warnOnBuffer = FALSE; @@ -162,7 +172,7 @@ $this->httpResponse->setCode($e instanceof BadRequestException ? ($e->getCode() ?: 404) : 500); } - $args = array('exception' => $e, 'request' => end($this->requests) ?: NULL); + $args = ['exception' => $e, 'request' => end($this->requests) ?: NULL]; if ($this->presenter instanceof UI\Presenter) { try { $this->presenter->forward(":$this->errorPresenter:", $args); diff -Nru php-nette-2.3.10/Nette/Application/ErrorPresenter.php php-nette-2.4-20160731/Nette/Application/ErrorPresenter.php --- php-nette-2.3.10/Nette/Application/ErrorPresenter.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/ErrorPresenter.php 2016-07-31 17:46:32.000000000 +0000 @@ -15,8 +15,10 @@ /** * Default Error Presenter. */ -class ErrorPresenter extends Nette\Object implements Application\IPresenter +class ErrorPresenter implements Application\IPresenter { + use Nette\SmartObject; + /** @var ILogger|NULL */ private $logger; diff -Nru php-nette-2.3.10/Nette/Application/Helpers.php php-nette-2.4-20160731/Nette/Application/Helpers.php --- php-nette-2.3.10/Nette/Application/Helpers.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Helpers.php 2016-07-31 17:46:32.000000000 +0000 @@ -0,0 +1,32 @@ +getMessage(), NULL, $e); } - if (is_subclass_of($class, 'Nette\Application\UI\Presenter')) { + if (is_subclass_of($class, UI\Presenter::class)) { if ($action === '') { $action = UI\Presenter::DEFAULT_ACTION; } if (method_exists($class, $method = $class::formatActionMethod($action)) || method_exists($class, $method = $class::formatRenderMethod($action)) ) { - UI\Presenter::argsToParams($class, $method, $params); + UI\Presenter::argsToParams($class, $method, $params, [], $missing); + if ($missing) { + $rp = $missing[0]; + throw new UI\InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()"); + } + + } elseif (array_key_exists(0, $params)) { + throw new UI\InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method."); } } diff -Nru php-nette-2.3.10/Nette/Application/MicroPresenter.php php-nette-2.4-20160731/Nette/Application/MicroPresenter.php --- php-nette-2.3.10/Nette/Application/MicroPresenter.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/MicroPresenter.php 2016-07-31 17:46:32.000000000 +0000 @@ -17,8 +17,10 @@ /** * Micro presenter. */ -class MicroPresenter extends Nette\Object implements Application\IPresenter +class MicroPresenter implements Application\IPresenter { + use Nette\SmartObject; + /** @var Nette\DI\Container|NULL */ private $context; @@ -72,11 +74,11 @@ $params['presenter'] = $this; $callback = $params['callback']; $reflection = Nette\Utils\Callback::toReflection(Nette\Utils\Callback::check($callback)); - $params = Application\UI\PresenterComponentReflection::combineArgs($reflection, $params); + $params = Application\UI\ComponentReflection::combineArgs($reflection, $params); if ($this->context) { foreach ($reflection->getParameters() as $param) { - if ($param->getClassName()) { + if ($param->getClass()) { unset($params[$param->getPosition()]); } } @@ -88,7 +90,7 @@ $response = call_user_func_array($callback, $params); if (is_string($response)) { - $response = array($response, array()); + $response = [$response, []]; } if (is_array($response)) { list($templateSource, $templateParams) = $response; @@ -109,12 +111,11 @@ /** * Template factory. * @param string - * @param callable * @return Application\UI\ITemplate */ - public function createTemplate($class = NULL, $latteFactory = NULL) + public function createTemplate($class = NULL, callable $latteFactory = NULL) { - $latte = $latteFactory ? $latteFactory() : $this->getContext()->getByType('Nette\Bridges\ApplicationLatte\ILatteFactory')->create(); + $latte = $latteFactory ? $latteFactory() : $this->getContext()->getByType(Nette\Bridges\ApplicationLatte\ILatteFactory::class)->create(); $template = $class ? new $class : new Nette\Bridges\ApplicationLatte\Template($latte); $template->setParameters($this->request->getParameters()); diff -Nru php-nette-2.3.10/Nette/Application/PresenterFactory.php php-nette-2.4-20160731/Nette/Application/PresenterFactory.php --- php-nette-2.3.10/Nette/Application/PresenterFactory.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/PresenterFactory.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,19 +13,18 @@ /** * Default presenter loader. */ -class PresenterFactory extends Nette\Object implements IPresenterFactory +class PresenterFactory implements IPresenterFactory { - /** @deprecated */ - public $caseSensitive = TRUE; + use Nette\SmartObject; /** @var array[] of module => splited mask */ - private $mapping = array( - '*' => array('', '*Module\\', '*Presenter'), - 'Nette' => array('NetteModule\\', '*\\', '*Presenter'), - ); + private $mapping = [ + '*' => ['', '*Module\\', '*Presenter'], + 'Nette' => ['NetteModule\\', '*\\', '*Presenter'], + ]; /** @var array */ - private $cache = array(); + private $cache = []; /** @var callable */ private $factory; @@ -34,7 +33,7 @@ /** * @param callable function (string $class): IPresenter */ - public function __construct($factory = NULL) + public function __construct(callable $factory = NULL) { $this->factory = $factory ?: function ($class) { return new $class; }; } @@ -75,7 +74,7 @@ $reflection = new \ReflectionClass($class); $class = $reflection->getName(); - if (!$reflection->implementsInterface('Nette\Application\IPresenter')) { + if (!$reflection->implementsInterface(IPresenter::class)) { throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor."); } elseif ($reflection->isAbstract()) { throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract."); @@ -103,9 +102,9 @@ if (!preg_match('#^\\\\?([\w\\\\]*\\\\)?(\w*\*\w*?\\\\)?([\w\\\\]*\*\w*)\z#', $mask, $m)) { throw new Nette\InvalidStateException("Invalid mapping mask '$mask'."); } - $this->mapping[$module] = array($m[1], $m[2] ?: '*Module\\', $m[3]); + $this->mapping[$module] = [$m[1], $m[2] ?: '*Module\\', $m[3]]; } elseif (is_array($mask) && count($mask) === 3) { - $this->mapping[$module] = array($mask[0] ? $mask[0] . '\\' : '', $mask[1] . '\\', $mask[2]); + $this->mapping[$module] = [$mask[0] ? $mask[0] . '\\' : '', $mask[1] . '\\', $mask[2]]; } else { throw new Nette\InvalidStateException("Invalid mapping mask for module $module."); } @@ -143,7 +142,7 @@ public function unformatPresenterClass($class) { foreach ($this->mapping as $module => $mapping) { - $mapping = str_replace(array('\\', '*'), array('\\\\', '(\w+)'), $mapping); + $mapping = str_replace(['\\', '*'], ['\\\\', '(\w+)'], $mapping); if (preg_match("#^\\\\?$mapping[0]((?:$mapping[1])*)$mapping[2]\\z#i", $class, $matches)) { return ($module === '*' ? '' : $module . ':') . preg_replace("#$mapping[1]#iA", '$1:', $matches[1]) . $matches[3]; diff -Nru php-nette-2.3.10/Nette/Application/Request.php php-nette-2.4-20160731/Nette/Application/Request.php --- php-nette-2.3.10/Nette/Application/Request.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Request.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,13 +13,16 @@ /** * Presenter request. * - * @property array $parameters - * @property array $post - * @property array $files - * @property string|NULL $method + * @property string $presenterName + * @property array $parameters + * @property array $post + * @property array $files + * @property string|NULL $method */ -class Request extends Nette\Object +class Request { + use Nette\SmartObject; + /** method */ const FORWARD = 'FORWARD'; @@ -33,7 +36,7 @@ private $method; /** @var array */ - private $flags = array(); + private $flags = []; /** @var string */ private $name; @@ -56,7 +59,7 @@ * @param array all uploaded files * @param array flags */ - public function __construct($name, $method = NULL, array $params = array(), array $post = array(), array $files = array(), array $flags = array()) + public function __construct($name, $method = NULL, array $params = [], array $post = [], array $files = [], array $flags = []) { $this->name = $name; $this->method = $method; @@ -206,16 +209,6 @@ } - /** - * @deprecated - */ - public function isPost() - { - trigger_error('Method isPost() is deprecated, use isMethod(\'POST\') instead.', E_USER_DEPRECATED); - return strcasecmp($this->method, 'post') === 0; - } - - /** * Sets the flag. * @param string diff -Nru php-nette-2.3.10/Nette/Application/Responses/CallbackResponse.php php-nette-2.4-20160731/Nette/Application/Responses/CallbackResponse.php --- php-nette-2.3.10/Nette/Application/Responses/CallbackResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/CallbackResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * Callback response. */ -class CallbackResponse extends Nette\Object implements Nette\Application\IResponse +class CallbackResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var callable */ private $callback; @@ -22,7 +24,7 @@ /** * @param callable function (Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) */ - public function __construct($callback) + public function __construct(callable $callback) { $this->callback = $callback; } diff -Nru php-nette-2.3.10/Nette/Application/Responses/FileResponse.php php-nette-2.4-20160731/Nette/Application/Responses/FileResponse.php --- php-nette-2.3.10/Nette/Application/Responses/FileResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/FileResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * File download response. */ -class FileResponse extends Nette\Object implements Nette\Application\IResponse +class FileResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var string */ private $file; diff -Nru php-nette-2.3.10/Nette/Application/Responses/ForwardResponse.php php-nette-2.4-20160731/Nette/Application/Responses/ForwardResponse.php --- php-nette-2.3.10/Nette/Application/Responses/ForwardResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/ForwardResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * Forwards to new request. */ -class ForwardResponse extends Nette\Object implements Nette\Application\IResponse +class ForwardResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var Nette\Application\Request */ private $request; diff -Nru php-nette-2.3.10/Nette/Application/Responses/JsonResponse.php php-nette-2.4-20160731/Nette/Application/Responses/JsonResponse.php --- php-nette-2.3.10/Nette/Application/Responses/JsonResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/JsonResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * JSON response used mainly for AJAX requests. */ -class JsonResponse extends Nette\Object implements Nette\Application\IResponse +class JsonResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var array|\stdClass */ private $payload; @@ -62,7 +64,6 @@ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) { $httpResponse->setContentType($this->contentType, 'utf-8'); - $httpResponse->setExpiration(FALSE); echo Nette\Utils\Json::encode($this->payload); } diff -Nru php-nette-2.3.10/Nette/Application/Responses/RedirectResponse.php php-nette-2.4-20160731/Nette/Application/Responses/RedirectResponse.php --- php-nette-2.3.10/Nette/Application/Responses/RedirectResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/RedirectResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -14,8 +14,10 @@ /** * Redirects to new URI. */ -class RedirectResponse extends Nette\Object implements Nette\Application\IResponse +class RedirectResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var string */ private $url; diff -Nru php-nette-2.3.10/Nette/Application/Responses/TextResponse.php php-nette-2.4-20160731/Nette/Application/Responses/TextResponse.php --- php-nette-2.3.10/Nette/Application/Responses/TextResponse.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Responses/TextResponse.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,8 +13,10 @@ /** * String output response. */ -class TextResponse extends Nette\Object implements Nette\Application\IResponse +class TextResponse implements Nette\Application\IResponse { + use Nette\SmartObject; + /** @var mixed */ private $source; diff -Nru php-nette-2.3.10/Nette/Application/Routers/CliRouter.php php-nette-2.4-20160731/Nette/Application/Routers/CliRouter.php --- php-nette-2.3.10/Nette/Application/Routers/CliRouter.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Routers/CliRouter.php 2016-07-31 17:46:32.000000000 +0000 @@ -14,8 +14,10 @@ /** * The unidirectional router for CLI. (experimental) */ -class CliRouter extends Nette\Object implements Application\IRouter +class CliRouter implements Application\IRouter { + use Nette\SmartObject; + const PRESENTER_KEY = 'action'; /** @var array */ @@ -25,7 +27,7 @@ /** * @param array default values */ - public function __construct($defaults = array()) + public function __construct($defaults = []) { $this->defaults = $defaults; } @@ -41,7 +43,7 @@ return NULL; } - $names = array(self::PRESENTER_KEY); + $names = [self::PRESENTER_KEY]; $params = $this->defaults; $args = $_SERVER['argv']; array_shift($args); @@ -77,10 +79,10 @@ if (!isset($params[self::PRESENTER_KEY])) { throw new Nette\InvalidStateException('Missing presenter & action in route definition.'); } - $presenter = $params[self::PRESENTER_KEY]; - if ($a = strrpos($presenter, ':')) { - $params[self::PRESENTER_KEY] = substr($presenter, $a + 1); - $presenter = substr($presenter, 0, $a); + list($module, $presenter) = Nette\Application\Helpers::splitName($params[self::PRESENTER_KEY]); + if ($module !== '') { + $params[self::PRESENTER_KEY] = $presenter; + $presenter = $module; } return new Application\Request( diff -Nru php-nette-2.3.10/Nette/Application/Routers/RouteList.php php-nette-2.4-20160731/Nette/Application/Routers/RouteList.php --- php-nette-2.3.10/Nette/Application/Routers/RouteList.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Routers/RouteList.php 2016-07-31 17:46:32.000000000 +0000 @@ -83,11 +83,10 @@ } - /** @internal */ public function warmupCache() { - $routes = array(); - $routes['*'] = array(); + $routes = []; + $routes['*'] = []; foreach ($this as $route) { $presenters = $route instanceof Route && is_array($tmp = $route->getTargetPresenters()) diff -Nru php-nette-2.3.10/Nette/Application/Routers/Route.php php-nette-2.4-20160731/Nette/Application/Routers/Route.php --- php-nette-2.3.10/Nette/Application/Routers/Route.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Routers/Route.php 2016-07-31 17:46:32.000000000 +0000 @@ -16,14 +16,13 @@ * The bidirectional route is responsible for mapping * HTTP request to a Request object for dispatch and vice-versa. */ -class Route extends Nette\Object implements Application\IRouter +class Route implements Application\IRouter { + use Nette\SmartObject; + const PRESENTER_KEY = 'presenter'; const MODULE_KEY = 'module'; - /** @deprecated */ - const CASE_SENSITIVE = 256; - /** @internal url type */ const HOST = 1, PATH = 2, @@ -42,39 +41,39 @@ PATH_OPTIONAL = 1, CONSTANT = 2; - /** @var int */ + /** @deprecated */ public static $defaultFlags = 0; /** @var array */ - public static $styles = array( - '#' => array( // default style for path parameters + public static $styles = [ + '#' => [ // default style for path parameters self::PATTERN => '[^/]+', - self::FILTER_OUT => array(__CLASS__, 'param2path'), - ), - '?#' => array( // default style for query parameters - ), - 'module' => array( + self::FILTER_OUT => [__CLASS__, 'param2path'], + ], + '?#' => [ // default style for query parameters + ], + 'module' => [ self::PATTERN => '[a-z][a-z0-9.-]*', - self::FILTER_IN => array(__CLASS__, 'path2presenter'), - self::FILTER_OUT => array(__CLASS__, 'presenter2path'), - ), - 'presenter' => array( + self::FILTER_IN => [__CLASS__, 'path2presenter'], + self::FILTER_OUT => [__CLASS__, 'presenter2path'], + ], + 'presenter' => [ self::PATTERN => '[a-z][a-z0-9.-]*', - self::FILTER_IN => array(__CLASS__, 'path2presenter'), - self::FILTER_OUT => array(__CLASS__, 'presenter2path'), - ), - 'action' => array( + self::FILTER_IN => [__CLASS__, 'path2presenter'], + self::FILTER_OUT => [__CLASS__, 'presenter2path'], + ], + 'action' => [ self::PATTERN => '[a-z][a-z0-9-]*', - self::FILTER_IN => array(__CLASS__, 'path2action'), - self::FILTER_OUT => array(__CLASS__, 'action2path'), - ), - '?module' => array( - ), - '?presenter' => array( - ), - '?action' => array( - ), - ); + self::FILTER_IN => [__CLASS__, 'path2action'], + self::FILTER_OUT => [__CLASS__, 'action2path'], + ], + '?module' => [ + ], + '?presenter' => [ + ], + '?action' => [ + ], + ]; /** @var string */ private $mask; @@ -89,7 +88,7 @@ private $aliases; /** @var array of [value & fixity, filterIn, filterOut] */ - private $metadata = array(); + private $metadata = []; /** @var array */ private $xlat; @@ -97,6 +96,9 @@ /** @var int HOST, PATH, RELATIVE */ private $type; + /** @var string http | https */ + private $scheme; + /** @var int */ private $flags; @@ -112,26 +114,35 @@ * @param array|string|\Closure default values or metadata or callback for NetteModule\MicroPresenter * @param int flags */ - public function __construct($mask, $metadata = array(), $flags = 0) + public function __construct($mask, $metadata = [], $flags = 0) { if (is_string($metadata)) { - $a = strrpos($tmp = $metadata, ':'); - if (!$a) { + list($presenter, $action) = Nette\Application\Helpers::splitName($metadata); + if (!$presenter) { throw new Nette\InvalidArgumentException("Second argument must be array or string in format Presenter:action, '$metadata' given."); } - $metadata = array(self::PRESENTER_KEY => substr($tmp, 0, $a)); - if ($a < strlen($tmp) - 1) { - $metadata['action'] = substr($tmp, $a + 1); + $metadata = [self::PRESENTER_KEY => $presenter]; + if ($action !== '') { + $metadata['action'] = $action; } } elseif ($metadata instanceof \Closure || $metadata instanceof Nette\Callback) { - $metadata = array( + if ($metadata instanceof Nette\Callback) { + trigger_error('Nette\Callback is deprecated, use Nette\Utils\Callback::closure().', E_USER_DEPRECATED); + } + $metadata = [ self::PRESENTER_KEY => 'Nette:Micro', 'callback' => $metadata, - ); + ]; } $this->flags = $flags | static::$defaultFlags; $this->setMask($mask, $metadata); + if (static::$defaultFlags) { + trigger_error('Route::$defaultFlags is deprecated, router by default keeps the used protocol.', E_USER_DEPRECATED); + } elseif ($flags & self::SECURED) { + trigger_error('Router::SECURED is deprecated, specify scheme in mask.', E_USER_DEPRECATED); + $this->scheme = 'https'; + } } @@ -150,12 +161,14 @@ if ($this->type === self::HOST) { $host = $url->getHost(); $path = '//' . $host . $url->getPath(); - $host = ip2long($host) ? array($host) : array_reverse(explode('.', $host)); - $re = strtr($re, array( + $parts = ip2long($host) ? [$host] : array_reverse(explode('.', $host)); + $re = strtr($re, [ '/%basePath%/' => preg_quote($url->getBasePath(), '#'), - '%tld%' => preg_quote($host[0], '#'), - '%domain%' => preg_quote(isset($host[1]) ? "$host[1].$host[0]" : $host[0], '#'), - )); + '%tld%' => preg_quote($parts[0], '#'), + '%domain%' => preg_quote(isset($parts[1]) ? "$parts[1].$parts[0]" : $parts[0], '#'), + '%sld%' => preg_quote(isset($parts[1]) ? $parts[1] : '', '#'), + '%host%' => preg_quote($host, '#'), + ]); } elseif ($this->type === self::RELATIVE) { $basePath = $url->getBasePath(); @@ -178,7 +191,7 @@ } // assigns matched values to parameters - $params = array(); + $params = []; foreach ($matches as $k => $v) { if (is_string($k) && $v !== '') { $params[$this->aliases[$k]] = $v; @@ -252,7 +265,7 @@ $params, $httpRequest->getPost(), $httpRequest->getFiles(), - array(Application\Request::SECURED => $httpRequest->isSecured()) + [Application\Request::SECURED => $httpRequest->isSecured()] ); } @@ -333,7 +346,7 @@ // compositing path $sequence = $this->sequence; - $brackets = array(); + $brackets = []; $required = NULL; // NULL for auto-optional $url = ''; $i = count($sequence) - 1; @@ -380,24 +393,25 @@ } while (TRUE); - if ($this->type !== self::HOST) { + if ($this->type === self::HOST) { + $host = $refUrl->getHost(); + $parts = ip2long($host) ? [$host] : array_reverse(explode('.', $host)); + $url = strtr($url, [ + '/%basePath%/' => $refUrl->getBasePath(), + '%tld%' => $parts[0], + '%domain%' => isset($parts[1]) ? "$parts[1].$parts[0]" : $parts[0], + '%sld%' => isset($parts[1]) ? $parts[1] : '', + '%host%' => $host, + ]); + $url = ($this->scheme ?: $refUrl->getScheme()) . ':' . $url; + } else { if ($this->lastRefUrl !== $refUrl) { - $scheme = ($this->flags & self::SECURED ? 'https://' : 'http://'); + $scheme = ($this->scheme ?: $refUrl->getScheme()); $basePath = ($this->type === self::RELATIVE ? $refUrl->getBasePath() : ''); - $this->lastBaseUrl = $scheme . $refUrl->getAuthority() . $basePath; + $this->lastBaseUrl = $scheme . '://' . $refUrl->getAuthority() . $basePath; $this->lastRefUrl = $refUrl; } $url = $this->lastBaseUrl . $url; - - } else { - $host = $refUrl->getHost(); - $host = ip2long($host) ? array($host) : array_reverse(explode('.', $host)); - $url = strtr($url, array( - '/%basePath%/' => $refUrl->getBasePath(), - '%tld%' => $host[0], - '%domain%' => isset($host[1]) ? "$host[1].$host[0]" : $host[0], - )); - $url = ($this->flags & self::SECURED ? 'https:' : 'http:') . $url; } if (strpos($url, '//', 7) !== FALSE) { @@ -430,8 +444,9 @@ $this->mask = $mask; // detect '//host/path' vs. '/abs. path' vs. 'relative path' - if (substr($mask, 0, 2) === '//') { + if (preg_match('#(?:(https?):)?(//.*)#A', $mask, $m)) { $this->type = self::HOST; + list(, $this->scheme, $mask) = $m; } elseif (substr($mask, 0, 1) === '/') { $this->type = self::PATH; @@ -442,7 +457,7 @@ foreach ($metadata as $name => $meta) { if (!is_array($meta)) { - $metadata[$name] = $meta = array(self::VALUE => $meta); + $metadata[$name] = $meta = [self::VALUE => $meta]; } if (array_key_exists(self::VALUE, $meta)) { @@ -453,37 +468,28 @@ } } - if (strpbrk($mask, '?<[') === FALSE) { + if (strpbrk($mask, '?<>[]') === FALSE) { $this->re = '#' . preg_quote($mask, '#') . '/?\z#A'; - $this->sequence = array($mask); + $this->sequence = [$mask]; $this->metadata = $metadata; return; } // PARSE MASK - // or [ or ] or ?... - $parts = Strings::split($mask, '/<([^>#= ]+)(=[^># ]*)? *([^>#]*)(#?[^>\[\]]*)>|(\[!?|\]|\s*\?.*)/'); + // or [ or ] or ?... + $parts = Strings::split($mask, '/<([^<>= ]+)(=[^<> ]*)? *([^<>]*)>|(\[!?|\]|\s*\?.*)/'); - $this->xlat = array(); + $this->xlat = []; $i = count($parts) - 1; // PARSE QUERY PART OF MASK if (isset($parts[$i - 1]) && substr(ltrim($parts[$i - 1]), 0, 1) === '?') { - // name= - $matches = Strings::matchAll($parts[$i - 1], '/(?:([a-zA-Z0-9_.-]+)=)?<([^># ]+) *([^>#]*)(#?[^>]*)>/'); - - foreach ($matches as $match) { - list(, $param, $name, $pattern, $class) = $match; // $pattern is not used + // name= + $matches = Strings::matchAll($parts[$i - 1], '/(?:([a-zA-Z0-9_.-]+)=)?<([^> ]+) *([^>]*)>/'); - if ($class !== '') { - if (!isset(static::$styles[$class])) { - throw new Nette\InvalidStateException("Parameter '$name' has '$class' flag, but Route::\$styles['$class'] is not set."); - } - $meta = static::$styles[$class]; - - } elseif (isset(static::$styles['?' . $name])) { + foreach ($matches as list(, $param, $name, $pattern)) { // $pattern is not used + if (isset(static::$styles['?' . $name])) { $meta = static::$styles['?' . $name]; - } else { $meta = static::$styles['?#']; } @@ -504,18 +510,22 @@ $this->xlat[$name] = $param; } } - $i -= 6; + $i -= 5; } // PARSE PATH PART OF MASK $brackets = 0; // optional level $re = ''; - $sequence = array(); + $sequence = []; $autoOptional = TRUE; - $aliases = array(); + $aliases = []; do { - array_unshift($sequence, $parts[$i]); - $re = preg_quote($parts[$i], '#') . $re; + $part = $parts[$i]; // part of path + if (strpbrk($part, '<>') !== FALSE) { + throw new Nette\InvalidArgumentException("Unexpected '$part' in mask '$mask'."); + } + array_unshift($sequence, $part); + $re = preg_quote($part, '#') . $re; if ($i === 0) { break; } @@ -529,11 +539,10 @@ } array_unshift($sequence, $part); $re = ($part[0] === '[' ? '(?:' : ')?') . $re; - $i -= 5; + $i -= 4; continue; } - $class = $parts[$i]; $i--; // validation class $pattern = trim($parts[$i]); $i--; // validation condition (as regexp) $default = $parts[$i]; $i--; // default value $name = $parts[$i]; $i--; // parameter name @@ -547,15 +556,8 @@ } // pattern, condition & metadata - if ($class !== '') { - if (!isset(static::$styles[$class])) { - throw new Nette\InvalidStateException("Parameter '$name' has '$class' flag, but Route::\$styles['$class'] is not set."); - } - $meta = static::$styles[$class]; - - } elseif (isset(static::$styles[$name])) { + if (isset(static::$styles[$name])) { $meta = static::$styles[$name]; - } else { $meta = static::$styles['#']; } @@ -611,7 +613,7 @@ } while (TRUE); if ($brackets) { - throw new Nette\InvalidArgumentException("Missing closing ']' in mask '$mask'."); + throw new Nette\InvalidArgumentException("Missing '[' in mask '$mask'."); } $this->aliases = $aliases; @@ -637,7 +639,7 @@ */ public function getDefaults() { - $defaults = array(); + $defaults = []; foreach ($this->metadata as $name => $meta) { if (isset($meta['fixity'])) { $defaults[$name] = $meta[self::VALUE]; @@ -668,7 +670,7 @@ public function getTargetPresenters() { if ($this->flags & self::ONE_WAY) { - return array(); + return []; } $m = $this->metadata; @@ -683,7 +685,7 @@ } if (isset($m[self::PRESENTER_KEY]['fixity']) && $m[self::PRESENTER_KEY]['fixity'] === self::CONSTANT) { - return array($module . $m[self::PRESENTER_KEY][self::VALUE]); + return [$module . $m[self::PRESENTER_KEY][self::VALUE]]; } return NULL; } @@ -701,7 +703,7 @@ return $arr; } - $res = array(); + $res = []; $occupied = array_flip($xlat); foreach ($arr as $k => $v) { if (isset($xlat[$k])) { @@ -786,42 +788,4 @@ return str_replace('%2F', '/', rawurlencode($s)); } - - /********************* Route::$styles manipulator ****************d*g**/ - - - /** - * @deprecated - */ - public static function addStyle($style, $parent = '#') - { - trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED); - if (isset(static::$styles[$style])) { - throw new Nette\InvalidArgumentException("Style '$style' already exists."); - } - - if ($parent !== NULL) { - if (!isset(static::$styles[$parent])) { - throw new Nette\InvalidArgumentException("Parent style '$parent' doesn't exist."); - } - static::$styles[$style] = static::$styles[$parent]; - - } else { - static::$styles[$style] = array(); - } - } - - - /** - * @deprecated - */ - public static function setStyleProperty($style, $key, $value) - { - trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED); - if (!isset(static::$styles[$style])) { - throw new Nette\InvalidArgumentException("Style '$style' doesn't exist."); - } - static::$styles[$style][$key] = $value; - } - } diff -Nru php-nette-2.3.10/Nette/Application/Routers/SimpleRouter.php php-nette-2.4-20160731/Nette/Application/Routers/SimpleRouter.php --- php-nette-2.3.10/Nette/Application/Routers/SimpleRouter.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/Routers/SimpleRouter.php 2016-07-31 17:46:32.000000000 +0000 @@ -14,8 +14,10 @@ /** * The bidirectional route for trivial routing via query parameters. */ -class SimpleRouter extends Nette\Object implements Application\IRouter +class SimpleRouter implements Application\IRouter { + use Nette\SmartObject; + const PRESENTER_KEY = 'presenter'; const MODULE_KEY = 'module'; @@ -33,17 +35,17 @@ * @param array default values * @param int flags */ - public function __construct($defaults = array(), $flags = 0) + public function __construct($defaults = [], $flags = 0) { if (is_string($defaults)) { - $a = strrpos($defaults, ':'); - if (!$a) { + list($presenter, $action) = Nette\Application\Helpers::splitName($defaults); + if (!$presenter) { throw new Nette\InvalidArgumentException("Argument must be array or string in format Presenter:action, '$defaults' given."); } - $defaults = array( - self::PRESENTER_KEY => substr($defaults, 0, $a), - 'action' => $a === strlen($defaults) - 1 ? Application\UI\Presenter::DEFAULT_ACTION : substr($defaults, $a + 1), - ); + $defaults = [ + self::PRESENTER_KEY => $presenter, + 'action' => $action === '' ? Application\UI\Presenter::DEFAULT_ACTION : $action, + ]; } if (isset($defaults[self::MODULE_KEY])) { @@ -53,6 +55,9 @@ $this->defaults = $defaults; $this->flags = $flags; + if ($flags & self::SECURED) { + trigger_error('IRouter::SECURED is deprecated, router by default keeps the used protocol.', E_USER_DEPRECATED); + } } @@ -82,7 +87,7 @@ $params, $httpRequest->getPost(), $httpRequest->getFiles(), - array(Application\Request::SECURED => $httpRequest->isSecured()) + [Application\Request::SECURED => $httpRequest->isSecured()] ); } @@ -113,7 +118,7 @@ } } - $url = ($this->flags & self::SECURED ? 'https://' : 'http://') . $refUrl->getAuthority() . $refUrl->getPath(); + $url = ($this->flags & self::SECURED ? 'https://' : $refUrl->getScheme() . '://') . $refUrl->getAuthority() . $refUrl->getPath(); $sep = ini_get('arg_separator.input'); $query = http_build_query($params, '', $sep ? $sep[0] : '&'); if ($query != '') { // intentionally == diff -Nru php-nette-2.3.10/Nette/Application/templates/error.phtml php-nette-2.4-20160731/Nette/Application/templates/error.phtml --- php-nette-2.3.10/Nette/Application/templates/error.phtml 2016-04-13 18:50:56.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/templates/error.phtml 2016-07-31 17:46:58.000000000 +0000 @@ -7,14 +7,14 @@ namespace NetteModule; -$messages = array( - 0 => array('Oops...', 'Your browser sent a request that this server could not understand or process.'), - 403 => array('Access Denied', 'You do not have permission to view this page. Please try contact the web site administrator if you believe you should be able to view this page.'), - 404 => array('Page Not Found', 'The page you requested could not be found. It is possible that the address is incorrect, or that the page no longer exists. Please use a search engine to find what you are looking for.'), - 405 => array('Method Not Allowed', 'The requested method is not allowed for the URL.'), - 410 => array('Page Not Found', 'The page you requested has been taken off the site. We apologize for the inconvenience.'), - 500 => array('Server Error', 'We\'re sorry! The server encountered an internal error and was unable to complete your request. Please try again later.'), -); +$messages = [ + 0 => ['Oops...', 'Your browser sent a request that this server could not understand or process.'], + 403 => ['Access Denied', 'You do not have permission to view this page. Please try contact the web site administrator if you believe you should be able to view this page.'], + 404 => ['Page Not Found', 'The page you requested could not be found. It is possible that the address is incorrect, or that the page no longer exists. Please use a search engine to find what you are looking for.'], + 405 => ['Method Not Allowed', 'The requested method is not allowed for the URL.'], + 410 => ['Page Not Found', 'The page you requested has been taken off the site. We apologize for the inconvenience.'], + 500 => ['Server Error', 'We\'re sorry! The server encountered an internal error and was unable to complete your request. Please try again later.'], +]; $message = isset($messages[$code]) ? $messages[$code] : $messages[0]; ?> @@ -24,10 +24,10 @@ -<?php echo $message[0] ?> +<?= $message[0] ?> -

+

-

+

-

error

+

error

diff -Nru php-nette-2.3.10/Nette/Application/UI/Component.php php-nette-2.4-20160731/Nette/Application/UI/Component.php --- php-nette-2.3.10/Nette/Application/UI/Component.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Component.php 2016-07-31 17:46:32.000000000 +0000 @@ -0,0 +1,429 @@ +lookup(Presenter::class, $need); + } + + + /** + * Returns a fully-qualified name that uniquely identifies the component + * within the presenter hierarchy. + * @return string + */ + public function getUniqueId() + { + return $this->lookupPath(Presenter::class, TRUE); + } + + + /** + * This method will be called when the component (or component's parent) + * becomes attached to a monitored object. Do not call this method yourself. + * @param Nette\ComponentModel\IComponent + * @return void + */ + protected function attached($presenter) + { + if ($presenter instanceof Presenter) { + $this->loadState($presenter->popGlobalParameters($this->getUniqueId())); + $this->onAnchor($this); + } + } + + + /** + * @return void + */ + protected function validateParent(Nette\ComponentModel\IContainer $parent) + { + parent::validateParent($parent); + $this->monitor(Presenter::class); + } + + + /** + * Calls public method if exists. + * @param string + * @param array + * @return bool does method exist? + */ + protected function tryCall($method, array $params) + { + $rc = $this->getReflection(); + if ($rc->hasMethod($method)) { + $rm = $rc->getMethod($method); + if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) { + $this->checkRequirements($rm); + $rm->invokeArgs($this, $rc->combineArgs($rm, $params)); + return TRUE; + } + } + return FALSE; + } + + + /** + * Checks for requirements such as authorization. + * @return void + */ + public function checkRequirements($element) + { + } + + + /** + * Access to reflection. + * @return ComponentReflection + */ + public static function getReflection() + { + return new ComponentReflection(get_called_class()); + } + + + /********************* interface IStatePersistent ****************d*g**/ + + + /** + * Loads state informations. + * @param array + * @return void + */ + public function loadState(array $params) + { + $reflection = $this->getReflection(); + foreach ($reflection->getPersistentParams() as $name => $meta) { + if (isset($params[$name])) { // NULLs are ignored + $type = gettype($meta['def']); + if (!$reflection->convertType($params[$name], $type)) { + throw new Nette\Application\BadRequestException(sprintf( + "Value passed to persistent parameter '%s' in %s must be %s, %s given.", + $name, + $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'", + $type === 'NULL' ? 'scalar' : $type, + is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name]) + )); + } + $this->$name = $params[$name]; + } else { + $params[$name] = $this->$name; + } + } + $this->params = $params; + } + + + /** + * Saves state informations for next request. + * @param array + * @param ComponentReflection (internal, used by Presenter) + * @return void + */ + public function saveState(array & $params, $reflection = NULL) + { + $reflection = $reflection === NULL ? $this->getReflection() : $reflection; + foreach ($reflection->getPersistentParams() as $name => $meta) { + + if (isset($params[$name])) { + // injected value + + } elseif (array_key_exists($name, $params)) { // NULLs are skipped + continue; + + } elseif ((!isset($meta['since']) || $this instanceof $meta['since']) && isset($this->$name)) { + $params[$name] = $this->$name; // object property value + + } else { + continue; // ignored parameter + } + + $type = gettype($meta['def']); + if (!ComponentReflection::convertType($params[$name], $type)) { + throw new InvalidLinkException(sprintf( + "Value passed to persistent parameter '%s' in %s must be %s, %s given.", + $name, + $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'", + $type === 'NULL' ? 'scalar' : $type, + is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name]) + )); + } + + if ($params[$name] === $meta['def'] || ($meta['def'] === NULL && $params[$name] === '')) { + $params[$name] = NULL; // value transmit is unnecessary + } + } + } + + + /** + * Returns component param. + * @param string key + * @param mixed default value + * @return mixed + */ + public function getParameter($name, $default = NULL) + { + if (isset($this->params[$name])) { + return $this->params[$name]; + + } else { + return $default; + } + } + + + /** + * Returns component parameters. + * @return array + */ + public function getParameters() + { + return $this->params; + } + + + /** + * Returns a fully-qualified name that uniquely identifies the parameter. + * @param string + * @return string + */ + public function getParameterId($name) + { + $uid = $this->getUniqueId(); + return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name; + } + + + /** @deprecated */ + function getParam($name = NULL, $default = NULL) + { + //trigger_error(__METHOD__ . '() is deprecated; use getParameter() instead.', E_USER_DEPRECATED); + return func_num_args() ? $this->getParameter($name, $default) : $this->getParameters(); + } + + + /** + * Returns array of classes persistent parameters. They have public visibility and are non-static. + * This default implementation detects persistent parameters by annotation @persistent. + * @return array + */ + public static function getPersistentParams() + { + $rc = new \ReflectionClass(get_called_class()); + $params = []; + foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) { + if (!$rp->isStatic() && ComponentReflection::parseAnnotation($rp, 'persistent')) { + $params[] = $rp->getName(); + } + } + return $params; + } + + + /********************* interface ISignalReceiver ****************d*g**/ + + + /** + * Calls signal handler method. + * @param string + * @return void + * @throws BadSignalException if there is not handler method + */ + public function signalReceived($signal) + { + if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) { + $class = get_class($this); + throw new BadSignalException("There is no handler for signal '$signal' in class $class."); + } + } + + + /** + * Formats signal handler method name -> case sensitivity doesn't matter. + * @param string + * @return string + */ + public static function formatSignalMethod($signal) + { + return $signal == NULL ? NULL : 'handle' . $signal; // intentionally == + } + + + /********************* navigation ****************d*g**/ + + + /** + * Generates URL to presenter, action or signal. + * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" + * @param array|mixed + * @return string + * @throws InvalidLinkException + */ + public function link($destination, $args = []) + { + try { + $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1); + return $this->getPresenter()->createRequest($this, $destination, $args, 'link'); + + } catch (InvalidLinkException $e) { + return $this->getPresenter()->handleInvalidLink($e); + } + } + + + /** + * Returns destination as Link object. + * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" + * @param array|mixed + * @return Link + */ + public function lazyLink($destination, $args = []) + { + $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1); + return new Link($this, $destination, $args); + } + + + /** + * Determines whether it links to the current page. + * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" + * @param array|mixed + * @return bool + * @throws InvalidLinkException + */ + public function isLinkCurrent($destination = NULL, $args = []) + { + if ($destination !== NULL) { + $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1); + $this->getPresenter()->createRequest($this, $destination, $args, 'test'); + } + return $this->getPresenter()->getLastCreatedRequestFlag('current'); + } + + + /** + * Redirect to another presenter, action or signal. + * @param int [optional] HTTP error code + * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" + * @param array|mixed + * @return void + * @throws Nette\Application\AbortException + */ + public function redirect($code, $destination = NULL, $args = []) + { + if (!is_numeric($code)) { // first parameter is optional + $args = func_num_args() < 3 && is_array($destination) ? $destination : array_slice(func_get_args(), 1); + $destination = $code; + $code = NULL; + + } elseif (func_num_args() > 3 || !is_array($args)) { + $args = array_slice(func_get_args(), 2); + } + + $presenter = $this->getPresenter(); + $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), $code); + } + + + /** + * Permanently redirects to presenter, action or signal. + * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" + * @param array|mixed + * @return void + * @throws Nette\Application\AbortException + */ + public function redirectPermanent($destination = NULL, $args = []) + { + $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1); + $presenter = $this->getPresenter(); + $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), 301); + } + + + /********************* interface \ArrayAccess ****************d*g**/ + + + /** + * Adds the component to the container. + * @param string component name + * @param Nette\ComponentModel\IComponent + * @return void + */ + public function offsetSet($name, $component) + { + $this->addComponent($component, $name); + } + + + /** + * Returns component specified by name. Throws exception if component doesn't exist. + * @param string component name + * @return Nette\ComponentModel\IComponent + * @throws Nette\InvalidArgumentException + */ + public function offsetGet($name) + { + return $this->getComponent($name, TRUE); + } + + + /** + * Does component specified by name exists? + * @param string component name + * @return bool + */ + public function offsetExists($name) + { + return $this->getComponent($name, FALSE) !== NULL; + } + + + /** + * Removes component from the container. + * @param string component name + * @return void + */ + public function offsetUnset($name) + { + $component = $this->getComponent($name, FALSE); + if ($component !== NULL) { + $this->removeComponent($component); + } + } + +} diff -Nru php-nette-2.3.10/Nette/Application/UI/ComponentReflection.php php-nette-2.4-20160731/Nette/Application/UI/ComponentReflection.php --- php-nette-2.3.10/Nette/Application/UI/ComponentReflection.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/ComponentReflection.php 2016-07-31 17:46:32.000000000 +0000 @@ -0,0 +1,304 @@ +getName() : $class; + $params = & self::$ppCache[$class]; + if ($params !== NULL) { + return $params; + } + $params = []; + if (is_subclass_of($class, Component::class)) { + $defaults = get_class_vars($class); + foreach ($class::getPersistentParams() as $name => $default) { + if (is_int($name)) { + $name = $default; + $default = $defaults[$name]; + } + $params[$name] = [ + 'def' => $default, + 'since' => $class, + ]; + } + foreach ($this->getPersistentParams(get_parent_class($class)) as $name => $param) { + if (isset($params[$name])) { + $params[$name]['since'] = $param['since']; + continue; + } + + $params[$name] = $param; + } + } + return $params; + } + + + /** + * @param string|NULL + * @return array of persistent components. + */ + public function getPersistentComponents($class = NULL) + { + $class = $class === NULL ? $this->getName() : $class; + $components = & self::$pcCache[$class]; + if ($components !== NULL) { + return $components; + } + $components = []; + if (is_subclass_of($class, Presenter::class)) { + foreach ($class::getPersistentComponents() as $name => $meta) { + if (is_string($meta)) { + $name = $meta; + } + $components[$name] = ['since' => $class]; + } + $components = $this->getPersistentComponents(get_parent_class($class)) + $components; + } + return $components; + } + + + /** + * Is a method callable? It means class is instantiable and method has + * public visibility, is non-static and non-abstract. + * @param string method name + * @return bool + */ + public function hasCallableMethod($method) + { + $class = $this->getName(); + $cache = & self::$mcCache[strtolower($class . ':' . $method)]; + if ($cache === NULL) { + try { + $cache = FALSE; + $rm = new \ReflectionMethod($class, $method); + $cache = $this->isInstantiable() && $rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic(); + } catch (\ReflectionException $e) { + } + } + return $cache; + } + + + /** + * @return array + */ + public static function combineArgs(\ReflectionFunctionAbstract $method, $args) + { + $res = []; + foreach ($method->getParameters() as $i => $param) { + $name = $param->getName(); + list($type, $isClass) = self::getParameterType($param); + if (isset($args[$name])) { + $res[$i] = $args[$name]; + if (!self::convertType($res[$i], $type, $isClass)) { + throw new BadRequestException(sprintf( + 'Argument $%s passed to %s() must be %s, %s given.', + $name, + ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName(), + $type === 'NULL' ? 'scalar' : $type, + is_object($args[$name]) ? get_class($args[$name]) : gettype($args[$name]) + )); + } + } elseif ($param->isDefaultValueAvailable()) { + $res[$i] = $param->getDefaultValue(); + } elseif ($type === 'array') { + $res[$i] = []; + } elseif ($type === 'NULL') { + $res[$i] = NULL; + } else { + throw new BadRequestException(sprintf( + 'Missing parameter $%s required by %s()', + $name, + ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName() + )); + } + } + return $res; + } + + + /** + * Non data-loss type conversion. + * @param mixed + * @param string + * @return bool + */ + public static function convertType(& $val, $type, $isClass = FALSE) + { + if ($isClass) { + return $val instanceof $type; + + } elseif ($type === 'callable') { + return FALSE; + + } elseif ($type === 'NULL') { // means 'not array' + return !is_array($val); + + } elseif ($type === 'array') { + return is_array($val); + + } elseif (!is_scalar($val)) { // array, resource, NULL, etc. + return FALSE; + + } else { + $old = $tmp = ($val === FALSE ? '0' : (string) $val); + settype($tmp, $type); + if ($old !== ($tmp === FALSE ? '0' : (string) $tmp)) { + return FALSE; // data-loss occurs + } + $val = $tmp; + } + return TRUE; + } + + + /** + * Returns an annotation value. + * @return array|FALSE + */ + public static function parseAnnotation(\Reflector $ref, $name) + { + if (!preg_match_all('#[\\s*]@' . preg_quote($name, '#') . '(?:\(\\s*([^)]*)\\s*\))?#', $ref->getDocComment(), $m)) { + return FALSE; + } + static $tokens = ['true' => TRUE, 'false' => FALSE, 'null' => NULL]; + $res = []; + foreach ($m[1] as $s) { + foreach (preg_split('#\s*,\s*#', $s, -1, PREG_SPLIT_NO_EMPTY) ?: ['true'] as $item) { + $res[] = array_key_exists($tmp = strtolower($item), $tokens) ? $tokens[$tmp] : $item; + } + } + return $res; + } + + + /** + * @return [string, bool] + */ + public static function getParameterType(\ReflectionParameter $param) + { + $def = gettype($param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL); + if (PHP_VERSION_ID >= 70000) { + return [(string) $param->getType() ?: $def, $param->hasType() && !$param->getType()->isBuiltin()]; + } elseif ($param->isArray() || $param->isCallable()) { + return [$param->isArray() ? 'array' : 'callable', FALSE]; + } else { + try { + return ($ref = $param->getClass()) ? [$ref->getName(), TRUE] : [$def, FALSE]; + } catch (\ReflectionException $e) { + if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) { + throw new \LogicException(sprintf( + "Class %s not found. Check type hint of parameter $%s in %s() or 'use' statements.", + $m[1], + $param->getName(), + $param->getDeclaringFunction()->getDeclaringClass()->getName() . '::' . $param->getDeclaringFunction()->getName() + )); + } + throw $e; + } + } + } + + + /********************* compatiblity with Nette\Reflection ****************d*g**/ + + + /** + * Has class specified annotation? + * @param string + * @return bool + */ + public function hasAnnotation($name) + { + return (bool) self::parseAnnotation($this, $name); + } + + + /** + * Returns an annotation value. + * @param string + * @return string|NULL + */ + public function getAnnotation($name) + { + $res = self::parseAnnotation($this, $name); + return $res ? end($res) : NULL; + } + + + public function getMethod($name) + { + return new MethodReflection($this->getName(), $name); + } + + + public function getMethods($filter = -1) + { + foreach ($res = parent::getMethods($filter) as $key => $val) { + $res[$key] = new MethodReflection($this->getName(), $val->getName()); + } + return $res; + } + + + public function __toString() + { + trigger_error(__METHOD__ . ' is deprecated.', E_USER_DEPRECATED); + return $this->getName(); + } + + + public function __get($name) + { + trigger_error("getReflection()->$name is deprecated.", E_USER_DEPRECATED); + return (new ClassType($this->getName()))->$name; + } + + + public function __call($name, $args) + { + if (method_exists(ClassType::class, $name)) { + trigger_error("getReflection()->$name() is deprecated, use Nette\\Reflection\\ClassType::from(\$presenter)->$name()", E_USER_DEPRECATED); + return call_user_func_array([new ClassType($this->getName()), $name], $args); + } + Nette\Utils\ObjectMixin::strictCall(get_class($this), $name); + } + +} diff -Nru php-nette-2.3.10/Nette/Application/UI/Control.php php-nette-2.4-20160731/Nette/Application/UI/Control.php --- php-nette-2.3.10/Nette/Application/UI/Control.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Control.php 2016-07-31 17:46:32.000000000 +0000 @@ -15,7 +15,7 @@ * * @property-read ITemplate $template */ -abstract class Control extends PresenterComponent implements IRenderable +abstract class Control extends Component implements IRenderable { /** @var ITemplateFactory */ private $templateFactory; @@ -24,7 +24,7 @@ private $template; /** @var array */ - private $invalidSnippets = array(); + private $invalidSnippets = []; /** @var bool */ public $snippetMode; @@ -86,10 +86,10 @@ { $id = $this->getParameterId('flash'); $messages = $this->getPresenter()->getFlashSession()->$id; - $messages[] = $flash = (object) array( + $messages[] = $flash = (object) [ 'message' => $message, 'type' => $type, - ); + ]; $this->getTemplate()->flashes = $messages; $this->getPresenter()->getFlashSession()->$id = $messages; return $flash; @@ -109,10 +109,10 @@ $this->invalidSnippets[$snippet === NULL ? "\0" : $snippet] = TRUE; } elseif ($snippet === NULL) { - $this->invalidSnippets = array(); + $this->invalidSnippets = []; } else { - unset($this->invalidSnippets[$snippet]); + $this->invalidSnippets[$snippet] = FALSE; } } @@ -120,12 +120,14 @@ /** @deprecated */ function invalidateControl($snippet = NULL) { + trigger_error(__METHOD__ . '() is deprecated; use $this->redrawControl($snippet) instead.', E_USER_DEPRECATED); $this->redrawControl($snippet); } /** @deprecated */ function validateControl($snippet = NULL) { + trigger_error(__METHOD__ . '() is deprecated; use $this->redrawControl($snippet, FALSE) instead.', E_USER_DEPRECATED); $this->redrawControl($snippet, FALSE); } @@ -142,7 +144,7 @@ return TRUE; } else { - $queue = array($this); + $queue = [$this]; do { foreach (array_shift($queue)->getComponents() as $component) { if ($component instanceof IRenderable) { @@ -160,8 +162,10 @@ return FALSE; } + } elseif (isset($this->invalidSnippets[$snippet])) { + return $this->invalidSnippets[$snippet]; } else { - return isset($this->invalidSnippets["\0"]) || isset($this->invalidSnippets[$snippet]); + return isset($this->invalidSnippets["\0"]); } } diff -Nru php-nette-2.3.10/Nette/Application/UI/Form.php php-nette-2.4-20160731/Nette/Application/UI/Form.php --- php-nette-2.3.10/Nette/Application/UI/Form.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Form.php 2016-07-31 17:46:32.000000000 +0000 @@ -15,6 +15,8 @@ */ class Form extends Nette\Forms\Form implements ISignalReceiver { + /** @var callable[] function (self $sender); Occurs when form is attached to presenter */ + public $onAnchor; /** * Application form constructor. @@ -34,7 +36,7 @@ protected function validateParent(Nette\ComponentModel\IContainer $parent) { parent::validateParent($parent); - $this->monitor('Nette\Application\UI\Presenter'); + $this->monitor(Presenter::class); } @@ -45,7 +47,7 @@ */ public function getPresenter($need = TRUE) { - return $this->lookup('Nette\Application\UI\Presenter', $need); + return $this->lookup(Presenter::class, $need); } @@ -58,26 +60,23 @@ protected function attached($presenter) { if ($presenter instanceof Presenter) { - $name = $this->lookupPath('Nette\Application\UI\Presenter'); - if (!isset($this->getElementPrototype()->id)) { - $this->getElementPrototype()->id = 'frm-' . $name; + $this->getElementPrototype()->id = 'frm-' . $this->lookupPath(Presenter::class); + } + if (!$this->getAction()) { + $this->setAction(new Link($presenter, 'this')); } - if (iterator_count($this->getControls()) && $this->isSubmitted()) { - foreach ($this->getControls() as $control) { + $controls = $this->getControls(); + if (iterator_count($controls) && $this->isSubmitted()) { + foreach ($controls as $control) { if (!$control->isDisabled()) { $control->loadHttpData(); } } } - if (!$this->getAction()) { - $this->setAction(new Link($presenter, 'this', array())); - $signal = new Nette\Forms\Controls\HiddenField($name . self::NAME_SEPARATOR . 'submit'); - $signal->setOmitted()->setHtmlId(FALSE); - $this[Presenter::SIGNAL_KEY] = $signal; - } + $this->onAnchor($this); } parent::attached($presenter); } @@ -104,19 +103,29 @@ return; } - $isPost = $this->getMethod() === self::POST; $request = $presenter->getRequest(); - if ($request->isMethod('forward') || $request->isMethod('post') !== $isPost) { + if ($request->isMethod('forward') || $request->isMethod('post') !== $this->isMethod('post')) { return; } - if ($isPost) { + if ($this->isMethod('post')) { return Nette\Utils\Arrays::mergeTree($request->getPost(), $request->getFiles()); } else { return $request->getParameters(); } } + + protected function beforeRender() + { + parent::beforeRender(); + $key = ($this->isMethod('post') ? '_' : '') . Presenter::SIGNAL_KEY; + if (!isset($this[$key])) { + $do = $this->lookupPath(Presenter::class) . self::NAME_SEPARATOR . 'submit'; + $this[$key] = (new Nette\Forms\Controls\HiddenField($do))->setOmitted()->setHtmlId(FALSE); + } + } + /********************* interface ISignalReceiver ****************d*g**/ diff -Nru php-nette-2.3.10/Nette/Application/UI/Link.php php-nette-2.4-20160731/Nette/Application/UI/Link.php --- php-nette-2.3.10/Nette/Application/UI/Link.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Link.php 2016-07-31 17:46:32.000000000 +0000 @@ -11,12 +11,14 @@ /** - * Lazy encapsulation of PresenterComponent::link(). - * Do not instantiate directly, use PresenterComponent::lazyLink() + * Lazy encapsulation of Component::link(). + * Do not instantiate directly, use Component::lazyLink() */ -class Link extends Nette\Object +class Link { - /** @var PresenterComponent */ + use Nette\SmartObject; + + /** @var Component */ private $component; /** @var string */ @@ -29,7 +31,7 @@ /** * Link specification. */ - public function __construct(PresenterComponent $component, $destination, array $params) + public function __construct(Component $component, $destination, array $params = []) { $this->component = $component; $this->destination = $destination; diff -Nru php-nette-2.3.10/Nette/Application/UI/MethodReflection.php php-nette-2.4-20160731/Nette/Application/UI/MethodReflection.php --- php-nette-2.3.10/Nette/Application/UI/MethodReflection.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/MethodReflection.php 2016-07-31 17:46:32.000000000 +0000 @@ -0,0 +1,64 @@ +getName() . '::' . $this->getName() . '()'; + } + + + public function __get($name) + { + trigger_error("getMethod('{$this->getName()}')->$name is deprecated.", E_USER_DEPRECATED); + return (new Method(parent::getDeclaringClass()->getName(), $this->getName()))->$name; + } + + + public function __call($name, $args) + { + trigger_error("getMethod('{$this->getName()}')->$name() is deprecated, use Nette\\Reflection\\Method::from(\$presenter, '{$this->getName()}')->$name()", E_USER_DEPRECATED); + return call_user_func_array([new Method(parent::getDeclaringClass()->getName(), $this->getName()), $name], $args); + } + +} diff -Nru php-nette-2.3.10/Nette/Application/UI/Multiplier.php php-nette-2.4-20160731/Nette/Application/UI/Multiplier.php --- php-nette-2.3.10/Nette/Application/UI/Multiplier.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Multiplier.php 2016-07-31 17:46:32.000000000 +0000 @@ -13,19 +13,16 @@ /** * Component multiplier. */ -class Multiplier extends PresenterComponent +class Multiplier extends Component { /** @var callable */ private $factory; - /** - * @param callable - */ - public function __construct($factory) + public function __construct(callable $factory) { parent::__construct(); - $this->factory = Nette\Utils\Callback::check($factory); + $this->factory = $factory; } diff -Nru php-nette-2.3.10/Nette/Application/UI/PresenterComponent.php php-nette-2.4-20160731/Nette/Application/UI/PresenterComponent.php --- php-nette-2.3.10/Nette/Application/UI/PresenterComponent.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/PresenterComponent.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,406 +0,0 @@ -lookup('Nette\Application\UI\Presenter', $need); - } - - - /** - * Returns a fully-qualified name that uniquely identifies the component - * within the presenter hierarchy. - * @return string - */ - public function getUniqueId() - { - return $this->lookupPath('Nette\Application\UI\Presenter', TRUE); - } - - - /** - * This method will be called when the component (or component's parent) - * becomes attached to a monitored object. Do not call this method yourself. - * @param Nette\ComponentModel\IComponent - * @return void - */ - protected function attached($presenter) - { - if ($presenter instanceof Presenter) { - $this->loadState($presenter->popGlobalParameters($this->getUniqueId())); - } - } - - - /** - * @return void - */ - protected function validateParent(Nette\ComponentModel\IContainer $parent) - { - parent::validateParent($parent); - $this->monitor('Nette\Application\UI\Presenter'); - } - - - /** - * Calls public method if exists. - * @param string - * @param array - * @return bool does method exist? - */ - protected function tryCall($method, array $params) - { - $rc = $this->getReflection(); - if ($rc->hasMethod($method)) { - $rm = $rc->getMethod($method); - if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) { - $this->checkRequirements($rm); - $rm->invokeArgs($this, $rc->combineArgs($rm, $params)); - return TRUE; - } - } - return FALSE; - } - - - /** - * Checks for requirements such as authorization. - * @return void - */ - public function checkRequirements($element) - { - } - - - /** - * Access to reflection. - * @return PresenterComponentReflection - */ - public static function getReflection() - { - return new PresenterComponentReflection(get_called_class()); - } - - - /********************* interface IStatePersistent ****************d*g**/ - - - /** - * Loads state informations. - * @param array - * @return void - */ - public function loadState(array $params) - { - $reflection = $this->getReflection(); - foreach ($reflection->getPersistentParams() as $name => $meta) { - if (isset($params[$name])) { // NULLs are ignored - $type = gettype($meta['def']); - if (!$reflection->convertType($params[$name], $type)) { - throw new Nette\Application\BadRequestException(sprintf( - "Value passed to persistent parameter '%s' in %s must be %s, %s given.", - $name, - $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'", - $type === 'NULL' ? 'scalar' : $type, - is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name]) - )); - } - $this->$name = $params[$name]; - } else { - $params[$name] = $this->$name; - } - } - $this->params = $params; - } - - - /** - * Saves state informations for next request. - * @param array - * @param PresenterComponentReflection (internal, used by Presenter) - * @return void - */ - public function saveState(array & $params, $reflection = NULL) - { - $reflection = $reflection === NULL ? $this->getReflection() : $reflection; - foreach ($reflection->getPersistentParams() as $name => $meta) { - - if (isset($params[$name])) { - // injected value - - } elseif (array_key_exists($name, $params)) { // NULLs are skipped - continue; - - } elseif ((!isset($meta['since']) || $this instanceof $meta['since']) && isset($this->$name)) { - $params[$name] = $this->$name; // object property value - - } else { - continue; // ignored parameter - } - - $type = gettype($meta['def']); - if (!PresenterComponentReflection::convertType($params[$name], $type)) { - throw new InvalidLinkException(sprintf( - "Value passed to persistent parameter '%s' in %s must be %s, %s given.", - $name, - $this instanceof Presenter ? 'presenter ' . $this->getName() : "component '{$this->getUniqueId()}'", - $type === 'NULL' ? 'scalar' : $type, - is_object($params[$name]) ? get_class($params[$name]) : gettype($params[$name]) - )); - } - - if ($params[$name] === $meta['def'] || ($meta['def'] === NULL && is_scalar($params[$name]) && (string) $params[$name] === '')) { - $params[$name] = NULL; // value transmit is unnecessary - } - } - } - - - /** - * Returns component param. - * @param string key - * @param mixed default value - * @return mixed - */ - public function getParameter($name, $default = NULL) - { - if (isset($this->params[$name])) { - return $this->params[$name]; - - } else { - return $default; - } - } - - - /** - * Returns component parameters. - * @return array - */ - public function getParameters() - { - return $this->params; - } - - - /** - * Returns a fully-qualified name that uniquely identifies the parameter. - * @param string - * @return string - */ - public function getParameterId($name) - { - $uid = $this->getUniqueId(); - return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name; - } - - - /** @deprecated */ - function getParam($name = NULL, $default = NULL) - { - //trigger_error(__METHOD__ . '() is deprecated; use getParameter() instead.', E_USER_DEPRECATED); - return func_num_args() ? $this->getParameter($name, $default) : $this->getParameters(); - } - - - /** - * Returns array of classes persistent parameters. They have public visibility and are non-static. - * This default implementation detects persistent parameters by annotation @persistent. - * @return array - */ - public static function getPersistentParams() - { - $rc = new \ReflectionClass(get_called_class()); - $params = array(); - foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) { - if (!$rp->isStatic() && PresenterComponentReflection::parseAnnotation($rp, 'persistent')) { - $params[] = $rp->getName(); - } - } - return $params; - } - - - /********************* interface ISignalReceiver ****************d*g**/ - - - /** - * Calls signal handler method. - * @param string - * @return void - * @throws BadSignalException if there is not handler method - */ - public function signalReceived($signal) - { - if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) { - $class = get_class($this); - throw new BadSignalException("There is no handler for signal '$signal' in class $class."); - } - } - - - /** - * Formats signal handler method name -> case sensitivity doesn't matter. - * @param string - * @return string - */ - public static function formatSignalMethod($signal) - { - return $signal == NULL ? NULL : 'handle' . $signal; // intentionally == - } - - - /********************* navigation ****************d*g**/ - - - /** - * Generates URL to presenter, action or signal. - * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed - * @return string - * @throws InvalidLinkException - */ - public function link($destination, $args = array()) - { - try { - return $this->getPresenter()->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'link'); - - } catch (InvalidLinkException $e) { - return $this->getPresenter()->handleInvalidLink($e); - } - } - - - /** - * Returns destination as Link object. - * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed - * @return Link - */ - public function lazyLink($destination, $args = array()) - { - return new Link($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1)); - } - - - /** - * Determines whether it links to the current page. - * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed - * @return bool - * @throws InvalidLinkException - */ - public function isLinkCurrent($destination = NULL, $args = array()) - { - if ($destination !== NULL) { - $this->getPresenter()->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'test'); - } - return $this->getPresenter()->getLastCreatedRequestFlag('current'); - } - - - /** - * Redirect to another presenter, action or signal. - * @param int [optional] HTTP error code - * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed - * @return void - * @throws Nette\Application\AbortException - */ - public function redirect($code, $destination = NULL, $args = array()) - { - if (!is_numeric($code)) { // first parameter is optional - $args = is_array($destination) ? $destination : array_slice(func_get_args(), 1); - $destination = $code; - $code = NULL; - - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 2); - } - - $presenter = $this->getPresenter(); - $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), $code); - } - - - /********************* interface \ArrayAccess ****************d*g**/ - - - /** - * Adds the component to the container. - * @param string component name - * @param Nette\ComponentModel\IComponent - * @return void - */ - public function offsetSet($name, $component) - { - $this->addComponent($component, $name); - } - - - /** - * Returns component specified by name. Throws exception if component doesn't exist. - * @param string component name - * @return Nette\ComponentModel\IComponent - * @throws Nette\InvalidArgumentException - */ - public function offsetGet($name) - { - return $this->getComponent($name, TRUE); - } - - - /** - * Does component specified by name exists? - * @param string component name - * @return bool - */ - public function offsetExists($name) - { - return $this->getComponent($name, FALSE) !== NULL; - } - - - /** - * Removes component from the container. - * @param string component name - * @return void - */ - public function offsetUnset($name) - { - $component = $this->getComponent($name, FALSE); - if ($component !== NULL) { - $this->removeComponent($component); - } - } - -} diff -Nru php-nette-2.3.10/Nette/Application/UI/PresenterComponentReflection.php php-nette-2.4-20160731/Nette/Application/UI/PresenterComponentReflection.php --- php-nette-2.3.10/Nette/Application/UI/PresenterComponentReflection.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/PresenterComponentReflection.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -getName() : $class; - $params = & self::$ppCache[$class]; - if ($params !== NULL) { - return $params; - } - $params = array(); - if (is_subclass_of($class, 'Nette\Application\UI\PresenterComponent')) { - $defaults = get_class_vars($class); - foreach ($class::getPersistentParams() as $name => $default) { - if (is_int($name)) { - $name = $default; - $default = $defaults[$name]; - } - $params[$name] = array( - 'def' => $default, - 'since' => $class, - ); - } - foreach ($this->getPersistentParams(get_parent_class($class)) as $name => $param) { - if (isset($params[$name])) { - $params[$name]['since'] = $param['since']; - continue; - } - - $params[$name] = $param; - } - } - return $params; - } - - - /** - * @param string|NULL - * @return array of persistent components. - */ - public function getPersistentComponents($class = NULL) - { - $class = $class === NULL ? $this->getName() : $class; - $components = & self::$pcCache[$class]; - if ($components !== NULL) { - return $components; - } - $components = array(); - if (is_subclass_of($class, 'Nette\Application\UI\Presenter')) { - foreach ($class::getPersistentComponents() as $name => $meta) { - if (is_string($meta)) { - $name = $meta; - } - $components[$name] = array('since' => $class); - } - $components = $this->getPersistentComponents(get_parent_class($class)) + $components; - } - return $components; - } - - - /** - * Is a method callable? It means class is instantiable and method has - * public visibility, is non-static and non-abstract. - * @param string method name - * @return bool - */ - public function hasCallableMethod($method) - { - $class = $this->getName(); - $cache = & self::$mcCache[strtolower($class . ':' . $method)]; - if ($cache === NULL) { - try { - $cache = FALSE; - $rm = new \ReflectionMethod($class, $method); - $cache = $this->isInstantiable() && $rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic(); - } catch (\ReflectionException $e) { - } - } - return $cache; - } - - - /** - * @return array - */ - public static function combineArgs(\ReflectionFunctionAbstract $method, $args) - { - $res = array(); - foreach ($method->getParameters() as $i => $param) { - $name = $param->getName(); - list($type, $isClass) = self::getParameterType($param); - if (isset($args[$name])) { - $res[$i] = $args[$name]; - if (!self::convertType($res[$i], $type, $isClass)) { - throw new BadRequestException(sprintf( - 'Argument $%s passed to %s() must be %s, %s given.', - $name, - ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName(), - $type === 'NULL' ? 'scalar' : $type, - is_object($args[$name]) ? get_class($args[$name]) : gettype($args[$name]) - )); - } - } elseif ($param->isDefaultValueAvailable()) { - $res[$i] = $param->getDefaultValue(); - } elseif ($type === 'array') { - $res[$i] = array(); - } elseif ($type === 'NULL' || $isClass) { - $res[$i] = NULL; - } else { - throw new BadRequestException(sprintf( - 'Missing parameter $%s required by %s()', - $name, - ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName() - )); - } - } - return $res; - } - - - /** - * Non data-loss type conversion. - * @param mixed - * @param string - * @return bool - */ - public static function convertType(& $val, $type, $isClass = FALSE) - { - if ($type === 'callable') { - return FALSE; - - } elseif ($type === 'NULL' || $isClass) { // means 'not array', ignore class type hint - return !is_array($val); - - } elseif (is_object($val)) { - // ignore - - } elseif ($type === 'array') { - return is_array($val); - - } elseif (!is_scalar($val)) { // array, resource, etc. - return FALSE; - - } else { - $old = $tmp = ($val === FALSE ? '0' : (string) $val); - settype($tmp, $type); - if ($old !== ($tmp === FALSE ? '0' : (string) $tmp)) { - return FALSE; // data-loss occurs - } - $val = $tmp; - } - return TRUE; - } - - - /** - * Returns an annotation value. - * @return array|FALSE - */ - public static function parseAnnotation(\Reflector $ref, $name) - { - if (!preg_match_all("#[\\s*]@$name(?:\(\\s*([^)]*)\\s*\))?#", $ref->getDocComment(), $m)) { - return FALSE; - } - $res = array(); - foreach ($m[1] as $s) { - $arr = $s === '' ? array(TRUE) : preg_split('#\s*,\s*#', $s, -1, PREG_SPLIT_NO_EMPTY); - $res = array_merge($res, $arr); - } - return $res; - } - - - /** - * @return [string, bool] - */ - public static function getParameterType(\ReflectionParameter $param) - { - $def = gettype($param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL); - if (PHP_VERSION_ID >= 70000) { - return array((string) $param->getType() ?: $def, $param->hasType() && !$param->getType()->isBuiltin()); - } elseif ($param->isArray()) { - return array('array', FALSE); - } elseif (PHP_VERSION_ID >= 50400 && $param->isCallable()) { - return array('callable', FALSE); - } else { - try { - return ($ref = $param->getClass()) ? array($ref->getName(), TRUE) : array($def, FALSE); - } catch (\ReflectionException $e) { - if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) { - throw new \LogicException(sprintf( - "Class %s not found. Check type hint of parameter $%s in %s() or 'use' statements.", - $m[1], - $param->getName(), - $param->getDeclaringFunction()->getDeclaringClass()->getName() . '::' . $param->getDeclaringFunction()->getName() - )); - } - throw $e; - } - } - } - -} diff -Nru php-nette-2.3.10/Nette/Application/UI/Presenter.php php-nette-2.4-20160731/Nette/Application/UI/Presenter.php --- php-nette-2.3.10/Nette/Application/UI/Presenter.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Application/UI/Presenter.php 2016-07-31 17:46:32.000000000 +0000 @@ -10,6 +10,7 @@ use Nette; use Nette\Application; use Nette\Application\Responses; +use Nette\Application\Helpers; use Nette\Http; @@ -28,10 +29,10 @@ abstract class Presenter extends Control implements Application\IPresenter { /** bad link handling {@link Presenter::$invalidLinkMode} */ - const INVALID_LINK_SILENT = 0, - INVALID_LINK_WARNING = 1, - INVALID_LINK_EXCEPTION = 2, - INVALID_LINK_TEXTUAL = 4; + const INVALID_LINK_SILENT = 0b0000, + INVALID_LINK_WARNING = 0b0001, + INVALID_LINK_EXCEPTION = 0b0010, + INVALID_LINK_TEXTUAL = 0b0100; /** @internal special parameter key */ const SIGNAL_KEY = 'do', @@ -120,6 +121,9 @@ /** @var ITemplateFactory */ private $templateFactory; + /** @var Nette\Http\Url */ + private $refUrlCache; + public function __construct() { @@ -228,6 +232,7 @@ $this->response->send($this->httpRequest, $this->httpResponse); $this->sendPayload(); } elseif (!$this->response && $hasPayload) { // back compatibility for use terminate() instead of sendPayload() + trigger_error('Use $presenter->sendPayload() instead of terminate() to send payload.'); $this->sendPayload(); } } catch (Application\AbortException $e) { @@ -289,7 +294,7 @@ */ public function checkRequirements($element) { - $user = (array) PresenterComponentReflection::parseAnnotation($element, 'User'); + $user = (array) ComponentReflection::parseAnnotation($element, 'User'); if (in_array('loggedIn', $user, TRUE) && !$this->getUser()->isLoggedIn()) { throw new Application\ForbiddenRequestException; } @@ -332,7 +337,7 @@ */ public function getSignal() { - return $this->signal === NULL ? NULL : array($this->signalReceiver, $this->signal); + return $this->signal === NULL ? NULL : [$this->signalReceiver, $this->signal]; } @@ -497,19 +502,21 @@ */ public function formatLayoutTemplateFiles() { - $name = $this->getName(); - $presenter = substr($name, strrpos(':' . $name, ':')); + if (preg_match('#/|\\\\#', $this->layout)) { + return [$this->layout]; + } + list($module, $presenter) = Helpers::splitName($this->getName()); $layout = $this->layout ? $this->layout : 'layout'; $dir = dirname($this->getReflection()->getFileName()); $dir = is_dir("$dir/templates") ? $dir : dirname($dir); - $list = array( + $list = [ "$dir/templates/$presenter/@$layout.latte", "$dir/templates/$presenter.@$layout.latte", - ); + ]; do { $list[] = "$dir/templates/@$layout.latte"; $dir = dirname($dir); - } while ($dir && ($name = substr($name, 0, strrpos($name, ':')))); + } while ($dir && $module && (list($module) = Helpers::splitName($module))); return $list; } @@ -520,14 +527,13 @@ */ public function formatTemplateFiles() { - $name = $this->getName(); - $presenter = substr($name, strrpos(':' . $name, ':')); + list(, $presenter) = Helpers::splitName($this->getName()); $dir = dirname($this->getReflection()->getFileName()); $dir = is_dir("$dir/templates") ? $dir : dirname($dir); - return array( + return [ "$dir/templates/$presenter/$this->view.latte", "$dir/templates/$presenter.$this->view.latte", - ); + ]; } @@ -638,18 +644,19 @@ /** * Forward to another presenter or action. - * @param string|Request + * @param string|Nette\Application\Request * @param array|mixed * @return void * @throws Nette\Application\AbortException */ - public function forward($destination, $args = array()) + public function forward($destination, $args = []) { if ($destination instanceof Application\Request) { $this->sendResponse(new Responses\ForwardResponse($destination)); } - $this->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'forward'); + $args = func_num_args() < 3 && is_array($args) ? $args : array_slice(func_get_args(), 1); + $this->createRequest($this, $destination, $args, 'forward'); $this->sendResponse(new Responses\ForwardResponse($this->lastCreatedRequest)); } @@ -696,6 +703,7 @@ */ public function backlink() { + trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED); return $this->getAction(TRUE); } @@ -744,7 +752,7 @@ /** * Attempts to cache the sent entity by its last modification date. - * @param string|int|\DateTime last modified time + * @param string|int|\DateTimeInterface last modified time * @param string strong entity tag validator * @param mixed optional expiration time * @return void @@ -764,7 +772,7 @@ /** * Request/URL factory. - * @param PresenterComponent base + * @param Component base * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" * @param array array of arguments * @param string forward|redirect|link @@ -791,7 +799,7 @@ // 2) ?query syntax $a = strpos($destination, '?'); if ($a !== FALSE) { - parse_str(substr($destination, $a + 1), $args); // requires disabled magic quotes + parse_str(substr($destination, $a + 1), $args); $destination = substr($destination, 0, $a); } @@ -806,13 +814,11 @@ // 4) signal or empty if (!$component instanceof self || substr($destination, -1) === '!') { - $signal = rtrim($destination, '!'); - $a = strrpos($signal, ':'); - if ($a !== FALSE) { - $component = $component->getComponent(strtr(substr($signal, 0, $a), ':', '-')); - $signal = (string) substr($signal, $a + 1); + list($cname, $signal) = Helpers::splitName(rtrim($destination, '!')); + if ($cname !== '') { + $component = $component->getComponent(strtr($cname, ':', '-')); } - if ($signal == NULL) { // intentionally == + if ($signal === '') { throw new InvalidLinkException('Signal must be non-empty string.'); } $destination = 'this'; @@ -824,28 +830,21 @@ // 5) presenter: action $current = FALSE; - $a = strrpos($destination, ':'); - if ($a === FALSE) { - $action = $destination === 'this' ? $this->action : $destination; + list($presenter, $action) = Helpers::splitName($destination); + if ($presenter === '') { + $action = $destination === 'this' ? $this->action : $action; $presenter = $this->getName(); $presenterClass = get_class($this); } else { - $action = (string) substr($destination, $a + 1); - if ($destination[0] === ':') { // absolute - if ($a < 2) { + if ($presenter[0] === ':') { // absolute + $presenter = substr($presenter, 1); + if (!$presenter) { throw new InvalidLinkException("Missing presenter name in '$destination'."); } - $presenter = substr($destination, 1, $a - 1); - } else { // relative - $presenter = $this->getName(); - $b = strrpos($presenter, ':'); - if ($b === FALSE) { // no module - $presenter = substr($destination, 0, $a); - } else { // with module - $presenter = substr($presenter, 0, $b + 1) . substr($destination, 0, $a); - } + list($module, , $sep) = Helpers::splitName($this->getName()); + $presenter = $module . $sep . $presenter; } if (!$this->presenterFactory) { throw new Nette\InvalidStateException('Unable to create link to other presenter, service PresenterFactory has not been set.'); @@ -859,7 +858,7 @@ // PROCESS SIGNAL ARGUMENTS if (isset($signal)) { // $component must be IStatePersistent - $reflection = new PresenterComponentReflection(get_class($component)); + $reflection = new ComponentReflection(get_class($component)); if ($signal === 'this') { // means "no signal" $signal = ''; if (array_key_exists(0, $args)) { @@ -873,7 +872,7 @@ throw new InvalidLinkException("Unknown signal '$signal', missing handler {$reflection->getName()}::$method()"); } // convert indexed parameters to named - self::argsToParams(get_class($component), $method, $args, array(), $mode === 'test'); + self::argsToParams(get_class($component), $method, $args, [], $missing); } // counterpart of IStatePersistent @@ -898,7 +897,7 @@ $current = ($action === '*' || strcasecmp($action, $this->action) === 0) && $presenterClass === get_class($this); - $reflection = new PresenterComponentReflection($presenterClass); + $reflection = new ComponentReflection($presenterClass); // counterpart of run() & tryCall() $method = $presenterClass::formatActionMethod($action); @@ -915,7 +914,7 @@ throw new InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method."); } } else { - self::argsToParams($presenterClass, $method, $args, $destination === 'this' ? $this->params : array(), $mode === 'test'); + self::argsToParams($presenterClass, $method, $args, $destination === 'this' ? $this->params : [], $missing); } // counterpart of IStatePersistent @@ -931,7 +930,7 @@ if ($current && $args) { $tmp = $globalState + $this->params; foreach ($args as $key => $val) { - if (http_build_query(array($val)) !== (isset($tmp[$key]) ? http_build_query(array($tmp[$key])) : '')) { + if (http_build_query([$val]) !== (isset($tmp[$key]) ? http_build_query([$tmp[$key]]) : '')) { $current = FALSE; break; } @@ -940,6 +939,14 @@ $args += $globalState; } + if ($mode !== 'test' && !empty($missing)) { + foreach ($missing as $rp) { + if (!array_key_exists($rp->getName(), $args)) { + throw new InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()"); + } + } + } + // ADD ACTION & SIGNAL & FLASH if ($action) { $args[self::ACTION_KEY] = $action; @@ -949,32 +956,31 @@ $current = $current && $args[self::SIGNAL_KEY] === $this->getParameter(self::SIGNAL_KEY); } if (($mode === 'redirect' || $mode === 'forward') && $this->hasFlashSession()) { - $args[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY); + $args[self::FLASH_KEY] = $this->getFlashKey(); } $this->lastCreatedRequest = new Application\Request( $presenter, Application\Request::FORWARD, $args, - array(), - array() + [], + [] ); - $this->lastCreatedRequestFlag = array('current' => $current); + $this->lastCreatedRequestFlag = ['current' => $current]; if ($mode === 'forward' || $mode === 'test') { return; } // CONSTRUCT URL - static $refUrl; - if ($refUrl === NULL) { - $refUrl = new Http\Url($this->httpRequest->getUrl()); - $refUrl->setPath($this->httpRequest->getUrl()->getScriptPath()); + if ($this->refUrlCache === NULL) { + $this->refUrlCache = new Http\Url($this->httpRequest->getUrl()); + $this->refUrlCache->setPath($this->httpRequest->getUrl()->getScriptPath()); } if (!$this->router) { throw new Nette\InvalidStateException('Unable to generate URL, service Router has not been set.'); } - $url = $this->router->constructUrl($this->lastCreatedRequest, $refUrl); + $url = $this->router->constructUrl($this->lastCreatedRequest, $this->refUrlCache); if ($url === NULL) { unset($args[self::ACTION_KEY]); $params = urldecode(http_build_query($args, NULL, ', ')); @@ -983,7 +989,7 @@ // make URL relative if possible if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls) { - $hostUrl = $refUrl->getHostUrl() . '/'; + $hostUrl = $this->refUrlCache->getHostUrl() . '/'; if (strncmp($url, $hostUrl, strlen($hostUrl)) === 0) { $url = substr($url, strlen($hostUrl) - 1); } @@ -999,17 +1005,17 @@ * @param string method name * @param array arguments * @param array supplemental arguments - * @param bool prevents 'Missing parameter' exception + * @param ReflectionParameter[] missing arguments * @return void * @throws InvalidLinkException * @internal */ - public static function argsToParams($class, $method, & $args, $supplemental = array(), $ignoreMissing = FALSE) + public static function argsToParams($class, $method, & $args, $supplemental = [], & $missing = []) { $i = 0; $rm = new \ReflectionMethod($class, $method); foreach ($rm->getParameters() as $param) { - list($type, $isClass) = PresenterComponentReflection::getParameterType($param); + list($type, $isClass) = ComponentReflection::getParameterType($param); $name = $param->getName(); if (array_key_exists($i, $args)) { @@ -1025,13 +1031,14 @@ } if (!isset($args[$name])) { - if ($param->isDefaultValueAvailable() || $type === 'NULL' || $type === 'array' || $isClass || $ignoreMissing) { - continue; + if (!$param->isDefaultValueAvailable() && $type !== 'NULL' && $type !== 'array') { + $missing[] = $param; + unset($args[$name]); } - throw new InvalidLinkException("Missing parameter \$$name required by $class::{$rm->getName()}()"); + continue; } - if (!PresenterComponentReflection::convertType($args[$name], $type, $isClass)) { + if (!ComponentReflection::convertType($args[$name], $type, $isClass)) { throw new InvalidLinkException(sprintf( 'Argument $%s passed to %s() must be %s, %s given.', $name, @@ -1042,7 +1049,7 @@ } $def = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL; - if ($args[$name] === $def || ($def === NULL && is_scalar($args[$name]) && (string) $args[$name] === '')) { + if ($args[$name] === $def || ($def === NULL && $args[$name] === '')) { $args[$name] = NULL; // value transmit is unnecessary } } @@ -1086,7 +1093,7 @@ $key = Nette\Utils\Random::generate(5); } while (isset($session[$key])); - $session[$key] = array($this->getUser()->getId(), $this->request); + $session[$key] = [$this->user ? $this->user->getId() : NULL, $this->request]; $session->setExpiration($expiration, $key); return $key; } @@ -1107,7 +1114,7 @@ unset($session[$key]); $request->setFlag(Application\Request::RESTORED, TRUE); $params = $request->getParameters(); - $params[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY); + $params[self::FLASH_KEY] = $this->getFlashKey(); $request->setParameters($params); $this->sendResponse(new Responses\ForwardResponse($request)); } @@ -1123,7 +1130,7 @@ */ public static function getPersistentComponents() { - return (array) PresenterComponentReflection::parseAnnotation(new \ReflectionClass(get_called_class()), 'persistent'); + return (array) ComponentReflection::parseAnnotation(new \ReflectionClass(get_called_class()), 'persistent'); } @@ -1136,24 +1143,24 @@ $sinces = & $this->globalStateSinces; if ($this->globalState === NULL) { - $state = array(); + $state = []; foreach ($this->globalParams as $id => $params) { $prefix = $id . self::NAME_SEPARATOR; foreach ($params as $key => $val) { $state[$prefix . $key] = $val; } } - $this->saveState($state, $forClass ? new PresenterComponentReflection($forClass) : NULL); + $this->saveState($state, $forClass ? new ComponentReflection($forClass) : NULL); if ($sinces === NULL) { - $sinces = array(); + $sinces = []; foreach ($this->getReflection()->getPersistentParams() as $name => $meta) { $sinces[$name] = $meta['since']; } } $components = $this->getReflection()->getPersistentComponents(); - $iterator = $this->getComponents(TRUE, 'Nette\Application\UI\IStatePersistent'); + $iterator = $this->getComponents(TRUE, IStatePersistent::class); foreach ($iterator as $name => $component) { if ($iterator->getDepth() === 0) { @@ -1161,7 +1168,7 @@ $since = isset($components[$name]['since']) ? $components[$name]['since'] : FALSE; // FALSE = nonpersistent } $prefix = $component->getUniqueId() . self::NAME_SEPARATOR; - $params = array(); + $params = []; $component->saveState($params); foreach ($params as $key => $val) { $state[$prefix . $key] = $val; @@ -1183,7 +1190,7 @@ } if ($since !== $sinces[$key]) { $since = $sinces[$key]; - $ok = $since && (is_subclass_of($forClass, $since) || $forClass === $since); + $ok = $since && is_a($forClass, $since, TRUE); } if (!$ok) { unset($state[$key]); @@ -1201,7 +1208,7 @@ */ protected function saveGlobalState() { - $this->globalParams = array(); + $this->globalParams = []; $this->globalState = $this->getGlobalState(); } @@ -1214,15 +1221,17 @@ private function initGlobalParameters() { // init $this->globalParams - $this->globalParams = array(); - $selfParams = array(); + $this->globalParams = []; + $selfParams = []; $params = $this->request->getParameters(); - if ($this->isAjax()) { - $params += $this->request->getPost(); - } - if (($tmp = $this->request->getPost(self::SIGNAL_KEY)) !== NULL) { + if (($tmp = $this->request->getPost('_' . self::SIGNAL_KEY)) !== NULL) { $params[self::SIGNAL_KEY] = $tmp; + } elseif ($this->isAjax()) { + $params += $this->request->getPost(); + if (($tmp = $this->request->getPost(self::SIGNAL_KEY)) !== NULL) { + $params[self::SIGNAL_KEY] = $tmp; + } } foreach ($params as $key => $value) { @@ -1276,7 +1285,7 @@ return $res; } else { - return array(); + return []; } } @@ -1285,13 +1294,26 @@ /** + * @return string|NULL + */ + private function getFlashKey() + { + $flashKey = $this->getParameter(self::FLASH_KEY); + return is_string($flashKey) && $flashKey !== '' + ? $flashKey + : NULL; + } + + + /** * Checks if a flash session namespace exists. * @return bool */ public function hasFlashSession() { - return !empty($this->params[self::FLASH_KEY]) - && $this->getSession()->hasSection('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]); + $flashKey = $this->getFlashKey(); + return $flashKey !== NULL + && $this->getSession()->hasSection('Nette.Application.Flash/' . $flashKey); } @@ -1301,10 +1323,11 @@ */ public function getFlashSession() { - if (empty($this->params[self::FLASH_KEY])) { - $this->params[self::FLASH_KEY] = Nette\Utils\Random::generate(4); + $flashKey = $this->getFlashKey(); + if ($flashKey === NULL) { + $this->params[self::FLASH_KEY] = $flashKey = Nette\Utils\Random::generate(4); } - return $this->getSession('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]); + return $this->getSession('Nette.Application.Flash/' . $flashKey); } diff -Nru php-nette-2.3.10/Nette/Bootstrap/Configurator.php php-nette-2.4-20160731/Nette/Bootstrap/Configurator.php --- php-nette-2.3.10/Nette/Bootstrap/Configurator.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bootstrap/Configurator.php 2016-07-31 17:46:32.000000000 +0000 @@ -15,8 +15,10 @@ /** * Initial system DI container generator. */ -class Configurator extends Object +class Configurator { + use SmartObject; + const AUTO = TRUE, NONE = FALSE; @@ -26,40 +28,39 @@ public $onCompile; /** @var array */ - public $defaultExtensions = array( - 'php' => 'Nette\DI\Extensions\PhpExtension', - 'constants' => 'Nette\DI\Extensions\ConstantsExtension', - 'extensions' => 'Nette\DI\Extensions\ExtensionsExtension', - 'application' => array('Nette\Bridges\ApplicationDI\ApplicationExtension', array('%debugMode%', array('%appDir%'), '%tempDir%/cache')), - 'decorator' => 'Nette\DI\Extensions\DecoratorExtension', - 'cache' => array('Nette\Bridges\CacheDI\CacheExtension', array('%tempDir%')), - 'database' => array('Nette\Bridges\DatabaseDI\DatabaseExtension', array('%debugMode%')), - 'di' => array('Nette\DI\Extensions\DIExtension', array('%debugMode%')), - 'forms' => 'Nette\Bridges\FormsDI\FormsExtension', - 'http' => 'Nette\Bridges\HttpDI\HttpExtension', - 'latte' => array('Nette\Bridges\ApplicationDI\LatteExtension', array('%tempDir%/cache/latte', '%debugMode%')), - 'mail' => 'Nette\Bridges\MailDI\MailExtension', - 'reflection' => array('Nette\Bridges\ReflectionDI\ReflectionExtension', array('%debugMode%')), - 'routing' => array('Nette\Bridges\ApplicationDI\RoutingExtension', array('%debugMode%')), - 'security' => array('Nette\Bridges\SecurityDI\SecurityExtension', array('%debugMode%')), - 'session' => array('Nette\Bridges\HttpDI\SessionExtension', array('%debugMode%')), - 'tracy' => array('Tracy\Bridges\Nette\TracyExtension', array('%debugMode%')), - 'inject' => 'Nette\DI\Extensions\InjectExtension', - ); + public $defaultExtensions = [ + 'php' => Nette\DI\Extensions\PhpExtension::class, + 'constants' => Nette\DI\Extensions\ConstantsExtension::class, + 'extensions' => Nette\DI\Extensions\ExtensionsExtension::class, + 'application' => [Nette\Bridges\ApplicationDI\ApplicationExtension::class, ['%debugMode%', ['%appDir%'], '%tempDir%/cache']], + 'decorator' => Nette\DI\Extensions\DecoratorExtension::class, + 'cache' => [Nette\Bridges\CacheDI\CacheExtension::class, ['%tempDir%']], + 'database' => [Nette\Bridges\DatabaseDI\DatabaseExtension::class, ['%debugMode%']], + 'di' => [Nette\DI\Extensions\DIExtension::class, ['%debugMode%']], + 'forms' => Nette\Bridges\FormsDI\FormsExtension::class, + 'http' => [Nette\Bridges\HttpDI\HttpExtension::class, ['%consoleMode%']], + 'latte' => [Nette\Bridges\ApplicationDI\LatteExtension::class, ['%tempDir%/cache/latte', '%debugMode%']], + 'mail' => Nette\Bridges\MailDI\MailExtension::class, + 'routing' => [Nette\Bridges\ApplicationDI\RoutingExtension::class, ['%debugMode%']], + 'security' => [Nette\Bridges\SecurityDI\SecurityExtension::class, ['%debugMode%']], + 'session' => [Nette\Bridges\HttpDI\SessionExtension::class, ['%debugMode%', '%consoleMode%']], + 'tracy' => [Tracy\Bridges\Nette\TracyExtension::class, ['%debugMode%', '%consoleMode%']], + 'inject' => Nette\DI\Extensions\InjectExtension::class, + ]; /** @var string[] of classes which shouldn't be autowired */ - public $autowireExcludedClasses = array( + public $autowireExcludedClasses = [ 'stdClass', - ); + ]; /** @var array */ protected $parameters; /** @var array */ - protected $services = array(); + protected $services = []; /** @var array [file|array, section] */ - protected $files = array(); + protected $files = []; public function __construct() @@ -82,7 +83,6 @@ } $this->parameters['debugMode'] = $value; $this->parameters['productionMode'] = !$this->parameters['debugMode']; // compatibility - $this->parameters['environment'] = $this->parameters['debugMode'] ? 'development' : 'production'; return $this; } @@ -108,6 +108,18 @@ /** + * Sets the default timezone. + * @return self + */ + public function setTimeZone($timezone) + { + date_default_timezone_set($timezone); + @ini_set('date.timezone', $timezone); // @ - function may be disabled + return $this; + } + + + /** * Adds new parameters. The %params% will be expanded. * @return self */ @@ -134,21 +146,16 @@ */ protected function getDefaultParameters() { - $trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $last = end($trace); $debugMode = static::detectDebugMode(); - return array( + return [ 'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : NULL, 'wwwDir' => isset($last['file']) ? dirname($last['file']) : NULL, 'debugMode' => $debugMode, 'productionMode' => !$debugMode, - 'environment' => $debugMode ? 'development' : 'production', 'consoleMode' => PHP_SAPI === 'cli', - 'container' => array( - 'class' => NULL, - 'parent' => NULL, - ), - ); + ]; } @@ -171,7 +178,7 @@ */ public function createRobotLoader() { - if (!class_exists('Nette\Loaders\RobotLoader')) { + if (!class_exists(Nette\Loaders\RobotLoader::class)) { throw new Nette\NotSupportedException('RobotLoader not found, do you have `nette/robot-loader` package installed?'); } @@ -186,18 +193,13 @@ * Adds configuration file. * @return self */ - public function addConfig($file, $section = NULL) + public function addConfig($file) { - if ($section === NULL && is_string($file) && $this->parameters['debugMode']) { // back compatibility - try { - $loader = new DI\Config\Loader; - $loader->load($file, $this->parameters['environment']); - trigger_error("Config file '$file' has sections, call addConfig() with second parameter Configurator::AUTO.", E_USER_WARNING); - $section = $this->parameters['environment']; - } catch (\Exception $e) { - } + $section = func_num_args() > 1 ? func_get_arg(1) : NULL; + if ($section !== NULL) { + trigger_error('Sections in config file are deprecated.', E_USER_DEPRECATED); } - $this->files[] = array($file, $section === self::AUTO ? $this->parameters['environment'] : $section); + $this->files[] = [$file, $section === self::AUTO ? ($this->parameters['debugMode'] ? 'development' : 'production') : $section]; return $this; } @@ -208,21 +210,13 @@ */ public function createContainer() { - $loader = new DI\ContainerLoader( - $this->getCacheDirectory() . '/Nette.Configurator', - $this->parameters['debugMode'] - ); - $class = $loader->load( - array($this->parameters, $this->files, PHP_VERSION_ID - PHP_RELEASE_VERSION), - array($this, 'generateContainer') - ); - - $container = new $class; + $class = $this->loadContainer(); + $container = new $class(); foreach ($this->services as $name => $service) { $container->addService($name, $service); } $container->initialize(); - if (class_exists('Nette\Environment')) { + if (class_exists(Nette\Environment::class)) { Nette\Environment::setContext($container); // back compatibility } return $container; @@ -230,14 +224,32 @@ /** + * Loads system DI container class and returns its name. + * @return string + */ + public function loadContainer() + { + $loader = new DI\ContainerLoader( + $this->getCacheDirectory() . '/Nette.Configurator', + $this->parameters['debugMode'] + ); + $class = $loader->load( + [$this, 'generateContainer'], + [$this->parameters, $this->files, PHP_VERSION_ID - PHP_RELEASE_VERSION] + ); + return $class; + } + + + /** * @return string * @internal */ public function generateContainer(DI\Compiler $compiler) { $loader = $this->createLoader(); - $compiler->addConfig(array('parameters' => $this->parameters)); - $fileInfo = array(); + $compiler->addConfig(['parameters' => $this->parameters]); + $fileInfo = []; foreach ($this->files as $info) { if (is_scalar($info[0])) { $fileInfo[] = "// source: $info[0] $info[1]"; @@ -251,24 +263,17 @@ $builder->addExcludedClasses($this->autowireExcludedClasses); foreach ($this->defaultExtensions as $name => $extension) { - list($class, $args) = is_string($extension) ? array($extension, array()) : $extension; + list($class, $args) = is_string($extension) ? [$extension, []] : $extension; if (class_exists($class)) { - $rc = new \ReflectionClass($class); $args = DI\Helpers::expand($args, $this->parameters, TRUE); - $compiler->addExtension($name, $args ? $rc->newInstanceArgs($args) : $rc->newInstance()); + $compiler->addExtension($name, (new \ReflectionClass($class))->newInstanceArgs($args)); } } $this->onCompile($this, $compiler); $classes = $compiler->compile(); - - if (!empty($builder->parameters['container']['parent'])) { - $classes[0]->setExtends($builder->parameters['container']['parent']); - } - - return implode("\n", $fileInfo) . "\n\n" . implode("\n\n\n", $classes) - . (($tmp = $builder->parameters['container']['class']) ? "\nclass $tmp extends {$builder->getClassName()} {}\n" : ''); + return implode("\n", $fileInfo) . "\n\n" . $classes; } @@ -304,12 +309,14 @@ $config['nette']['http']['frames'] = $config['nette']['security']['frames']; unset($config['nette']['security']['frames']); } - foreach (array('application', 'cache', 'database', 'di' => 'container', 'forms', 'http', - 'latte', 'mail' => 'mailer', 'routing', 'security', 'session', 'tracy' => 'debugger') as $new => $old) { + foreach (['application', 'cache', 'database', 'di' => 'container', 'forms', 'http', + 'latte', 'mail' => 'mailer', 'routing', 'security', 'session', 'tracy' => 'debugger'] as $new => $old) { if (isset($config['nette'][$old])) { $new = is_int($new) ? $old : $new; if (isset($config[$new])) { throw new Nette\DeprecatedException("You can use (deprecated) section 'nette.$old' or new section '$new', but not both of them."); + } else { + trigger_error("Configuration section 'nette.$old' is deprecated, use section '$new' (without 'nette')", E_USER_DEPRECATED); } $config[$new] = $config['nette'][$old]; unset($config['nette'][$old]); diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationDI/ApplicationExtension.php php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/ApplicationExtension.php --- php-nette-2.3.10/Nette/Bridges/ApplicationDI/ApplicationExtension.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/ApplicationExtension.php 2016-07-31 17:46:32.000000000 +0000 @@ -9,6 +9,8 @@ use Nette; use Nette\Application\UI; +use Tracy; +use Composer\Autoload\ClassLoader; /** @@ -16,16 +18,16 @@ */ class ApplicationExtension extends Nette\DI\CompilerExtension { - public $defaults = array( + public $defaults = [ 'debugger' => NULL, 'errorPresenter' => 'Nette:Error', 'catchExceptions' => NULL, 'mapping' => NULL, - 'scanDirs' => array(), + 'scanDirs' => [], 'scanComposer' => NULL, 'scanFilter' => 'Presenter', 'silentLinks' => FALSE, - ); + ]; /** @var bool */ private $debugMode; @@ -39,9 +41,9 @@ public function __construct($debugMode = FALSE, array $scanDirs = NULL, $tempDir = NULL) { - $this->defaults['debugger'] = interface_exists('Tracy\IBarPanel'); + $this->defaults['debugger'] = interface_exists(Tracy\IBarPanel::class); $this->defaults['scanDirs'] = (array) $scanDirs; - $this->defaults['scanComposer'] = class_exists('Composer\Autoload\ClassLoader'); + $this->defaults['scanComposer'] = class_exists(ClassLoader::class); $this->defaults['catchExceptions'] = !$debugMode; $this->debugMode = $debugMode; $this->tempFile = $tempDir ? $tempDir . '/' . urlencode(__CLASS__) : NULL; @@ -51,65 +53,65 @@ public function loadConfiguration() { $config = $this->validateConfig($this->defaults); - $container = $this->getContainerBuilder(); - $container->addExcludedClasses(array('Nette\Application\UI\Control')); + $builder = $this->getContainerBuilder(); + $builder->addExcludedClasses([UI\Presenter::class]); $this->invalidLinkMode = $this->debugMode ? UI\Presenter::INVALID_LINK_TEXTUAL | ($config['silentLinks'] ? 0 : UI\Presenter::INVALID_LINK_WARNING) : UI\Presenter::INVALID_LINK_WARNING; - $application = $container->addDefinition($this->prefix('application')) - ->setClass('Nette\Application\Application') - ->addSetup('$catchExceptions', array($config['catchExceptions'])) - ->addSetup('$errorPresenter', array($config['errorPresenter'])); + $application = $builder->addDefinition($this->prefix('application')) + ->setClass(Nette\Application\Application::class) + ->addSetup('$catchExceptions', [$config['catchExceptions']]) + ->addSetup('$errorPresenter', [$config['errorPresenter']]); if ($config['debugger']) { $application->addSetup('Nette\Bridges\ApplicationTracy\RoutingPanel::initializePanel'); } $touch = $this->debugMode && $config['scanDirs'] ? $this->tempFile : NULL; - $presenterFactory = $container->addDefinition($this->prefix('presenterFactory')) - ->setClass('Nette\Application\IPresenterFactory') - ->setFactory('Nette\Application\PresenterFactory', array(new Nette\DI\Statement( - 'Nette\Bridges\ApplicationDI\PresenterFactoryCallback', array(1 => $this->invalidLinkMode, $touch) - ))); + $presenterFactory = $builder->addDefinition($this->prefix('presenterFactory')) + ->setClass(Nette\Application\IPresenterFactory::class) + ->setFactory(Nette\Application\PresenterFactory::class, [new Nette\DI\Statement( + Nette\Bridges\ApplicationDI\PresenterFactoryCallback::class, [1 => $this->invalidLinkMode, $touch] + )]); if ($config['mapping']) { - $presenterFactory->addSetup('setMapping', array($config['mapping'])); + $presenterFactory->addSetup('setMapping', [$config['mapping']]); } - $container->addDefinition($this->prefix('linkGenerator')) - ->setFactory('Nette\Application\LinkGenerator', array( + $builder->addDefinition($this->prefix('linkGenerator')) + ->setFactory(Nette\Application\LinkGenerator::class, [ 1 => new Nette\DI\Statement('@Nette\Http\IRequest::getUrl'), - )); + ]); if ($this->name === 'application') { - $container->addAlias('application', $this->prefix('application')); - $container->addAlias('nette.presenterFactory', $this->prefix('presenterFactory')); + $builder->addAlias('application', $this->prefix('application')); + $builder->addAlias('nette.presenterFactory', $this->prefix('presenterFactory')); } } public function beforeCompile() { - $container = $this->getContainerBuilder(); - $all = array(); + $builder = $this->getContainerBuilder(); + $all = []; - foreach ($container->findByType('Nette\Application\IPresenter') as $def) { + foreach ($builder->findByType(Nette\Application\IPresenter::class) as $def) { $all[$def->getClass()] = $def; } $counter = 0; foreach ($this->findPresenters() as $class) { if (empty($all[$class])) { - $all[$class] = $container->addDefinition($this->prefix(++$counter))->setClass($class); + $all[$class] = $builder->addDefinition($this->prefix(++$counter))->setClass($class); } } foreach ($all as $def) { - $def->setInject(TRUE)->setAutowired(FALSE)->addTag('nette.presenter', $def->getClass()); - if (is_subclass_of($def->getClass(), 'Nette\Application\UI\Presenter')) { - $def->addSetup('$invalidLinkMode', array($this->invalidLinkMode)); + $def->setInject(TRUE)->addTag('nette.presenter', $def->getClass()); + if (is_subclass_of($def->getClass(), UI\Presenter::class)) { + $def->addSetup('$invalidLinkMode', [$this->invalidLinkMode]); } } } @@ -119,10 +121,10 @@ private function findPresenters() { $config = $this->getConfig(); - $classes = array(); + $classes = []; if ($config['scanDirs']) { - if (!class_exists('Nette\Loaders\RobotLoader')) { + if (!class_exists(Nette\Loaders\RobotLoader::class)) { throw new Nette\NotSupportedException("RobotLoader is required to find presenters, install package `nette/robot-loader` or disable option {$this->prefix('scanDirs')}: false"); } $robot = new Nette\Loaders\RobotLoader; @@ -135,7 +137,7 @@ } if ($config['scanComposer']) { - $rc = new \ReflectionClass('Composer\Autoload\ClassLoader'); + $rc = new \ReflectionClass(ClassLoader::class); $classFile = dirname($rc->getFileName()) . '/autoload_classmap.php'; if (is_file($classFile)) { $this->getContainerBuilder()->addDependency($classFile); @@ -145,10 +147,10 @@ } } - $presenters = array(); + $presenters = []; foreach (array_unique($classes) as $class) { if (strpos($class, $config['scanFilter']) !== FALSE && class_exists($class) - && ($rc = new \ReflectionClass($class)) && $rc->implementsInterface('Nette\Application\IPresenter') + && ($rc = new \ReflectionClass($class)) && $rc->implementsInterface(Nette\Application\IPresenter::class) && !$rc->isAbstract() ) { $presenters[] = $rc->getName(); diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationDI/LatteExtension.php php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/LatteExtension.php --- php-nette-2.3.10/Nette/Bridges/ApplicationDI/LatteExtension.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/LatteExtension.php 2016-07-31 17:46:32.000000000 +0000 @@ -16,10 +16,10 @@ */ class LatteExtension extends Nette\DI\CompilerExtension { - public $defaults = array( + public $defaults = [ 'xhtml' => FALSE, - 'macros' => array(), - ); + 'macros' => [], + ]; /** @var bool */ private $debugMode; @@ -37,33 +37,24 @@ public function loadConfiguration() { - if (!class_exists('Latte\Engine')) { + if (!class_exists(Latte\Engine::class)) { return; } $config = $this->validateConfig($this->defaults); - $container = $this->getContainerBuilder(); + $builder = $this->getContainerBuilder(); - $latteFactory = $container->addDefinition($this->prefix('latteFactory')) - ->setClass('Latte\Engine') - ->addSetup('setTempDirectory', array($this->tempDir)) - ->addSetup('setAutoRefresh', array($this->debugMode)) - ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML)) - ->addSetup('Nette\Utils\Html::$xhtml = ?', array((bool) $config['xhtml'])) - ->setImplement('Nette\Bridges\ApplicationLatte\ILatteFactory'); - - $container->addDefinition($this->prefix('templateFactory')) - ->setClass('Nette\Application\UI\ITemplateFactory') - ->setFactory('Nette\Bridges\ApplicationLatte\TemplateFactory'); - - $container->addDefinition('nette.latte') - ->setClass('Latte\Engine') - ->addSetup('::trigger_error', array('Service nette.latte is deprecated, implement Nette\Bridges\ApplicationLatte\ILatteFactory.', E_USER_DEPRECATED)) - ->addSetup('setTempDirectory', array($this->tempDir)) - ->addSetup('setAutoRefresh', array($this->debugMode)) - ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML)) - ->addSetup('Nette\Utils\Html::$xhtml = ?', array((bool) $config['xhtml'])) - ->setAutowired(FALSE); + $builder->addDefinition($this->prefix('latteFactory')) + ->setClass(Latte\Engine::class) + ->addSetup('setTempDirectory', [$this->tempDir]) + ->addSetup('setAutoRefresh', [$this->debugMode]) + ->addSetup('setContentType', [$config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML]) + ->addSetup('Nette\Utils\Html::$xhtml = ?', [(bool) $config['xhtml']]) + ->setImplement(Nette\Bridges\ApplicationLatte\ILatteFactory::class); + + $builder->addDefinition($this->prefix('templateFactory')) + ->setClass(Nette\Application\UI\ITemplateFactory::class) + ->setFactory(Nette\Bridges\ApplicationLatte\TemplateFactory::class); foreach ($config['macros'] as $macro) { if (strpos($macro, '::') === FALSE && class_exists($macro)) { @@ -72,18 +63,9 @@ $this->addMacro($macro); } - if (class_exists('Nette\Templating\FileTemplate')) { - $container->addDefinition('nette.template') - ->setFactory('Nette\Templating\FileTemplate') - ->addSetup('::trigger_error', array('Service nette.template is deprecated.', E_USER_DEPRECATED)) - ->addSetup('registerFilter', array(new Nette\DI\Statement(array($latteFactory, 'create')))) - ->addSetup('registerHelperLoader', array('Nette\Templating\Helpers::loader')) - ->setAutowired(FALSE); - } - if ($this->name === 'latte') { - $container->addAlias('nette.latteFactory', $this->prefix('latteFactory')); - $container->addAlias('nette.templateFactory', $this->prefix('templateFactory')); + $builder->addAlias('nette.latteFactory', $this->prefix('latteFactory')); + $builder->addAlias('nette.templateFactory', $this->prefix('templateFactory')); } } @@ -92,16 +74,11 @@ * @param callable * @return void */ - public function addMacro($macro) + public function addMacro(callable $macro) { - Nette\Utils\Validators::assert($macro, 'callable'); - - $container = $this->getContainerBuilder(); - $container->getDefinition('nette.latte') - ->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self')); - - $container->getDefinition($this->prefix('latteFactory')) - ->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self')); + $builder = $this->getContainerBuilder(); + $builder->getDefinition($this->prefix('latteFactory')) + ->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', ['@self']); } } diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationDI/RoutingExtension.php php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/RoutingExtension.php --- php-nette-2.3.10/Nette/Bridges/ApplicationDI/RoutingExtension.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationDI/RoutingExtension.php 2016-07-31 17:46:32.000000000 +0000 @@ -8,6 +8,7 @@ namespace Nette\Bridges\ApplicationDI; use Nette; +use Tracy; /** @@ -15,11 +16,11 @@ */ class RoutingExtension extends Nette\DI\CompilerExtension { - public $defaults = array( + public $defaults = [ 'debugger' => NULL, - 'routes' => array(), // of [mask => action] + 'routes' => [], // of [mask => action] 'cache' => FALSE, - ); + ]; /** @var bool */ private $debugMode; @@ -27,7 +28,7 @@ public function __construct($debugMode = FALSE) { - $this->defaults['debugger'] = interface_exists('Tracy\IBarPanel'); + $this->defaults['debugger'] = interface_exists(Tracy\IBarPanel::class); $this->debugMode = $debugMode; } @@ -35,30 +36,30 @@ public function loadConfiguration() { $config = $this->validateConfig($this->defaults); - $container = $this->getContainerBuilder(); + $builder = $this->getContainerBuilder(); - $router = $container->addDefinition($this->prefix('router')) - ->setClass('Nette\Application\IRouter') - ->setFactory('Nette\Application\Routers\RouteList'); + $router = $builder->addDefinition($this->prefix('router')) + ->setClass(Nette\Application\IRouter::class) + ->setFactory(Nette\Application\Routers\RouteList::class); foreach ($config['routes'] as $mask => $action) { - $router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?);', array($mask, $action)); + $router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?);', [$mask, $action]); } if ($this->name === 'routing') { - $container->addAlias('router', $this->prefix('router')); + $builder->addAlias('router', $this->prefix('router')); } } public function beforeCompile() { - $container = $this->getContainerBuilder(); + $builder = $this->getContainerBuilder(); - if ($this->debugMode && $this->config['debugger'] && $application = $container->getByType('Nette\Application\Application')) { - $container->getDefinition($application)->addSetup('@Tracy\Bar::addPanel', array( - new Nette\DI\Statement('Nette\Bridges\ApplicationTracy\RoutingPanel'), - )); + if ($this->debugMode && $this->config['debugger'] && $application = $builder->getByType(Nette\Application\Application::class)) { + $builder->getDefinition($application)->addSetup('@Tracy\Bar::addPanel', [ + new Nette\DI\Statement(Nette\Bridges\ApplicationTracy\RoutingPanel::class), + ]); } } @@ -78,7 +79,7 @@ } catch (\Exception $e) { throw new Nette\DI\ServiceCreationException('Unable to cache router due to error: ' . $e->getMessage(), 0, $e); } - $method->setBody('return unserialize(?);', array($s)); + $method->setBody('return unserialize(?);', [$s]); } } diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationLatte/SnippetBridge.php php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/SnippetBridge.php --- php-nette-2.3.10/Nette/Bridges/ApplicationLatte/SnippetBridge.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/SnippetBridge.php 2016-07-31 17:46:32.000000000 +0000 @@ -0,0 +1,95 @@ +control = $control; + } + + + public function isSnippetMode() + { + return $this->control->snippetMode; + } + + + public function setSnippetMode($snippetMode) + { + $this->control->snippetMode = $snippetMode; + } + + + public function needsRedraw($name) + { + return $this->control->isControlInvalid($name); + } + + + public function markRedrawn($name) + { + if ($name !== '') { + $this->control->redrawControl($name, FALSE); + } + } + + + public function getHtmlId($name) + { + return $this->control->getSnippetId($name); + } + + + public function addSnippet($name, $content) + { + if ($this->payload === NULL) { + $this->payload = $this->control->getPresenter()->getPayload(); + } + $this->payload->snippets[$this->control->getSnippetId($name)] = $content; + } + + + public function renderChildren() + { + $queue = [$this->control]; + do { + foreach (array_shift($queue)->getComponents() as $child) { + if ($child instanceof IRenderable) { + if ($child->isControlInvalid()) { + $child->snippetMode = TRUE; + $child->render(); + $child->snippetMode = FALSE; + } + } elseif ($child instanceof Nette\ComponentModel\IContainer) { + $queue[] = $child; + } + } + } while ($queue); + } + +} diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationLatte/TemplateFactory.php php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/TemplateFactory.php --- php-nette-2.3.10/Nette/Bridges/ApplicationLatte/TemplateFactory.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/TemplateFactory.php 2016-07-31 17:46:32.000000000 +0000 @@ -9,22 +9,22 @@ use Nette; use Nette\Application\UI; +use Latte; /** * Latte powered template factory. */ -class TemplateFactory extends Nette\Object implements UI\ITemplateFactory +class TemplateFactory implements UI\ITemplateFactory { + use Nette\SmartObject; + /** @var ILatteFactory */ private $latteFactory; /** @var Nette\Http\IRequest */ private $httpRequest; - /** @var Nette\Http\IResponse */ - private $httpResponse; - /** @var Nette\Security\User */ private $user; @@ -33,11 +33,10 @@ public function __construct(ILatteFactory $latteFactory, Nette\Http\IRequest $httpRequest = NULL, - Nette\Http\IResponse $httpResponse = NULL, Nette\Security\User $user = NULL, Nette\Caching\IStorage $cacheStorage = NULL) + Nette\Security\User $user = NULL, Nette\Caching\IStorage $cacheStorage = NULL) { $this->latteFactory = $latteFactory; $this->httpRequest = $httpRequest; - $this->httpResponse = $httpResponse; $this->user = $user; $this->cacheStorage = $cacheStorage; } @@ -61,10 +60,9 @@ } array_unshift($latte->onCompile, function ($latte) use ($control, $template) { - $latte->getParser()->shortNoEscape = TRUE; $latte->getCompiler()->addMacro('cache', new Nette\Bridges\CacheLatte\CacheMacro($latte->getCompiler())); UIMacros::install($latte->getCompiler()); - if (class_exists('Nette\Bridges\FormsLatte\FormMacros')) { + if (class_exists(Nette\Bridges\FormsLatte\FormMacros::class)) { Nette\Bridges\FormsLatte\FormMacros::install($latte->getCompiler()); } if ($control) { @@ -73,32 +71,38 @@ }); $latte->addFilter('url', 'rawurlencode'); // back compatiblity - foreach (array('normalize', 'toAscii', 'webalize', 'padLeft', 'padRight', 'reverse') as $name) { + foreach (['normalize', 'toAscii', 'webalize', 'padLeft', 'padRight', 'reverse'] as $name) { $latte->addFilter($name, 'Nette\Utils\Strings::' . $name); } $latte->addFilter('null', function () {}); - $latte->addFilter('length', function ($var) { - return is_string($var) ? Nette\Utils\Strings::length($var) : count($var); - }); $latte->addFilter('modifyDate', function ($time, $delta, $unit = NULL) { return $time == NULL ? NULL : Nette\Utils\DateTime::from($time)->modify($delta . $unit); // intentionally == }); - if (!array_key_exists('translate', $latte->getFilters())) { - $latte->addFilter('translate', function () { + if (!isset($latte->getFilters()['translate'])) { + $latte->addFilter('translate', function (Latte\Runtime\FilterInfo $fi) { throw new Nette\InvalidStateException('Translator has not been set. Set translator using $template->setTranslator().'); }); } // default parameters - $template->control = $template->_control = $control; - $template->presenter = $template->_presenter = $presenter; $template->user = $this->user; - $template->netteHttpResponse = $this->httpResponse; - $template->netteCacheStorage = $this->cacheStorage; $template->baseUri = $template->baseUrl = $this->httpRequest ? rtrim($this->httpRequest->getUrl()->getBaseUrl(), '/') : NULL; $template->basePath = preg_replace('#https?://[^/]+#A', '', $template->baseUrl); - $template->flashes = array(); + $template->flashes = []; + if ($control) { + $template->control = $control; + $template->presenter = $presenter; + $latte->addProvider('uiControl', $control); + $latte->addProvider('uiPresenter', $presenter); + $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($control)); + } + $latte->addProvider('cacheStorage', $this->cacheStorage); + + // back compatibility + $template->_control = $control; + $template->_presenter = $presenter; + $template->netteCacheStorage = $this->cacheStorage; if ($presenter instanceof UI\Presenter && $presenter->hasFlashSession()) { $id = $control->getParameterId('flash'); diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationLatte/Template.php php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/Template.php --- php-nette-2.3.10/Nette/Bridges/ApplicationLatte/Template.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/Template.php 2016-07-31 17:46:32.000000000 +0000 @@ -14,8 +14,10 @@ /** * Latte powered template. */ -class Template extends Nette\Object implements Nette\Application\UI\ITemplate +class Template implements Nette\Application\UI\ITemplate { + use Nette\SmartObject; + /** @var Latte\Engine */ private $latte; @@ -23,7 +25,7 @@ private $file; /** @var array */ - private $params = array(); + private $params = []; public function __construct(Latte\Engine $latte) @@ -45,7 +47,7 @@ * Renders template to output. * @return void */ - public function render($file = NULL, array $params = array()) + public function render($file = NULL, array $params = []) { $this->latte->render($file ?: $this->file, $params + $this->params); } @@ -93,48 +95,24 @@ */ public function registerHelper($name, $callback) { - //trigger_error(__METHOD__ . '() is deprecated, use getLatte()->addFilter().', E_USER_DEPRECATED); + trigger_error(__METHOD__ . '() is deprecated, use getLatte()->addFilter().', E_USER_DEPRECATED); return $this->latte->addFilter($name, $callback); } /** - * Alias for addFilterLoader() - * @deprecated - */ - public function registerHelperLoader($loader) - { - trigger_error(__METHOD__ . '() is deprecated, use dynamic getLatte()->addFilter().', E_USER_DEPRECATED); - $latte = $this->latte; - $this->latte->addFilter(NULL, function ($name) use ($loader, $latte) { - if ($callback = call_user_func($loader, $name)) { - $latte->addFilter($name, $callback); - } - }); - return $this; - } - - - /** * Sets translate adapter. * @return self */ public function setTranslator(Nette\Localization\ITranslator $translator = NULL) { - $this->latte->addFilter('translate', $translator === NULL ? NULL : array($translator, 'translate')); + $this->latte->addFilter('translate', $translator === NULL ? NULL : function (Latte\Runtime\FilterInfo $fi, ...$args) use ($translator) { + return $translator->translate(...$args); + }); return $this; } - /** - * @deprecated - */ - public function registerFilter($callback) - { - throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated.'); - } - - /********************* template parameters ****************d*g**/ diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationLatte/UIMacros.php php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/UIMacros.php --- php-nette-2.3.10/Nette/Bridges/ApplicationLatte/UIMacros.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/UIMacros.php 2016-07-31 17:46:32.000000000 +0000 @@ -24,18 +24,33 @@ */ class UIMacros extends Latte\Macros\MacroSet { + /** @var bool */ + private $extends; + public static function install(Latte\Compiler $compiler) { $me = new static($compiler); - $me->addMacro('control', array($me, 'macroControl')); + $me->addMacro('control', [$me, 'macroControl']); $me->addMacro('href', NULL, NULL, function (MacroNode $node, PhpWriter $writer) use ($me) { return ' ?> href="macroLink($node, $writer) . ' ?>"addMacro('plink', array($me, 'macroLink')); - $me->addMacro('link', array($me, 'macroLink')); - $me->addMacro('ifCurrent', array($me, 'macroIfCurrent'), '}'); // deprecated; use n:class="$presenter->linkCurrent ? ..." + $me->addMacro('plink', [$me, 'macroLink']); + $me->addMacro('link', [$me, 'macroLink']); + $me->addMacro('ifCurrent', [$me, 'macroIfCurrent'], '}'); // deprecated; use n:class="$presenter->linkCurrent ? ..." + $me->addMacro('extends', [$me, 'macroExtends']); + $me->addMacro('layout', [$me, 'macroExtends']); + } + + + /** + * Initializes before template parsing. + * @return void + */ + public function initialize() + { + $this->extends = FALSE; } @@ -45,12 +60,7 @@ */ public function finalize() { - $prolog = ' -// snippets support -if (empty($_l->extends) && !empty($_control->snippetMode)) { - return Nette\Bridges\ApplicationLatte\UIRuntime::renderSnippets($_control, $_b, get_defined_vars()); -}'; - return array($prolog, ''); + return [$this->extends . 'Nette\Bridges\ApplicationLatte\UIRuntime::initialize($this, $this->parentName, $this->blocks);']; } @@ -69,14 +79,28 @@ $name = $writer->formatWord($words[0]); $method = isset($words[1]) ? ucfirst($words[1]) : ''; $method = Strings::match($method, '#^\w*\z#') ? "render$method" : "{\"render$method\"}"; + + $tokens = $node->tokenizer; + $pos = $tokens->position; $param = $writer->formatArray(); - if (!Strings::contains($node->args, '=>')) { - $param = substr($param, $param[0] === '[' ? 1 : 6, -1); // removes array() or [] + $tokens->position = $pos; + while ($tokens->nextToken()) { + if ($tokens->isCurrent('=>') && !$tokens->depth) { + $wrap = TRUE; + break; + } } - return ($name[0] === '$' ? "if (is_object($name)) \$_l->tmp = $name; else " : '') - . '$_l->tmp = $_control->getComponent(' . $name . '); ' - . 'if ($_l->tmp instanceof Nette\Application\UI\IRenderable) $_l->tmp->redrawControl(NULL, FALSE); ' - . ($node->modifiers === '' ? "\$_l->tmp->$method($param)" : $writer->write("ob_start(function () {}); \$_l->tmp->$method($param); echo %modify(ob_get_clean())")); + if (empty($wrap)) { + $param = substr($param, 1, -1); // removes array() or [] + } + return "/* line $node->startLine */ " + . ($name[0] === '$' ? "if (is_object($name)) \$_tmp = $name; else " : '') + . '$_tmp = $this->global->uiControl->getComponent(' . $name . '); ' + . 'if ($_tmp instanceof Nette\Application\UI\IRenderable) $_tmp->redrawControl(NULL, FALSE); ' + . ($node->modifiers === '' + ? "\$_tmp->$method($param);" + : $writer->write("ob_start(function () {}); \$_tmp->$method($param); echo %modify(ob_get_clean());") + ); } @@ -89,7 +113,10 @@ { $node->modifiers = preg_replace('#\|safeurl\s*(?=\||\z)#i', '', $node->modifiers); return $writer->using($node, $this->getCompiler()) - ->write('echo %escape(%modify(' . ($node->name === 'plink' ? '$_presenter' : '$_control') . '->link(%node.word, %node.array?)))'); + ->write('echo %escape(%modify(' + . ($node->name === 'plink' ? '$this->global->uiPresenter' : '$this->global->uiControl') + . '->link(%node.word, %node.array?)))' + ); } @@ -99,18 +126,31 @@ public function macroIfCurrent(MacroNode $node, PhpWriter $writer) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); } return $writer->write($node->args - ? 'if ($_presenter->isLinkCurrent(%node.word, %node.array?)) {' - : 'if ($_presenter->getLastCreatedRequestFlag("current")) {' + ? 'if ($this->global->uiPresenter->isLinkCurrent(%node.word, %node.array?)) {' + : 'if ($this->global->uiPresenter->getLastCreatedRequestFlag("current")) {' ); } + /** + * {extends auto} + */ + public function macroExtends(MacroNode $node, PhpWriter $writer) + { + if ($node->modifiers || $node->parentNode || $node->args !== 'auto') { + return $this->extends = FALSE; + } + $this->extends = $writer->write('$this->parentName = $this->global->uiPresenter->findLayoutTemplateFile();'); + } + + /** @deprecated */ public static function renderSnippets(Nette\Application\UI\Control $control, \stdClass $local, array $params) { + trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED); UIRuntime::renderSnippets($control, $local, $params); } diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationLatte/UIRuntime.php php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/UIRuntime.php --- php-nette-2.3.10/Nette/Bridges/ApplicationLatte/UIRuntime.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationLatte/UIRuntime.php 2016-07-31 17:46:32.000000000 +0000 @@ -8,53 +8,39 @@ namespace Nette\Bridges\ApplicationLatte; use Nette; -use Nette\Application\UI; +use Latte; /** * Runtime helpers for UI macros. * @internal */ -class UIRuntime extends Nette\Object +class UIRuntime { + use Nette\StaticClass; - public static function renderSnippets(UI\Control $control, \stdClass $local, array $params) + /** + * @return void + */ + public static function initialize(Latte\Runtime\Template $template, & $parentName, array $blocks) { - $control->snippetMode = FALSE; - $payload = $control->getPresenter()->getPayload(); - if (isset($local->blocks)) { - foreach ($local->blocks as $name => $function) { - if ($name[0] !== '_' || !$control->isControlInvalid((string) substr($name, 1))) { - continue; - } - ob_start(function () {}); - $function = reset($function); - $snippets = $function($local, $params + array('_snippetMode' => TRUE)); - $payload->snippets[$id = $control->getSnippetId((string) substr($name, 1))] = ob_get_clean(); - if ($snippets !== NULL) { // pass FALSE from snippetArea - if ($snippets) { - $payload->snippets += $snippets; - } - unset($payload->snippets[$id]); - } - } + $providers = $template->global; + $blocks = array_filter(array_keys($blocks), function ($s) { return $s[0] !== '_'; }); + if ($parentName === NULL && $blocks && !$template->getReferringTemplate() + && isset($providers->uiControl) && $providers->uiControl instanceof Nette\Application\UI\Presenter + ) { + $parentName = $providers->uiControl->findLayoutTemplateFile(); } - $control->snippetMode = TRUE; - if ($control instanceof UI\IRenderable) { - $queue = array($control); - do { - foreach (array_shift($queue)->getComponents() as $child) { - if ($child instanceof UI\IRenderable) { - if ($child->isControlInvalid()) { - $child->snippetMode = TRUE; - $child->render(); - $child->snippetMode = FALSE; - } - } elseif ($child instanceof Nette\ComponentModel\IContainer) { - $queue[] = $child; - } - } - } while ($queue); + + // back compatiblity + $params = $template->getParameters(); + if (empty($providers->uiControl) && isset($params['_control'])) { + trigger_error('Replace template variable $_control with provider: $latte->addProvider("uiControl", ...)', E_USER_DEPRECATED); + $providers->uiControl = $params['_control']; + } + if (empty($providers->uiPresenter) && isset($params['_presenter'])) { + trigger_error('Replace template variable $_presenter with provider: $latte->addProvider("uiPresenter", ...)', E_USER_DEPRECATED); + $providers->uiPresenter = $params['_presenter']; } } diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationTracy/RoutingPanel.php php-nette-2.4-20160731/Nette/Bridges/ApplicationTracy/RoutingPanel.php --- php-nette-2.3.10/Nette/Bridges/ApplicationTracy/RoutingPanel.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationTracy/RoutingPanel.php 2016-07-31 17:46:32.000000000 +0000 @@ -17,8 +17,10 @@ /** * Routing debugger for Debug Bar. */ -class RoutingPanel extends Nette\Object implements Tracy\IBarPanel +class RoutingPanel implements Tracy\IBarPanel { + use Nette\SmartObject; + /** @var Nette\Application\IRouter */ private $router; @@ -29,7 +31,7 @@ private $presenterFactory; /** @var array */ - private $routers = array(); + private $routers = []; /** @var Nette\Application\Request */ private $request; @@ -41,11 +43,11 @@ public static function initializePanel(Nette\Application\Application $application) { Tracy\Debugger::getBlueScreen()->addPanel(function ($e) use ($application) { - return $e ? NULL : array( + return $e ? NULL : [ 'tab' => 'Nette Application', - 'panel' => '

Requests

' . Dumper::toHtml($application->getRequests(), array(Dumper::LIVE => TRUE)) - . '

Presenter

' . Dumper::toHtml($application->getPresenter(), array(Dumper::LIVE => TRUE)), - ); + 'panel' => '

Requests

' . Dumper::toHtml($application->getRequests(), [Dumper::LIVE => TRUE]) + . '

Presenter

' . Dumper::toHtml($application->getPresenter(), [Dumper::LIVE => TRUE]), + ]; }); } @@ -116,14 +118,14 @@ } } - $this->routers[] = array( + $this->routers[] = [ 'matched' => $matched, 'class' => get_class($router), - 'defaults' => $router instanceof Routers\Route || $router instanceof Routers\SimpleRouter ? $router->getDefaults() : array(), + 'defaults' => $router instanceof Routers\Route || $router instanceof Routers\SimpleRouter ? $router->getDefaults() : [], 'mask' => $router instanceof Routers\Route ? $router->getMask() : NULL, 'request' => $request, 'module' => rtrim($module, ':'), - ); + ]; } @@ -138,7 +140,7 @@ } $rc = new \ReflectionClass($class); - if ($rc->isSubclassOf('Nette\Application\UI\Presenter')) { + if ($rc->isSubclassOf(Nette\Application\UI\Presenter::class)) { if ($request->getParameter(Presenter::SIGNAL_KEY)) { $method = $class::formatSignalMethod($request->getParameter(Presenter::SIGNAL_KEY)); diff -Nru php-nette-2.3.10/Nette/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml php-nette-2.4-20160731/Nette/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml --- php-nette-2.3.10/Nette/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml 2016-04-13 18:50:56.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml 2016-07-31 17:46:58.000000000 +0000 @@ -15,7 +15,7 @@ no route - getPresenterName() . ':' . (isset($request->parameters[Presenter::ACTION_KEY]) ? $request->parameters[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION) . (isset($request->parameters[Presenter::SIGNAL_KEY]) ? " {$request->parameters[Presenter::SIGNAL_KEY]}!" : ''), ENT_NOQUOTES, 'UTF-8') ?> + getPresenterName() . ':' . (isset($request->parameters[Presenter::ACTION_KEY]) ? $request->parameters[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION) . (isset($request->parameters[Presenter::SIGNAL_KEY]) ? " {$request->parameters[Presenter::SIGNAL_KEY]}!" : ''), ENT_NOQUOTES, 'UTF-8') ?> @@ -37,25 +37,25 @@ - - + + - + $value): ?> - ' : Dumper::toHtml($value, array(Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE)) ?> + ' : Dumper::toHtml($value, [Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE]) ?> - + getParameters(); ?> - getPresenterName() . ':' . (isset($params[Presenter::ACTION_KEY]) ? $params[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION), ENT_NOQUOTES, 'UTF-8') ?>
+ getPresenterName() . ':' . (isset($params[Presenter::ACTION_KEY]) ? $params[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION), ENT_NOQUOTES, 'UTF-8') ?>
$value): ?> - ' : Dumper::toHtml($value, array(Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE)) ?> + ' : Dumper::toHtml($value, [Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE]) ?>
@@ -64,11 +64,11 @@ -

- getBaseUrl(), ENT_IGNORE, 'UTF-8') ?>getRelativeUrl(), ENT_IGNORE, 'UTF-8') ?>

+

+ getBaseUrl(), ENT_IGNORE, 'UTF-8') ?>getRelativeUrl(), ENT_IGNORE, 'UTF-8') ?>

-

getName() : $source->getDeclaringClass()->getName() . '::' . $source->getName() . '()' ?>

+

getName() : $source->getDeclaringClass()->getName() . '::' . $source->getName() . '()' ?>

diff -Nru php-nette-2.3.10/Nette/Bridges/CacheDI/CacheExtension.php php-nette-2.4-20160731/Nette/Bridges/CacheDI/CacheExtension.php --- php-nette-2.3.10/Nette/Bridges/CacheDI/CacheExtension.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/CacheDI/CacheExtension.php 2016-07-31 17:46:32.000000000 +0000 @@ -27,19 +27,19 @@ public function loadConfiguration() { - $container = $this->getContainerBuilder(); + $builder = $this->getContainerBuilder(); - $container->addDefinition($this->prefix('journal')) - ->setClass('Nette\Caching\Storages\IJournal') - ->setFactory('Nette\Caching\Storages\FileJournal', array($this->tempDir)); + $builder->addDefinition($this->prefix('journal')) + ->setClass(Nette\Caching\Storages\IJournal::class) + ->setFactory(Nette\Caching\Storages\SQLiteJournal::class, [$this->tempDir . '/cache/journal.s3db']); - $container->addDefinition($this->prefix('storage')) - ->setClass('Nette\Caching\IStorage') - ->setFactory('Nette\Caching\Storages\FileStorage', array($this->tempDir . '/cache')); + $builder->addDefinition($this->prefix('storage')) + ->setClass(Nette\Caching\IStorage::class) + ->setFactory(Nette\Caching\Storages\FileStorage::class, [$this->tempDir . '/cache']); if ($this->name === 'cache') { - $container->addAlias('nette.cacheJournal', $this->prefix('journal')); - $container->addAlias('cacheStorage', $this->prefix('storage')); + $builder->addAlias('nette.cacheJournal', $this->prefix('journal')); + $builder->addAlias('cacheStorage', $this->prefix('storage')); } } diff -Nru php-nette-2.3.10/Nette/Bridges/CacheLatte/CacheMacro.php php-nette-2.4-20160731/Nette/Bridges/CacheLatte/CacheMacro.php --- php-nette-2.3.10/Nette/Bridges/CacheLatte/CacheMacro.php 2016-04-13 18:50:40.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/CacheLatte/CacheMacro.php 2016-07-31 17:46:32.000000000 +0000 @@ -8,14 +8,17 @@ namespace Nette\Bridges\CacheLatte; use Nette; +use Nette\Caching\Cache; use Latte; /** * Macro {cache} ... {/cache} */ -class CacheMacro extends Nette\Object implements Latte\IMacro +class CacheMacro implements Latte\IMacro { + use Nette\SmartObject; + /** @var bool */ private $used; @@ -37,7 +40,7 @@ public function finalize() { if ($this->used) { - return array('Nette\Bridges\CacheLatte\CacheMacro::initRuntime($template, $_g);'); + return ['Nette\Bridges\CacheLatte\CacheMacro::initRuntime($this);']; } } @@ -49,12 +52,12 @@ public function nodeOpened(Latte\MacroNode $node) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new Latte\CompileException('Modifiers are not allowed in ' . $node->getNotation()); } $this->used = TRUE; - $node->isEmpty = FALSE; + $node->empty = FALSE; $node->openingCode = Latte\PhpWriter::using($node) - ->write('caches, %node.array?)) { ?>', + ->write('global->cacheStorage, %var, $this->global->cacheStack, %node.array?)) { ?>', Nette\Utils\Random::generate() ); } @@ -66,7 +69,7 @@ */ public function nodeClosed(Latte\MacroNode $node) { - $node->closingCode = 'tmp = array_pop($_g->caches); if (!$_l->tmp instanceof stdClass) $_l->tmp->end(); } ?>'; + $node->closingCode = 'global->cacheStack); if (!$_tmp instanceof stdClass) $_tmp->end(); } ?>'; } @@ -76,10 +79,13 @@ /** * @return void */ - public static function initRuntime(Latte\Template $template, \stdClass $global) + public static function initRuntime(Latte\Runtime\Template $template) { - if (!empty($global->caches) && $template->getEngine()->getLoader() instanceof Latte\Loaders\FileLoader) { - end($global->caches)->dependencies[Nette\Caching\Cache::FILES][] = $template->getName(); + if (!empty($template->global->cacheStack)) { + $file = (new \ReflectionClass($template))->getFileName(); + if (@is_file($file)) { // @ - may trigger error + end($template->global->cacheStack)->dependencies[Cache::FILES][] = $file; + } } } @@ -98,13 +104,13 @@ if (array_key_exists('if', $args) && !$args['if']) { return $parents[] = new \stdClass; } - $key = array_merge(array($key), array_intersect_key($args, range(0, count($args)))); + $key = array_merge([$key], array_intersect_key($args, range(0, count($args)))); } if ($parents) { - end($parents)->dependencies[Nette\Caching\Cache::ITEMS][] = $key; + end($parents)->dependencies[Cache::ITEMS][] = $key; } - $cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Templating.Cache'); + $cache = new Cache($cacheStorage, 'Nette.Templating.Cache'); if ($helper = $cache->start($key)) { if (isset($args['dependencies'])) { $args += call_user_func($args['dependencies']); @@ -112,10 +118,10 @@ if (isset($args['expire'])) { $args['expiration'] = $args['expire']; // back compatibility } - $helper->dependencies = array( - Nette\Caching\Cache::TAGS => isset($args['tags']) ? $args['tags'] : NULL, - Nette\Caching\Cache::EXPIRATION => isset($args['expiration']) ? $args['expiration'] : '+ 7 days', - ); + $helper->dependencies = [ + $cache::TAGS => isset($args['tags']) ? $args['tags'] : NULL, + $cache::EXPIRATION => isset($args['expiration']) ? $args['expiration'] : '+ 7 days', + ]; $parents[] = $helper; } return $helper; diff -Nru php-nette-2.3.10/Nette/Bridges/DatabaseDI/DatabaseExtension.php php-nette-2.4-20160731/Nette/Bridges/DatabaseDI/DatabaseExtension.php --- php-nette-2.3.10/Nette/Bridges/DatabaseDI/DatabaseExtension.php 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DatabaseDI/DatabaseExtension.php 2016-07-31 17:46:34.000000000 +0000 @@ -15,7 +15,7 @@ */ class DatabaseExtension extends Nette\DI\CompilerExtension { - public $databaseDefaults = array( + public $databaseDefaults = [ 'dsn' => NULL, 'user' => NULL, 'password' => NULL, @@ -25,7 +25,7 @@ 'reflection' => NULL, // BC 'conventions' => 'discovered', // Nette\Database\Conventions\DiscoveredConventions 'autowired' => NULL, - ); + ]; /** @var bool */ private $debugMode; @@ -40,8 +40,11 @@ public function loadConfiguration() { $configs = $this->getConfig(); - if (isset($configs['dsn'])) { - $configs = array('default' => $configs); + foreach ($configs as $k => $v) { + if (is_scalar($v)) { + $configs = ['default' => $configs]; + break; + } } $defaults = $this->databaseDefaults; @@ -59,7 +62,7 @@ private function setupDatabase($config, $name) { - $container = $this->getContainerBuilder(); + $builder = $this->getContainerBuilder(); foreach ((array) $config['options'] as $key => $value) { if (preg_match('#^PDO::\w+\z#', $key)) { @@ -68,19 +71,19 @@ } } - $connection = $container->addDefinition($this->prefix("$name.connection")) - ->setClass('Nette\Database\Connection', array($config['dsn'], $config['user'], $config['password'], $config['options'])) + $connection = $builder->addDefinition($this->prefix("$name.connection")) + ->setClass(Nette\Database\Connection::class, [$config['dsn'], $config['user'], $config['password'], $config['options']]) ->setAutowired($config['autowired']); - $structure = $container->addDefinition($this->prefix("$name.structure")) - ->setClass('Nette\Database\Structure') - ->setArguments(array($connection)) + $structure = $builder->addDefinition($this->prefix("$name.structure")) + ->setClass(Nette\Database\Structure::class) + ->setArguments([$connection]) ->setAutowired($config['autowired']); if (!empty($config['reflection'])) { $conventionsServiceName = 'reflection'; $config['conventions'] = $config['reflection']; - if (strtolower($config['conventions']) === 'conventional') { + if (is_string($config['conventions']) && strtolower($config['conventions']) === 'conventional') { $config['conventions'] = 'Static'; } } else { @@ -91,35 +94,35 @@ $conventions = NULL; } elseif (is_string($config['conventions'])) { - $conventions = $container->addDefinition($this->prefix("$name.$conventionsServiceName")) + $conventions = $builder->addDefinition($this->prefix("$name.$conventionsServiceName")) ->setClass(preg_match('#^[a-z]+\z#i', $config['conventions']) ? 'Nette\Database\Conventions\\' . ucfirst($config['conventions']) . 'Conventions' : $config['conventions']) - ->setArguments(strtolower($config['conventions']) === 'discovered' ? array($structure) : array()) + ->setArguments(strtolower($config['conventions']) === 'discovered' ? [$structure] : []) ->setAutowired($config['autowired']); } else { - $tmp = Nette\DI\Compiler::filterArguments(array($config['conventions'])); + $tmp = Nette\DI\Compiler::filterArguments([$config['conventions']]); $conventions = reset($tmp); } - $container->addDefinition($this->prefix("$name.context")) - ->setClass('Nette\Database\Context', array($connection, $structure, $conventions)) + $builder->addDefinition($this->prefix("$name.context")) + ->setClass(Nette\Database\Context::class, [$connection, $structure, $conventions]) ->setAutowired($config['autowired']); if ($config['debugger']) { - $connection->addSetup('@Tracy\BlueScreen::addPanel', array( + $connection->addSetup('@Tracy\BlueScreen::addPanel', [ 'Nette\Bridges\DatabaseTracy\ConnectionPanel::renderException' - )); + ]); if ($this->debugMode) { - $connection->addSetup('Nette\Database\Helpers::createDebugPanel', array($connection, !empty($config['explain']), $name)); + $connection->addSetup('Nette\Database\Helpers::createDebugPanel', [$connection, !empty($config['explain']), $name]); } } if ($this->name === 'database') { - $container->addAlias($this->prefix($name), $this->prefix("$name.connection")); - $container->addAlias("nette.database.$name", $this->prefix($name)); - $container->addAlias("nette.database.$name.context", $this->prefix("$name.context")); + $builder->addAlias($this->prefix($name), $this->prefix("$name.connection")); + $builder->addAlias("nette.database.$name", $this->prefix($name)); + $builder->addAlias("nette.database.$name.context", $this->prefix("$name.context")); } } diff -Nru php-nette-2.3.10/Nette/Bridges/DatabaseTracy/ConnectionPanel.php php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/ConnectionPanel.php --- php-nette-2.3.10/Nette/Bridges/DatabaseTracy/ConnectionPanel.php 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/ConnectionPanel.php 2016-07-31 17:46:34.000000000 +0000 @@ -15,8 +15,10 @@ /** * Debug panel for Nette\Database. */ -class ConnectionPanel extends Nette\Object implements Tracy\IBarPanel +class ConnectionPanel implements Tracy\IBarPanel { + use Nette\SmartObject; + /** @var int */ public $maxQueries = 100; @@ -27,7 +29,7 @@ private $count = 0; /** @var array */ - private $queries = array(); + private $queries = []; /** @var string */ public $name; @@ -41,7 +43,7 @@ public function __construct(Nette\Database\Connection $connection) { - $connection->onQuery[] = array($this, 'logQuery'); + $connection->onQuery[] = [$this, 'logQuery']; } @@ -53,7 +55,7 @@ $this->count++; $source = NULL; - $trace = $result instanceof \PDOException ? $result->getTrace() : debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE); + $trace = $result instanceof \PDOException ? $result->getTrace() : debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); foreach ($trace as $row) { if (isset($row['file']) && is_file($row['file']) && !Tracy\Debugger::getBluescreen()->isCollapsed($row['file'])) { if ((isset($row['function']) && strpos($row['function'], 'call_user_func') === 0) @@ -61,18 +63,18 @@ ) { continue; } - $source = array($row['file'], (int) $row['line']); + $source = [$row['file'], (int) $row['line']]; break; } } if ($result instanceof Nette\Database\ResultSet) { $this->totalTime += $result->getTime(); if ($this->count < $this->maxQueries) { - $this->queries[] = array($connection, $result->getQueryString(), $result->getParameters(), $source, $result->getTime(), $result->getRowCount(), NULL); + $this->queries[] = [$connection, $result->getQueryString(), $result->getParameters(), $source, $result->getTime(), $result->getRowCount(), NULL]; } } elseif ($result instanceof \PDOException && $this->count < $this->maxQueries) { - $this->queries[] = array($connection, $result->queryString, NULL, $source, NULL, NULL, $result->getMessage()); + $this->queries[] = [$connection, $result->queryString, NULL, $source, NULL, NULL, $result->getMessage()]; } } @@ -88,10 +90,10 @@ } elseif ($item = Tracy\Helpers::findTrace($e->getTrace(), 'PDO::prepare')) { $sql = $item['args'][0]; } - return isset($sql) ? array( + return isset($sql) ? [ 'tab' => 'SQL', 'panel' => Helpers::dumpSql($sql), - ) : NULL; + ] : NULL; } @@ -100,7 +102,7 @@ $name = $this->name; $count = $this->count; $totalTime = $this->totalTime; - ob_start(); + ob_start(function () {}); require __DIR__ . '/templates/ConnectionPanel.tab.phtml'; return ob_get_clean(); } @@ -116,7 +118,7 @@ $name = $this->name; $count = $this->count; $totalTime = $this->totalTime; - $queries = array(); + $queries = []; foreach ($this->queries as $query) { list($connection, $sql, $params, $source, $time, $rows, $error) = $query; $explain = NULL; @@ -131,7 +133,7 @@ $queries[] = $query; } - ob_start(); + ob_start(function () {}); require __DIR__ . '/templates/ConnectionPanel.panel.phtml'; return ob_get_clean(); } diff -Nru php-nette-2.3.10/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml --- php-nette-2.3.10/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml 2016-04-13 18:50:56.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml 2016-07-31 17:46:58.000000000 +0000 @@ -9,7 +9,7 @@ ?> -

Queries: getDsn(), ENT_QUOTES, 'UTF-8') ?>">Queries:

@@ -22,24 +22,24 @@ - ERROR + ERROR
explain - + $foo): ?> - + - + @@ -47,7 +47,7 @@ - +
diff -Nru php-nette-2.3.10/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml --- php-nette-2.3.10/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml 2016-07-31 17:46:34.000000000 +0000 @@ -5,7 +5,7 @@ use Nette; ?> - - - + + + diff -Nru php-nette-2.3.10/Nette/Bridges/DITracy/ContainerPanel.php php-nette-2.4-20160731/Nette/Bridges/DITracy/ContainerPanel.php --- php-nette-2.3.10/Nette/Bridges/DITracy/ContainerPanel.php 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DITracy/ContainerPanel.php 2016-07-31 17:46:34.000000000 +0000 @@ -15,8 +15,10 @@ /** * Dependency injection container panel for Debugger Bar. */ -class ContainerPanel extends Nette\Object implements Tracy\IBarPanel +class ContainerPanel implements Tracy\IBarPanel { + use Nette\SmartObject; + /** @var int */ public static $compilationTime; @@ -55,9 +57,8 @@ { $container = $this->container; $registry = $this->getContainerProperty('registry'); - $rc = new \ReflectionClass($container); - $file = $rc->getFileName(); - $tags = array(); + $file = (new \ReflectionClass($container))->getFileName(); + $tags = []; $meta = $this->getContainerProperty('meta'); $services = $meta[Container::SERVICES]; ksort($services); @@ -77,8 +78,7 @@ private function getContainerProperty($name) { - $rc = new \ReflectionClass('Nette\DI\Container'); - $prop = $rc->getProperty($name); + $prop = (new \ReflectionClass(Nette\DI\Container::class))->getProperty($name); $prop->setAccessible(TRUE); return $prop->getValue($this->container); } diff -Nru php-nette-2.3.10/Nette/Bridges/DITracy/templates/ContainerPanel.panel.phtml php-nette-2.4-20160731/Nette/Bridges/DITracy/templates/ContainerPanel.panel.phtml --- php-nette-2.3.10/Nette/Bridges/DITracy/templates/ContainerPanel.panel.phtml 2016-04-13 18:50:56.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DITracy/templates/ContainerPanel.panel.phtml 2016-07-31 17:46:58.000000000 +0000 @@ -10,7 +10,7 @@
-

+

Services

@@ -28,18 +28,18 @@ $class): ?> - - + + - TRUE, Dumper::LIVE => TRUE)); ?> + TRUE, Dumper::LIVE => TRUE]); ?> - + - + - TRUE)); } ?> + TRUE]); } ?> @@ -48,9 +48,9 @@

Parameters

- parameters); ?> + parameters); ?>
-

Source:

+

Source:

diff -Nru php-nette-2.3.10/Nette/Bridges/DITracy/templates/ContainerPanel.tab.phtml php-nette-2.4-20160731/Nette/Bridges/DITracy/templates/ContainerPanel.tab.phtml --- php-nette-2.3.10/Nette/Bridges/DITracy/templates/ContainerPanel.tab.phtml 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/DITracy/templates/ContainerPanel.tab.phtml 2016-07-31 17:46:34.000000000 +0000 @@ -7,5 +7,5 @@ ?> - + diff -Nru php-nette-2.3.10/Nette/Bridges/FormsDI/FormsExtension.php php-nette-2.4-20160731/Nette/Bridges/FormsDI/FormsExtension.php --- php-nette-2.3.10/Nette/Bridges/FormsDI/FormsExtension.php 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/FormsDI/FormsExtension.php 2016-07-31 17:46:36.000000000 +0000 @@ -15,9 +15,9 @@ */ class FormsExtension extends Nette\DI\CompilerExtension { - public $defaults = array( - 'messages' => array(), - ); + public $defaults = [ + 'messages' => [], + ]; public function afterCompile(Nette\PhpGenerator\ClassType $class) @@ -27,9 +27,9 @@ foreach ((array) $config['messages'] as $name => $text) { if (defined('Nette\Forms\Form::' . $name)) { - $initialize->addBody('Nette\Forms\Validator::$messages[Nette\Forms\Form::?] = ?;', array($name, $text)); + $initialize->addBody('Nette\Forms\Validator::$messages[Nette\Forms\Form::?] = ?;', [$name, $text]); } elseif (defined($name)) { - $initialize->addBody('Nette\Forms\Validator::$messages[' . $name . '] = ?;', array($text)); + $initialize->addBody('Nette\Forms\Validator::$messages[' . $name . '] = ?;', [$text]); } else { throw new Nette\InvalidArgumentException('Constant Nette\Forms\Form::' . $name . ' or constant ' . $name . ' does not exist.'); } diff -Nru php-nette-2.3.10/Nette/Bridges/FormsLatte/FormMacros.php php-nette-2.4-20160731/Nette/Bridges/FormsLatte/FormMacros.php --- php-nette-2.3.10/Nette/Bridges/FormsLatte/FormMacros.php 2016-04-13 18:50:42.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Bridges/FormsLatte/FormMacros.php 2016-07-31 17:46:36.000000000 +0000 @@ -31,12 +31,12 @@ public static function install(Latte\Compiler $compiler) { $me = new static($compiler); - $me->addMacro('form', array($me, 'macroForm'), 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd($_form)'); - $me->addMacro('formContainer', array($me, 'macroFormContainer'), '$formContainer = $_form = array_pop($_formStack)'); - $me->addMacro('label', array($me, 'macroLabel'), array($me, 'macroLabelEnd')); - $me->addMacro('input', array($me, 'macroInput'), NULL, array($me, 'macroInputAttr')); - $me->addMacro('name', array($me, 'macroName'), array($me, 'macroNameEnd'), array($me, 'macroNameAttr')); - $me->addMacro('inputError', array($me, 'macroInputError')); + $me->addMacro('form', [$me, 'macroForm'], 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack));'); + $me->addMacro('formContainer', [$me, 'macroFormContainer'], 'array_pop($this->global->formsStack); $formContainer = $_form = end($this->global->formsStack)'); + $me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd'], NULL, self::AUTO_EMPTY); + $me->addMacro('input', [$me, 'macroInput']); + $me->addMacro('name', [$me, 'macroName'], [$me, 'macroNameEnd'], [$me, 'macroNameAttr']); + $me->addMacro('inputError', [$me, 'macroInputError']); } @@ -49,20 +49,22 @@ public function macroForm(MacroNode $node, PhpWriter $writer) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); } if ($node->prefix) { throw new CompileException('Did you mean
?'); } $name = $node->tokenizer->fetchWord(); if ($name === FALSE) { - throw new CompileException("Missing form name in {{$node->name}}."); + throw new CompileException('Missing form name in ' . $node->getNotation()); } + $node->replaced = TRUE; $node->tokenizer->reset(); return $writer->write( - 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form = $_form = ' + "/* line $node->startLine */\n" + . 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form = $_form = $this->global->formsStack[] = ' . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '') - . '$_control[%node.word], %node.array)' + . '$this->global->uiControl[%node.word], %node.array);' ); } @@ -73,15 +75,17 @@ public function macroFormContainer(MacroNode $node, PhpWriter $writer) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); } $name = $node->tokenizer->fetchWord(); if ($name === FALSE) { - throw new CompileException("Missing name in {{$node->name}}."); + throw new CompileException('Missing name in ' . $node->getNotation()); } $node->tokenizer->reset(); return $writer->write( - '$_formStack[] = $_form; $formContainer = $_form = ' . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '') . '$_form[%node.word]' + '$this->global->formsStack[] = $formContainer = $_form = ' + . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '') + . 'end($this->global->formsStack)[%node.word];' ); } @@ -92,19 +96,20 @@ public function macroLabel(MacroNode $node, PhpWriter $writer) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); } $words = $node->tokenizer->fetchWords(); if (!$words) { - throw new CompileException("Missing name in {{$node->name}}."); + throw new CompileException('Missing name in ' . $node->getNotation()); } + $node->replaced = true; $name = array_shift($words); return $writer->write( - ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : $_form[%0.word]; if ($_label = $_input' : 'if ($_label = $_form[%0.word]') + ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word]; if ($_label = $_input' : 'if ($_label = end($this->global->formsStack)[%0.word]') . '->%1.raw) echo $_label' . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''), $name, - $words ? ('getLabelPart(' . implode(', ', array_map(array($writer, 'formatWord'), $words)) . ')') : 'getLabel()' + $words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()' ); } @@ -127,63 +132,57 @@ public function macroInput(MacroNode $node, PhpWriter $writer) { if ($node->modifiers) { - trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING); + throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); } $words = $node->tokenizer->fetchWords(); if (!$words) { - throw new CompileException("Missing name in {{$node->name}}."); + throw new CompileException('Missing name in ' . $node->getNotation()); } + $node->replaced = true; $name = array_shift($words); return $writer->write( - ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : $_form[%0.word]; echo $_input' : 'echo $_form[%0.word]') + ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word]; echo $_input' : 'echo end($this->global->formsStack)[%0.word]') . '->%1.raw' - . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''), + . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : '') + . " /* line $node->startLine */", $name, - $words ? 'getControlPart(' . implode(', ', array_map(array($writer, 'formatWord'), $words)) . ')' : 'getControl()' + $words ? 'getControlPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')' : 'getControl()' ); } /** - * deprecated n:input - */ - public function macroInputAttr(MacroNode $node, PhpWriter $writer) - { - throw new CompileException('Use n:name instead of n:input.'); - } - - - /** * , , - - - - - - - <?php echo htmlspecialchars($title . ': ' . $exception->getMessage() . $code, ENT_IGNORE, 'UTF-8') ?> - getPrevious()): ?> - - - - - - - - - -
- -
-
- getMessage()): ?>

- - -

getMessage() ?: $title . $code, ENT_IGNORE, 'UTF-8') ?> - getMessage())) ?>" target="_blank" rel="noreferrer">search► - skip error►

-
- - getPrevious()): ?> - - - - - - - - -
> -

Caused by

- -
-
-

getCode() ? ' #' . $ex->getCode() : ''), ENT_NOQUOTES, 'UTF-8') ?>

- -

getMessage(), ENT_IGNORE, 'UTF-8') ?>

-
- - - - - - -
-

- -
- -
- - - - getTrace(); $expanded = NULL ?> - getSeverity(), array(E_USER_NOTICE, E_USER_WARNING, E_USER_DEPRECATED))) && $this->isCollapsed($ex->getFile())) { - foreach ($stack as $key => $row) { - if (isset($row['file']) && !$this->isCollapsed($row['file'])) { $expanded = $key; break; } - } - } ?> - -
-

Source file

- -
-

File: getFile(), $ex->getLine()) ?>

- getFile())): ?>getFile(), $ex->getLine(), 15, $ex instanceof \ErrorException && isset($ex->context) ? $ex->context : NULL) ?> -
- - - - -
-

Call stack

- -
-
    - $row): ?> -
  1. - - - - - inner-code - - - source  - - "; - if (isset($row['class'])) echo htmlspecialchars($row['class'] . $row['type'], ENT_NOQUOTES, 'UTF-8'); - if (isset($row['object'])) echo ''; - echo htmlspecialchars($row['function'], ENT_NOQUOTES, 'UTF-8'), '('; - if (!empty($row['args'])): ?>arguments) -

    - - -
    - - - -
    TRUE)) ?>
    - - - -
    - - getParameters(); - } catch (\Exception $e) { - $params = array(); - } - foreach ($row['args'] as $k => $v) { - echo '\n"; - } - ?> -
    ', htmlspecialchars(isset($params[$k]) ? '$' . $params[$k]->name : "#$k", ENT_IGNORE, 'UTF-8'), ''; - echo Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)); - echo "
    -
    - -
  2. - -
-
- - - - context) && is_array($ex->context)):?> -
-

Variables

- -
-
- - context as $k => $v) { - echo '\n"; - } - ?> -
$', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
-
-
- - - getPrevious()); ?> -
' ?> - - - count((array) new \Exception)):?> -
-

Exception

-
- Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)) ?> -
- - - - - - - -
-

- -
- -
- - - -
-

Environment

- -
-

$_SERVER

-
- - $v) echo '\n"; - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', Dumper::toHtml($v), "
-
- - -

$_SESSION

-
- -

empty

- - - $v) echo '\n"; - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', $k === '__NF' ? 'Nette Session' : Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
- -
- - - -

Nette Session

-
- - $v) echo '\n"; - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
-
- - - - -

Constants

-
- - $v) { - echo ''; - echo '\n"; - } - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', Dumper::toHtml($v), "
-
- - - -

Included files ()

-
- - \n"; - } - ?> -
', htmlspecialchars($v, ENT_IGNORE, 'UTF-8'), "
-
- - -

Configuration options

-
- |.+\z#s', '', ob_get_clean()) // @ phpinfo can be disabled ?> -
-
- - -
-

HTTP request

- -
- -

Headers

-
- - $v) echo '\n"; - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', htmlspecialchars($v, ENT_IGNORE, 'UTF-8'), "
-
- - - - -

$

- -

empty

- -
- - $v) echo '\n"; - ?> -
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '', Dumper::toHtml($v), "
-
- - -
- - -
-

HTTP response

- -
-

Headers

- -
';
-			?>
- -

no headers

- -
- - - -
-

- -
- -
- - - -
    -
  • Report generated at
  • -
  • -
  • -
- - -
-
- - - - - diff -Nru php-nette-2.3.10/Nette/Tracy/assets/BlueScreen/content.phtml php-nette-2.4-20160731/Nette/Tracy/assets/BlueScreen/content.phtml --- php-nette-2.3.10/Nette/Tracy/assets/BlueScreen/content.phtml 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/BlueScreen/content.phtml 2016-07-31 17:46:44.000000000 +0000 @@ -0,0 +1,335 @@ +getCode() ? ' #' . $exception->getCode() : ''; + +?> +
+ +
+
+ getMessage()): ?>

+ + +

getMessage() ?: $title . $code)) ?> + getMessage())) ?>" target="_blank" rel="noreferrer noopener">search► + skip error►

+
+ + getPrevious()): ?> + + + + + + + + +
> +

Caused by

+ +
+
+

getCode() ? ' #' . $ex->getCode() : '')) ?>

+ +

getMessage()) ?>

+
+ + + + renderPanels($ex) as $panel): ?> +
+

tab) ?>

+ +
+ panel ?> +
+ + + + getTrace(); $expanded = NULL ?> + getSeverity(), [E_USER_NOTICE, E_USER_WARNING, E_USER_DEPRECATED])) && $this->isCollapsed($ex->getFile())) { + foreach ($stack as $key => $row) { + if (isset($row['file']) && !$this->isCollapsed($row['file'])) { $expanded = $key; break; } + } + } ?> + +
+

Source file

+ +
+

File: getFile(), $ex->getLine()) ?>

+ getFile())): ?>getFile(), $ex->getLine(), 15, $ex instanceof \ErrorException && isset($ex->context) ? $ex->context : NULL) ?> +
+ + + + +
+

Call stack

+ +
+
    + $row): ?> +
  1. + + + + + inner-code + + + source  + + "; + if (isset($row['class'])) echo Helpers::escapeHtml($row['class'] . $row['type']); + if (isset($row['object'])) echo ''; + echo Helpers::escapeHtml($row['function']), '('; + if (!empty($row['args'])): ?>arguments) +

    + + +
    + + + +
    + + + +
    + + getParameters(); + } catch (\Exception $e) { + $params = []; + } + foreach ($row['args'] as $k => $v) { + echo '\n"; + } + ?> +
    ', Helpers::escapeHtml(isset($params[$k]) ? '$' . $params[$k]->name : "#$k"), ''; + echo $dump($v); + echo "
    +
    + +
  2. + +
+
+ + + + context) && is_array($ex->context)):?> +
+

Variables

+ +
+
+ + context as $k => $v) { + echo '\n"; + } + ?> +
$', Helpers::escapeHtml($k), '', $dump($v), "
+
+
+ + + getPrevious()); ?> +
' ?> + + + count((array) new \Exception)):?> +
+

Exception

+
+ +
+ + + + +
+

Last muted error

+
+ +

:

+ +

+
+ +

inner-code

+ + +
+ + + + + renderPanels(NULL) as $panel): ?> + bottom)) { $bottomPanels[] = $panel; continue; } ?> +
+

tab) ?>

+ +
+ panel ?> +
+ + + +
+

Environment

+ +
+

$_SERVER

+
+ + $v) echo '\n"; + ?> +
', Helpers::escapeHtml($k), '', $dump($v), "
+
+ + +

$_SESSION

+
+ +

empty

+ + + $v) echo '\n"; + ?> +
', Helpers::escapeHtml($k), '', $k === '__NF' ? 'Nette Session' : $dump($v), "
+ +
+ + + +

Nette Session

+
+ + $v) echo '\n"; + ?> +
', Helpers::escapeHtml($k), '', $dump($v), "
+
+ + + + +

Constants

+
+ + $v) { + echo ''; + echo '\n"; + } + ?> +
', Helpers::escapeHtml($k), '', $dump($v), "
+
+ + + +

Configuration options

+
+ |.+\z#s', '', ob_get_clean()) // @ phpinfo can be disabled ?> +
+
+ + +
+

HTTP request

+ +
+ +

Headers

+
+ + $v) echo '\n"; + ?> +
', Helpers::escapeHtml($k), '', Helpers::escapeHtml($v), "
+
+ + + + +

$

+ +

empty

+ +
+ + $v) echo '\n"; + ?> +
', Helpers::escapeHtml($k), '', $dump($v), "
+
+ + +
+ + +
+

HTTP response

+ +
+

Headers

+ +
';
+			?>
+ +

no headers

+ +
+ + + +
+

tab) ?>

+ +
+ panel ?> +
+ + + +
    +
  • Report generated at
  • +
  • +
  • +
+ + +
+
diff -Nru php-nette-2.3.10/Nette/Tracy/assets/BlueScreen/page.phtml php-nette-2.4-20160731/Nette/Tracy/assets/BlueScreen/page.phtml --- php-nette-2.3.10/Nette/Tracy/assets/BlueScreen/page.phtml 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/BlueScreen/page.phtml 2016-07-31 17:47:04.000000000 +0000 @@ -0,0 +1,56 @@ +getCode() ? ' #' . $exception->getCode() : ''; + +?>
+ + + + + + + <?= Helpers::escapeHtml($title . ': ' . $exception->getMessage() . $code) ?> + getPrevious()): ?> + + + + + + + + + + + + + + + + diff -Nru php-nette-2.3.10/Nette/Tracy/assets/Dumper/dumper.css php-nette-2.4-20160731/Nette/Tracy/assets/Dumper/dumper.css --- php-nette-2.3.10/Nette/Tracy/assets/Dumper/dumper.css 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/Dumper/dumper.css 2016-07-31 17:47:04.000000000 +0000 @@ -1,70 +1 @@ -/** - * This file is part of the Tracy (https://tracy.nette.org) - */ - -/* toggle */ -.tracy-collapsed { - display: none; -} - -.tracy-toggle.tracy-collapsed { - display: inline; -} - -.tracy-toggle { - cursor: pointer; -} - -.tracy-toggle:after { - content: " ▼"; - opacity: .4; -} - -.tracy-toggle.tracy-collapsed:after { - content: " ►"; -} - - -/* dump */ -pre.tracy-dump { - text-align: left; - color: #444; - background: white; -} - -pre.tracy-dump div { - padding-left: 3ex; -} - -pre.tracy-dump div div { - border-left: 1px solid rgba(0, 0, 0, .1); - margin-left: .5ex; -} - -.tracy-dump-array, .tracy-dump-object { - color: #C22; -} - -.tracy-dump-string { - color: #35D; -} - -.tracy-dump-number { - color: #090; -} - -.tracy-dump-null, .tracy-dump-bool { - color: #850; -} - -.tracy-dump-visibility, .tracy-dump-hash { - font-size: 85%; color: #999; -} - -.tracy-dump-indent { - display: none; -} - -span[data-tracy-href] { - border-bottom: 1px dotted rgba(0, 0, 0, .2); -} +pre.tracy-dump{text-align:left;color:#444;background:white}pre.tracy-dump div{padding-left:3ex}pre.tracy-dump div div{border-left:1px solid rgba(0,0,0,.1);margin-left:.5ex}.tracy-dump-array,.tracy-dump-object{color:#C22}.tracy-dump-string{color:#35D}.tracy-dump-number{color:#090}.tracy-dump-null,.tracy-dump-bool{color:#850}.tracy-dump-visibility,.tracy-dump-hash{font-size:85%;color:#999}.tracy-dump-indent{display:none}span[data-tracy-href]{border-bottom:1px dotted rgba(0,0,0,.2)} \ No newline at end of file diff -Nru php-nette-2.3.10/Nette/Tracy/assets/Dumper/dumper.js php-nette-2.4-20160731/Nette/Tracy/assets/Dumper/dumper.js --- php-nette-2.3.10/Nette/Tracy/assets/Dumper/dumper.js 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/Dumper/dumper.js 2016-07-31 17:47:04.000000000 +0000 @@ -1,207 +1,6 @@ -/** - * This file is part of the Tracy (https://tracy.nette.org) - */ - -(function() { - var COLLAPSE_COUNT = 7, - COLLAPSE_COUNT_TOP = 14; - - Tracy = window.Tracy || {}; - - Tracy.Dumper = Tracy.Dumper || {}; - - Tracy.Dumper.init = function(repository) { - if (repository) { - [].forEach.call(document.querySelectorAll('.tracy-dump[data-tracy-dump]'), function(el) { - try { - el.appendChild(build(JSON.parse(el.getAttribute('data-tracy-dump')), repository, el.classList.contains('tracy-collapsed'))); - el.classList.remove('tracy-collapsed'); - el.removeAttribute('data-tracy-dump'); - } catch (e) { - if (!(e instanceof UnknownEntityException)) { - throw e; - } - } - }); - } - - if (this.inited) { - return; - } - this.inited = true; - - document.body.addEventListener('click', function(e) { - var link; - - // enables & ctrl key - if (e.ctrlKey && (link = closest(e.target, '[data-tracy-href]'))) { - location.href = link.getAttribute('data-tracy-href'); - return false; - } - - if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) { - return; - } - - // enables or toggling - if (link = closest(e.target, '.tracy-toggle')) { - var collapsed = link.classList.contains('tracy-collapsed'), - ref = link.getAttribute('data-tracy-ref') || link.getAttribute('href', 2), - dest = link; - - if (!ref || ref === '#') { - ref = '+'; - } else if (ref.substr(0, 1) === '#') { - dest = document; - } - ref = ref.match(/(\^\s*([^+\s]*)\s*)?(\+\s*(\S*)\s*)?(.*)/); - dest = ref[1] ? closest(dest.parentNode, ref[2]) : dest; - dest = ref[3] ? closest(dest.nextElementSibling, ref[4], 'nextElementSibling') : dest; - dest = ref[5] ? dest.querySelector(ref[5]) : dest; - - link.classList.toggle('tracy-collapsed', !collapsed); - dest.classList.toggle('tracy-collapsed', !collapsed); - e.preventDefault(); - } - }); - }; - - - var build = function(data, repository, collapsed, parentIds) { - var type = data === null ? 'null' : typeof data, - collapseCount = typeof collapsed === 'undefined' ? COLLAPSE_COUNT_TOP : COLLAPSE_COUNT; - - if (type === 'null' || type === 'string' || type === 'number' || type === 'boolean') { - data = type === 'string' ? '"' + data + '"' : (data + '').toUpperCase(); - return createEl(null, null, [ - createEl( - 'span', - {'class': 'tracy-dump-' + type.replace('ean', '')}, - [data + '\n'] - ) - ]); - - } else if (Array.isArray(data)) { - return buildStruct([ - createEl('span', {'class': 'tracy-dump-array'}, ['array']), - ' (' + (data[0] && data.length || '') + ')' - ], - ' [ ... ]', - data[0] === null ? null : data, - collapsed === true || data.length >= collapseCount, - repository, - parentIds - ); - - } else if (type === 'object' && data.number) { - return createEl(null, null, [ - createEl('span', {'class': 'tracy-dump-number'}, [data.number + '\n']) - ]); - - } else if (type === 'object' && data.type) { - return createEl(null, null, [ - createEl('span', null, [data.type + '\n']) - ]); - - } else if (type === 'object') { - var id = data.object || data.resource, - object = repository[id]; - - if (!object) { - throw new UnknownEntityException; - } - parentIds = parentIds || []; - recursive = parentIds.indexOf(id) > -1; - parentIds.push(id); - - return buildStruct([ - createEl('span', { - 'class': data.object ? 'tracy-dump-object' : 'tracy-dump-resource', - title: object.editor ? 'Declared in file ' + object.editor.file + ' on line ' + object.editor.line : null, - 'data-tracy-href': object.editor ? object.editor.url : null - }, [object.name]), - ' ', - createEl('span', {'class': 'tracy-dump-hash'}, ['#' + id]) - ], - ' { ... }', - object.items, - collapsed === true || recursive || (object.items && object.items.length >= collapseCount), - repository, - parentIds - ); - } - }; - - - var buildStruct = function(span, ellipsis, items, collapsed, repository, parentIds) { - var res, toggle, div, handler; - - if (!items || !items.length) { - span.push(!items || items.length ? ellipsis + '\n' : '\n'); - return createEl(null, null, span); - } - - res = createEl(null, null, [ - toggle = createEl('span', {'class': collapsed ? 'tracy-toggle tracy-collapsed' : 'tracy-toggle'}, span), - '\n', - div = createEl('div', {'class': collapsed ? 'tracy-collapsed' : ''}) - ]); - - if (collapsed) { - toggle.addEventListener('click', handler = function() { - toggle.removeEventListener('click', handler); - createItems(div, items, repository, parentIds); - }); - } else { - createItems(div, items, repository, parentIds); - } - return res; - }; - - - var createEl = function(el, attrs, content) { - if (!(el instanceof Node)) { - el = el ? document.createElement(el) : document.createDocumentFragment(); - } - for (var id in attrs || {}) { - if (attrs[id] !== null) { - el.setAttribute(id, attrs[id]); - } - } - content = content || []; - for (id = 0; id < content.length; id++) { - var child = content[id]; - if (child !== null) { - el.appendChild(child instanceof Node ? child : document.createTextNode(child)); - } - } - return el; - }; - - - var createItems = function(el, items, repository, parentIds) { - for (var i = 0; i < items.length; i++) { - var vis = items[i][2]; - createEl(el, null, [ - createEl('span', {'class': 'tracy-dump-key'}, [items[i][0]]), - vis ? ' ' : null, - vis ? createEl('span', {'class': 'tracy-dump-visibility'}, [vis === 1 ? 'protected' : 'private']) : null, - ' => ', - build(items[i][1], repository, null, parentIds) - ]); - } - }; - - var UnknownEntityException = function() {}; - - - // finds closing maching element - var closest = function(el, selector, func) { - var matches = el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector; - while (el && selector && !(el.nodeType === 1 && matches.call(el, selector))) { - el = el[func || 'parentNode']; - } - return el; - }; - -})(); +(function(){Tracy=window.Tracy||{};Tracy.Dumper=Tracy.Dumper||{};Tracy.Dumper.init=function(a,e){a&&[].forEach.call((e||document).querySelectorAll(".tracy-dump[data-tracy-dump]"),function(c){try{c.appendChild(k(JSON.parse(c.getAttribute("data-tracy-dump")),a,c.classList.contains("tracy-collapsed"))),c.classList.remove("tracy-collapsed"),c.removeAttribute("data-tracy-dump")}catch(b){if(!(b instanceof m))throw b;}});this.inited||(this.inited=!0,document.body.addEventListener("click",function(a){var b; +if(a.ctrlKey&&(b=Tracy.closest(a.target,"[data-tracy-href]")))return location.href=b.getAttribute("data-tracy-href"),!1}),Tracy.Toggle.init())};var k=function(a,e,c,b){var d=null===a?"null":typeof a,h="undefined"===typeof c?14:7;if("null"===d||"string"===d||"number"===d||"boolean"===d)return a="string"===d?'"'+a+'"':(a+"").toUpperCase(),f(null,null,[f("span",{"class":"tracy-dump-"+d.replace("ean","")},[a+"\n"])]);if(Array.isArray(a))return n([f("span",{"class":"tracy-dump-array"},["array"])," ("+ +(a[0]&&a.length||"")+")"]," [ ... ]",null===a[0]?null:a,!0===c||a.length>=h,e,b);if("object"===d&&a.number)return f(null,null,[f("span",{"class":"tracy-dump-number"},[a.number+"\n"])]);if("object"===d&&a.type)return f(null,null,[f("span",null,[a.type+"\n"])]);if("object"===d){var d=a.object||a.resource,g=e[d];if(!g)throw new m;b=b||[];recursive=-1=h,e,b)}},n=function(a,e,c,b,d,h){var g,l,k;if(!c||!c.length)return a.push(!c||c.length?e+"\n":"\n"),f(null,null,a);a=f(null,null,[g=f("span",{"class":b?"tracy-toggle tracy-collapsed":"tracy-toggle"},a),"\n",l=f("div",{"class":b?"tracy-collapsed":""})]);b?g.addEventListener("tracy-toggle",k=function(){g.removeEventListener("tracy-toggle", +k);p(l,c,d,h)}):p(l,c,d,h);return a},f=function(a,e,c){a instanceof Node||(a=a?document.createElement(a):document.createDocumentFragment());for(var b in e||{})null!==e[b]&&a.setAttribute(b,e[b]);c=c||[];for(b=0;b ",k(e[d][1],c,null,b)])}},m=function(){}})(); \ No newline at end of file diff -Nru php-nette-2.3.10/Nette/Tracy/assets/Toggle/toggle.css php-nette-2.4-20160731/Nette/Tracy/assets/Toggle/toggle.css --- php-nette-2.3.10/Nette/Tracy/assets/Toggle/toggle.css 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/Toggle/toggle.css 2016-07-31 17:47:04.000000000 +0000 @@ -0,0 +1 @@ +.tracy-collapsed{display:none}.tracy-toggle.tracy-collapsed{display:inline}.tracy-toggle{cursor:pointer}.tracy-toggle:after{content:" ▼";opacity:.4}.tracy-toggle.tracy-collapsed:after{content:" ►"} \ No newline at end of file diff -Nru php-nette-2.3.10/Nette/Tracy/assets/Toggle/toggle.js php-nette-2.4-20160731/Nette/Tracy/assets/Toggle/toggle.js --- php-nette-2.3.10/Nette/Tracy/assets/Toggle/toggle.js 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/assets/Toggle/toggle.js 2016-07-31 17:47:06.000000000 +0000 @@ -0,0 +1,4 @@ +(function(){Tracy=window.Tracy||{};Tracy.Toggle=Tracy.Toggle||{};Tracy.Toggle.init=function(){document.body.addEventListener("click",function(a){var d=Tracy.closest(a.target,".tracy-toggle");!d||(a.shiftKey||a.altKey||a.ctrlKey||a.metaKey)||Tracy.Toggle.toggle(d)});this.init=function(){}};Tracy.Toggle.toggle=function(a,d){var e=a.classList.contains("tracy-collapsed"),b=a.getAttribute("data-tracy-ref")||a.getAttribute("href",2),c=a;if("undefined"===typeof d)d=e;else if(!d===e)return;b&&"#"!==b?"#"=== +b.substr(0,1)&&(c=document):b="+";b=b.match(/(\^\s*([^+\s]*)\s*)?(\+\s*(\S*)\s*)?(.*)/);c=b[1]?Tracy.closest(c.parentNode,b[2]):c;c=b[3]?Tracy.closest(c.nextElementSibling,b[4],"nextElementSibling"):c;c=b[5]?c.querySelector(b[5]):c;a.classList.toggle("tracy-collapsed",!d);c.classList.toggle("tracy-collapsed",!d);"function"===typeof window.Event?e=new Event("tracy-toggle",{bubbles:!0}):(e=document.createEvent("Event"),e.initEvent("tracy-toggle",!0,!1));a.dispatchEvent(e)};Tracy.Toggle.persist=function(a, +d){var e=[];a.addEventListener("tracy-toggle",function(a){0>e.indexOf(a.target)&&e.push(a.target)});var b=JSON.parse(sessionStorage.getItem("tracy-toggles-"+a.id));b&&!1!==d&&b.forEach(function(c){var b=a,d;for(d in c.path)if(!(b=b.children[c.path[d]]))return;b.textContent===c.text&&Tracy.Toggle.toggle(b,c.show)});window.addEventListener("unload",function(){b=[].map.call(e,function(c){var b={path:[],text:c.textContent,show:!c.classList.contains("tracy-collapsed")};do b.path.unshift([].indexOf.call(c.parentNode.children, +c)),c=c.parentNode;while(c&&c!==a);return b});sessionStorage.setItem("tracy-toggles-"+a.id,JSON.stringify(b))})};Tracy.closest=function(a,d,e){for(var b=a.matches||a.matchesSelector||a.msMatchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.oMatchesSelector;a&&d&&(1!==a.nodeType||!b.call(a,d));)a=a[e||"parentNode"];return a}})(); \ No newline at end of file diff -Nru php-nette-2.3.10/Nette/Tracy/Bar.php php-nette-2.4-20160731/Nette/Tracy/Bar.php --- php-nette-2.3.10/Nette/Tracy/Bar.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/Bar.php 2016-07-31 17:46:44.000000000 +0000 @@ -13,11 +13,11 @@ */ class Bar { - /** @deprecated */ - public $info = array(); - /** @var IBarPanel[] */ - private $panels = array(); + private $panels = []; + + /** @var bool */ + private $dispatched; /** @@ -56,65 +56,170 @@ */ public function render() { - @session_start(); // @ session may be already started or it is not possible to start session - $session = & $_SESSION['__NF']['debuggerbar']; - $redirect = preg_match('#^Location:#im', implode("\n", headers_list())); - if ($redirect) { + $useSession = $this->dispatched && session_status() === PHP_SESSION_ACTIVE; + $redirectQueue = & $_SESSION['_tracy']['redirect']; + + if (!Helpers::isHtmlMode() && !Helpers::isAjax()) { + return; + + } elseif (Helpers::isAjax()) { + $rows[] = (object) ['type' => 'ajax', 'panels' => $this->renderPanels('-ajax')]; + $dumps = Dumper::fetchLiveData(); + $contentId = $useSession ? $_SERVER['HTTP_X_TRACY_AJAX'] . '-ajax' : NULL; + + } elseif (preg_match('#^Location:#im', implode("\n", headers_list()))) { // redirect + $redirectQueue = array_slice((array) $redirectQueue, -10); Dumper::fetchLiveData(); - Dumper::$livePrefix = count($session) . 'p'; + Dumper::$livePrefix = count($redirectQueue) . 'p'; + $redirectQueue[] = [ + 'panels' => $this->renderPanels('-r' . count($redirectQueue)), + 'dumps' => Dumper::fetchLiveData(), + ]; + return; + + } else { + $rows[] = (object) ['type' => 'main', 'panels' => $this->renderPanels()]; + $dumps = Dumper::fetchLiveData(); + foreach (array_reverse((array) $redirectQueue) as $info) { + $rows[] = (object) ['type' => 'redirect', 'panels' => $info['panels']]; + $dumps += $info['dumps']; + } + $redirectQueue = NULL; + $contentId = $useSession ? substr(md5(uniqid('', TRUE)), 0, 10) : NULL; + } + + ob_start(function () {}); + require __DIR__ . '/assets/Bar/panels.phtml'; + require __DIR__ . '/assets/Bar/bar.phtml'; + $content = Helpers::fixEncoding(ob_get_clean()); + + if ($contentId) { + $queue = & $_SESSION['_tracy']['bar']; + $queue = array_slice(array_filter((array) $queue), -5, NULL, TRUE); + $queue[$contentId] = ['content' => $content, 'dumps' => $dumps]; + } + + if (Helpers::isHtmlMode()) { + $stopXdebug = extension_loaded('xdebug') ? ['XDEBUG_SESSION_STOP' => 1, 'XDEBUG_PROFILE' => 0, 'XDEBUG_TRACE' => 0] : []; + $path = isset($_SERVER['REQUEST_URI']) ? explode('?', $_SERVER['REQUEST_URI'])[0] : '/'; + $lpath = strtolower($path); + $script = isset($_SERVER['SCRIPT_NAME']) ? strtolower($_SERVER['SCRIPT_NAME']) : ''; + if ($lpath !== $script) { + $max = min(strlen($lpath), strlen($script)); + for ($i = 0; $i < $max && $lpath[$i] === $script[$i]; $i++); + $path = $i ? substr($path, 0, strrpos($path, '/', $i - strlen($path) - 1) + 1) : '/'; + $cookiePath = session_get_cookie_params()['path']; + if (substr($cookiePath, 0, strlen($path)) === $path) { + $path = rtrim($cookiePath, '/') . '/'; + } + } + require __DIR__ . '/assets/Bar/loader.phtml'; } + } + + + /** + * @return array + */ + private function renderPanels($suffix = NULL) + { + set_error_handler(function ($severity, $message, $file, $line) { + if (error_reporting() & $severity) { + throw new \ErrorException($message, 0, $severity, $file, $line); + } + }); $obLevel = ob_get_level(); - $panels = array(); + $panels = []; + foreach ($this->panels as $id => $panel) { - $idHtml = preg_replace('#[^a-z0-9]+#i', '-', $id); + $idHtml = preg_replace('#[^a-z0-9]+#i', '-', $id) . $suffix; try { $tab = (string) $panel->getTab(); $panelHtml = $tab ? (string) $panel->getPanel() : NULL; if ($tab && $panel instanceof \Nette\Diagnostics\IBarPanel) { - $panelHtml = preg_replace('~(["\'.\s#])nette-(debug|inner|collapsed|toggle|toggle-collapsed)(["\'\s])~', '$1tracy-$2$3', $panelHtml); - $panelHtml = str_replace('tracy-toggle-collapsed', 'tracy-toggle tracy-collapsed', $panelHtml); + $e = new \Exception('Support for Nette\Diagnostics\IBarPanel is deprecated'); } - $panels[] = array('id' => $idHtml, 'tab' => $tab, 'panel' => $panelHtml); } catch (\Throwable $e) { } catch (\Exception $e) { } if (isset($e)) { - $panels[] = array( - 'id' => "error-$idHtml", - 'tab' => "Error in $id", - 'panel' => '

Error: ' . $id . '

' - . nl2br(htmlSpecialChars($e, ENT_IGNORE, 'UTF-8')) . '
', - ); while (ob_get_level() > $obLevel) { // restore ob-level if broken ob_end_clean(); } + $idHtml = "error-$idHtml"; + $tab = "Error in $id"; + $panelHtml = "

Error: $id

" . nl2br(Helpers::escapeHtml($e)) . '
'; + unset($e); } + $panels[] = (object) ['id' => $idHtml, 'tab' => $tab, 'panel' => $panelHtml]; } - if ($redirect) { - $session[] = array('panels' => $panels, 'liveData' => Dumper::fetchLiveData()); - return; + restore_error_handler(); + return $panels; + } + + + /** + * Renders debug bar assets. + * @return bool + */ + public function dispatchAssets() + { + $asset = isset($_GET['_tracy_bar']) ? $_GET['_tracy_bar'] : NULL; + if ($asset === 'css') { + header('Content-Type: text/css; charset=utf-8'); + header('Cache-Control: max-age=864000'); + header_remove('Pragma'); + header_remove('Set-Cookie'); + readfile(__DIR__ . '/assets/Bar/bar.css'); + readfile(__DIR__ . '/assets/Toggle/toggle.css'); + readfile(__DIR__ . '/assets/Dumper/dumper.css'); + readfile(__DIR__ . '/assets/BlueScreen/bluescreen.css'); + return TRUE; + + } elseif ($asset === 'js') { + header('Content-Type: text/javascript'); + header('Cache-Control: max-age=864000'); + header_remove('Pragma'); + header_remove('Set-Cookie'); + readfile(__DIR__ . '/assets/Bar/bar.js'); + readfile(__DIR__ . '/assets/Toggle/toggle.js'); + readfile(__DIR__ . '/assets/Dumper/dumper.js'); + readfile(__DIR__ . '/assets/BlueScreen/bluescreen.js'); + return TRUE; } + } - $liveData = Dumper::fetchLiveData(); - foreach (array_reverse((array) $session) as $reqId => $info) { - $panels[] = array( - 'tab' => 'previous', - 'panel' => NULL, - 'previous' => TRUE, - ); - foreach ($info['panels'] as $panel) { - $panel['id'] .= '-' . $reqId; - $panels[] = $panel; + /** + * Renders debug bar content. + * @return bool + */ + public function dispatchContent() + { + $this->dispatched = TRUE; + if (Helpers::isAjax()) { + header('X-Tracy-Ajax: 1'); // session must be already locked + } + if (preg_match('#^content(-ajax)?.(\w+)$#', isset($_GET['_tracy_bar']) ? $_GET['_tracy_bar'] : '', $m)) { + $session = & $_SESSION['_tracy']['bar'][$m[2] . $m[1]]; + header('Content-Type: text/javascript'); + header('Cache-Control: max-age=60'); + header_remove('Set-Cookie'); + if ($session) { + $method = $m[1] ? 'loadAjax' : 'init'; + echo "Tracy.Debug.$method(", json_encode($session['content']), ', ', json_encode($session['dumps']), ');'; + $session = NULL; + } + $session = & $_SESSION['_tracy']['bluescreen'][$m[2]]; + if ($session) { + echo "Tracy.BlueScreen.loadAjax(", json_encode($session['content']), ', ', json_encode($session['dumps']), ');'; + $session = NULL; } - $liveData += $info['liveData']; + return TRUE; } - $session = NULL; - - require __DIR__ . '/assets/Bar/bar.phtml'; } } diff -Nru php-nette-2.3.10/Nette/Tracy/BlueScreen.php php-nette-2.4-20160731/Nette/Tracy/BlueScreen.php --- php-nette-2.3.10/Nette/Tracy/BlueScreen.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/BlueScreen.php 2016-07-31 17:46:44.000000000 +0000 @@ -14,13 +14,19 @@ class BlueScreen { /** @var string[] */ - public $info = array(); + public $info = []; /** @var callable[] */ - private $panels = array(); + private $panels = []; /** @var string[] paths to be collapsed in stack trace (e.g. core libraries) */ - public $collapsePaths = array(); + public $collapsePaths = []; + + /** @var int */ + public $maxDepth = 3; + + /** @var int */ + public $maxLength = 150; public function __construct() @@ -52,7 +58,41 @@ */ public function render($exception) { - $panels = $this->panels; + if (Helpers::isAjax() && session_status() === PHP_SESSION_ACTIVE) { + ob_start(function () {}); + $this->renderTemplate($exception, __DIR__ . '/assets/BlueScreen/content.phtml'); + $contentId = $_SERVER['HTTP_X_TRACY_AJAX']; + $queue = & $_SESSION['_tracy']['bluescreen']; + $queue = array_slice(array_filter((array) $queue), -5, NULL, TRUE); + $queue[$contentId] = ['content' => ob_get_clean(), 'dumps' => Dumper::fetchLiveData()]; + + } else { + $this->renderTemplate($exception, __DIR__ . '/assets/BlueScreen/page.phtml'); + } + } + + + /** + * Renders blue screen to file (if file exists, it will not be overwritten). + * @param \Exception|\Throwable + * @param string file path + * @return void + */ + public function renderToFile($exception, $file) + { + if ($handle = @fopen($file, 'x')) { + ob_start(); // double buffer prevents sending HTTP headers in some PHP + ob_start(function ($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096); + $this->renderTemplate($exception, __DIR__ . '/assets/BlueScreen/page.phtml'); + ob_end_flush(); + ob_end_clean(); + fclose($handle); + } + } + + + private function renderTemplate($exception, $template) + { $info = array_filter($this->info); $source = Helpers::getSource(); $sourceIsUrl = preg_match('#^https?://#', $source); @@ -62,8 +102,48 @@ $skipError = $sourceIsUrl && $exception instanceof \ErrorException && !empty($exception->skippable) ? $source . (strpos($source, '?') ? '&' : '?') . '_tracy_skip_error' : NULL; + $lastError = $exception instanceof \ErrorException || $exception instanceof \Error ? NULL : error_get_last(); + $dump = function($v) { + return Dumper::toHtml($v, [ + Dumper::DEPTH => $this->maxDepth, + Dumper::TRUNCATE => $this->maxLength, + Dumper::LIVE => TRUE, + Dumper::LOCATION => Dumper::LOCATION_CLASS, + ]); + }; - require __DIR__ . '/assets/BlueScreen/bluescreen.phtml'; + require $template; + } + + + /** + * @return \stdClass[] + */ + private function renderPanels($ex) + { + $obLevel = ob_get_level(); + $res = []; + foreach ($this->panels as $callback) { + try { + $panel = call_user_func($callback, $ex); + if (empty($panel['tab']) || empty($panel['panel'])) { + continue; + } + $res[] = (object) $panel; + continue; + } catch (\Throwable $e) { + } catch (\Exception $e) { + } + while (ob_get_level() > $obLevel) { // restore ob-level if broken + ob_end_clean(); + } + is_callable($callback, TRUE, $name); + $res[] = (object) [ + 'tab' => "Error in panel $name", + 'panel' => nl2br(Helpers::escapeHtml($e)), + ]; + } + return $res; } @@ -80,7 +160,7 @@ if ($source) { $source = static::highlightPhp($source, $line, $lines, $vars); if ($editor = Helpers::editorUri($file, $line)) { - $source = substr_replace($source, ' data-tracy-href="' . htmlspecialchars($editor, ENT_QUOTES, 'UTF-8') . '"', 4, 0); + $source = substr_replace($source, ' data-tracy-href="' . Helpers::escapeHtml($editor) . '"', 4, 0); } return $source; } @@ -104,7 +184,7 @@ ini_set('highlight.string', '#080'); } - $source = str_replace(array("\r\n", "\r"), "\n", $source); + $source = str_replace(["\r\n", "\r"], "\n", $source); $source = explode("\n", highlight_string($source, TRUE)); $out = $source[0]; // $source = str_replace('
', "\n", $source[1]); @@ -114,14 +194,14 @@ $out = preg_replace_callback('#">\$(\w+)( )?
#', function ($m) use ($vars) { return array_key_exists($m[1], $vars) ? '" title="' - . str_replace('"', '"', trim(strip_tags(Dumper::toHtml($vars[$m[1]], array(Dumper::DEPTH => 1))))) + . str_replace('"', '"', trim(strip_tags(Dumper::toHtml($vars[$m[1]], [Dumper::DEPTH => 1])))) . $m[0] : $m[0]; }, $out); } $out = str_replace(' ', ' ', $out); - return "
$out
"; + return "
$out
"; } @@ -135,7 +215,7 @@ $source = explode("\n", "\n" . str_replace("\r\n", "\n", $html)); $out = ''; $spans = 1; - $start = $i = max(1, $line - floor($lines * 2 / 3)); + $start = $i = max(1, min($line, count($source) - 1) - floor($lines * 2 / 3)); while (--$i >= 1) { // find last highlighted block if (preg_match('#.*(]*>)#', $source[$i], $m)) { if ($m[1] !== '
') { @@ -152,7 +232,7 @@ foreach ($source as $n => $s) { $spans += substr_count($s, ']+>#', $s, $tags); if ($n == $line) { $out .= sprintf( diff -Nru php-nette-2.3.10/Nette/Tracy/Debugger.php php-nette-2.4-20160731/Nette/Tracy/Debugger.php --- php-nette-2.3.10/Nette/Tracy/Debugger.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/Debugger.php 2016-07-31 17:46:44.000000000 +0000 @@ -16,9 +16,9 @@ */ class Debugger { - const VERSION = '2.3.10'; + const VERSION = '2.4.2'; - /** server modes {@link Debugger::enable()} */ + /** server modes for Debugger::enable() */ const DEVELOPMENT = FALSE, PRODUCTION = TRUE, @@ -26,16 +26,13 @@ const COOKIE_SECRET = 'tracy-debug'; - /** @deprecated */ - public static $version = self::VERSION; - /** @var bool in production mode is suppressed any debugging output */ public static $productionMode = self::DETECT; /** @var bool whether to display debug bar in development mode */ public static $showBar = TRUE; - /** @var bool {@link Debugger::enable()} */ + /** @var bool */ private static $enabled = FALSE; /** @var string reserved memory; also prevents double rendering */ @@ -46,26 +43,29 @@ /********************* errors and exceptions reporting ****************d*g**/ - /** @var bool|int determines whether any error will cause immediate death; if integer that it's matched against error severity */ + /** @var bool|int determines whether any error will cause immediate death in development mode; if integer that it's matched against error severity */ public static $strictMode = FALSE; /** @var bool disables the @ (shut-up) operator so that notices and warnings are no longer hidden */ public static $scream = FALSE; /** @var array of callables specifies the functions that are automatically called after fatal error */ - public static $onFatalError = array(); + public static $onFatalError = []; /********************* Debugger::dump() ****************d*g**/ - /** @var int how many nested levels of array/object properties display {@link Debugger::dump()} */ + /** @var int how many nested levels of array/object properties display by dump() */ public static $maxDepth = 3; - /** @var int how long strings display {@link Debugger::dump()} */ - public static $maxLen = 150; + /** @var int how long strings display by dump() */ + public static $maxLength = 150; - /** @var bool display location? {@link Debugger::dump()} */ + /** @var bool display location by dump()? */ public static $showLocation = FALSE; + /** @deprecated */ + public static $maxLen = 150; + /********************* logging ****************d*g**/ /** @var string name of the directory where errors should be logged */ @@ -77,7 +77,7 @@ /** @var string|array email(s) to which send error notifications */ public static $email; - /** {@link Debugger::log()} and {@link Debugger::fireLog()} */ + /** for Debugger::log() and Debugger::fireLog() */ const DEBUG = ILogger::DEBUG, INFO = ILogger::INFO, @@ -91,12 +91,12 @@ /** @var int timestamp with microseconds of the start of the request */ public static $time; - /** @deprecated */ - public static $source; - /** @var string URI pattern mask to open editor */ public static $editor = 'editor://open/?file=%file&line=%line'; + /** @var array replacements in path */ + public static $editorMapping = []; + /** @var string command to open browser (use 'start ""' in Windows) */ public static $browser; @@ -143,6 +143,7 @@ self::$productionMode = is_bool($mode) ? $mode : !self::detectDebugMode($mode); } + self::$maxLen = & self::$maxLength; self::$reserved = str_repeat('t', 3e5); self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE); self::$obLevel = ob_get_level(); @@ -173,17 +174,61 @@ ) { self::exceptionHandler(new \RuntimeException("Unable to set 'display_errors' because function ini_set() is disabled.")); } - error_reporting(E_ALL | E_STRICT); + error_reporting(E_ALL); + + if (self::$enabled) { + return; + } + self::$enabled = TRUE; + + register_shutdown_function([__CLASS__, 'shutdownHandler']); + set_exception_handler([__CLASS__, 'exceptionHandler']); + set_error_handler([__CLASS__, 'errorHandler']); + + array_map('class_exists', ['Tracy\Bar', 'Tracy\BlueScreen', 'Tracy\DefaultBarPanel', 'Tracy\Dumper', + 'Tracy\FireLogger', 'Tracy\Helpers', 'Tracy\Logger']); + + if (self::$productionMode) { + + } elseif (headers_sent($file, $line) || ob_get_length()) { + throw new \LogicException( + __METHOD__ . '() called after some output has been sent. ' + . ($file ? "Output started at $file:$line." : 'Try Tracy\OutputDebugger to find where output started.') + ); + + } elseif (self::getBar()->dispatchAssets()) { + exit; + + } elseif (session_status() === PHP_SESSION_ACTIVE) { + self::dispatch(); + } + } + - if (!self::$enabled) { - register_shutdown_function(array(__CLASS__, 'shutdownHandler')); - set_exception_handler(array(__CLASS__, 'exceptionHandler')); - set_error_handler(array(__CLASS__, 'errorHandler')); + /** + * @return void + */ + public static function dispatch() + { + if (self::$productionMode) { + return; - array_map('class_exists', array('Tracy\Bar', 'Tracy\BlueScreen', 'Tracy\DefaultBarPanel', 'Tracy\Dumper', - 'Tracy\FireLogger', 'Tracy\Helpers', 'Tracy\Logger')); + } elseif (headers_sent($file, $line) || ob_get_length()) { + throw new \LogicException( + __METHOD__ . '() called after some output has been sent. ' + . ($file ? "Output started at $file:$line." : 'Try Tracy\OutputDebugger to find where output started.') + ); - self::$enabled = TRUE; + } elseif (session_status() !== PHP_SESSION_ACTIVE) { + ini_set('session.use_cookies', '1'); + ini_set('session.use_only_cookies', '1'); + ini_set('session.use_trans_sid', '0'); + ini_set('session.cookie_path', '/'); + ini_set('session.cookie_httponly', '1'); + session_start(); + } + if (self::getBar()->dispatchContent()) { + exit; } } @@ -209,13 +254,13 @@ } $error = error_get_last(); - if (in_array($error['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, E_RECOVERABLE_ERROR, E_USER_ERROR), TRUE)) { + if (in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, E_RECOVERABLE_ERROR, E_USER_ERROR], TRUE)) { self::exceptionHandler( Helpers::fixStack(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line'])), FALSE ); - } elseif (self::$showBar && !connection_aborted() && !self::$productionMode && self::isHtmlMode()) { + } elseif (self::$showBar && !self::$productionMode) { self::$reserved = NULL; self::removeOutputBuffers(FALSE); self::getBar()->render(); @@ -240,7 +285,7 @@ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'; $code = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== FALSE ? 503 : 500; header("$protocol $code", TRUE, $code); - if (self::isHtmlMode()) { + if (Helpers::isHtmlMode()) { header('Content-Type: text/html; charset=UTF-8'); } } @@ -255,7 +300,7 @@ } catch (\Exception $e) { } - if (self::isHtmlMode()) { + if (Helpers::isHtmlMode()) { $logged = empty($e); require self::$errorTemplate ?: __DIR__ . '/assets/Debugger/error.500.phtml'; } elseif (PHP_SAPI === 'cli') { @@ -263,7 +308,7 @@ . (isset($e) ? "Unable to log error.\n" : "Error was logged.\n")); } - } elseif (!connection_aborted() && self::isHtmlMode()) { + } elseif (!connection_aborted() && (Helpers::isHtmlMode() || Helpers::isAjax())) { self::getBlueScreen()->render($exception); if (self::$showBar) { self::getBar()->render(); @@ -307,7 +352,7 @@ } if ($exit) { - exit($exception instanceof \Error ? 255 : 254); + exit(255); } } @@ -321,11 +366,11 @@ public static function errorHandler($severity, $message, $file, $line, $context) { if (self::$scream) { - error_reporting(E_ALL | E_STRICT); + error_reporting(E_ALL); } if ($severity === E_RECOVERABLE_ERROR || $severity === E_USER_ERROR) { - if (Helpers::findTrace(debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE), '*::__toString')) { + if (Helpers::findTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), '*::__toString')) { $previous = isset($context['e']) && ($context['e'] instanceof \Exception || $context['e'] instanceof \Throwable) ? $context['e'] : NULL; $e = new ErrorException($message, 0, $severity, $file, $line, $previous); $e->context = $context; @@ -374,25 +419,16 @@ } else { self::fireLog(new ErrorException($message, 0, $severity, $file, $line)); - return self::isHtmlMode() ? NULL : FALSE; // FALSE calls normal error handler + return Helpers::isHtmlMode() || Helpers::isAjax() ? NULL : FALSE; // FALSE calls normal error handler } } - private static function isHtmlMode() - { - return empty($_SERVER['HTTP_X_REQUESTED_WITH']) - && PHP_SAPI !== 'cli' - && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list())); - } - - private static function removeOutputBuffers($errorOccurred) { while (ob_get_level() > self::$obLevel) { - $tmp = ob_get_status(TRUE); - $status = end($tmp); - if (in_array($status['name'], array('ob_gzhandler', 'zlib output compression'))) { + $status = ob_get_status(); + if (in_array($status['name'], ['ob_gzhandler', 'zlib output compression'])) { break; } $fnc = $status['chunk_size'] || !$errorOccurred ? 'ob_end_flush' : 'ob_end_clean'; @@ -413,11 +449,11 @@ { if (!self::$blueScreen) { self::$blueScreen = new BlueScreen; - self::$blueScreen->info = array( + self::$blueScreen->info = [ 'PHP ' . PHP_VERSION, isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : NULL, 'Tracy ' . self::VERSION, - ); + ]; } return self::$blueScreen; } @@ -487,18 +523,18 @@ { if ($return) { ob_start(function () {}); - Dumper::dump($var, array( + Dumper::dump($var, [ Dumper::DEPTH => self::$maxDepth, - Dumper::TRUNCATE => self::$maxLen, - )); + Dumper::TRUNCATE => self::$maxLength, + ]); return ob_get_clean(); } elseif (!self::$productionMode) { - Dumper::dump($var, array( + Dumper::dump($var, [ Dumper::DEPTH => self::$maxDepth, - Dumper::TRUNCATE => self::$maxLen, + Dumper::TRUNCATE => self::$maxLength, Dumper::LOCATION => self::$showLocation, - )); + ]); } return $var; @@ -512,7 +548,7 @@ */ public static function timer($name = NULL) { - static $time = array(); + static $time = []; $now = microtime(TRUE); $delta = isset($time[$name]) ? $now - $time[$name] : 0; $time[$name] = $now; @@ -533,13 +569,13 @@ if (!self::$productionMode) { static $panel; if (!$panel) { - self::getBar()->addPanel($panel = new DefaultBarPanel('dumps')); + self::getBar()->addPanel($panel = new DefaultBarPanel('dumps'), 'Tracy:dumps'); } - $panel->data[] = array('title' => $title, 'dump' => Dumper::toHtml($var, (array) $options + array( + $panel->data[] = ['title' => $title, 'dump' => Dumper::toHtml($var, (array) $options + [ Dumper::DEPTH => self::$maxDepth, - Dumper::TRUNCATE => self::$maxLen, + Dumper::TRUNCATE => self::$maxLength, Dumper::LOCATION => self::$showLocation ?: Dumper::LOCATION_CLASS | Dumper::LOCATION_SOURCE, - ))); + ])]; } return $var; } diff -Nru php-nette-2.3.10/Nette/Tracy/Dumper.php php-nette-2.4-20160731/Nette/Tracy/Dumper.php --- php-nette-2.3.10/Nette/Tracy/Dumper.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/Dumper.php 2016-07-31 17:46:44.000000000 +0000 @@ -25,12 +25,12 @@ LIVE = 'live'; // will be rendered using JavaScript const - LOCATION_SOURCE = 1, // shows where dump was called - LOCATION_LINK = 2, // appends clickable anchor - LOCATION_CLASS = 4; // shows where class is defined + LOCATION_SOURCE = 0b0001, // shows where dump was called + LOCATION_LINK = 0b0010, // appends clickable anchor + LOCATION_CLASS = 0b0100; // shows where class is defined /** @var array */ - public static $terminalColors = array( + public static $terminalColors = [ 'bool' => '1;33', 'null' => '1;33', 'number' => '1;32', @@ -41,28 +41,28 @@ 'visibility' => '1;30', 'resource' => '1;37', 'indent' => '1;30', - ); + ]; /** @var array */ - public static $resources = array( + public static $resources = [ 'stream' => 'stream_get_meta_data', 'stream-context' => 'stream_context_get_options', 'curl' => 'curl_getinfo', - ); + ]; /** @var array */ - public static $objectExporters = array( + public static $objectExporters = [ 'Closure' => 'Tracy\Dumper::exportClosure', 'SplFileInfo' => 'Tracy\Dumper::exportSplFileInfo', 'SplObjectStorage' => 'Tracy\Dumper::exportSplObjectStorage', '__PHP_Incomplete_Class' => 'Tracy\Dumper::exportPhpIncompleteClass', - ); + ]; /** @var string @internal */ public static $livePrefix; /** @var array */ - private static $liveStorage = array(); + private static $liveStorage = []; /** @@ -88,19 +88,19 @@ */ public static function toHtml($var, array $options = NULL) { - $options = (array) $options + array( + $options = (array) $options + [ self::DEPTH => 4, self::TRUNCATE => 150, self::COLLAPSE => 14, self::COLLAPSE_COUNT => 7, self::OBJECT_EXPORTERS => NULL, - ); + ]; $loc = & $options[self::LOCATION]; $loc = $loc === TRUE ? ~0 : (int) $loc; $options[self::OBJECT_EXPORTERS] = (array) $options[self::OBJECT_EXPORTERS] + self::$objectExporters; uksort($options[self::OBJECT_EXPORTERS], function ($a, $b) { - return $b === '' || (class_exists($a, FALSE) && ($rc = new \ReflectionClass($a)) && $rc->isSubclassOf($b)) ? -1 : 1; + return $b === '' || (class_exists($a, FALSE) && is_subclass_of($a, $b)) ? -1 : 1; }); $live = !empty($options[self::LIVE]) && $var && (is_array($var) || is_object($var) || is_resource($var)); @@ -111,7 +111,7 @@ return '
" : '>')
+			. ($live ? " data-tracy-dump='" . json_encode(self::toJson($var, $options), JSON_HEX_APOS | JSON_HEX_AMP) . "'>" : '>')
 			. ($live ? '' : self::dumpVar($var, $options))
 			. ($file && $loc & self::LOCATION_LINK ? 'in ' . Helpers::editorLink($file, $line) . '' : '')
 			. "
\n"; @@ -135,7 +135,7 @@ public static function toTerminal($var, array $options = NULL) { return htmlspecialchars_decode(strip_tags(preg_replace_callback('#|#', function ($m) { - return "\033[" . (isset($m[1], Dumper::$terminalColors[$m[1]]) ? Dumper::$terminalColors[$m[1]] : '0') . 'm'; + return "\033[" . (isset($m[1], self::$terminalColors[$m[1]]) ? self::$terminalColors[$m[1]] : '0') . 'm'; }, self::toHtml($var, $options))), ENT_QUOTES); } @@ -187,7 +187,7 @@ private static function dumpString(& $var, $options) { return '"' - . htmlspecialchars(self::encodeString($var, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') + . Helpers::escapeHtml(self::encodeString($var, $options[self::TRUNCATE])) . '"' . (strlen($var) > 1 ? ' (' . strlen($var) . ')' : '') . "\n"; } @@ -215,7 +215,7 @@ $var[$marker] = TRUE; foreach ($var as $k => & $v) { if ($k !== $marker) { - $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"'; + $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . Helpers::escapeHtml(self::encodeString($k, $options[self::TRUNCATE])) . '"'; $out .= ' ' . str_repeat('| ', $level) . '' . '' . $k . ' => ' . self::dumpVar($v, $options, $level + 1); @@ -242,9 +242,9 @@ . ($editor ? Helpers::formatHtml( ' title="Declared in file % on line %" data-tracy-href="%"', $rc->getFileName(), $rc->getStartLine(), $editor ) : '') - . '>' . htmlspecialchars(Helpers::getClass($var)) . '
#' . substr(md5(spl_object_hash($var)), 0, 4) . ''; + . '>' . Helpers::escapeHtml(Helpers::getClass($var)) . ' #' . substr(md5(spl_object_hash($var)), 0, 4) . ''; - static $list = array(); + static $list = []; if (empty($fields)) { return $out . "\n"; @@ -264,7 +264,7 @@ $vis = ' ' . ($k[1] === '*' ? 'protected' : 'private') . ''; $k = substr($k, strrpos($k, "\x00") + 1); } - $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"'; + $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . Helpers::escapeHtml(self::encodeString($k, $options[self::TRUNCATE])) . '"'; $out .= ' ' . str_repeat('| ', $level) . '' . '' . $k . "$vis => " . self::dumpVar($v, $options, $level + 1); @@ -281,13 +281,13 @@ private static function dumpResource(& $var, $options, $level) { $type = get_resource_type($var); - $out = '' . htmlSpecialChars($type, ENT_IGNORE, 'UTF-8') . ' resource ' + $out = '' . Helpers::escapeHtml($type) . ' resource ' . '#' . intval($var) . ''; if (isset(self::$resources[$type])) { $out = "$out\n
"; foreach (call_user_func(self::$resources[$type], $var) as $k => $v) { $out .= ' ' . str_repeat('| ', $level) . '' - . '' . htmlSpecialChars($k, ENT_IGNORE, 'UTF-8') . ' => ' . self::dumpVar($v, $options, $level + 1); + . '' . Helpers::escapeHtml($k) . ' => ' . self::dumpVar($v, $options, $level + 1); } return $out . '
'; } @@ -305,8 +305,8 @@ } elseif (is_float($var)) { return is_finite($var) - ? (strpos($tmp = json_encode($var), '.') ? $var : array('number' => "$tmp.0")) - : array('type' => (string) $var); + ? (strpos($tmp = json_encode($var), '.') ? $var : ['number' => "$tmp.0"]) + : ['type' => (string) $var]; } elseif (is_string($var)) { return self::encodeString($var, $options[self::TRUNCATE]); @@ -317,14 +317,14 @@ $marker = uniqid("\x00", TRUE); } if (isset($var[$marker]) || $level >= $options[self::DEPTH]) { - return array(NULL); + return [NULL]; } - $res = array(); + $res = []; $var[$marker] = TRUE; foreach ($var as $k => & $v) { if ($k !== $marker) { $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"'; - $res[] = array($k, self::toJson($v, $options, $level + 1)); + $res[] = [$k, self::toJson($v, $options, $level + 1)]; } } unset($var[$marker]); @@ -333,7 +333,7 @@ } elseif (is_object($var)) { $obj = & self::$liveStorage[spl_object_hash($var)]; if ($obj && $obj['level'] <= $level) { - return array('object' => $obj['id']); + return ['object' => $obj['id']]; } if ($options[self::LOCATION] & self::LOCATION_CLASS) { @@ -341,17 +341,17 @@ $editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine()); } static $counter = 1; - $obj = $obj ?: array( + $obj = $obj ?: [ 'id' => self::$livePrefix . '0' . $counter++, // differentiate from resources 'name' => Helpers::getClass($var), - 'editor' => empty($editor) ? NULL : array('file' => $rc->getFileName(), 'line' => $rc->getStartLine(), 'url' => $editor), + 'editor' => empty($editor) ? NULL : ['file' => $rc->getFileName(), 'line' => $rc->getStartLine(), 'url' => $editor], 'level' => $level, 'object' => $var, - ); + ]; if ($level < $options[self::DEPTH] || !$options[self::DEPTH]) { $obj['level'] = $level; - $obj['items'] = array(); + $obj['items'] = []; foreach (self::exportObject($var, $options[self::OBJECT_EXPORTERS]) as $k => $v) { $vis = 0; @@ -360,26 +360,26 @@ $k = substr($k, strrpos($k, "\x00") + 1); } $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"'; - $obj['items'][] = array($k, self::toJson($v, $options, $level + 1), $vis); + $obj['items'][] = [$k, self::toJson($v, $options, $level + 1), $vis]; } } - return array('object' => $obj['id']); + return ['object' => $obj['id']]; } elseif (is_resource($var)) { $obj = & self::$liveStorage[(string) $var]; if (!$obj) { $type = get_resource_type($var); - $obj = array('id' => self::$livePrefix . (int) $var, 'name' => $type . ' resource'); + $obj = ['id' => self::$livePrefix . (int) $var, 'name' => $type . ' resource']; if (isset(self::$resources[$type])) { foreach (call_user_func(self::$resources[$type], $var) as $k => $v) { - $obj['items'][] = array($k, self::toJson($v, $options, $level + 1)); + $obj['items'][] = [$k, self::toJson($v, $options, $level + 1)]; } } } - return array('resource' => $obj['id']); + return ['resource' => $obj['id']]; } else { - return array('type' => 'unknown type'); + return ['type' => 'unknown type']; } } @@ -387,13 +387,13 @@ /** @return array */ public static function fetchLiveData() { - $res = array(); + $res = []; foreach (self::$liveStorage as $obj) { $id = $obj['id']; unset($obj['level'], $obj['object'], $obj['id']); $res[$id] = $obj; } - self::$liveStorage = array(); + self::$liveStorage = []; return $res; } @@ -421,14 +421,16 @@ } $s = strtr($s, $table); - } elseif ($shortened = ($maxLength && strlen(utf8_decode($s)) > $maxLength)) { + } elseif ($maxLength && $s !== '') { if (function_exists('iconv_substr')) { - $s = iconv_substr($s, 0, $maxLength, 'UTF-8'); + $s = iconv_substr($tmp = $s, 0, $maxLength, 'UTF-8'); + $shortened = $s !== $tmp; } else { $i = $len = 0; do { if (($s[$i] < "\x80" || $s[$i] >= "\xC0") && (++$len > $maxLength)) { $s = substr($s, 0, $i); + $shortened = TRUE; break; } } while (isset($s[++$i])); @@ -459,16 +461,16 @@ private static function exportClosure(\Closure $obj) { $rc = new \ReflectionFunction($obj); - $res = array(); + $res = []; foreach ($rc->getParameters() as $param) { $res[] = '$' . $param->getName(); } - return array( + return [ 'file' => $rc->getFileName(), 'line' => $rc->getStartLine(), 'variables' => $rc->getStaticVariables(), 'parameters' => implode(', ', $res), - ); + ]; } @@ -477,7 +479,7 @@ */ private static function exportSplFileInfo(\SplFileInfo $obj) { - return array('path' => $obj->getPathname()); + return ['path' => $obj->getPathname()]; } @@ -486,9 +488,9 @@ */ private static function exportSplObjectStorage(\SplObjectStorage $obj) { - $res = array(); + $res = []; foreach (clone $obj as $item) { - $res[] = array('object' => $item, 'data' => $obj[$item]); + $res[] = ['object' => $item, 'data' => $obj[$item]]; } return $res; } @@ -499,7 +501,7 @@ */ private static function exportPhpIncompleteClass(\__PHP_Incomplete_Class $obj) { - $info = array('className' => NULL, 'private' => array(), 'protected' => array(), 'public' => array()); + $info = ['className' => NULL, 'private' => [], 'protected' => [], 'public' => []]; foreach ((array) $obj as $name => $value) { if ($name === '__PHP_Incomplete_Class_Name') { $info['className'] = $value; @@ -521,7 +523,7 @@ */ private static function findLocation() { - foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) { + foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $item) { if (isset($item['class']) && $item['class'] === __CLASS__) { $location = $item; continue; @@ -543,11 +545,11 @@ if (isset($location['file'], $location['line']) && is_file($location['file'])) { $lines = file($location['file']); $line = $lines[$location['line'] - 1]; - return array( + return [ $location['file'], $location['line'], trim(preg_match('#\w*dump(er::\w+)?\(.*\)#i', $line, $m) ? $m[0] : $line), - ); + ]; } } diff -Nru php-nette-2.3.10/Nette/Tracy/FireLogger.php php-nette-2.4-20160731/Nette/Tracy/FireLogger.php --- php-nette-2.3.10/Nette/Tracy/FireLogger.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/FireLogger.php 2016-07-31 17:46:44.000000000 +0000 @@ -24,7 +24,7 @@ public $maxLength = 150; /** @var array */ - private $payload = array('logs' => array()); + private $payload = ['logs' => []]; /** @@ -38,7 +38,7 @@ return FALSE; } - $item = array( + $item = [ 'name' => 'PHP', 'level' => $priority, 'order' => count($this->payload['logs']), @@ -46,7 +46,7 @@ 'template' => '', 'message' => '', 'style' => 'background:#767ab6', - ); + ]; $args = func_get_args(); if (isset($args[0]) && is_string($args[0])) { @@ -85,23 +85,23 @@ } } - $item['exc_info'] = array('', '', array()); - $item['exc_frames'] = array(); + $item['exc_info'] = ['', '', []]; + $item['exc_frames'] = []; foreach ($trace as $frame) { - $frame += array('file' => NULL, 'line' => NULL, 'class' => NULL, 'type' => NULL, 'function' => NULL, 'object' => NULL, 'args' => NULL); - $item['exc_info'][2][] = array($frame['file'], $frame['line'], "$frame[class]$frame[type]$frame[function]", $frame['object']); + $frame += ['file' => NULL, 'line' => NULL, 'class' => NULL, 'type' => NULL, 'function' => NULL, 'object' => NULL, 'args' => NULL]; + $item['exc_info'][2][] = [$frame['file'], $frame['line'], "$frame[class]$frame[type]$frame[function]", $frame['object']]; $item['exc_frames'][] = $frame['args']; } - if (isset($args[0]) && in_array($args[0], array(self::DEBUG, self::INFO, self::WARNING, self::ERROR, self::CRITICAL), TRUE)) { + if (isset($args[0]) && in_array($args[0], [self::DEBUG, self::INFO, self::WARNING, self::ERROR, self::CRITICAL], TRUE)) { $item['level'] = array_shift($args); } $item['args'] = $args; $this->payload['logs'][] = $this->jsonDump($item, -1); - foreach (str_split(base64_encode(@json_encode($this->payload)), 4990) as $k => $v) { // intentionally @ + foreach (str_split(base64_encode(json_encode($this->payload)), 4990) as $k => $v) { header("FireLogger-de11e-$k:$v"); } return TRUE; @@ -132,7 +132,7 @@ } elseif ($level < $this->maxDepth || !$this->maxDepth) { $var[$marker] = TRUE; - $res = array(); + $res = []; foreach ($var as $k => & $v) { if ($k !== $marker) { $res[$this->jsonDump($k)] = $this->jsonDump($v, $level + 1); @@ -147,13 +147,13 @@ } elseif (is_object($var)) { $arr = (array) $var; - static $list = array(); + static $list = []; if (in_array($var, $list, TRUE)) { return "\xE2\x80\xA6RECURSION\xE2\x80\xA6"; } elseif ($level < $this->maxDepth || !$this->maxDepth) { $list[] = $var; - $res = array("\x00" => '(object) ' . Helpers::getClass($var)); + $res = ["\x00" => '(object) ' . Helpers::getClass($var)]; foreach ($arr as $k => & $v) { if (isset($k[0]) && $k[0] === "\x00") { $k = substr($k, strrpos($k, "\x00") + 1); diff -Nru php-nette-2.3.10/Nette/Tracy/Helpers.php php-nette-2.4-20160731/Nette/Tracy/Helpers.php --- php-nette-2.3.10/Nette/Tracy/Helpers.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/Helpers.php 2016-07-31 17:46:44.000000000 +0000 @@ -20,7 +20,8 @@ */ public static function editorLink($file, $line = NULL) { - if ($editor = self::editorUri($file, $line)) { + $file = strtr($origFile = $file, Debugger::$editorMapping); + if ($editor = self::editorUri($origFile, $line)) { $file = strtr($file, '\\', '/'); if (preg_match('#(^[a-z]:)?/.{1,50}$#i', $file, $m) && strlen($file) > strlen($m[0])) { $file = '...' . $m[0]; @@ -46,7 +47,8 @@ public static function editorUri($file, $line = NULL) { if (Debugger::$editor && $file && is_file($file)) { - return strtr(Debugger::$editor, array('%file' => rawurlencode($file), '%line' => $line ? (int) $line : 1)); + $file = strtr($file, Debugger::$editorMapping); + return strtr(Debugger::$editor, ['%file' => rawurlencode($file), '%line' => $line ? (int) $line : 1]); } } @@ -55,18 +57,24 @@ { $args = func_get_args(); return preg_replace_callback('#%#', function () use (& $args, & $count) { - return htmlspecialchars($args[++$count], ENT_IGNORE | ENT_QUOTES, 'UTF-8'); + return Helpers::escapeHtml($args[++$count]); }, $mask); } + public static function escapeHtml($s) + { + return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); + } + + public static function findTrace(array $trace, $method, & $index = NULL) { $m = explode('::', $method); foreach ($trace as $i => $item) { if (isset($item['function']) && $item['function'] === end($m) && isset($item['class']) === isset($m[1]) - && (!isset($item['class']) || $item['class'] === $m[0] || $m[0] === '*' || is_subclass_of($item['class'], $m[0])) + && (!isset($item['class']) || $m[0] === '*' || is_a($item['class'], $m[0], TRUE)) ) { $index = $i; return $item; @@ -80,7 +88,7 @@ */ public static function getClass($obj) { - return current(explode("\x00", get_class($obj))); + return explode("\x00", get_class($obj))[0]; } @@ -88,14 +96,14 @@ public static function fixStack($exception) { if (function_exists('xdebug_get_function_stack')) { - $stack = array(); + $stack = []; foreach (array_slice(array_reverse(xdebug_get_function_stack()), 2, -1) as $row) { - $frame = array( + $frame = [ 'file' => $row['file'], 'line' => $row['line'], 'function' => isset($row['function']) ? $row['function'] : '*unknown*', - 'args' => array(), - ); + 'args' => [], + ]; if (!empty($row['class'])) { $frame['type'] = isset($row['type']) && $row['type'] === 'dynamic' ? '->' : '::'; $frame['class'] = $row['class']; @@ -113,18 +121,14 @@ /** @internal */ public static function fixEncoding($s) { - if (PHP_VERSION_ID < 50400) { - return @iconv('UTF-16', 'UTF-8//IGNORE', iconv('UTF-8', 'UTF-16//IGNORE', $s)); // intentionally @ - } else { - return htmlspecialchars_decode(htmlspecialchars($s, ENT_NOQUOTES | ENT_IGNORE, 'UTF-8'), ENT_NOQUOTES); - } + return htmlspecialchars_decode(htmlspecialchars($s, ENT_NOQUOTES | ENT_IGNORE, 'UTF-8'), ENT_NOQUOTES); } /** @internal */ public static function errorTypeToString($type) { - $types = array( + $types = [ E_ERROR => 'Fatal Error', E_USER_ERROR => 'User Error', E_RECOVERABLE_ERROR => 'Recoverable Error', @@ -140,7 +144,7 @@ E_STRICT => 'Strict standards', E_DEPRECATED => 'Deprecated', E_USER_DEPRECATED => 'User Deprecated', - ); + ]; return isset($types[$type]) ? $types[$type] : 'Unknown error'; } @@ -153,7 +157,8 @@ . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '') . $_SERVER['REQUEST_URI']; } else { - return empty($_SERVER['argv']) ? 'CLI' : 'CLI: ' . implode(' ', $_SERVER['argv']); + return 'CLI (PID: ' . getmypid() . ')' + . (empty($_SERVER['argv']) ? '' : ': ' . implode(' ', $_SERVER['argv'])); } } @@ -165,8 +170,7 @@ if (!$e instanceof \Error && !$e instanceof \ErrorException) { // do nothing } elseif (preg_match('#^Call to undefined function (\S+\\\\)?(\w+)\(#', $message, $m)) { - $funcs = get_defined_functions(); - $funcs = array_merge($funcs['internal'], $funcs['user']); + $funcs = array_merge(get_defined_functions()['internal'], get_defined_functions()['user']); $hint = self::getSuggestion($funcs, $m[1] . $m[2]) ?: self::getSuggestion($funcs, $m[2]); $message .= ", did you mean $hint()?"; @@ -218,4 +222,20 @@ return $best; } + + /** @internal */ + public static function isHtmlMode() + { + return empty($_SERVER['HTTP_X_REQUESTED_WITH']) && empty($_SERVER['HTTP_X_TRACY_AJAX']) + && PHP_SAPI !== 'cli' + && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list())); + } + + + /** @internal */ + public static function isAjax() + { + return isset($_SERVER['HTTP_X_TRACY_AJAX']) && preg_match('#^\w{10}\z#', $_SERVER['HTTP_X_TRACY_AJAX']); + } + } diff -Nru php-nette-2.3.10/Nette/Tracy/Logger.php php-nette-2.4-20160731/Nette/Tracy/Logger.php --- php-nette-2.3.10/Nette/Tracy/Logger.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/Logger.php 2016-07-31 17:46:44.000000000 +0000 @@ -37,7 +37,7 @@ $this->directory = $directory; $this->email = $email; $this->blueScreen = $blueScreen; - $this->mailer = array($this, 'defaultMailer'); + $this->mailer = [$this, 'defaultMailer']; } @@ -69,7 +69,7 @@ $this->logException($message, $exceptionFile); } - if (in_array($priority, array(self::ERROR, self::EXCEPTION, self::CRITICAL), TRUE)) { + if (in_array($priority, [self::ERROR, self::EXCEPTION, self::CRITICAL], TRUE)) { $this->sendEmail($message); } @@ -107,12 +107,12 @@ */ protected function formatLogLine($message, $exceptionFile = NULL) { - return implode(' ', array( + return implode(' ', [ @date('[Y-m-d H-i-s]'), // @ timezone may not be set preg_replace('#\s*\r?\n\s*#', ' ', $this->formatMessage($message)), ' @ ' . Helpers::getSource(), $exceptionFile ? ' @@ ' . basename($exceptionFile) : NULL, - )); + ]); } @@ -141,15 +141,8 @@ protected function logException($exception, $file = NULL) { $file = $file ?: $this->getExceptionFile($exception); - if ($handle = @fopen($file, 'x')) { // @ file may already exist - ob_start(); // double buffer prevents sending HTTP headers in some PHP - ob_start(function ($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096); - $bs = $this->blueScreen ?: new BlueScreen; - $bs->render($exception); - ob_end_flush(); - ob_end_clean(); - fclose($handle); - } + $bs = $this->blueScreen ?: new BlueScreen; + $bs->renderToFile($exception, $file); return $file; } @@ -184,18 +177,18 @@ { $host = preg_replace('#[^\w.-]+#', '', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n')); $parts = str_replace( - array("\r\n", "\n"), - array("\n", PHP_EOL), - array( - 'headers' => implode("\n", array( + ["\r\n", "\n"], + ["\n", PHP_EOL], + [ + 'headers' => implode("\n", [ 'From: ' . ($this->fromEmail ?: "noreply@$host"), 'X-Mailer: Tracy', 'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: 8bit', - )) . "\n", + ]) . "\n", 'subject' => "PHP: An error occurred on the server $host", 'body' => $this->formatMessage($message) . "\n\nsource: " . Helpers::getSource(), - ) + ] ); mail($email, $parts['subject'], $parts['body'], $parts['headers']); diff -Nru php-nette-2.3.10/Nette/Tracy/OutputDebugger.php php-nette-2.4-20160731/Nette/Tracy/OutputDebugger.php --- php-nette-2.3.10/Nette/Tracy/OutputDebugger.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Tracy/OutputDebugger.php 2016-07-31 17:46:44.000000000 +0000 @@ -16,7 +16,7 @@ const BOM = "\xEF\xBB\xBF"; /** @var array of [file, line, output, stack] */ - private $list = array(); + private $list = []; public static function enable() @@ -30,17 +30,17 @@ { foreach (get_included_files() as $file) { if (fread(fopen($file, 'r'), 3) === self::BOM) { - $this->list[] = array($file, 1, self::BOM); + $this->list[] = [$file, 1, self::BOM]; } } - ob_start(array($this, 'handler'), PHP_VERSION_ID >= 50400 ? 1 : 2); + ob_start([$this, 'handler'], 1); } /** @internal */ public function handler($s, $phase) { - $trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); if (isset($trace[0]['file'], $trace[0]['line'])) { $stack = $trace; unset($stack[0]['line'], $stack[0]['args']); @@ -48,7 +48,7 @@ if ($i && $this->list[$i - 1][3] === $stack) { $this->list[$i - 1][2] .= $s; } else { - $this->list[] = array($trace[0]['file'], $trace[0]['line'], $s, $stack); + $this->list[] = [$trace[0]['file'], $trace[0]['line'], $s, $stack]; } } if ($phase === PHP_OUTPUT_HANDLER_FINAL) { @@ -61,15 +61,15 @@ { $res = ''; foreach ($this->list as $item) { - $stack = array(); + $stack = []; foreach (array_slice($item[3], 1) as $t) { - $t += array('class' => '', 'type' => '', 'function' => ''); + $t += ['class' => '', 'type' => '', 'function' => '']; $stack[] = "$t[class]$t[type]$t[function]()" . (isset($t['file'], $t['line']) ? ' in ' . basename($t['file']) . ":$t[line]" : ''); } - $res .= Helpers::editorLink($item[0], $item[1]) . ' ' - . '' + $res .= '' + . Helpers::editorLink($item[0], $item[1]) . ' ' . str_replace(self::BOM, 'BOM', Dumper::toHtml($item[2])) . "
\n"; } diff -Nru php-nette-2.3.10/Nette/Utils/ArrayList.php php-nette-2.4-20160731/Nette/Utils/ArrayList.php --- php-nette-2.3.10/Nette/Utils/ArrayList.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/ArrayList.php 2016-07-31 17:46:44.000000000 +0000 @@ -13,9 +13,11 @@ /** * Provides the base class for a generic list (items can be accessed by index). */ -class ArrayList extends Nette\Object implements \ArrayAccess, \Countable, \IteratorAggregate +class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate { - private $list = array(); + use Nette\SmartObject; + + private $list = []; /** @@ -99,4 +101,17 @@ array_splice($this->list, (int) $index, 1); } + + /** + * Prepends a item. + * @param mixed + * @return void + */ + public function prepend($value) + { + $first = array_slice($this->list, 0, 1); + $this->offsetSet(0, $value); + array_splice($this->list, 1, 0, $first); + } + } diff -Nru php-nette-2.3.10/Nette/Utils/Arrays.php php-nette-2.4-20160731/Nette/Utils/Arrays.php --- php-nette-2.3.10/Nette/Utils/Arrays.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Arrays.php 2016-07-31 17:46:44.000000000 +0000 @@ -15,15 +15,7 @@ */ class Arrays { - - /** - * Static class - cannot be instantiated. - */ - final public function __construct() - { - throw new Nette\StaticClassException; - } - + use Nette\StaticClass; /** * Returns item from array or $default if item is not set. @@ -35,7 +27,7 @@ */ public static function get(array $arr, $key, $default = NULL) { - foreach (is_array($key) ? $key : array($key) as $k) { + foreach (is_array($key) ? $key : [$key] as $k) { if (is_array($arr) && array_key_exists($k, $arr)) { $arr = $arr[$k]; } else { @@ -56,9 +48,9 @@ * @return mixed * @throws Nette\InvalidArgumentException if traversed item is not an array */ - public static function & getRef(& $arr, $key) + public static function & getRef(array & $arr, $key) { - foreach (is_array($key) ? $key : array($key) as $k) { + foreach (is_array($key) ? $key : [$key] as $k) { if (is_array($arr) || $arr === NULL) { $arr = & $arr[$k]; } else { @@ -73,7 +65,7 @@ * Recursively appends elements of remaining keys from the second array to the first. * @return array */ - public static function mergeTree($arr1, $arr2) + public static function mergeTree(array $arr1, array $arr2) { $res = $arr1 + $arr2; foreach (array_intersect_key($arr1, $arr2) as $k => $v) { @@ -89,9 +81,9 @@ * Searches the array for a given key and returns the offset if successful. * @return int|FALSE offset if it is found, FALSE otherwise */ - public static function searchKey($arr, $key) + public static function searchKey(array $arr, $key) { - $foo = array($key => NULL); + $foo = [$key => NULL]; return array_search(key($foo), array_keys($arr), TRUE); } @@ -102,7 +94,7 @@ */ public static function insertBefore(array & $arr, $key, array $inserted) { - $offset = self::searchKey($arr, $key); + $offset = (int) self::searchKey($arr, $key); $arr = array_slice($arr, 0, $offset, TRUE) + $inserted + array_slice($arr, $offset, count($arr), TRUE); } @@ -140,7 +132,7 @@ */ public static function grep(array $arr, $pattern, $flags = 0) { - return Strings::pcre('preg_grep', array($pattern, $arr, $flags)); + return Strings::pcre('preg_grep', [$pattern, $arr, $flags]); } @@ -150,7 +142,7 @@ */ public static function flatten(array $arr, $preserveKeys = FALSE) { - $res = array(); + $res = []; $cb = $preserveKeys ? function ($v, $k) use (& $res) { $res[$k] = $v; } : function ($v) use (& $res) { $res[] = $v; }; @@ -177,13 +169,13 @@ { $parts = is_array($path) ? $path - : preg_split('#(\[\]|->|=|\|)#', $path, NULL, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + : preg_split('#(\[\]|->|=|\|)#', $path, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - if (!$parts || $parts[0] === '=' || $parts[0] === '|' || $parts === array('->')) { + if (!$parts || $parts[0] === '=' || $parts[0] === '|' || $parts === ['->']) { throw new Nette\InvalidArgumentException("Invalid path '$path'."); } - $res = $parts[0] === '->' ? new \stdClass : array(); + $res = $parts[0] === '->' ? new \stdClass : []; foreach ($arr as $rowOrig) { $row = (array) $rowOrig; @@ -227,7 +219,7 @@ */ public static function normalize(array $arr, $filling = NULL) { - $res = array(); + $res = []; foreach ($arr as $k => $v) { $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v; } diff -Nru php-nette-2.3.10/Nette/Utils/Callback.php php-nette-2.4-20160731/Nette/Utils/Callback.php --- php-nette-2.3.10/Nette/Utils/Callback.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Callback.php 2016-07-31 17:46:44.000000000 +0000 @@ -15,6 +15,7 @@ */ class Callback { + use Nette\StaticClass; /** * @param mixed class, object, callable @@ -24,7 +25,7 @@ public static function closure($callable, $m = NULL) { if ($m !== NULL) { - $callable = array($callable, $m); + $callable = [$callable, $m]; } elseif (is_string($callable) && count($tmp = explode('::', $callable)) === 2) { $callable = $tmp; @@ -33,24 +34,20 @@ return $callable; } elseif (is_object($callable)) { - $callable = array($callable, '__invoke'); + $callable = [$callable, '__invoke']; } - if (PHP_VERSION_ID >= 50400) { - if (is_string($callable) && function_exists($callable)) { - $r = new \ReflectionFunction($callable); - return $r->getClosure(); + if (is_string($callable) && function_exists($callable)) { + return (new \ReflectionFunction($callable))->getClosure(); - } elseif (is_array($callable) && method_exists($callable[0], $callable[1])) { - $r = new \ReflectionMethod($callable[0], $callable[1]); - return $r->getClosure($callable[0]); - } + } elseif (is_array($callable) && method_exists($callable[0], $callable[1])) { + return (new \ReflectionMethod($callable[0], $callable[1]))->getClosure($callable[0]); } self::check($callable); $_callable_ = $callable; - return function () use ($_callable_) { - return call_user_func_array($_callable_, func_get_args()); + return function (...$args) use ($_callable_) { + return $_callable_(...$args); }; } @@ -59,10 +56,10 @@ * Invokes callback. * @return mixed */ - public static function invoke($callable) + public static function invoke($callable, ...$args) { self::check($callable); - return call_user_func_array($callable, array_slice(func_get_args(), 1)); + return call_user_func_array($callable, $args); } @@ -70,7 +67,7 @@ * Invokes callback with an array of parameters. * @return mixed */ - public static function invokeArgs($callable, array $args = array()) + public static function invokeArgs($callable, array $args = []) { self::check($callable); return call_user_func_array($callable, $args); @@ -84,9 +81,9 @@ */ public static function invokeSafe($function, array $args, $onError) { - $prev = set_error_handler(function ($severity, $message, $file, $line, $context = NULL, $stack = NULL) use ($onError, & $prev, $function) { + $prev = set_error_handler(function ($severity, $message, $file) use ($onError, & $prev, $function) { if ($file === '' && defined('HHVM_VERSION')) { // https://github.com/facebook/hhvm/issues/4625 - $file = $stack[1]['file']; + $file = func_get_arg(5)[1]['file']; } if ($file === __FILE__) { $msg = preg_replace("#^$function\(.*?\): #", '', $message); @@ -94,11 +91,11 @@ return; } } - return $prev ? call_user_func_array($prev, func_get_args()) : FALSE; + return $prev ? $prev(...func_get_args()) : FALSE; }); try { - $res = call_user_func_array($function, $args); + $res = $function(...$args); restore_error_handler(); return $res; @@ -152,10 +149,11 @@ if ($callable instanceof \Closure) { $callable = self::unwrap($callable); } elseif ($callable instanceof Nette\Callback) { + trigger_error('Nette\Callback is deprecated.', E_USER_DEPRECATED); $callable = $callable->getNative(); } - $class = class_exists('Nette\Reflection\Method') ? 'Nette\Reflection\Method' : 'ReflectionMethod'; + $class = class_exists(Nette\Reflection\Method::class) ? Nette\Reflection\Method::class : 'ReflectionMethod'; if (is_string($callable) && strpos($callable, '::')) { return new $class($callable); } elseif (is_array($callable)) { @@ -163,7 +161,7 @@ } elseif (is_object($callable) && !$callable instanceof \Closure) { return new $class($callable, '__invoke'); } else { - $class = class_exists('Nette\Reflection\GlobalFunction') ? 'Nette\Reflection\GlobalFunction' : 'ReflectionFunction'; + $class = class_exists(Nette\Reflection\GlobalFunction::class) ? Nette\Reflection\GlobalFunction::class : 'ReflectionFunction'; return new $class($callable); } } @@ -191,10 +189,10 @@ return isset($vars['_callable_']) ? $vars['_callable_'] : $closure; } elseif ($obj = $r->getClosureThis()) { - return array($obj, $r->getName()); + return [$obj, $r->getName()]; } elseif ($class = $r->getClosureScopeClass()) { - return array($class->getName(), $r->getName()); + return [$class->getName(), $r->getName()]; } else { return $r->getName(); diff -Nru php-nette-2.3.10/Nette/Utils/DateTime.php php-nette-2.4-20160731/Nette/Utils/DateTime.php --- php-nette-2.3.10/Nette/Utils/DateTime.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/DateTime.php 2016-07-31 17:46:44.000000000 +0000 @@ -13,19 +13,21 @@ /** * DateTime. */ -class DateTime extends \DateTime +class DateTime extends \DateTime implements \JsonSerializable { + use Nette\SmartObject; + /** minute in seconds */ const MINUTE = 60; /** hour in seconds */ - const HOUR = 3600; + const HOUR = 60 * self::MINUTE; /** day in seconds */ - const DAY = 86400; + const DAY = 24 * self::HOUR; /** week in seconds */ - const WEEK = 604800; + const WEEK = 7 * self::DAY; /** average month in seconds */ const MONTH = 2629800; @@ -36,20 +38,19 @@ /** * DateTime object factory. - * @param string|int|\DateTime + * @param string|int|\DateTimeInterface * @return self */ public static function from($time) { - if ($time instanceof \DateTime || $time instanceof \DateTimeInterface) { + if ($time instanceof \DateTimeInterface) { return new static($time->format('Y-m-d H:i:s'), $time->getTimezone()); } elseif (is_numeric($time)) { if ($time <= self::YEAR) { $time += time(); } - $tmp = new static('@' . $time); - return $tmp->setTimeZone(new \DateTimeZone(date_default_timezone_get())); + return (new static('@' . $time))->setTimeZone(new \DateTimeZone(date_default_timezone_get())); } else { // textual or NULL return new static($time); @@ -122,4 +123,14 @@ return $date ? static::from($date) : FALSE; } + + /** + * Returns JSON representation in ISO 8601 (used by JavaScript). + * @return string + */ + public function jsonSerialize() + { + return $this->format('c'); + } + } diff -Nru php-nette-2.3.10/Nette/Utils/FileSystem.php php-nette-2.4-20160731/Nette/Utils/FileSystem.php --- php-nette-2.3.10/Nette/Utils/FileSystem.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/FileSystem.php 2016-07-31 17:46:44.000000000 +0000 @@ -15,6 +15,7 @@ */ class FileSystem { + use Nette\StaticClass; /** * Creates a directory. @@ -45,13 +46,13 @@ } elseif (is_dir($source)) { static::createDir($dest); foreach (new \FilesystemIterator($dest) as $item) { - static::delete($item); + static::delete($item->getPathname()); } foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) { if ($item->isDir()) { static::createDir($dest . '/' . $iterator->getSubPathName()); } else { - static::copy($item, $dest . '/' . $iterator->getSubPathName()); + static::copy($item->getPathname(), $dest . '/' . $iterator->getSubPathName()); } } @@ -79,7 +80,7 @@ } elseif (is_dir($path)) { foreach (new \FilesystemIterator($path) as $item) { - static::delete($item); + static::delete($item->getPathname()); } if (!@rmdir($path)) { // @ is escalated to exception throw new Nette\IOException("Unable to delete directory '$path'."); @@ -112,6 +113,21 @@ } + /** + * Reads file content. + * @return string + * @throws Nette\IOException + */ + public static function read($file) + { + $content = @file_get_contents($file); // @ is escalated to exception + if ($content === FALSE) { + throw new Nette\IOException("Unable to read file '$file'."); + } + return $content; + } + + /** * Writes a string to a file. * @return void diff -Nru php-nette-2.3.10/Nette/Utils/Html.php php-nette-2.4-20160731/Nette/Utils/Html.php --- php-nette-2.3.10/Nette/Utils/Html.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Html.php 2016-07-31 17:46:44.000000000 +0000 @@ -21,8 +21,10 @@ * echo $el->startTag(), $el->endTag(); *
*/ -class Html extends Nette\Object implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString +class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString { + use Nette\SmartObject; + /** @var string element's name */ private $name; @@ -30,20 +32,20 @@ private $isEmpty; /** @var array element's attributes */ - public $attrs = array(); + public $attrs = []; /** @var array of Html | string nodes */ - protected $children = array(); + protected $children = []; /** @var bool use XHTML syntax? */ public static $xhtml = FALSE; /** @var array empty (void) elements */ - public static $emptyElements = array( + public static $emptyElements = [ 'img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1, 'source' => 1, 'base' => 1, 'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1, 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1, - ); + ]; /** @@ -55,7 +57,7 @@ public static function el($name = NULL, $attrs = NULL) { $el = new static; - $parts = explode(' ', $name, 2); + $parts = explode(' ', (string) $name, 2); $el->setName($parts[0]); if (is_array($attrs)) { @@ -127,6 +129,68 @@ /** + * Appends value to element's attribute. + * @param string + * @param string|array value to append + * @param string|bool value option + * @return self + */ + public function appendAttribute($name, $value, $option = TRUE) + { + if (is_array($value)) { + $prev = isset($this->attrs[$name]) ? (array) $this->attrs[$name] : []; + $this->attrs[$name] = $value + $prev; + + } elseif ((string) $value === '') { + $tmp = & $this->attrs[$name]; // appending empty value? -> ignore, but ensure it exists + + } elseif (!isset($this->attrs[$name]) || is_array($this->attrs[$name])) { // needs array + $this->attrs[$name][$value] = $option; + + } else { + $this->attrs[$name] = [$this->attrs[$name] => TRUE, $value => $option]; + } + return $this; + } + + + /** + * Sets element's attribute. + * @param string + * @param mixed + * @return self + */ + public function setAttribute($name, $value) + { + $this->attrs[$name] = $value; + return $this; + } + + + /** + * Returns element's attribute. + * @param string + * @return mixed + */ + public function getAttribute($name) + { + return isset($this->attrs[$name]) ? $this->attrs[$name] : NULL; + } + + + /** + * Unsets element's attribute. + * @param string + * @return self + */ + public function removeAttribute($name) + { + unset($this->attrs[$name]); + return $this; + } + + + /** * Overloaded setter for element's attribute. * @param string HTML attribute name * @param mixed HTML attribute value @@ -175,7 +239,7 @@ * Overloaded setter for element's attribute. * @param string HTML attribute name * @param array (string) HTML attribute value or pair? - * @return self + * @return mixed */ public function __call($m, $args) { @@ -196,14 +260,8 @@ } elseif (count($args) === 1) { // set $this->attrs[$m] = $args[0]; - } elseif ((string) $args[0] === '') { - $tmp = & $this->attrs[$m]; // appending empty value? -> ignore, but ensure it exists - - } elseif (!isset($this->attrs[$m]) || is_array($this->attrs[$m])) { // needs array - $this->attrs[$m][$args[0]] = $args[1]; - - } else { - $this->attrs[$m] = array($this->attrs[$m], $args[0] => $args[1]); + } else { // add + $this->appendAttribute($m, $args[0], $args[1]); } return $this; @@ -219,7 +277,7 @@ public function href($path, $query = NULL) { if ($query) { - $query = http_build_query($query, NULL, '&'); + $query = http_build_query($query, '', '&'); if ($query !== '') { $path .= '?' . $query; } @@ -305,17 +363,39 @@ /** + * @deprecated + */ + public function add($child) + { + trigger_error(__METHOD__ . '() is deprecated, use addHtml() or addText() instead.', E_USER_DEPRECATED); + return $this->addHtml($child); + } + + + /** * Adds new element's child. * @param Html|string Html node or raw HTML string * @return self */ - public function add($child) + public function addHtml($child) { return $this->insert(NULL, $child); } /** + * Appends plain-text string to element content. + * @param string plain-text string + * @return self + */ + public function addText($text) + { + $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); + return $this->insert(NULL, $text); + } + + + /** * Creates and adds a new Html child. * @param string elements's name * @param array|string element's attributes or raw HTML string @@ -343,7 +423,7 @@ $this->children[] = $child; } else { // insert or replace - array_splice($this->children, (int) $index, $replace ? 1 : 0, array($child)); + array_splice($this->children, (int) $index, $replace ? 1 : 0, [$child]); } } else { @@ -417,7 +497,7 @@ */ public function removeChildren() { - $this->children = array(); + $this->children = []; } @@ -524,6 +604,7 @@ $s = ''; $attrs = $this->attrs; if (isset($attrs['data']) && is_array($attrs['data'])) { // deprecated + trigger_error('Expanded attribute "data" is deprecated.', E_USER_DEPRECATED); foreach ($attrs['data'] as $key => $value) { $attrs['data-' . $key] = $value; } @@ -571,8 +652,8 @@ $q = strpos($value, '"') === FALSE ? '"' : "'"; $s .= ' ' . $key . '=' . $q . str_replace( - array('&', $q, '<'), - array('&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'), + ['&', $q, '<'], + ['&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'], $value ) . (strpos($value, '`') !== FALSE && strpbrk($value, ' <>"\'') === FALSE ? ' ' : '') diff -Nru php-nette-2.3.10/Nette/Utils/Image.php php-nette-2.4-20160731/Nette/Utils/Image.php --- php-nette-2.3.10/Nette/Utils/Image.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Image.php 2016-07-31 17:46:44.000000000 +0000 @@ -47,6 +47,7 @@ * @method void copyMergeGray(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity) * @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) * @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) + * @method Image cropAuto(int $mode = -1, float $threshold = .5, int $color = -1) * @method void dashedLine($x1, $y1, $x2, $y2, $color) * @method void ellipse($cx, $cy, $w, $h, $color) * @method void fill($x, $y, $color) @@ -56,6 +57,7 @@ * @method void filledRectangle($x1, $y1, $x2, $y2, $color) * @method void fillToBorder($x, $y, $border, $color) * @method void filter($filtertype) + * @method void flip(int $mode) * @method array ftText($size, $angle, $x, $y, $col, string $fontFile, string $text, array $extrainfo = NULL) * @method void gammaCorrect(float $inputgamma, float $outputgamma) * @method int interlace($interlace = NULL) @@ -63,11 +65,13 @@ * @method void layerEffect($effect) * @method void line($x1, $y1, $x2, $y2, $color) * @method void paletteCopy(Image $source) + * @method void paletteToTrueColor() * @method void polygon(array $points, $numPoints, $color) * @method array psText(string $text, $font, $size, $color, $backgroundColor, $x, $y, $space = NULL, $tightness = NULL, float $angle = NULL, $antialiasSteps = NULL) * @method void rectangle($x1, $y1, $x2, $y2, $col) * @method Image rotate(float $angle, $backgroundColor) * @method void saveAlpha(bool $saveflag) + * @method Image scale(int $newWidth, int $newHeight = -1, int $mode = IMG_BILINEAR_FIXED) * @method void setBrush(Image $brush) * @method void setPixel($x, $y, $color) * @method void setStyle(array $style) @@ -81,22 +85,24 @@ * @property-read int $height * @property-read resource $imageResource */ -class Image extends Nette\Object +class Image { + use Nette\SmartObject; + /** {@link resize()} only shrinks images */ - const SHRINK_ONLY = 1; + const SHRINK_ONLY = 0b0001; /** {@link resize()} will ignore aspect ratio */ - const STRETCH = 2; + const STRETCH = 0b0010; /** {@link resize()} fits in given area so its dimensions are less than or equal to the required dimensions */ - const FIT = 0; + const FIT = 0b0000; /** {@link resize()} fills given area so its dimensions are greater than or equal to the required dimensions */ - const FILL = 4; + const FILL = 0b0100; /** {@link resize()} fills given area exactly */ - const EXACT = 8; + const EXACT = 0b1000; /** image types */ const JPEG = IMAGETYPE_JPEG, @@ -122,12 +128,12 @@ */ public static function rgb($red, $green, $blue, $transparency = 0) { - return array( + return [ 'red' => max(0, min(255, (int) $red)), 'green' => max(0, min(255, (int) $green)), 'blue' => max(0, min(255, (int) $blue)), 'alpha' => max(0, min(127, (int) $transparency)), - ); + ]; } @@ -145,36 +151,23 @@ throw new Nette\NotSupportedException('PHP extension GD is not loaded.'); } - static $funcs = array( + static $funcs = [ self::JPEG => 'imagecreatefromjpeg', self::PNG => 'imagecreatefrompng', self::GIF => 'imagecreatefromgif', - ); - $info = @getimagesize($file); // @ - files smaller than 12 bytes causes read error - $format = $info[2]; + ]; + $format = @getimagesize($file)[2]; // @ - files smaller than 12 bytes causes read error if (!isset($funcs[$format])) { throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found."); } - return new static(Callback::invokeSafe($funcs[$format], array($file), function ($message) { + return new static(Callback::invokeSafe($funcs[$format], [$file], function ($message) { throw new ImageException($message); })); } /** - * @deprecated - */ - public static function getFormatFromString($s) - { - trigger_error(__METHOD__ . '() is deprecated; use finfo_buffer() instead.', E_USER_DEPRECATED); - $types = array('image/jpeg' => self::JPEG, 'image/gif' => self::GIF, 'image/png' => self::PNG); - $type = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $s); - return isset($types[$type]) ? $types[$type] : NULL; - } - - - /** * Create a new image from the image stream in the string. * @param string * @param mixed detected image format @@ -188,10 +181,11 @@ } if (func_num_args() > 1) { - $format = @static::getFormatFromString($s); // @ suppress trigger_error + $tmp = @getimagesizefromstring($s)[2]; // @ - strings smaller than 12 bytes causes read error + $format = in_array($tmp, [self::JPEG, self::PNG, self::GIF], TRUE) ? $tmp : NULL; } - return new static(Callback::invokeSafe('imagecreatefromstring', array($s), function ($message) { + return new static(Callback::invokeSafe('imagecreatefromstring', [$s], function ($message) { throw new ImageException($message); })); } @@ -218,7 +212,7 @@ $image = imagecreatetruecolor($width, $height); if (is_array($color)) { - $color += array('alpha' => 0); + $color += ['alpha' => 0]; $color = imagecolorresolvealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']); imagealphablending($image, FALSE); imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color); @@ -309,14 +303,8 @@ $this->image = $newImage; } - if ($width < 0 || $height < 0) { // flip is processed in two steps for better quality - $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource(); - imagecopyresampled( - $newImage, $this->image, - 0, 0, $width < 0 ? $newWidth - 1 : 0, $height < 0 ? $newHeight - 1 : 0, - $newWidth, $newHeight, $width < 0 ? -$newWidth : $newWidth, $height < 0 ? -$newHeight : $newHeight - ); - $this->image = $newImage; + if ($width < 0 || $height < 0) { + imageflip($this->image, $width < 0 ? ($height < 0 ? IMG_FLIP_BOTH : IMG_FLIP_HORIZONTAL) : IMG_FLIP_VERTICAL); } return $this; } @@ -333,15 +321,15 @@ */ public static function calculateSize($srcWidth, $srcHeight, $newWidth, $newHeight, $flags = self::FIT) { - if (substr($newWidth, -1) === '%') { - $newWidth = round($srcWidth / 100 * abs($newWidth)); + if (is_string($newWidth) && substr($newWidth, -1) === '%') { + $newWidth = (int) round($srcWidth / 100 * abs($newWidth)); $percents = TRUE; } else { $newWidth = (int) abs($newWidth); } - if (substr($newHeight, -1) === '%') { - $newHeight = round($srcHeight / 100 * abs($newHeight)); + if (is_string($newHeight) && substr($newHeight, -1) === '%') { + $newHeight = (int) round($srcHeight / 100 * abs($newHeight)); $flags |= empty($percents) ? 0 : self::STRETCH; } else { $newHeight = (int) abs($newHeight); @@ -353,8 +341,8 @@ } if ($flags & self::SHRINK_ONLY) { - $newWidth = round($srcWidth * min(1, $newWidth / $srcWidth)); - $newHeight = round($srcHeight * min(1, $newHeight / $srcHeight)); + $newWidth = (int) round($srcWidth * min(1, $newWidth / $srcWidth)); + $newHeight = (int) round($srcHeight * min(1, $newHeight / $srcHeight)); } } else { // proportional @@ -362,7 +350,7 @@ throw new Nette\InvalidArgumentException('At least width or height must be specified.'); } - $scale = array(); + $scale = []; if ($newWidth > 0) { // fit width $scale[] = $newWidth / $srcWidth; } @@ -372,7 +360,7 @@ } if ($flags & self::FILL) { - $scale = array(max($scale)); + $scale = [max($scale)]; } if ($flags & self::SHRINK_ONLY) { @@ -380,11 +368,11 @@ } $scale = min($scale); - $newWidth = round($srcWidth * $scale); - $newHeight = round($srcHeight * $scale); + $newWidth = (int) round($srcWidth * $scale); + $newHeight = (int) round($srcHeight * $scale); } - return array(max((int) $newWidth, 1), max((int) $newHeight, 1)); + return [max($newWidth, 1), max($newHeight, 1)]; } @@ -398,10 +386,15 @@ */ public function crop($left, $top, $width, $height) { - list($left, $top, $width, $height) = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height); - $newImage = static::fromBlank($width, $height, self::RGB(0, 0, 0, 127))->getImageResource(); - imagecopy($newImage, $this->image, 0, 0, $left, $top, $width, $height); - $this->image = $newImage; + list($r['x'], $r['y'], $r['width'], $r['height']) + = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height); + if (PHP_VERSION_ID > 50611) { // PHP bug #67447 + $this->image = imagecrop($this->image, $r); + } else { + $newImage = static::fromBlank($r['width'], $r['height'], self::RGB(0, 0, 0, 127))->getImageResource(); + imagecopy($newImage, $this->image, 0, 0, $r['x'], $r['y'], $r['width'], $r['height']); + $this->image = $newImage; + } return $this; } @@ -418,17 +411,17 @@ */ public static function calculateCutout($srcWidth, $srcHeight, $left, $top, $newWidth, $newHeight) { - if (substr($newWidth, -1) === '%') { - $newWidth = round($srcWidth / 100 * $newWidth); + if (is_string($newWidth) && substr($newWidth, -1) === '%') { + $newWidth = (int) round($srcWidth / 100 * $newWidth); } - if (substr($newHeight, -1) === '%') { - $newHeight = round($srcHeight / 100 * $newHeight); + if (is_string($newHeight) && substr($newHeight, -1) === '%') { + $newHeight = (int) round($srcHeight / 100 * $newHeight); } - if (substr($left, -1) === '%') { - $left = round(($srcWidth - $newWidth) / 100 * $left); + if (is_string($left) && substr($left, -1) === '%') { + $left = (int) round(($srcWidth - $newWidth) / 100 * $left); } - if (substr($top, -1) === '%') { - $top = round(($srcHeight - $newHeight) / 100 * $top); + if (is_string($top) && substr($top, -1) === '%') { + $top = (int) round(($srcHeight - $newHeight) / 100 * $top); } if ($left < 0) { $newWidth += $left; @@ -438,9 +431,9 @@ $newHeight += $top; $top = 0; } - $newWidth = min((int) $newWidth, $srcWidth - $left); - $newHeight = min((int) $newHeight, $srcHeight - $top); - return array($left, $top, $newWidth, $newHeight); + $newWidth = min($newWidth, $srcWidth - $left); + $newHeight = min($newHeight, $srcHeight - $top); + return [$left, $top, $newWidth, $newHeight]; } @@ -450,11 +443,11 @@ */ public function sharpen() { - imageconvolution($this->image, array( // my magic numbers ;) - array(-1, -1, -1), - array(-1, 24, -1), - array(-1, -1, -1), - ), 16, 0); + imageconvolution($this->image, [ // my magic numbers ;) + [-1, -1, -1], + [-1, 24, -1], + [-1, -1, -1], + ], 16, 0); return $this; } @@ -470,38 +463,48 @@ public function place(Image $image, $left = 0, $top = 0, $opacity = 100) { $opacity = max(0, min(100, (int) $opacity)); - - if (substr($left, -1) === '%') { - $left = round(($this->getWidth() - $image->getWidth()) / 100 * $left); + if ($opacity === 0) { + return $this; } - if (substr($top, -1) === '%') { - $top = round(($this->getHeight() - $image->getHeight()) / 100 * $top); + $width = $image->getWidth(); + $height = $image->getHeight(); + + if (is_string($left) && substr($left, -1) === '%') { + $left = (int) round(($this->getWidth() - $width) / 100 * $left); } - if ($opacity === 100) { - imagecopy( - $this->image, $image->getImageResource(), - $left, $top, 0, 0, $image->getWidth(), $image->getHeight() - ); + if (is_string($top) && substr($top, -1) === '%') { + $top = (int) round(($this->getHeight() - $height) / 100 * $top); + } - } elseif ($opacity != 0) { - $cutting = imagecreatetruecolor($image->getWidth(), $image->getHeight()); - imagecopy( - $cutting, $this->image, - 0, 0, $left, $top, $image->getWidth(), $image->getHeight() - ); - imagecopy( - $cutting, $image->getImageResource(), - 0, 0, 0, 0, $image->getWidth(), $image->getHeight() - ); + $output = $input = $image->image; + if ($opacity < 100) { + for ($i = 0; $i < 128; $i++) { + $tbl[$i] = round(127 - (127 - $i) * $opacity / 100); + } - imagecopymerge( - $this->image, $cutting, - $left, $top, 0, 0, $image->getWidth(), $image->getHeight(), - $opacity - ); + $output = imagecreatetruecolor($width, $height); + imagealphablending($output, FALSE); + if (!$image->isTrueColor()) { + $input = $output; + imagefilledrectangle($output, 0, 0, $width, $height, imagecolorallocatealpha($output, 0, 0, 0, 127)); + imagecopy($output, $image->image, 0, 0, 0, 0, $width, $height); + } + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $c = \imagecolorat($input, $x, $y); + $c = ($c & 0xFFFFFF) + ($tbl[$c >> 24] << 24); + \imagesetpixel($output, $x, $y, $c); + } + } + imagealphablending($output, TRUE); } + + imagecopy( + $this->image, $output, + $left, $top, 0, 0, $width, $height + ); return $this; } @@ -592,7 +595,7 @@ */ public function send($type = self::JPEG, $quality = NULL) { - if (!in_array($type, array(self::JPEG, self::PNG, self::GIF), TRUE)) { + if (!in_array($type, [self::JPEG, self::PNG, self::GIF], TRUE)) { throw new Nette\InvalidArgumentException("Unsupported image type '$type'."); } header('Content-Type: ' . image_type_to_mime_type($type)); @@ -612,7 +615,7 @@ { $function = 'image' . $name; if (!function_exists($function)) { - return parent::__call($name, $args); + ObjectMixin::strictCall(get_class($this), $name); } foreach ($args as $key => $value) { @@ -629,9 +632,7 @@ ); } } - array_unshift($args, $this->image); - - $res = call_user_func_array($function, $args); + $res = $function($this->image, ...$args); return is_resource($res) && get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res; } diff -Nru php-nette-2.3.10/Nette/Utils/Json.php php-nette-2.4-20160731/Nette/Utils/Json.php --- php-nette-2.3.10/Nette/Utils/Json.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Json.php 2016-07-31 17:46:44.000000000 +0000 @@ -15,26 +15,10 @@ */ class Json { - const FORCE_ARRAY = 1; - const PRETTY = 2; + use Nette\StaticClass; - /** @var array */ - private static $messages = array( - JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded', - JSON_ERROR_STATE_MISMATCH => 'Syntax error, malformed JSON', - JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', - JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', - 5 /*JSON_ERROR_UTF8*/ => 'Invalid UTF-8 sequence', // exists since 5.3.3, but is returned since 5.3.1 - ); - - - /** - * Static class - cannot be instantiated. - */ - final public function __construct() - { - throw new Nette\StaticClassException; - } + const FORCE_ARRAY = 0b0001; + const PRETTY = 0b0010; /** @@ -45,23 +29,16 @@ */ public static function encode($value, $options = 0) { - $flags = PHP_VERSION_ID >= 50400 ? (JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | ($options & self::PRETTY ? JSON_PRETTY_PRINT : 0)) : 0; - - if (PHP_VERSION_ID < 50500) { - $json = Callback::invokeSafe('json_encode', array($value, $flags), function ($message) { // needed to receive 'recursion detected' error - throw new JsonException($message); - }); - } else { - $json = json_encode($value, $flags); - } + $flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES + | ($options & self::PRETTY ? JSON_PRETTY_PRINT : 0) + | (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); // since PHP 5.6.6 & PECL JSON-C 1.3.7 + $json = json_encode($value, $flags); if ($error = json_last_error()) { - $message = isset(static::$messages[$error]) ? static::$messages[$error] - : (PHP_VERSION_ID >= 50500 ? json_last_error_msg() : 'Unknown error'); - throw new JsonException($message, $error); + throw new JsonException(json_last_error_msg(), $error); } - $json = str_replace(array("\xe2\x80\xa8", "\xe2\x80\xa9"), array('\u2028', '\u2029'), $json); + $json = str_replace(["\xe2\x80\xa8", "\xe2\x80\xa9"], ['\u2028', '\u2029'], $json); return $json; } @@ -75,23 +52,21 @@ public static function decode($json, $options = 0) { $json = (string) $json; - if (!preg_match('##u', $json)) { - throw new JsonException('Invalid UTF-8 sequence', 5); // workaround for PHP < 5.3.3 & PECL JSON-C + if (defined('JSON_C_VERSION') && !preg_match('##u', $json)) { + throw new JsonException('Invalid UTF-8 sequence', 5); + } elseif ($json === '') { // for PHP < 7 + throw new JsonException('Syntax error'); } $forceArray = (bool) ($options & self::FORCE_ARRAY); - if (!$forceArray && preg_match('#(?<=[^\\\\]")\\\\u0000(?:[^"\\\\]|\\\\.)*+"\s*+:#', $json)) { // workaround for json_decode fatal error when object key starts with \u0000 - throw new JsonException(static::$messages[JSON_ERROR_CTRL_CHAR]); + if (PHP_VERSION_ID < 70000 && !$forceArray && preg_match('#(?<=[^\\\\]")\\\\u0000(?:[^"\\\\]|\\\\.)*+"\s*+:#', $json)) { + throw new JsonException('The decoded property name is invalid'); // workaround for json_decode fatal error when object key starts with \u0000 } - $args = array($json, $forceArray, 512); - if (PHP_VERSION_ID >= 50400 && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) { // not implemented in PECL JSON-C 1.3.2 for 64bit systems - $args[] = JSON_BIGINT_AS_STRING; - } - $value = call_user_func_array('json_decode', $args); + $flags = !defined('JSON_C_VERSION') || PHP_INT_SIZE === 4 ? JSON_BIGINT_AS_STRING : 0; // not implemented in PECL JSON-C 1.3.2 for 64bit systems - if ($value === NULL && $json !== '' && strcasecmp(trim($json, " \t\n\r"), 'null') !== 0) { // '' is not clearing json_last_error - $error = json_last_error(); - throw new JsonException(isset(static::$messages[$error]) ? static::$messages[$error] : 'Unknown error', $error); + $value = json_decode($json, $forceArray, 512, $flags); + if ($error = json_last_error()) { + throw new JsonException(json_last_error_msg(), $error); } return $value; } diff -Nru php-nette-2.3.10/Nette/Utils/ObjectMixin.php php-nette-2.4-20160731/Nette/Utils/ObjectMixin.php --- php-nette-2.3.10/Nette/Utils/ObjectMixin.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/ObjectMixin.php 2016-07-31 17:46:44.000000000 +0000 @@ -16,25 +16,77 @@ */ class ObjectMixin { - /** @var array (name => 0 | bool | array) used by getMethods() */ - private static $methods; + use Nette\StaticClass; - /** @var array (name => 'event' | TRUE) used by hasProperty() */ - private static $props; + /** @var array [name => [type => callback]] used by extension methods */ + private static $extMethods = []; - /** @var array (name => array(type => callback)) used by get|setExtensionMethod() */ - private static $extMethods; + + /********************* strictness ****************d*g**/ + + + /** + * @throws MemberAccessException + */ + public static function strictGet($class, $name) + { + $rc = new \ReflectionClass($class); + $hint = self::getSuggestion(array_merge( + array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) { return !$p->isStatic(); }), + self::parseFullDoc($rc, '~^[ \t*]*@property(?:-read)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m') + ), $name); + throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } + + + /** + * @throws MemberAccessException + */ + public static function strictSet($class, $name) + { + $rc = new \ReflectionClass($class); + $hint = self::getSuggestion(array_merge( + array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) { return !$p->isStatic(); }), + self::parseFullDoc($rc, '~^[ \t*]*@property(?:-write)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m') + ), $name); + throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } /** - * Static class - cannot be instantiated. + * @throws MemberAccessException */ - final public function __construct() + public static function strictCall($class, $method, $additionalMethods = []) { - throw new Nette\StaticClassException; + $hint = self::getSuggestion(array_merge( + get_class_methods($class), + self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:\S+[ \t]+)??(\w+)\(~m'), + $additionalMethods + ), $method); + + if (method_exists($class, $method)) { // called parent::$method() + $class = 'parent'; + } + throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.')); + } + + + /** + * @throws MemberAccessException + */ + public static function strictStaticCall($class, $method) + { + $hint = self::getSuggestion( + array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), function ($m) { return $m->isStatic(); }), + $method + ); + throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.')); } + /********************* Nette\Object ****************d*g**/ + + /** * __call() implementation. * @param object @@ -51,9 +103,6 @@ if ($name === '') { throw new MemberAccessException("Call to class '$class' method without name."); - } elseif ($isProp && $_this->$name instanceof \Closure) { // closure in property - return call_user_func_array($_this->$name, $args); - } elseif ($isProp === 'event') { // calling event handlers if (is_array($_this->$name) || $_this->$name instanceof \Traversable) { foreach ($_this->$name as $handler) { @@ -63,6 +112,9 @@ throw new Nette\UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($_this->$name) . ' given.'); } + } elseif ($isProp && $_this->$name instanceof \Closure) { // closure in property + return call_user_func_array($_this->$name, $args); + } elseif (($methods = & self::getMethods($class)) && isset($methods[$name]) && is_array($methods[$name])) { // magic @methods list($op, $rp, $type) = $methods[$name]; if (count($args) !== ($op === 'get' ? 0 : 1)) { @@ -84,20 +136,10 @@ return $_this; } elseif ($cb = self::getExtensionMethod($class, $name)) { // extension methods - array_unshift($args, $_this); - return Callback::invokeArgs($cb, $args); + return Callback::invoke($cb, $_this, ...$args); } else { - $hint = self::getSuggestion(array_merge( - get_class_methods($class), - self::parseFullDoc($class, '~^[ \t*]*@method[ \t]+(?:\S+[ \t]+)??(\w+)\(~m'), - array_keys(self::getExtensionMethods($class)) - ), $name); - - if (method_exists($class, $name)) { // called parent::$name() - $class = 'parent'; - } - throw new MemberAccessException("Call to undefined method $class::$name()" . ($hint ? ", did you mean $hint()?" : '.')); + self::strictCall($class, $name, array_keys(self::getExtensionMethods($class))); } } @@ -112,11 +154,7 @@ */ public static function callStatic($class, $method, $args) { - $hint = self::getSuggestion(array_filter( - get_class_methods($class), - function ($m) use ($class) { $rm = new \ReflectionMethod($class, $m); return $rm->isStatic(); } - ), $method); - throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.')); + self::strictStaticCall($class, $method); } @@ -138,8 +176,7 @@ } elseif (isset($methods[$m = 'get' . $uname]) || isset($methods[$m = 'is' . $uname])) { // property getter if ($methods[$m] === 0) { - $rm = new \ReflectionMethod($class, $m); - $methods[$m] = $rm->returnsReference(); + $methods[$m] = (new \ReflectionMethod($class, $m))->returnsReference(); } if ($methods[$m] === TRUE) { return $_this->$m(); @@ -149,28 +186,17 @@ } } elseif (isset($methods[$name])) { // public method as closure getter - if (preg_match('#^(is|get|has)([A-Z]|$)#', $name) && ($rm = new \ReflectionMethod($class, $name)) && !$rm->getNumberOfRequiredParameters()) { - $source = ''; - foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) { - if (isset($item['file']) && dirname($item['file']) !== __DIR__) { - $source = " in $item[file]:$item[line]"; - break; - } - } - trigger_error("Did you forgot parentheses after $name$source?", E_USER_WARNING); + if (preg_match('#^(is|get|has)([A-Z]|$)#', $name) && !(new \ReflectionMethod($class, $name))->getNumberOfRequiredParameters()) { + trigger_error("Did you forget parentheses after $name" . self::getSource() . '?', E_USER_WARNING); } $val = Callback::closure($_this, $name); return $val; - } elseif (isset($methods['set' . $uname])) { // strict class + } elseif (isset($methods['set' . $uname])) { // property getter throw new MemberAccessException("Cannot read a write-only property $class::\$$name."); - } else { // strict class - $hint = self::getSuggestion(array_merge( - array_keys(get_class_vars($class)), - self::parseFullDoc($class, '~^[ \t*]*@property(?:-read)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m') - ), $name); - throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } else { + self::strictGet($class, $name); } } @@ -198,15 +224,11 @@ } elseif (isset($methods[$m = 'set' . $uname])) { // property setter $_this->$m($value); - } elseif (isset($methods['get' . $uname]) || isset($methods['is' . $uname])) { // strict class + } elseif (isset($methods['get' . $uname]) || isset($methods['is' . $uname])) { // property setter throw new MemberAccessException("Cannot write to a read-only property $class::\$$name."); - } else { // strict class - $hint = self::getSuggestion(array_merge( - array_keys(get_class_vars($class)), - self::parseFullDoc($class, '~^[ \t*]*@property(?:-write)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m') - ), $name); - throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } else { + self::strictSet($class, $name); } } @@ -221,7 +243,7 @@ public static function remove($_this, $name) { $class = get_class($_this); - if (!self::hasProperty($class, $name)) { // strict class + if (!self::hasProperty($class, $name)) { throw new MemberAccessException("Cannot unset the property $class::\$$name."); } } @@ -241,43 +263,60 @@ } + /********************* magic @properties ****************d*g**/ + + /** - * Checks if the public non-static property exists. - * @return mixed + * Returns array of magic properties defined by annotation @property. + * @return array of [name => bit mask] */ - private static function hasProperty($class, $name) + public static function getMagicProperties($class) { - $prop = & self::$props[$class][$name]; - if ($prop === NULL) { - $prop = FALSE; - try { - $rp = new \ReflectionProperty($class, $name); - if ($rp->isPublic() && !$rp->isStatic()) { - $prop = $name >= 'onA' && $name < 'on_' ? 'event' : TRUE; - } - } catch (\ReflectionException $e) { + static $cache; + $props = & $cache[$class]; + if ($props !== NULL) { + return $props; + } + + $rc = new \ReflectionClass($class); + preg_match_all( + '~^ [ \t*]* @property(|-read|-write) [ \t]+ [^\s$]+ [ \t]+ \$ (\w+) ()~mx', + (string) $rc->getDocComment(), $matches, PREG_SET_ORDER + ); + + $props = []; + foreach ($matches as list(, $type, $name)) { + $uname = ucfirst($name); + $write = $type !== '-read' + && $rc->hasMethod($nm = 'set' . $uname) + && ($rm = $rc->getMethod($nm)) && $rm->getName() === $nm && !$rm->isPrivate() && !$rm->isStatic(); + $read = $type !== '-write' + && ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname)) + && ($rm = $rc->getMethod($nm)) && $rm->getName() === $nm && !$rm->isPrivate() && !$rm->isStatic(); + + if ($read || $write) { + $props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3; } } - return $prop; + + if ($parent = get_parent_class($class)) { + $props += self::getMagicProperties($parent); + } + return $props; } - /** - * Returns array of public (static, non-static and magic) methods. - * @return array - */ - private static function & getMethods($class) + /** @internal */ + public static function getMagicProperty($class, $name) { - if (!isset(self::$methods[$class])) { - self::$methods[$class] = array_fill_keys(get_class_methods($class), 0) + self::getMagicMethods($class); - if ($parent = get_parent_class($class)) { - self::$methods[$class] += self::getMethods($parent); - } - } - return self::$methods[$class]; + $props = self::getMagicProperties($class); + return isset($props[$name]) ? $props[$name] : NULL; } + /********************* magic @methods ****************d*g**/ + + /** * Returns array of magic methods defined by annotation @method. * @return array @@ -288,13 +327,15 @@ preg_match_all('~^ [ \t*]* @method [ \t]+ (?: [^\s(]+ [ \t]+ )? - (set|get|is|add) ([A-Z]\w*) [ \t]* - (?: \( [ \t]* ([^)$\s]+) )? - ()~mx', $rc->getDocComment(), $matches, PREG_SET_ORDER); - - $methods = array(); - foreach ($matches as $m) { - list(, $op, $prop, $type) = $m; + (set|get|is|add) ([A-Z]\w*) + (?: ([ \t]* \() [ \t]* ([^)$\s]*) )? + ()~mx', (string) $rc->getDocComment(), $matches, PREG_SET_ORDER); + + $methods = []; + foreach ($matches as list(, $op, $prop, $bracket, $type)) { + if ($bracket !== '(') { + trigger_error("Bracket must be immediately after @method $op$prop() in class $class.", E_USER_WARNING); + } $name = $op . $prop; $prop = strtolower($prop[0]) . substr($prop, 1) . ($op === 'add' ? 's' : ''); if ($rc->hasProperty($prop) && ($rp = $rc->getProperty($prop)) && !$rp->isStatic()) { @@ -302,13 +343,13 @@ if ($op === 'get' || $op === 'is') { $type = NULL; $op = 'get'; - } elseif (!$type && preg_match('#@var[ \t]+(\S+)' . ($op === 'add' ? '\[\]#' : '#'), $rp->getDocComment(), $m)) { + } elseif (!$type && preg_match('#@var[ \t]+(\S+)' . ($op === 'add' ? '\[\]#' : '#'), (string) $rp->getDocComment(), $m)) { $type = $m[1]; } - if ($rc->inNamespace() && preg_match('#^[A-Z]\w+(\[|\||\z)#', $type)) { + if ($rc->inNamespace() && preg_match('#^[A-Z]\w+(\[|\||\z)#', (string) $type)) { $type = $rc->getNamespaceName() . '\\' . $type; } - $methods[$name] = array($op, $rp, $type); + $methods[$name] = [$op, $rp, $type]; } } return $methods; @@ -344,7 +385,7 @@ return FALSE; } $type = substr($type, 0, -2); - $res = array(); + $res = []; foreach ($val as $k => $v) { if (!self::checkType($v, $type)) { return FALSE; @@ -382,6 +423,9 @@ } + /********************* extension methods ****************d*g**/ + + /** * Adds a method to class. * @param string @@ -411,7 +455,7 @@ return $cache; } - foreach (array($class) + class_parents($class) + class_implements($class) as $cl) { + foreach ([$class] + class_parents($class) + class_implements($class) as $cl) { if (isset($list[$cl])) { return $cache = $list[$cl]; } @@ -427,7 +471,7 @@ */ public static function getExtensionMethods($class) { - $res = array(); + $res = []; foreach (array_keys(self::$extMethods) as $name) { if ($cb = self::getExtensionMethod($class, $name)) { $res[$name] = $cb; @@ -437,17 +481,21 @@ } + /********************* utilities ****************d*g**/ + + /** * Finds the best suggestion (for 8-bit encoding). * @return string|NULL * @internal */ - public static function getSuggestion(array $items, $value) + public static function getSuggestion(array $possibilities, $value) { $norm = preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '', $value); $best = NULL; $min = (strlen($value) / 4 + 1) * 10 + .1; - foreach (array_unique($items) as $item) { + foreach (array_unique($possibilities, SORT_REGULAR) as $item) { + $item = $item instanceof \Reflector ? $item->getName() : $item; if ($item !== $value && ( ($len = levenshtein($item, $value, 10, 11, 10)) < $min || ($len = levenshtein(preg_replace($re, '', $item), $norm, 10, 11, 10) + 20) < $min @@ -460,13 +508,64 @@ } - private static function parseFullDoc($class, $pattern) + private static function parseFullDoc(\ReflectionClass $rc, $pattern) { - $rc = new \ReflectionClass($class); do { $doc[] = $rc->getDocComment(); } while ($rc = $rc->getParentClass()); - return preg_match_all($pattern, implode($doc), $m) ? $m[1] : array(); + return preg_match_all($pattern, implode($doc), $m) ? $m[1] : []; + } + + + /** + * Checks if the public non-static property exists. + * @return bool|'event' + * @internal + */ + public static function hasProperty($class, $name) + { + static $cache; + $prop = & $cache[$class][$name]; + if ($prop === NULL) { + $prop = FALSE; + try { + $rp = new \ReflectionProperty($class, $name); + if ($rp->isPublic() && !$rp->isStatic()) { + $prop = $name >= 'onA' && $name < 'on_' ? 'event' : TRUE; + } + } catch (\ReflectionException $e) { + } + } + return $prop; + } + + + /** + * Returns array of public (static, non-static and magic) methods. + * @return array + * @internal + */ + public static function & getMethods($class) + { + static $cache; + if (!isset($cache[$class])) { + $cache[$class] = array_fill_keys(get_class_methods($class), 0) + self::getMagicMethods($class); + if ($parent = get_parent_class($class)) { + $cache[$class] += self::getMethods($parent); + } + } + return $cache[$class]; + } + + + /** @internal */ + public static function getSource() + { + foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $item) { + if (isset($item['file']) && dirname($item['file']) !== __DIR__) { + return " in $item[file]:$item[line]"; + } + } } } diff -Nru php-nette-2.3.10/Nette/Utils/Object.php php-nette-2.4-20160731/Nette/Utils/Object.php --- php-nette-2.3.10/Nette/Utils/Object.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Object.php 2016-07-31 17:46:44.000000000 +0000 @@ -8,7 +8,6 @@ namespace Nette; use Nette; -use Nette\Utils\ObjectMixin; /** @@ -58,7 +57,7 @@ */ public static function getReflection() { - $class = class_exists('Nette\Reflection\ClassType') ? 'Nette\Reflection\ClassType' : 'ReflectionClass'; + $class = class_exists(Nette\Reflection\ClassType::class) ? Nette\Reflection\ClassType::class : 'ReflectionClass'; return new $class(get_called_class()); } @@ -72,7 +71,7 @@ */ public function __call($name, $args) { - return ObjectMixin::call($this, $name, $args); + return Nette\Utils\ObjectMixin::call($this, $name, $args); } @@ -85,7 +84,7 @@ */ public static function __callStatic($name, $args) { - return ObjectMixin::callStatic(get_called_class(), $name, $args); + return Nette\Utils\ObjectMixin::callStatic(get_called_class(), $name, $args); } @@ -101,13 +100,12 @@ $class = get_called_class(); } else { list($class, $name) = explode('::', $name); - $rc = new \ReflectionClass($class); - $class = $rc->getName(); + $class = (new \ReflectionClass($class))->getName(); } if ($callback === NULL) { - return ObjectMixin::getExtensionMethod($class, $name); + return Nette\Utils\ObjectMixin::getExtensionMethod($class, $name); } else { - ObjectMixin::setExtensionMethod($class, $name, $callback); + Nette\Utils\ObjectMixin::setExtensionMethod($class, $name, $callback); } } @@ -120,7 +118,7 @@ */ public function &__get($name) { - return ObjectMixin::get($this, $name); + return Nette\Utils\ObjectMixin::get($this, $name); } @@ -133,7 +131,7 @@ */ public function __set($name, $value) { - ObjectMixin::set($this, $name, $value); + Nette\Utils\ObjectMixin::set($this, $name, $value); } @@ -144,7 +142,7 @@ */ public function __isset($name) { - return ObjectMixin::has($this, $name); + return Nette\Utils\ObjectMixin::has($this, $name); } @@ -156,7 +154,7 @@ */ public function __unset($name) { - ObjectMixin::remove($this, $name); + Nette\Utils\ObjectMixin::remove($this, $name); } } diff -Nru php-nette-2.3.10/Nette/Utils/Paginator.php php-nette-2.4-20160731/Nette/Utils/Paginator.php --- php-nette-2.3.10/Nette/Utils/Paginator.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Paginator.php 2016-07-31 17:46:44.000000000 +0000 @@ -26,8 +26,10 @@ * @property-read int|NULL $countdownOffset * @property-read int|NULL $length */ -class Paginator extends Nette\Object +class Paginator { + use Nette\SmartObject; + /** @var int */ private $base = 1; diff -Nru php-nette-2.3.10/Nette/Utils/Random.php php-nette-2.4-20160731/Nette/Utils/Random.php --- php-nette-2.3.10/Nette/Utils/Random.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Random.php 2016-07-31 17:46:44.000000000 +0000 @@ -7,12 +7,15 @@ namespace Nette\Utils; +use Nette; + /** * Secure random string generator. */ class Random { + use Nette\StaticClass; /** * Generate random string. @@ -22,15 +25,15 @@ */ public static function generate($length = 10, $charlist = '0-9a-z') { - $charlist = count_chars(preg_replace_callback('#.-.#', function ($m) { + $charlist = count_chars(preg_replace_callback('#.-.#', function (array $m) { return implode('', range($m[0][0], $m[0][2])); }, $charlist), 3); $chLen = strlen($charlist); if ($length < 1) { - return ''; // mcrypt_create_iv does not support zero length + throw new Nette\InvalidArgumentException('Length must be greater than zero.'); } elseif ($chLen < 2) { - return str_repeat($charlist, $length); // random_int does not support empty interval + throw new Nette\InvalidArgumentException('Character list must contain as least two chars.'); } $res = ''; @@ -41,21 +44,18 @@ return $res; } - $windows = defined('PHP_WINDOWS_VERSION_BUILD'); $bytes = ''; - if (function_exists('openssl_random_pseudo_bytes') - && (PHP_VERSION_ID >= 50400 || !defined('PHP_WINDOWS_VERSION_BUILD')) // slow in PHP 5.3 & Windows - ) { - $bytes = openssl_random_pseudo_bytes($length, $secure); + if (function_exists('openssl_random_pseudo_bytes')) { + $bytes = (string) openssl_random_pseudo_bytes($length, $secure); if (!$secure) { $bytes = ''; } } - if (strlen($bytes) < $length && function_exists('mcrypt_create_iv') && (PHP_VERSION_ID >= 50307 || !$windows)) { // PHP bug #52523 - $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if (strlen($bytes) < $length && function_exists('mcrypt_create_iv')) { + $bytes = (string) mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); } - if (strlen($bytes) < $length && !$windows && @is_readable('/dev/urandom')) { - $bytes = file_get_contents('/dev/urandom', FALSE, NULL, -1, $length); + if (strlen($bytes) < $length && !defined('PHP_WINDOWS_VERSION_BUILD') && is_readable('/dev/urandom')) { + $bytes = (string) file_get_contents('/dev/urandom', FALSE, NULL, -1, $length); } if (strlen($bytes) < $length) { $rand3 = md5(serialize($_SERVER), TRUE); diff -Nru php-nette-2.3.10/Nette/Utils/SmartObject.php php-nette-2.4-20160731/Nette/Utils/SmartObject.php --- php-nette-2.3.10/Nette/Utils/SmartObject.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/SmartObject.php 2016-07-31 17:46:44.000000000 +0000 @@ -0,0 +1,231 @@ +$name) || $this->$name instanceof \Traversable) { + foreach ($this->$name as $handler) { + Callback::invokeArgs($handler, $args); + } + } elseif ($this->$name !== NULL) { + throw new UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($this->$name) . ' given.'); + } + + } elseif ($isProp && $this->$name instanceof \Closure) { // closure in property + trigger_error("Invoking closure in property via \$obj->$name() is deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED); + return call_user_func_array($this->$name, $args); + + } elseif (($methods = & ObjectMixin::getMethods($class)) && isset($methods[$name]) && is_array($methods[$name])) { // magic @methods + trigger_error("Magic methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED); + list($op, $rp, $type) = $methods[$name]; + if (count($args) !== ($op === 'get' ? 0 : 1)) { + throw new InvalidArgumentException("$class::$name() expects " . ($op === 'get' ? 'no' : '1') . ' argument, ' . count($args) . ' given.'); + + } elseif ($type && $args && !ObjectMixin::checkType($args[0], $type)) { + throw new InvalidArgumentException("Argument passed to $class::$name() must be $type, " . gettype($args[0]) . ' given.'); + } + + if ($op === 'get') { + return $rp->getValue($this); + } elseif ($op === 'set') { + $rp->setValue($this, $args[0]); + } elseif ($op === 'add') { + $val = $rp->getValue($this); + $val[] = $args[0]; + $rp->setValue($this, $val); + } + return $this; + + } elseif ($cb = ObjectMixin::getExtensionMethod($class, $name)) { // extension methods + trigger_error("Extension methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED); + return Callback::invoke($cb, $this, ...$args); + + } else { + ObjectMixin::strictCall($class, $name); + } + } + + + /** + * @return void + * @throws MemberAccessException + */ + public static function __callStatic($name, $args) + { + ObjectMixin::strictStaticCall(get_called_class(), $name); + } + + + /** + * @return mixed property value + * @throws MemberAccessException if the property is not defined. + */ + public function & __get($name) + { + $class = get_class($this); + $uname = ucfirst($name); + + if ($prop = ObjectMixin::getMagicProperty($class, $name)) { // property getter + if (!($prop & 0b0001)) { + throw new MemberAccessException("Cannot read a write-only property $class::\$$name."); + } + $m = ($prop & 0b0010 ? 'get' : 'is') . $uname; + if ($prop & 0b0100) { // return by reference + return $this->$m(); + } else { + $val = $this->$m(); + return $val; + } + + } elseif ($name === '') { + throw new MemberAccessException("Cannot read a class '$class' property without name."); + + } elseif (($methods = & ObjectMixin::getMethods($class)) && isset($methods[$m = 'get' . $uname]) || isset($methods[$m = 'is' . $uname])) { // old property getter + trigger_error("Missing annotation @property for $class::\$$name used" . ObjectMixin::getSource(), E_USER_DEPRECATED); + if ($methods[$m] === 0) { + $methods[$m] = (new \ReflectionMethod($class, $m))->returnsReference(); + } + if ($methods[$m] === TRUE) { + return $this->$m(); + } else { + $val = $this->$m(); + return $val; + } + + } elseif (isset($methods[$name])) { // public method as closure getter + trigger_error("Accessing methods as properties via \$obj->$name is deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED); + $val = Callback::closure($this, $name); + return $val; + + } elseif (isset($methods['set' . $uname])) { // property getter + throw new MemberAccessException("Cannot read a write-only property $class::\$$name."); + + } else { + ObjectMixin::strictGet($class, $name); + } + } + + + /** + * @return void + * @throws MemberAccessException if the property is not defined or is read-only + */ + public function __set($name, $value) + { + $class = get_class($this); + $uname = ucfirst($name); + + if (ObjectMixin::hasProperty($class, $name)) { // unsetted property + $this->$name = $value; + + } elseif ($prop = ObjectMixin::getMagicProperty($class, $name)) { // property setter + if (!($prop & 0b1000)) { + throw new MemberAccessException("Cannot write to a read-only property $class::\$$name."); + } + $this->{'set' . $name}($value); + + } elseif ($name === '') { + throw new MemberAccessException("Cannot write to a class '$class' property without name."); + + } elseif (($methods = & ObjectMixin::getMethods($class)) && isset($methods[$m = 'set' . $uname])) { // old property setter + trigger_error("Missing annotation @property for $class::\$$name used" . ObjectMixin::getSource(), E_USER_DEPRECATED); + $this->$m($value); + + } elseif (isset($methods['get' . $uname]) || isset($methods['is' . $uname])) { // property setter + throw new MemberAccessException("Cannot write to a read-only property $class::\$$name."); + + } else { + ObjectMixin::strictSet($class, $name); + } + } + + + /** + * @return void + * @throws MemberAccessException + */ + public function __unset($name) + { + $class = get_class($this); + if (!ObjectMixin::hasProperty($class, $name)) { + throw new MemberAccessException("Cannot unset the property $class::\$$name."); + } + } + + + /** + * @return bool + */ + public function __isset($name) + { + $uname = ucfirst($name); + return ObjectMixin::getMagicProperty(get_class($this), $name) + || ($name !== '' && ($methods = ObjectMixin::getMethods(get_class($this))) && (isset($methods['get' . $uname]) || isset($methods['is' . $uname]))); + } + + + /** + * @return Reflection\ClassType|\ReflectionClass + * @deprecated + */ + public static function getReflection() + { + trigger_error(get_called_class() . '::getReflection() is deprecated' . ObjectMixin::getSource(), E_USER_DEPRECATED); + $class = class_exists(Reflection\ClassType::class) ? Reflection\ClassType::class : \ReflectionClass::class; + return new $class(get_called_class()); + } + + + /** + * @return mixed + * @deprecated use Nette\Utils\ObjectMixin::setExtensionMethod() + */ + public static function extensionMethod($name, $callback = NULL) + { + if (strpos($name, '::') === FALSE) { + $class = get_called_class(); + } else { + list($class, $name) = explode('::', $name); + $class = (new \ReflectionClass($class))->getName(); + } + trigger_error("Extension methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED); + if ($callback === NULL) { + return ObjectMixin::getExtensionMethod($class, $name); + } else { + ObjectMixin::setExtensionMethod($class, $name, $callback); + } + } + +} diff -Nru php-nette-2.3.10/Nette/Utils/StaticClass.php php-nette-2.4-20160731/Nette/Utils/StaticClass.php --- php-nette-2.3.10/Nette/Utils/StaticClass.php 1970-01-01 00:00:00.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/StaticClass.php 2016-07-31 17:46:44.000000000 +0000 @@ -0,0 +1,35 @@ +transliterate($s); } if (ICONV_IMPL === 'glibc') { $s = str_replace( - array("\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"), - array('>>', '<<', '...', 'TM', '(c)', '(R)'), $s + ["\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"], + ['>>', '<<', '...', 'TM', '(c)', '(R)'], $s ); - $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); // intentionally @ + $s = iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e" . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3" . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" @@ -197,9 +182,9 @@ 'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.'); $s = preg_replace('#[^\x00-\x7F]++#', '', $s); } else { - $s = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); // intentionally @ + $s = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); } - $s = str_replace(array('`', "'", '"', '^', '~', '?'), '', $s); + $s = str_replace(['`', "'", '"', '^', '~', '?'], '', $s); return strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?'); } @@ -217,7 +202,7 @@ if ($lower) { $s = strtolower($s); } - $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s); + $s = preg_replace('#[^a-z0-9' . ($charlist !== NULL ? preg_quote($charlist, '#') : '') . ']+#i', '-', $s); $s = trim($s, '-'); return $s; } @@ -344,10 +329,10 @@ * @param string|array * @return string */ - public static function findPrefix($strings) + public static function findPrefix(...$strings) { - if (!is_array($strings)) { - $strings = func_get_args(); + if (is_array($strings[0])) { + $strings = $strings[0]; } $first = array_shift($strings); for ($i = 0; $i < strlen($first); $i++) { @@ -400,7 +385,7 @@ { $length = max(0, $length - self::length($s)); $padLen = self::length($pad); - return str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen) . $s; + return str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen) . $s; } @@ -415,7 +400,7 @@ { $length = max(0, $length - self::length($s)); $padLen = self::length($pad); - return $s . str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen); + return $s . str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen); } @@ -426,7 +411,7 @@ */ public static function reverse($s) { - return @iconv('UTF-32LE', 'UTF-8', strrev(@iconv('UTF-8', 'UTF-32BE', $s))); + return iconv('UTF-32LE', 'UTF-8', strrev(iconv('UTF-8', 'UTF-32BE', $s))); } @@ -436,6 +421,7 @@ */ public static function random($length = 10, $charlist = '0-9a-z') { + trigger_error(__METHOD__ . '() is deprecated, use Nette\Utils\Random::generate()', E_USER_DEPRECATED); return Random::generate($length, $charlist); } @@ -474,6 +460,22 @@ /** * Returns position of $nth occurence of $needle in $haystack. + * @param string + * @param string + * @param int negative value means searching from the end + * @return int|FALSE offset in characters or FALSE if the needle was not found + */ + public static function indexOf($haystack, $needle, $nth = 1) + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === FALSE + ? FALSE + : self::length(substr($haystack, 0, $pos)); + } + + + /** + * Returns position of $nth occurence of $needle in $haystack. * @return int|FALSE offset in bytes or FALSE if the needle was not found */ private static function pos($haystack, $needle, $nth = 1) @@ -511,7 +513,7 @@ */ public static function split($subject, $pattern, $flags = 0) { - return self::pcre('preg_split', array($pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE)); + return self::pcre('preg_split', [$pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE]); } @@ -528,7 +530,7 @@ if ($offset > strlen($subject)) { return NULL; } - return self::pcre('preg_match', array($pattern, $subject, & $m, $flags, $offset)) + return self::pcre('preg_match', [$pattern, $subject, & $m, $flags, $offset]) ? $m : NULL; } @@ -545,13 +547,13 @@ public static function matchAll($subject, $pattern, $flags = 0, $offset = 0) { if ($offset > strlen($subject)) { - return array(); + return []; } - self::pcre('preg_match_all', array( + self::pcre('preg_match_all', [ $pattern, $subject, & $m, ($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER), $offset, - )); + ]); return $m; } @@ -568,41 +570,42 @@ { if (is_object($replacement) || is_array($replacement)) { if ($replacement instanceof Nette\Callback) { + trigger_error('Nette\Callback is deprecated, use PHP callback.', E_USER_DEPRECATED); $replacement = $replacement->getNative(); } if (!is_callable($replacement, FALSE, $textual)) { throw new Nette\InvalidStateException("Callback '$textual' is not callable."); } - return self::pcre('preg_replace_callback', array($pattern, $replacement, $subject, $limit)); + return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit]); } elseif ($replacement === NULL && is_array($pattern)) { $replacement = array_values($pattern); $pattern = array_keys($pattern); } - return self::pcre('preg_replace', array($pattern, $replacement, $subject, $limit)); + return self::pcre('preg_replace', [$pattern, $replacement, $subject, $limit]); } /** @internal */ public static function pcre($func, $args) { - static $messages = array( + static $messages = [ PREG_INTERNAL_ERROR => 'Internal error', PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted', PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted', PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data', PREG_BAD_UTF8_OFFSET_ERROR => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', 6 => 'Failed due to limited JIT stack space', // PREG_JIT_STACKLIMIT_ERROR - ); + ]; $res = Callback::invokeSafe($func, $args, function ($message) use ($args) { // compile-time error, not detectable by preg_last_error throw new RegexpException($message . ' in pattern: ' . implode(' or ', (array) $args[0])); }); if (($code = preg_last_error()) // run-time error, but preg_last_error & return code are liars - && ($res === NULL || !in_array($func, array('preg_filter', 'preg_replace_callback', 'preg_replace'))) + && ($res === NULL || !in_array($func, ['preg_filter', 'preg_replace_callback', 'preg_replace'])) ) { throw new RegexpException((isset($messages[$code]) ? $messages[$code] : 'Unknown error') . ' (pattern: ' . implode(' or ', (array) $args[0]) . ')', $code); diff -Nru php-nette-2.3.10/Nette/Utils/Validators.php php-nette-2.4-20160731/Nette/Utils/Validators.php --- php-nette-2.3.10/Nette/Utils/Validators.php 2016-04-13 18:50:46.000000000 +0000 +++ php-nette-2.4-20160731/Nette/Utils/Validators.php 2016-07-31 17:46:44.000000000 +0000 @@ -13,32 +13,34 @@ /** * Validation utilities. */ -class Validators extends Nette\Object +class Validators { - protected static $validators = array( + use Nette\StaticClass; + + protected static $validators = [ 'bool' => 'is_bool', 'boolean' => 'is_bool', 'int' => 'is_int', 'integer' => 'is_int', 'float' => 'is_float', 'number' => NULL, // is_int || is_float, - 'numeric' => array(__CLASS__, 'isNumeric'), - 'numericint' => array(__CLASS__, 'isNumericInt'), + 'numeric' => [__CLASS__, 'isNumeric'], + 'numericint' => [__CLASS__, 'isNumericInt'], 'string' => 'is_string', - 'unicode' => array(__CLASS__, 'isUnicode'), + 'unicode' => [__CLASS__, 'isUnicode'], 'array' => 'is_array', - 'list' => array('Nette\Utils\Arrays', 'isList'), + 'list' => [Arrays::class, 'isList'], 'object' => 'is_object', 'resource' => 'is_resource', 'scalar' => 'is_scalar', - 'callable' => array(__CLASS__, 'isCallable'), + 'callable' => [__CLASS__, 'isCallable'], 'null' => 'is_null', - 'email' => array(__CLASS__, 'isEmail'), - 'url' => array(__CLASS__, 'isUrl'), - 'uri' => array(__CLASS__, 'isUri'), - 'none' => array(__CLASS__, 'isNone'), - 'type' => array(__CLASS__, 'isType'), - 'identifier' => array(__CLASS__, 'isPhpIdentifier'), + 'email' => [__CLASS__, 'isEmail'], + 'url' => [__CLASS__, 'isUrl'], + 'uri' => [__CLASS__, 'isUri'], + 'none' => [__CLASS__, 'isNone'], + 'type' => [__CLASS__, 'isType'], + 'identifier' => [__CLASS__, 'isPhpIdentifier'], 'pattern' => NULL, 'alnum' => 'ctype_alnum', 'alpha' => 'ctype_alpha', @@ -47,11 +49,11 @@ 'upper' => 'ctype_upper', 'space' => 'ctype_space', 'xdigit' => 'ctype_xdigit', - ); + ]; - protected static $counters = array( + protected static $counters = [ 'string' => 'strlen', - 'unicode' => array('Nette\Utils\Strings', 'length'), + 'unicode' => [Strings::class, 'length'], 'array' => 'count', 'list' => 'count', 'alnum' => 'strlen', @@ -61,7 +63,7 @@ 'space' => 'strlen', 'upper' => 'strlen', 'xdigit' => 'strlen', - ); + ]; /** @@ -74,7 +76,7 @@ public static function assert($value, $expected, $label = 'variable') { if (!static::is($value, $expected)) { - $expected = str_replace(array('|', ':'), array(' or ', ' in range '), $expected); + $expected = str_replace(['|', ':'], [' or ', ' in range '], $expected); if (is_array($value)) { $type = 'array(' . count($value) . ')'; } elseif (is_object($value)) { @@ -287,7 +289,7 @@ */ public static function isType($type) { - return class_exists($type) || interface_exists($type) || (PHP_VERSION_ID >= 50400 && trait_exists($type)); + return class_exists($type) || interface_exists($type) || trait_exists($type); } diff -Nru php-nette-2.3.10/readme.txt php-nette-2.4-20160731/readme.txt --- php-nette-2.3.10/readme.txt 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/readme.txt 2016-07-31 17:46:18.000000000 +0000 @@ -43,8 +43,9 @@ The best way to install Nette Framework is to download the latest package from https://nette.org/download or use [Composer](https://doc.nette.org/composer). -All Nette components are 100% compatible with PHP 7. Minimal required version is PHP 5.3.1. Please -run [Requirements Checker](https://doc.nette.org/requirements) to obtain more detailed information. +All Nette components are 100% compatible with PHP 7. Minimal required version of +PHP is 5.6.0 for Nette Framework 2.4-dev and PHP 5.3.1 for stable Nette Framework 2.3. +Please run [Requirements Checker](https://doc.nette.org/requirements) to obtain more detailed information. Getting started diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/checker.phtml php-nette-2.4-20160731/tools/Requirements-Checker/assets/checker.phtml --- php-nette-2.3.10/tools/Requirements-Checker/assets/checker.phtml 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/checker.phtml 1970-01-01 00:00:00.000000000 +0000 @@ -1,218 +0,0 @@ - - - - - - - - - - Nette Framework Requirements Checker - - - - - - - -
-

Nette Framework Requirements Checker

- -

This script checks if your server and PHP configuration meets the requirements - for running Nette Framework. It checks version of PHP, - if appropriate PHP extensions have been loaded, and if PHP directives are set correctly.

- - -
-

Sorry, your server configuration does not satisfy the requirements of Nette Framework.

-
- -
-

Congratulations! Server configuration meets the minimum requirements for Nette Framework.

-

Please see the warnings listed below.

-
- - - -

Details

- - - $requirement):?> - passed) ? ($requirement->passed ? 'passed' : ($requirement->required ? 'failed' : 'warning')) : 'info' ?> - - - - passed) && isset($requirement->errorMessage)): ?> - - message)): ?> - - passed)): ?> - - - - - - - description)): ?> - - - - - - script)): ?> - script ?> - - - -
title) ?>errorMessage) ?>message) ?>passed ? 'Enabled' : 'Disabled' ?>Not tested
description ?>
- -

Please check the error messages and try again.

-
- - diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/denied/checker.js php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/checker.js --- php-nette-2.3.10/tools/Requirements-Checker/assets/denied/checker.js 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/checker.js 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -fileProtectionChecker = true; diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/denied/.htaccess php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/.htaccess --- php-nette-2.3.10/tools/Requirements-Checker/assets/denied/.htaccess 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/.htaccess 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -Order Allow,Deny -Deny from all diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/denied/web.config php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/web.config --- php-nette-2.3.10/tools/Requirements-Checker/assets/denied/web.config 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/denied/web.config 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file Binary files /tmp/tmpdZCFV9/WT0Stc0_Wo/php-nette-2.3.10/tools/Requirements-Checker/assets/failed.gif and /tmp/tmpdZCFV9/izdFZJ78Jb/php-nette-2.4-20160731/tools/Requirements-Checker/assets/failed.gif differ Binary files /tmp/tmpdZCFV9/WT0Stc0_Wo/php-nette-2.3.10/tools/Requirements-Checker/assets/info.gif and /tmp/tmpdZCFV9/izdFZJ78Jb/php-nette-2.4-20160731/tools/Requirements-Checker/assets/info.gif differ Binary files /tmp/tmpdZCFV9/WT0Stc0_Wo/php-nette-2.3.10/tools/Requirements-Checker/assets/logo.png and /tmp/tmpdZCFV9/izdFZJ78Jb/php-nette-2.4-20160731/tools/Requirements-Checker/assets/logo.png differ Binary files /tmp/tmpdZCFV9/WT0Stc0_Wo/php-nette-2.3.10/tools/Requirements-Checker/assets/passed.gif and /tmp/tmpdZCFV9/izdFZJ78Jb/php-nette-2.4-20160731/tools/Requirements-Checker/assets/passed.gif differ diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/checker.js php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/checker.js --- php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/checker.js 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/checker.js 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -modRewriteChecker = true; diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/.htaccess php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/.htaccess --- php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/.htaccess 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/.htaccess 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -RewriteEngine On -RewriteRule .* checker.js [L] diff -Nru php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/web.config php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/web.config --- php-nette-2.3.10/tools/Requirements-Checker/assets/rewrite/web.config 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/assets/rewrite/web.config 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file Binary files /tmp/tmpdZCFV9/WT0Stc0_Wo/php-nette-2.3.10/tools/Requirements-Checker/assets/warning.gif and /tmp/tmpdZCFV9/izdFZJ78Jb/php-nette-2.4-20160731/tools/Requirements-Checker/assets/warning.gif differ diff -Nru php-nette-2.3.10/tools/Requirements-Checker/checker.php php-nette-2.4-20160731/tools/Requirements-Checker/checker.php --- php-nette-2.3.10/tools/Requirements-Checker/checker.php 2016-04-13 18:50:22.000000000 +0000 +++ php-nette-2.4-20160731/tools/Requirements-Checker/checker.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,297 +0,0 @@ - 'Web server', - 'message' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'unknown', -); - -$tests[] = array( - 'title' => 'PHP version', - 'required' => TRUE, - 'passed' => version_compare(PHP_VERSION, '5.3.1', '>='), - 'message' => PHP_VERSION, - 'description' => 'Your PHP version is too old. Nette Framework requires at least PHP 5.3.1 or higher.', -); - -$tests[] = array( - 'title' => 'Memory limit', - 'message' => ini_get('memory_limit'), -); - -if (!isset($_SERVER['SERVER_SOFTWARE']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== FALSE) { - $tests['hf'] = array( - 'title' => '.htaccess file protection', - 'required' => FALSE, - 'description' => 'File protection by .htaccess is not present. You must be careful to put files into document_root folder.', - 'script' => ' ', - ); - - $tests['hr'] = array( - 'title' => '.htaccess mod_rewrite', - 'required' => FALSE, - 'description' => 'Mod_rewrite is probably not present. You will not be able to use Cool URL.', - 'script' => ' ', - ); -} - -$tests[] = array( - 'title' => 'Function ini_set()', - 'required' => FALSE, - 'passed' => function_exists('ini_set'), - 'description' => 'Function ini_set() is disabled. Some parts of Nette Framework may not work properly.', -); - -$tests[] = array( - 'title' => 'Function error_reporting()', - 'required' => TRUE, - 'passed' => function_exists('error_reporting'), - 'description' => 'Function error_reporting() is disabled. Nette Framework requires this to be enabled.', -); - -$tests[] = array( - 'title' => 'Function flock()', - 'required' => TRUE, - 'passed' => flock(fopen(__FILE__, 'r'), LOCK_SH), - 'description' => 'Function flock() is not supported on this filesystem. Nette Framework requires this to process atomic file operations.', -); - -$tests[] = array( - 'title' => 'Register_globals', - 'required' => TRUE, - 'passed' => !iniFlag('register_globals'), - 'message' => 'Disabled', - 'errorMessage' => 'Enabled', - 'description' => 'Configuration directive register_globals is enabled. Nette Framework requires this to be disabled.', -); - -$tests[] = array( - 'title' => 'Variables_order', - 'required' => TRUE, - 'passed' => strpos(ini_get('variables_order'), 'G') !== FALSE && strpos(ini_get('variables_order'), 'P') !== FALSE && strpos(ini_get('variables_order'), 'C') !== FALSE, - 'description' => 'Configuration directive variables_order is missing. Nette Framework requires this to be set.', -); - -$tests[] = array( - 'title' => 'Session auto-start', - 'required' => FALSE, - 'passed' => session_id() === '' && !defined('SID'), - 'description' => 'Session auto-start is enabled. Nette Framework recommends not to use this directive for security reasons.', -); - -$tests[] = array( - 'title' => 'PCRE with UTF-8 support', - 'required' => TRUE, - 'passed' => @preg_match('/pcre/u', 'pcre'), - 'description' => 'PCRE extension must support UTF-8.', -); - -$reflection = new ReflectionFunction('paint'); -$tests[] = array( - 'title' => 'Reflection phpDoc', - 'required' => TRUE, - 'passed' => strpos($reflection->getDocComment(), 'Paints') !== FALSE, - 'description' => 'Reflection phpDoc are not available (probably due to an eAccelerator bug). You cannot use @annotations.', -); - -$tests[] = array( - 'title' => 'ICONV extension', - 'required' => TRUE, - 'passed' => extension_loaded('iconv') && (ICONV_IMPL !== 'unknown') && @iconv('UTF-16', 'UTF-8//IGNORE', iconv('UTF-8', 'UTF-16//IGNORE', 'test')) === 'test', - 'message' => 'Enabled and works properly', - 'errorMessage' => 'Disabled or does not work properly', - 'description' => 'ICONV extension is required and must work properly.', -); - -$tests[] = array( - 'title' => 'JSON extension', - 'required' => TRUE, - 'passed' => extension_loaded('json'), -); - -$tests[] = array( - 'title' => 'Fileinfo extension', - 'required' => FALSE, - 'passed' => extension_loaded('fileinfo'), - 'description' => 'Fileinfo extension is absent. You will not be able to detect content-type of uploaded files.', -); - -$tests[] = array( - 'title' => 'PHP tokenizer', - 'required' => TRUE, - 'passed' => extension_loaded('tokenizer'), - 'description' => 'PHP tokenizer is required.', -); - -$tests[] = array( - 'title' => 'PDO extension', - 'required' => FALSE, - 'passed' => $pdo = extension_loaded('pdo') && PDO::getAvailableDrivers(), - 'message' => $pdo ? 'Available drivers: ' . implode(' ', PDO::getAvailableDrivers()) : NULL, - 'description' => 'PDO extension or PDO drivers are absent. You will not be able to use Nette\Database.', -); - -$tests[] = array( - 'title' => 'Multibyte String extension', - 'required' => FALSE, - 'passed' => extension_loaded('mbstring'), - 'description' => 'Multibyte String extension is absent. Some internationalization components may not work properly.', -); - -$tests[] = array( - 'title' => 'Multibyte String function overloading', - 'required' => TRUE, - 'passed' => !extension_loaded('mbstring') || !(mb_get_info('func_overload') & 2), - 'message' => 'Disabled', - 'errorMessage' => 'Enabled', - 'description' => 'Multibyte String function overloading is enabled. Nette Framework requires this to be disabled. If it is enabled, some string function may not work properly.', -); - -$tests[] = array( - 'title' => 'Memcache extension', - 'required' => FALSE, - 'passed' => extension_loaded('memcache'), - 'description' => 'Memcache extension is absent. You will not be able to use Nette\Caching\Storages\MemcachedStorage.', -); - -$tests[] = array( - 'title' => 'GD extension', - 'required' => FALSE, - 'passed' => extension_loaded('gd'), - 'description' => 'GD extension is absent. You will not be able to use Nette\Image.', -); - -$tests[] = array( - 'title' => 'Bundled GD extension', - 'required' => FALSE, - 'passed' => extension_loaded('gd') && GD_BUNDLED, - 'description' => 'Bundled GD extension is absent. You will not be able to use some functions such as Nette\Image::filter() or Nette\Image::rotate().', -); - -$tests[] = array( - 'title' => 'Fileinfo extension or mime_content_type()', - 'required' => FALSE, - 'passed' => extension_loaded('fileinfo') || function_exists('mime_content_type'), - 'description' => 'Fileinfo extension or function mime_content_type() are absent. You will not be able to determine mime type of uploaded files.', -); - -$tests[] = array( - 'title' => 'Intl extension', - 'required' => FALSE, - 'passed' => class_exists('Transliterator', FALSE), - 'description' => 'Class Transliterator is absent, the output of Nette\Utils\Strings::webalize() and Nette\Utils\Strings::toAscii() may not be accurate for non-latin alphabets.', -); - -$tests[] = array( - 'title' => 'HTTP_HOST or SERVER_NAME', - 'required' => TRUE, - 'passed' => isset($_SERVER['HTTP_HOST']) || isset($_SERVER['SERVER_NAME']), - 'message' => 'Present', - 'errorMessage' => 'Absent', - 'description' => 'Either $_SERVER["HTTP_HOST"] or $_SERVER["SERVER_NAME"] must be available for resolving host name.', -); - -$tests[] = array( - 'title' => 'REQUEST_URI or ORIG_PATH_INFO', - 'required' => TRUE, - 'passed' => isset($_SERVER['REQUEST_URI']) || isset($_SERVER['ORIG_PATH_INFO']), - 'message' => 'Present', - 'errorMessage' => 'Absent', - 'description' => 'Either $_SERVER["REQUEST_URI"] or $_SERVER["ORIG_PATH_INFO"] must be available for resolving request URL.', -); - -$tests[] = array( - 'title' => 'SCRIPT_NAME or DOCUMENT_ROOT & SCRIPT_FILENAME', - 'required' => TRUE, - 'passed' => isset($_SERVER['SCRIPT_NAME']) || isset($_SERVER['DOCUMENT_ROOT'], $_SERVER['SCRIPT_FILENAME']), - 'message' => 'Present', - 'errorMessage' => 'Absent', - 'description' => '$_SERVER["SCRIPT_NAME"] or $_SERVER["DOCUMENT_ROOT"] with $_SERVER["SCRIPT_FILENAME"] must be available for resolving script file path.', -); - -$tests[] = array( - 'title' => 'REMOTE_ADDR or php_uname("n")', - 'required' => TRUE, - 'passed' => isset($_SERVER['REMOTE_ADDR']) || function_exists('php_uname'), - 'message' => 'Present', - 'errorMessage' => 'Absent', - 'description' => '$_SERVER["REMOTE_ADDR"] or php_uname("n") must be available for detecting development / production mode.', -); - -paint($tests); - - - -/** - * Paints checker. - * @param array - * @return void - */ -function paint($requirements) -{ - $redirect = round(time(), -1); - if (!isset($_GET) || (isset($_GET['r']) && $_GET['r'] == $redirect)) { - $redirect = NULL; - } - - $errors = $warnings = FALSE; - - foreach ($requirements as $id => $requirement) - { - $requirements[$id] = $requirement = (object) $requirement; - if (isset($requirement->passed) && !$requirement->passed) { - if ($requirement->required) { - $errors = TRUE; - } else { - $warnings = TRUE; - } - } - } - - require TEMPLATE_FILE; -} - - - -/** - * Gets the boolean value of a configuration option. - * @param string configuration option name - * @return bool - */ -function iniFlag($var) -{ - $status = strtolower(ini_get($var)); - return $status === 'on' || $status === 'true' || $status === 'yes' || (int) $status; -} diff -Nru php-nette-2.3.10/version.txt php-nette-2.4-20160731/version.txt --- php-nette-2.3.10/version.txt 2016-04-13 18:50:48.000000000 +0000 +++ php-nette-2.4-20160731/version.txt 2016-07-31 17:46:46.000000000 +0000 @@ -1 +1,23 @@ -Nette 2.3.10 (revision 79d539f released on 2016-04-13) \ No newline at end of file +Nette 2.4-20160731 + +latte/latte v2.4.1 Latte: the amazing template engine for PHP +nette/application v2.4.1 Nette Application MVC Component +nette/bootstrap v2.4.1 Nette Bootstrap +nette/caching v2.5.1 Nette Caching Component +nette/component-model v2.3.0 Nette Component Model +nette/database v2.4.0 Nette Database Component +nette/deprecated v2.4.0 APIs and features removed from Nette Framework +nette/di v2.4.2 Nette Dependency Injection Component +nette/finder v2.4.0 Nette Finder: Files Searching +nette/forms v2.4.1 Nette Forms: greatly facilitates web forms +nette/http v2.4.0 Nette HTTP Component +nette/mail v2.4.1 Nette Mail: Sending E-mails +nette/neon v2.4.0 Nette NEON: parser & generator for Nette Object Notation +nette/php-generator v2.4.1 Nette PHP Generator +nette/reflection v2.4.0 Nette PHP Reflection Component +nette/robot-loader v2.4.0 Nette RobotLoader: comfortable autoloading +nette/safe-stream v2.3.2 Nette SafeStream: Atomic Operations +nette/security v2.4.0 Nette Security: Access Control Component +nette/tokenizer v2.2.3 Nette Tokenizer +nette/utils v2.4.0 Nette Utility Classes +tracy/tracy v2.4.2 Tracy: useful PHP debugger