Missing argument 3 for App\Forms\ResetFormFactory::App\Forms\{closure}()

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
SontoEremo
Člen | 341
+
0
-

Po pridaní premenných na mňa vyskočí Tracy
Missing argument 3 for App\Forms\ResetFormFactory::App\Forms\{closure}()
Ako teda pridávať premenné do functions?

$form->onSuccess[] = function (Form $form, $email, $values, $token) use ($onSuccess) {
Pavel Kravčík
Člen | 1196
+
0
-

Success hádám předává jen 2 parametry. Tenhle zápis je nesmysl. A neduplikuj vlákna, když Ti David radil dobře.

SontoEremo
Člen | 341
+
0
-

Pavel Kravčík napsal(a):

Success hádám předává jen 2 parametry. Tenhle zápis je nesmysl. A neduplikuj vlákna, když Ti David radil dobře.

Môžeš mi prosím ta napísať kde mi David radil dobre na túto otázku? a kde je duplikátne vlákno?

SontoEremo
Člen | 341
+
0
-

Pavel Kravčík napsal(a):

https://forum.nette.org/…-s-databazou#…

Tam riešim úplne inú vec predsa

jiri.pudil
Nette Blogger | 1032
+
0
-

Tady ti David psal, že do druhého argumentu té funkce se předávají hodnoty formuláře, tedy úplně totéž, co si o řádek níž získáváš přes $form->getValues(). Takže buďto:

$form->onSuccess[] = function (Form $form) {
	$values = $form->getValues();
	// ...
};

nebo

$form->onSuccess[] = function (Form $form, $values) {
	// ...
};

Oběma způsoby dojdeš ke stejnému výsledku: ve $values máš odeslané hodnoty.

SontoEremo
Člen | 341
+
0
-

jiri.pudil napsal(a):

Tady ti David psal, že do druhého argumentu té funkce se předávají hodnoty formuláře, tedy úplně totéž, co si o řádek níž získáváš přes $form->getValues(). Takže buďto:

$form->onSuccess[] = function (Form $form) {
	$values = $form->getValues();
	// ...
};

nebo

$form->onSuccess[] = function (Form $form, $values) {
	// ...
};

Oběma způsoby dojdeš ke stejnému výsledku: ve $values máš odeslané hodnoty.

Ja to chápem preto som udával $values = $form->getValue();
Ale ja potrebujem vedieť ako do

$form->onSuccess[] = function (Form $form, $values)

dopísať viac premenných $token, $mail, $atď…

jiri.pudil
Nette Blogger | 1032
+
+1
-

Pokud je tam potřebuješ předat z vnějšího kontextu, použij k tomu use, stejně jako předáváš $onSuccess:

// tu v tomto kontextu existují $onSuccess, $mail, $token

$form->onSuccess[] = function (Form $form, $values) use ($onSuccess, $mail, $token) {
	// tu uvnitř můžeš navíc ještě přistupovat k $this
};

Více informací, pokud budou potřeba, můžeš najít v dokumentaci

SontoEremo
Člen | 341
+
0
-

jiri.pudil napsal(a):

Pokud je tam potřebuješ předat z vnějšího kontextu, použij k tomu use, stejně jako předáváš $onSuccess:

// tu v tomto kontextu existují $onSuccess, $mail, $token

$form->onSuccess[] = function (Form $form, $values) use ($onSuccess, $mail, $token) {
	// tu uvnitř můžeš navíc ještě přistupovat k $this
};

Více informací, pokud budou potřeba, můžeš najít v dokumentaci

Skúšal som vtedy to končí chybou Undefined variable: token nevie nájsť token ale keď to vkladam do function() tam to ide v pohode akurát tam viac nemôže byť.

jiri.pudil
Nette Blogger | 1032
+
0
-

Já ten první komentář myslel jako předpoklad. Pro lepší pochopení takto:

// tu v tomto kontextu MUSÍ EXISTOVAT $onSuccess, $mail, $token

Odkud se ten token bere?

Jinak bych ještě pro názornost doplnil, že parametry toho callbacku skutečně nijak neovlivníš, neb je určuje a předává ten, kdo ji volá, což je v tomhle případě Form

SontoEremo
Člen | 341
+
0
-

@jiri.pudil
Odkud se ten token bere?
z userManageru

public function selectToken($token) {
	    return $this->database->table(self::TABLE_NAME)->where(self::COLUMN_TOKEN, $token)->fetch();
	}

Editoval SontoEremo (10. 1. 2017 16:12)

David Matějka
Moderator | 6445
+
0
-

Ten token, ktery tam chces, je predpokladam nejaky retezec. Kde vznika? to je nejaky parametr v presenteru?

Mysteria
Člen | 797
+
0
-

Nepotřebuješ náhodou dostat do toho formuláře parametr z URL adresy?

SontoEremo
Člen | 341
+
0
-

Mysteria napsal(a):

Nepotřebuješ náhodou dostat do toho formuláře parametr z URL adresy?

@DavidMatějka @Mysteria
Ospravedlňujem sa ale celé som to doplietol.. namiesto toho aby som updatoval $token v db som sa ho snažil vytiahnuť ale momentálne je token prázdny a ja ho potrebujem naplňiť… takže tak.

Neviete ako aktualizovať pretože mne to furt vyhadzuje chybu
Call to a member function update() on boolean

public function updateToken() {
		$update = $this->database->table(self::TABLE_NAME)->where(self::COLUMN_TOKEN, 'token')->fetch();
	}
$selectToken = $this->userManager->updateToken('token');
$token = Random::generate(32);
$selectToken->update(array('token' => $token));

Editoval SontoEremo (10. 1. 2017 19:48)

David Matějka
Moderator | 6445
+
0
-

vzdyt z te metody nic nevracis..

Mysteria
Člen | 797
+
0
-

Vždyť ale tohle jsou základy PHP jako takového. Voláš ->updateToken(‚token‘) ale metoda updateToken nemá žádný parametr, takže k ničemu. Chceš z metody návratovou hodnotu, ale nemáš v ní nikde return něco.

SontoEremo
Člen | 341
+
0
-

@Mysteria
Takto to vysvetlím
Robím obnovenie hesla:
tak, že v tabuľke users mám token ktorý po registrácii musí užívateľ aktívovať po aktivácii sa zmení na null a následne sa ďalší stĺpček activation zmeni z no na yes… potom pri prihlásení kontrolujem či si užívateľ aktivoval účet a či je activation yes tak ho prihlásim …

No a do toho tokenu ktorý je momentálne null chcem po správne zadanej emailovej adresy updatnúť token ktorý sa odošle na mail išlo mi o to aby sa najprv skontrolovalo či je email v db ak áno tak sa potom overí či je token null alebo už bol vygenerovaný ak áno vyhodím flashMessage, že už sa zažiadalo o heslo atď… ak token nie je null updatne sa tabuľka a vloží sa token…

Lenže ja som sa snažil ťahať tabulku či je token null alebo nie … preto som to tam drbal…
Hádam som to vysvetlil aspoň pre pochopenie :)

