Vstupní data pro Nette/Database multi insert
- m.brecher
- Generous Backer | 871
Dobrý den, měl jsem tyto problémy s multi insertem do Nette\Database
$accounts = [
1 => ['bank_id' => 44, 'number' => '444-888'], // index nezačínají nulou - toto NEFUNGUJE
2 => ['bank_id' => 32, 'number' => '556643'],
];
$user = $this->database->table('user')->get($userId);
$user->related('bank_account')->insert($accounts);
Obdržel jsem chybovou hlášku: Nette\Database\SqlPreprocessor::delimite(): Argument #1 ($name) must be of type string, int given
Po delším zkoušení jsem objevil, že problém není v tom, že by nějaký parametr měl být string a byl místo toho integer, ale v číselných indexech vstupního pole. Když jsem číselné indexy pole opravil tak, aby začínaly od 0 tak multi insert fungoval:
$accounts = [
0 => ['bank_id' => 44, 'number' => '444-888'], // indexy začínají nulou - toto funguje
1 => ['bank_id' => 32, 'number' => '556643'],
];
$user = $this->database->table('user')->get($userId);
$user->related('bank_account')->insert($accounts);
Navrhuji provést tyto úpravy v metodě insert() pro multiinsert:
- Povolit vstupní pole začínající i jiným indexem než 0, pokud by to nešlo, vyhodit výjimku s odpovídající hláškou, že jsou špatně indexy pole, protože jinak se ta chyba špatně zjišťuje
- Jak už jsem psal v jiném příspěvku, metoda insert() by měla akceptovat na vstupu i „dvourozměrný“ ArrayHash (objekt ArrayHash obsahující další ArrayHashe), protože v tomto formátu vrací formuláře Nette $values.
- Další variantou dat na vstupu je pole objektů ArrayHash, i tuto variantu formátu dat pro mulitiinsert by měla metoda insert() akceptovat.
- Polki
- Člen | 553
a. Tak udělej PR
b. Proč? To, že má Nette pro práci s poli příjemnější
třídu ArrayHash, a ne obyč pole, nebo object nemá co dělat s tím, co by
měla přijmat metoda insert
z NDBT. V rámci Nette formulářů
můžeš klidně napsat $form->getValues(true)
, nebo
$form->getValues(Nette\Forms\Container::ARRAY)
a to ti vrátí
rekurzivně zanořené pole, které už do insert metody narveš v klidu.
Nebosi dokonce můžeš nechat vrátit objekt
$form->getValues(User::class)
a ty taky nenarveš do metody
insert, protože prostě nejsou iterable… A stejně jako si tam můžeš
narvat jakoukoliv třídu do návratové hodnoty formulářů, tak i ArrayHash
je třída, takže jak by se to mělo chovat? Některé třídy by to mělo
akceptovat a jiné ne? Nevidím důvod akceptovat ArrayHash. Když budeš
používat mapování na sou třídu, tak stejně budeš dělat
přetransformování na pole jako u ArrayHashe. Pokud ti to moc vadí prostě
si nech z Values vrátit pole rovnou.
c. Stejný případ jako v b.
- m.brecher
- Generous Backer | 871
Polki napsal(a):
a. Tak udělej PR
b. Proč? To, že má Nette pro práci s poli příjemnější třídu ArrayHash, a ne obyč pole, nebo object nemá co dělat s tím, co by měla přijmat metodainsert
z NDBT. V rámci Nette formulářů můžeš klidně napsat$form->getValues(true)
, nebo$form->getValues(Nette\Forms\Container::ARRAY)
a to ti vrátí rekurzivně zanořené pole, které už do insert metody narveš v klidu. Nebosi dokonce můžeš nechat vrátit objekt$form->getValues(User::class)
a ty taky nenarveš do metody insert, protože prostě nejsou iterable… A stejně jako si tam můžeš narvat jakoukoliv třídu do návratové hodnoty formulářů, tak i ArrayHash je třída, takže jak by se to mělo chovat? Některé třídy by to mělo akceptovat a jiné ne? Nevidím důvod akceptovat ArrayHash. Když budeš používat mapování na sou třídu, tak stejně budeš dělat přetransformování na pole jako u ArrayHashe. Pokud ti to moc vadí prostě si nech z Values vrátit pole rovnou.
c. Stejný případ jako v b.
@Polki Když metoda insert() akceptuje jednorozměrný ArrayHash,
nevidím jako logické, aby neuměla akceptovat dvourozměrný ArrayHash a
právě fakt, že to nejde trochu kazí tu pohodlnost třídy ArrayHash.
Dvourozměrný ArrayHash je iterable úplně stejně jako array. O možnostech
$form->getValues(Nette\Forms\Container::ARRAY)
nebo
$form->getValues(true)
jsem nevěděl, ArrayHash jsem si
převedl na pole svojí funkcí, ale než jsem přišel na to čím to je, tak
jsem tam strávil daleko víc času, než mě ušetřil jeden formulář Nette
oproti PHP – chybová hláška vůbec nepomůže pochopit, kde je
problém.
- Polki
- Člen | 553
@mbrecher Tam jde o to, že Selection třída přijmá na vstup
iterable. Tedy jakýkoliv objekt implementující Traversable nebo čistý
array. Zatímco vnitřně nad těmi hodnotami z toho prvního ArrayHashe se
volají další metody jiných tříd, které pro jednoduchost vyžadují
čistý array.
Dokážeš si představit to množství práce, kdyby si tam mohl uživatel
narvat cokoliv a muselo by se ověřovat jestli to je to či ono aby to
proběhlo jak kdo chce a nepadalo to? :D Už tak se vsadím, že nad tím bylo
stráveno víc času, než kdokoliv z nás vůbec programuje. :D
Ato není všechno. Dotazy do databáze jsou už tak pomalá záležitost.
Vsadím se, že nikdo nechce ještě čekat na ověřování, co se do těch
metod posílá a potom to převádět na nějakou hodnotu se kterou se dá
pracovat. Nikdo nechce aby příprava na db dotaz trvala několikrát déle,
než samotný dotaz. Proto je lepší vyžádat si jednoduše Array a nemuset
ověřovat a transformovat pokaždé.
Jestli si ale myslíš, že to je dobrá cesta, tak pořád je tu možnost PR
nad upraveným Nette\Database\SqlPreprocessor
konkrétně
metodou formatValue()