creating form factory for file upload

jdan1131x
Member | 38
+
0
-

The code below works fine in a presenter, but not in a FormFactory thats
not extending Nette\Application\UI\Presenter. I tried injecting Nette\Http\Request
but get tracy error (two request objects…)

protected function createComponentUploadPdfForm(): Form {
		$size = 1024 * 1024;
		$form = new Form();

		//post required for uploads
		$form->setMethod('POST');

		$form->addUpload('document')
			->addRule($form::MAX_FILE_SIZE, "Maximum size is 1 MB", $size);

		$form->addSubmit('send');
		$form->addSubmit('clear');

		$form->onSubmit[] = function () {

			//per the Nette Website documentation at https://doc.nette.org/en/3.1/http-request-response#toc-getpost
			$request = $this->getHttpRequest();

			//returns tree of uploaded normalized files each instance is Nette\Http\FileUpload
			//FileUpload object returned by request https://doc.nette.org/en/3.1/http-request-response#toc-getfile
			$file = $request->getFile('document');

			//test 1 https://doc.nette.org/en/3.1/http-request-response#toc-getfile
			if($file->hasFile() != true) {
				$form->addError(sprintf('File was not received'));
			}
		};
		$form->onSuccess[] = function () {
			// Some handling on success...

			$this->redrawControl('docStatus');
			$this->flashMessage("Success", 'success');
			$this->redrawControl('nextStep');
		};

	return $form;
	}

I want to extract the code above from presenter and put
in a formfactory service so its easily available elswhere on site.
I have two formfactories working fine, but the upload file form …
i cant seem to instantiate or inject the httpRequest object
so that i can get access to the FileUpload object and its methods..

I am afraid i dont know what URL to send when attempting $request = $new HttpRequest($url).
i think that may be my issue. ??
thanks very much, sorry to bug…
James

jdan1131x
Member | 38
+
0
-

and when I move the working code to the Form Factory (shown above)
then tracy says :

Service of type JDApp\Forms\LessonThreeFormFactory used in type hint at App\Presenters\LessonWizardStep3Presenter::$formfactory3 not found. Did you add it to configuration file? search►

the answeris yes, i did add to the services.neon file that was added to Bootstrap.php

$configurator->addConfig($appDir . '/config/services.neon');

jdan1131x
Member | 38
+
0
-

i get the tracy error on the presenter although
this code works elsewhere

class LessonWizardStep3Presenter extends LessonWizardPresenter {
	/** @var \JDApp\Forms\LessonThreeFormFactory @inject */
	public \JDApp\Forms\LessonThreeFormFactory $formfactory3;

and

	protected function createComponentUploadPdfForm(): Form {
		//see details in /app/forms...
		$form = $this->formfactory3->create();
		return $form;
	}

the only diff between the other working form factories and this one is the use of the
file upload input type:

	<div class="struct"><input class="form-group" type="file" n:name="document"> Use PDF</div>
jdan1131x
Member | 38
+
0
-

again thanks so much for any feedback. it is mission critical
that i can aggregate logic outside presenters. really helps
me move faster…

James

dsar
Backer | 36
+
0
-

The business of onSubmit and onSuccess is best left to the Presenter or the Control.

Below an example of a Login form within a Control, it allows you to have some more specific events (such onAuthenticationSuccess) and it is more fine grained.

Factory:

final class LoginFormFactory
{
	public function create(): Form
    {
		$form = new Form;

		$form->addText('email', 'Email')
			->setRequired('Enter your email');

		$form->addPassword('password', 'Password')
			->setRequired('Enter your password');

		$form->addSubmit('submit', 'Login');

		return $form;
	}
}

Control:

use App\Forms\LoginFormFactory;

final class LoginControl extends Control
{
	private LoginFormFactory $loginFormFactory;

	private User $user;

	public $onAuthenticationSuccess = [];

	public function __construct(LoginFormFactory $loginFormFactory, User $user)
	{
		$this->loginFormFactory = $loginFormFactory;
		$this->user = $user;
	}


	protected function createComponentLoginForm(): Form
	{
		$form = $this->loginFormFactory->create();

		$form->onSuccess[] = [$this, 'doAuthentication'];

		return $form;
	}

	public function doAuthentication(Form $form, \stdClass $values): void
	{
		try {
			$this->user->login($values->email, $values->password);
		} catch (AuthenticationException $e) {
			$form->addError($e->getMessage());
			return;
		}
		Arrays::invoke($this->onAuthenticationSuccess);
	}
}

Presenter:

use App\Controls\LoginControl;
use App\Factories\LoginControlFactory;

final class UserPresenter extends Presenter
{
	private LoginControlFactory $loginControlFactory;

	public function __construct(LoginControlFactory $loginControlFactory)
	{
		parent::__construct();

		$this->loginControlFactory = $loginControlFactory;
	}

	protected function createComponentLogin(): LoginControl
	{
		$control = $this->loginControlFactory->create();

		$control->onAuthenticationSuccess[] = [$this, 'loginFormSucceeded'];

		return $control;
	}

	public function loginFormSucceeded()
	{
		$this->redirect('Homepage:default');
	}
}
jdan1131x
Member | 38
+
0
-

hehe makes my brain spin at higher rpm. thanks very much.
have most in play already…