iguana007
Člen | 970
+
0
-

Ale lidi tady chápou o co ti jde, problém je v tom, že ty pravděpodobně nerozumíš jejich radám.

Tj.: Když chceš nějaké metodě předávat parametr, tak jej musíš u té metody definovat. A pokud chceš ověřovat výsledek operace té metody, tak jej musíš vrátit, pomocí return.

Takže metoda updateToken by měla vypadat cca takto:

public function updateToken($token) {
	return $this->database->table(self::TABLE_NAME)->where(self::COLUMN_TOKEN, $token)->fetch();
}
SontoEremo
Člen | 341
+
0
-

@iguana007
Keď si pozrieš 8 komentár od spodu mám to tak… ale ja neviem ako predať z userMageru do ResetFormFactory funkciu updateToken().

napríklad

$addToken = $this->userManager->updateToken($token);

Vykočí Undefined variable: token

Ak vynechám $token
Missing argument 1 for App\Model\UserManager::updateToken(), called in C:\xampp\htdocs\pagename\app\forms\ResetFormFactory.php on line 42 and defined

Ak $token pridám a prídám ho aj do function $form->onSuccess[] = function (Form $form, $email, $token) use ($onSuccess) {
Vyhodí to Missing argument 3 for App\Forms\ResetFormFactory::App\Forms\{closure}()

Tak ako potom pridať parametre z userManageru do Factory alebo Presenteru?

Jan Mikeš
Člen | 771
+
+1
-

Procetl jsem cele vlakno a nezlob se, ale z meho pohledu pozorovatele se na to vyprdni.
Nejdrive se poradne douc zaklady OOP PHP a az pote se zkousej pustit do Nette, usetris tim spoustu nervu sobe i lidem na tomto foru.

Editoval Jan Mikeš (11. 1. 2017 16:26)

jiri.pudil
Nette Blogger | 1032
+
+1
-

@SontoEremo já to s tebou ještě zkusím :) vždyť sis ten algoritmus vlastně celkem přesně popsal sám, a dokonce v něm máš i napsáno, odkud se vezme $token:

