Mapování dat formuláře na třídy

Pepino
Člen | 249
+
0
-

Zdravím,

mám následující příklad:

class CustomFormData
{
	/** @var string */
	public $name;
	/** @var array */
	public $links;
}
protected function createComponentCustomForm(): Form {
	$form = new Form();
	$form->addText('name');
	$links = $form->addContainer('links');
	$links->addText('link_1');
	$links->addText('link_2');
	$links->addText('link_3');
	$form->addSubmit('send');
	$form->setMappedType(CustomFormData::class);
	$form->onSuccess[] = [
		$this,
		'processForm'
	];
	return $form;
}
public function processForm(Form $form, CustomFormData $customFormData): void {
	bdump($customFormData);
}

Jde nějak docílit aby $links byl array namísto ArrayHash?

Editoval Pepino (23. 3. 2022 15:35)

netteman
Člen | 122
+
0
-

Pokud máš PHP 8

class CustomFormData
{
	public string $name;
	public array $links;
}
NouF
Backer | 65
+
0
-

Ahoj,

co je špatně s arrayHash? Je to celkem šikovná věc.

Editoval NouF (23. 3. 2022 20:44)

Pepino
Člen | 249
+
+2
-

@netteman Funguje. Dík!

@NouF S ArrayHash není nic špatně. Ale formulář mi links nasetuje jako ArrayHash ale odjinud se mi tam zase setuje obyčejný array a pro další použití to potřebuju mít jednotné.

mkoula
Backer | 52
+
0
-

Když už je tu vlákno :-) Já mám problém s mapováním hidden na integer. Ve formuláři mám:

$form->addHidden('request_id', $this->bookingRequestId);

No a udělal jsem si:

class YesNoForm
{
    public function __construct(
        public string $lang,
        public int $request_id,
        public string $secure_key,
    ) {
    }
}

Ale vyřve mě to, že `request_id ` je string. Není nějaké řešení, jak u input.hidden definovat, že jde o integer? Pokud ne, tak to je krapet k ničemu a musím si to přemapovat u většiny formulářů ně nějaký svůj objekt ručně z defaultního ArrayHash…

jendaa
Člen | 6
+
+2
-

@mkoula
https://doc.nette.org/…rms/controls#…

$form->addHidden('request_id', $this->bookingRequestId)->addFilter(function ($item){return (int)$item;});
Zdeno1981
Člen | 114
+
+4
-

já to řeším takto

$form->addHidden(UsersRolesData::EDIT_ID, 0)
			->addRule(Form::INTEGER);
Pepino
Člen | 249
+
0
-

Jde nějakým způsobem mapovat i (sub)kontejnery formuláře?

Příklad:

protected function createComponentCustomForm(): Form {
	$form = new Form();
	$form->addText('name');
	$players = $form->addContainer('players');
	for ($a = 0; $a < 5; $a++) {
		$player = $players->addContainer('player_' . $a);
		$player->addText('name');
		$player->addText('age');
	}
	$form->setMappedType(CustomFormData::class);
	return $form;
}

Následující kód samozřejmě nefunguje protože players je array a až položky toho pole jsou typ PlayerData.

class CustomFormData
{
	public string $name;
	public PlayerData $players;
}
Jan Tvrdík
Nette guru | 2595
+
+1
-

@Pepino Containery to podporuje (viz testy), nicméně ty máš dynamické containery. Zkusil bych něco jako

class CustomFormData
{
	public string $name;

	/** @var PlayerData[] */
	public array $players;
}

a

$player = $players->addContainer('player_' . $a);
$player->setMappedType(PlayerData::class);
...

Případně od PHP 8 to můžeš zkusit přes konstuktor https://github.com/…tructor.phpt

Pepino
Člen | 249
+
0
-

@JanTvrdík Tohle řešení funguje, nicméně neexistuje nějaké elegantnější řešení než mapovat každý takový kontejner? Představoval bych si, že zavolám setMappedType na celý formulář a mapovací třída bude obsahovat právě i dané kontejnery.

David Grudl
Nette Core | 8109
+
+1
-

Podporovat anotace @var je opruz, šlo by to asi řešit pomocí atributu, něco jako

#[Type\ArrayOf(PlayerData::class)]
public array $players;

ale jednodušší mi přijde zůstat u setMappedType().

Pepino
Člen | 249
+
0
-

David Grudl napsal(a):

#[Type\ArrayOf(PlayerData::class)]
public array $players;

Do budoucna bych osobně něco takového určitě přivítal.

Jan Tvrdík
Nette guru | 2595
+
+2
-

Až na to, že reálně by to muselo být

/** @var PlayerData[] */
#[Type\ArrayOf(PlayerData::class)]
public array $players;

což už tak dobře nevypadá.