From 54858a9eeb0c57c316a07cea5aa2fa135c6807ac Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 11 Feb 2021 02:18:47 +0100 Subject: [PATCH] added Form::initialize() for standalone forms --- src/Forms/Form.php | 34 +++++++++++++++++-- tests/Forms/Container.values.ArrayHash.phpt | 2 ++ tests/Forms/Container.values.array.phpt | 2 ++ tests/Forms/Container.values.mapping.phpt | 2 ++ tests/Forms/Controls.BaseControl.phpt | 5 +++ tests/Forms/Controls.Button.loadData.phpt | 1 + tests/Forms/Controls.Checkbox.loadData.phpt | 1 + .../Forms/Controls.CheckboxList.loadData.phpt | 1 + .../Controls.ChoiceControl.loadData.phpt | 1 + .../Forms/Controls.HiddenField.loadData.phpt | 1 + .../Forms/Controls.ImageButton.loadData.phpt | 1 + .../Controls.MultiChoiceControl.loadData.phpt | 1 + .../Controls.MultiSelectBox.loadData.phpt | 1 + tests/Forms/Controls.RadioList.loadData.phpt | 1 + tests/Forms/Controls.SelectBox.isOk.phpt | 1 + tests/Forms/Controls.SelectBox.loadData.phpt | 1 + tests/Forms/Controls.TextBase.loadData.phpt | 1 + tests/Forms/Forms.crossOrigin.phpt | 1 + tests/Forms/Forms.getHttpData.get.phpt | 1 + tests/Forms/Forms.getHttpData.post.phpt | 4 +++ tests/Forms/Forms.submittedBy.phpt | 1 + 21 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/Forms/Form.php b/src/Forms/Form.php index ba685ed0d..10c1591c2 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -103,6 +103,9 @@ class Form extends Container implements Nette\HtmlStringable /** @var bool */ protected $crossOrigin = false; + /** @var Nette\Http\IRequest */ + private static $defaultHttpRequest; + /** @var mixed or null meaning: not detected yet */ private $submittedBy; @@ -666,6 +669,32 @@ public function getToggles(): array /********************* backend ****************d*g**/ + /** + * Initialize standalone forms. + */ + public static function initialize(bool $reinit = false): void + { + if ($reinit) { + self::$defaultHttpRequest = null; + return; + } elseif (self::$defaultHttpRequest) { + return; + } + + self::$defaultHttpRequest = (new Nette\Http\RequestFactory)->fromGlobals(); + + if (PHP_SAPI !== 'cli') { + if (headers_sent($file, $line)) { + throw new Nette\InvalidStateException( + 'Create a form or call Nette\Forms\Form::initialize() before the headers are sent to initialize CSRF protection.' + . ($file ? " (output started at $file:$line)" : '') . '. ' + ); + } + Nette\Http\Helpers::initCookie(self::$defaultHttpRequest, new Nette\Http\Response); + } + } + + /** @internal */ public function setHttpRequest(Nette\Http\IRequest $request) { @@ -676,9 +705,8 @@ public function setHttpRequest(Nette\Http\IRequest $request) private function getHttpRequest(): Nette\Http\IRequest { if (!$this->httpRequest) { - $factory = new Nette\Http\RequestFactory; - $this->httpRequest = $factory->createHttpRequest(); - Nette\Http\Helpers::initCookie($this->httpRequest, new Nette\Http\Response); + self::initialize(); + $this->httpRequest = self::$defaultHttpRequest; } return $this->httpRequest; } diff --git a/tests/Forms/Container.values.ArrayHash.phpt b/tests/Forms/Container.values.ArrayHash.phpt index 7666c62b6..02ebea072 100644 --- a/tests/Forms/Container.values.ArrayHash.phpt +++ b/tests/Forms/Container.values.ArrayHash.phpt @@ -24,6 +24,8 @@ $_POST = [ function createForm(): Form { + Form::initialize(true); + $form = new Form; $form->addText('title'); diff --git a/tests/Forms/Container.values.array.phpt b/tests/Forms/Container.values.array.phpt index ceb77519b..428a4abad 100644 --- a/tests/Forms/Container.values.array.phpt +++ b/tests/Forms/Container.values.array.phpt @@ -24,6 +24,8 @@ $_POST = [ function createForm(): Form { + Form::initialize(true); + $form = new Form; $form->addText('title'); diff --git a/tests/Forms/Container.values.mapping.phpt b/tests/Forms/Container.values.mapping.phpt index aeadb79ee..8f5951ac2 100644 --- a/tests/Forms/Container.values.mapping.phpt +++ b/tests/Forms/Container.values.mapping.phpt @@ -64,6 +64,8 @@ $_POST = [ function createForm(): Form { + Form::initialize(true); + $form = new Form; $form->addText('title'); diff --git a/tests/Forms/Controls.BaseControl.phpt b/tests/Forms/Controls.BaseControl.phpt index 4333849e1..8d8466136 100644 --- a/tests/Forms/Controls.BaseControl.phpt +++ b/tests/Forms/Controls.BaseControl.phpt @@ -14,6 +14,11 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; +before(function () { + Form::initialize(true); +}); + + test('error handling', function () { $form = new Form; $input = $form->addText('text') diff --git a/tests/Forms/Controls.Button.loadData.phpt b/tests/Forms/Controls.Button.loadData.phpt index a864c8430..49b3de46a 100644 --- a/tests/Forms/Controls.Button.loadData.phpt +++ b/tests/Forms/Controls.Button.loadData.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.Checkbox.loadData.phpt b/tests/Forms/Controls.Checkbox.loadData.phpt index 23fbf2475..937ef10fe 100644 --- a/tests/Forms/Controls.Checkbox.loadData.phpt +++ b/tests/Forms/Controls.Checkbox.loadData.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.CheckboxList.loadData.phpt b/tests/Forms/Controls.CheckboxList.loadData.phpt index 9abc6d9fc..e606bfa41 100644 --- a/tests/Forms/Controls.CheckboxList.loadData.phpt +++ b/tests/Forms/Controls.CheckboxList.loadData.phpt @@ -19,6 +19,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.ChoiceControl.loadData.phpt b/tests/Forms/Controls.ChoiceControl.loadData.phpt index d126b203c..e0ac8134e 100644 --- a/tests/Forms/Controls.ChoiceControl.loadData.phpt +++ b/tests/Forms/Controls.ChoiceControl.loadData.phpt @@ -23,6 +23,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.HiddenField.loadData.phpt b/tests/Forms/Controls.HiddenField.loadData.phpt index 832b6d3c6..89a240cac 100644 --- a/tests/Forms/Controls.HiddenField.loadData.phpt +++ b/tests/Forms/Controls.HiddenField.loadData.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.ImageButton.loadData.phpt b/tests/Forms/Controls.ImageButton.loadData.phpt index 26248c011..976b25acf 100644 --- a/tests/Forms/Controls.ImageButton.loadData.phpt +++ b/tests/Forms/Controls.ImageButton.loadData.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.MultiChoiceControl.loadData.phpt b/tests/Forms/Controls.MultiChoiceControl.loadData.phpt index 9eeaacc74..6349b9cf6 100644 --- a/tests/Forms/Controls.MultiChoiceControl.loadData.phpt +++ b/tests/Forms/Controls.MultiChoiceControl.loadData.phpt @@ -24,6 +24,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.MultiSelectBox.loadData.phpt b/tests/Forms/Controls.MultiSelectBox.loadData.phpt index acc770578..c5c26c1ab 100644 --- a/tests/Forms/Controls.MultiSelectBox.loadData.phpt +++ b/tests/Forms/Controls.MultiSelectBox.loadData.phpt @@ -19,6 +19,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.RadioList.loadData.phpt b/tests/Forms/Controls.RadioList.loadData.phpt index 25539cd8c..e4bf30153 100644 --- a/tests/Forms/Controls.RadioList.loadData.phpt +++ b/tests/Forms/Controls.RadioList.loadData.phpt @@ -18,6 +18,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.SelectBox.isOk.phpt b/tests/Forms/Controls.SelectBox.isOk.phpt index d35c2b2d2..72ed77a2e 100644 --- a/tests/Forms/Controls.SelectBox.isOk.phpt +++ b/tests/Forms/Controls.SelectBox.isOk.phpt @@ -44,6 +44,7 @@ Assert::false($select->isOk()); // error message is processed via Rules $_SERVER['REQUEST_METHOD'] = 'POST'; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; +Form::initialize(true); Validator::$messages[Nette\Forms\Controls\SelectBox::VALID] = 'SelectBox "%label" must be filled.'; $form = new Form; $form->addSelect('foo', 'Foo', ['bar' => 'Bar']); diff --git a/tests/Forms/Controls.SelectBox.loadData.phpt b/tests/Forms/Controls.SelectBox.loadData.phpt index 7b154dd49..36c393e03 100644 --- a/tests/Forms/Controls.SelectBox.loadData.phpt +++ b/tests/Forms/Controls.SelectBox.loadData.phpt @@ -18,6 +18,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Controls.TextBase.loadData.phpt b/tests/Forms/Controls.TextBase.loadData.phpt index 8dfd79d5a..2d7996e76 100644 --- a/tests/Forms/Controls.TextBase.loadData.phpt +++ b/tests/Forms/Controls.TextBase.loadData.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST = $_FILES = []; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; + Form::initialize(true); }); diff --git a/tests/Forms/Forms.crossOrigin.phpt b/tests/Forms/Forms.crossOrigin.phpt index 7b72f6c9b..14ff4ea65 100644 --- a/tests/Forms/Forms.crossOrigin.phpt +++ b/tests/Forms/Forms.crossOrigin.phpt @@ -16,6 +16,7 @@ require __DIR__ . '/../bootstrap.php'; before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_GET = $_POST = $_FILES = $_COOKIE = []; + Form::initialize(true); }); diff --git a/tests/Forms/Forms.getHttpData.get.phpt b/tests/Forms/Forms.getHttpData.get.phpt index 3c69a8f86..795ff6a8f 100644 --- a/tests/Forms/Forms.getHttpData.get.phpt +++ b/tests/Forms/Forms.getHttpData.get.phpt @@ -16,6 +16,7 @@ require __DIR__ . '/../bootstrap.php'; before(function () { $_SERVER['REQUEST_METHOD'] = 'GET'; $_GET = $_POST = $_FILES = []; + Form::initialize(true); }); diff --git a/tests/Forms/Forms.getHttpData.post.phpt b/tests/Forms/Forms.getHttpData.post.phpt index 6eadb4fa3..219e3a3be 100644 --- a/tests/Forms/Forms.getHttpData.post.phpt +++ b/tests/Forms/Forms.getHttpData.post.phpt @@ -18,6 +18,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; $_GET = $_POST = $_FILES = []; + Form::initialize(true); }); @@ -76,7 +77,10 @@ test('', function () { $input = $form->addSubmit('send', 'Send'); Assert::false($input->isSubmittedBy()); Assert::false(Validator::validateSubmitted($input)); +}); + +test('', function () { $_POST = ['send' => '']; $form = new Form; $input = $form->addSubmit('send', 'Send'); diff --git a/tests/Forms/Forms.submittedBy.phpt b/tests/Forms/Forms.submittedBy.phpt index dc80f5973..6ca4fbafd 100644 --- a/tests/Forms/Forms.submittedBy.phpt +++ b/tests/Forms/Forms.submittedBy.phpt @@ -17,6 +17,7 @@ before(function () { $_SERVER['REQUEST_METHOD'] = 'POST'; $_COOKIE[Nette\Http\Helpers::STRICT_COOKIE_NAME] = '1'; $_GET = $_POST = $_FILES = []; + Form::initialize(true); });