išlo mi o to aby sa najprv skontrolovalo či je email v db ak áno tak sa potom overí či je token null alebo už bol vygenerovaný ak áno vyhodím flashMessage, že už sa zažiadalo o heslo atď… ak token nie je null updatne sa tabuľka a vloží sa token…

Pojďme si to rozebrat:

išlo mi o to aby sa najprv skontrolovalo či je email v db

Ve vedlejším vlákně jsi už doufám dospěl k fungující matchEmail, která ti vrátí:

  • FALSE, pokud e-mail není v databázi → flashMessage, konec, není co řešit; nebo
  • záznam o uživateli s daným e-mailem, říkejme mu třeba $user.

ak áno tak sa potom overí či je token null alebo už bol vygenerovaný

Z toho řádku, který dostaneš, přečti a zkontroluj token: $user->token. Tohle je ten tvůj $token, od kterého očekáváš, že se ti někde zčistajasna zjeví. Nezjeví; tady si ho přečteš ze záznamu načteného z databáze.

ak áno vyhodím flashMessage, že už sa zažiadalo o heslo atď…

Spíš bych vygeneroval a poslal nový token, protože co když uživateli třeba jenom nedošel ten první e-mail? To už se nedostane do svého účtu?

ak token nie je null updatne sa tabuľka a vloží sa token…

Tady jsi myslel „ak token je null“, tj. ještě nebyl vygenerovaný. V tom případě vygeneruj nový, ulož ho – $user->update(['token' => $token]) – a pošli uživateli e-mailem.

SontoEremo
Člen | 341
+
0
-

@JanMikeš ďakujem píšem si to do denníčka :)
@jiri.pudil zabudol som tam dopísať to že ako to mám už urobené :) takže Ďakujem za rozsiahli opis ale už som to dal do kopy len som to popísal dosť na prd za čo sa ospravedlňujem… ide mi stále iba o jeden problém ku ktorému sa nemôžem ani za boha dopátrať.
ešte raz ti priložím problém ktorý ma trápy!

neviem ako predať z userMageru do ResetFormFactory funkciu updateToken().

napríklad

$addToken = $this->userManager->updateToken($token);

Vykočí Undefined variable: token

Ak vynechám $token
Missing argument 1 for App\Model\UserManager::updateToken(), called in C:\xampp\htdocs\pagename\app\forms\ResetFormFactory.php on line 42 and defined

Ak $token pridám a prídám ho aj do function $form->onSuccess[] = function (Form $form, $email, $token) use ($onSuccess) {
Vyhodí to Missing argument 3 for App\Forms\ResetFormFactory::App\Forms\{closure}()

Tak ako potom pridať parametre z userManageru do Factory alebo Presenteru?

David Matějka
Moderator | 6445
+
0
-

to je porad dokola. do onSuccess se predava $form a $values. nic vic, nic min.

Kde je pritomna ta hodnota, kterou chces mit v $token? nekde jako parametr v presenteru?

CZechBoY
Člen | 3608
+
+1
-

Pošli sem co nejvíc kodu nebo to zabal, tohle nemá moc smysl – opakujou se příspěvky tvoje i rádců.

jiri.pudil
Nette Blogger | 1032
+
0
-

Ty už z toho máš vlčí mlhu, tolik se soustředíš na jeden problém, až přehlížíš, že to je důsledek, a ne příčina, a že bys ten problém vůbec mít nemusel.

jiri.pudil napsal(a):

Z toho řádku, který dostaneš, přečti a zkontroluj token: $user->token. Tohle je ten tvůj $token, od kterého očekáváš, že se ti někde zčistajasna zjeví. Nezjeví; tady si ho přečteš ze záznamu načteného z databáze.

Líp už to vysvětlit nedokážu.

SontoEremo
Člen | 341
+
0
-

David Matějka napsal(a):

to je porad dokola. do onSuccess se predava $form a $values. nic vic, nic min.

Ale to viem pre boha…
Takto aby sme to už absolútne nerozoberali
V userManager mám
napr.

public function theEmail($email) {
	.....
}
public function nieco($volaco) {
	....
}
public function nieco2($volaco2) {
	....
}

a chcem to preniesť do NiecoFormFacory

a potrebujem to dostať sem tak aby bol výsledok
$form->onSuccess[] = function (Form $form, $email <- Toto už tu je viac sa nedá) use ($onSuccess) {
	$addEmail = $this->userManager->theEmail($email)
	$foo = $this->userManager->nieco($volaco);
	$foo2 = $this->userManager->nieco2($volaco2);
	Končí chybou Undefined variable: nieco
}

A ja neviem ako preniesť
$foo = $this->userManager->nieco($volaco);
$foo2 = $this->userManager->nieco2($volaco2);

do NiecoFormFacory

Editoval SontoEremo (11. 1. 2017 18:05)

Mysteria
Člen | 797
+
+1
-

SontoEremo napsal(a):

@iguana007
Keď si pozrieš 8 komentár od spodu mám to tak… ale ja neviem ako predať z userMageru do ResetFormFactory funkciu updateToken().

Ne, tohle je špatně. Žádná funkce se nikam nepředává, to co ty potřebuješ, je předat token, a v tom je rozdíl.

A teď k tomu, jak to udělat:

/** @var string */
private $token;

// Na tuhle akci bude směřovat link, který pošleš v tom emailu,
// takže v emailu bude něco jako example.com/sign/change-password/?token=123456789
public function actionChangePassword($token = NULL) {
	$this->token = $token;
}

protected function createComponentChangePasswword() {
	$form = new \Nette\Application\UI\Form;
	$form->addEmail('email');
	$form->addPassword('password');
	$form->addSubmit('submit');
	$form->onSuccess[] = function(\Nette\Application\UI\Form $form) {
		$something = $this->userManager->updateToken($this->token);
	};
}

Ale jak psal @Jan Mikeš tak tohle nemá nic společného se samotným Nette, tohle jsou klasické znalosti z objektově orientovaného programování. Snažit se používat Nette a neumět samotné OOP PHP je to samé jako snažit se psát knihu a neumět abecedu. A to není problém Nette, na tohle bys narazil u jakéhokoliv jiného frameworku, protože:

Když definuješ funkci a dáš jí tam parametr, tak je logické, že když ji budeš volat, tak jí ten parametr taky musíš dát (nebo ho udělat volitelný, ale to není tenhle případ), jinak to bude psát chybu. Druhá věc, když si v nějaké funkci vytvoříš proměnnou a chceš jí použít v jiné funkci, tak lokální proměnná tam samozřejmě nebude dostupná (viz Undefined variable: token) a musí to být třídní proměnná.

Každopádně zdá se mi že celkově ten proces resetování hesla řešíš nějak zvláště (možná se mi to jenom zdá). Tady ti dávám příklad, z jednoho staršího projektu, jak to je řešené tam:

// Uživatel zadá do formuláře svůj email, na který se mu pošle link pro změnu hesla
// $user je klasicky $form->values z presenteru a obsahuje položku email
public function forgottenPassword(\Nette\Utils\ArrayHash $user) {
	if ($user = $this->database->table('user')->where('email = ?', $user->email)->fetch()) {
		$this->database->table('forgotten_password')->insert([
			'user_id' => $user->id,
			'token' => $token = \Nette\Security\Passwords::hash(\Nette\Utils\Random::generate(60))
		]);
		$this->mailer->send((new \Nette\Mail\Message)
				->setFrom('no-reply@example.com')
				->addTo($user->email)
				->setBody($this->link->link('Guest:Sign:forgottenPassword', ['email' => $user->email, 'token' => $token]))
		);
	} else throw new UserException('Invalid email', 3);
}

// Uživatel kliknul na link v emailu, ve kterém je v parametrech email + token
// $user obsahuje email z URL + token z URL (to, že ty to máš z formuláře je jedno, jenom při volání téhle metody v presenteru předáš data od jinud)
// Plus tady v téhle metodě heslo generuju náhodně a posílám mu na email (což dneska není považováno za bezpečné),
// ale upravit to na formulář je jednoduchý, stačí přepsat $password = \Nette\Utils\Random::generate(10) na $user->password
public function forgottenPasswordVerify(\Nette\Utils\ArrayHash $user) {
	if ($forgottenPassword = $this->database->table('forgotten_password')->where('user.email = ?', $user->email)->fetch()) {
		if ($forgottenPassword->token === $user->token) {
			if ($forgottenPassword->timestamp > new \DateTime('-1 hour')) {
				$this->database->table('user')->where('email = ?', $user->email)->update([
					'password' => \Nette\Security\Passwords::hash($password = \Nette\Utils\Random::generate(10), ['cost' => 10])
				]);
				$forgottenPassword->delete();
				$this->mailer->send((new \Nette\Mail\Message)
						->setFrom('no-reply@example.com')
						->addTo($user->email)
						->setBody('New password: ' . $password)
				);
			} else throw new UserException('Invalid timestamp', 5);
		} else throw new UserException('Invalid token', 4);
	} else throw new UserException('Invalid email', 3);
}

Editoval Mysteria (11. 1. 2017 18:09)

SontoEremo
Člen | 341
+
0
-

@Mysteria KONEČNE
Veľmi pekne Ďakujem ty si pán :) (v dobrom zmysle slova)
Ďakujem aj za kód budem sa z toho učiť :)

/** @var string */
	private $nieco;

	/** @var string */
	private $nieco2;

$this->nieco
a
$this->nieco2

To je to o čo som sa snažil celý čas veľmi pekne ti Ďakujem Problém vyriešený
Samozrejme aj ostatným :)

SontoEremo
Člen | 341
+
0
-

@Mysteria
Ďakujem za kód prechádzam krok po kroku avšak som sa zasekol na
// $user obsahuje email z URL + token z URL (to, že ty to máš z formuláře je jedno, jenom při volání téhle metody v presenteru předáš data od jinud)

if ($forgottenPassword = $this->database->table('forgotten_password')->where('user.email = ?', $user->email)->fetch()) {
	if ($forgottenPassword->token === $user->token) {
		......
	}
}

Spravujem to v NewpasswordFormFactory ako to myslíš předáš data od jinud? mám si to v userManager vytiahnuť?
napr.

public function selectEmai($email) {
	return $this->database->table(self::TABLE_NAME)->where('email', $email)->fetch();
}

a predať ho do NewpassFormFactory?

if ($forgottenPassword = $this->userManager->selectEmai($this->email)) {
	.....
}

Lebo stále je hodnota NULL

Mysteria
Člen | 797
+
0
-

To je myšleno tak, že já tu metodu volám přímo z action metody presenteru, protože už tam nemám formulář na zadání nového hesla, ale heslo mu generuju, takže to mám nějak takto:

public function actionCompleteChangePassword($email, $token) {
	$this->userManager->forgottenPasswordVerify(['email' => $email, 'token' => $token]);
}

Ty když tam máš formulář, tak to budeš mít nějak takto (psáno z hlavy):

protected function createComponentPickNewPasswword() {
    $form = new \Nette\Application\UI\Form;
    $form->addEmail('email');
    $form->addPassword('password');
    $form->addSubmit('submit');
    $form->onSuccess[] = function(\Nette\Application\UI\Form $form) {
		$values = $form->values;
		$values->token = $this->token;
        $this->userManager->forgottenPasswordVerify($values);
    };
}