Podpora databázového typu ENUM ve formulářích
- horakmar
- Člen | 16
Ahoj.
Jeden krátký dotaz. Má Nette nějakou podporu databázového typu ENUM? Resp.
existuje nějaká best practise, jak s nimi pracovat? Já mám ve své aplikaci
poměrně dost takových polí a řeším to zatím tak, že mám v modelu
pole, které popisuje onen ENUM:
class EntryPresenter extends BaseRacePresenter {
public static $start_options = [
'none' => 'Nic',
'early' => 'Brzy',
'late' => 'Pozdě',
'red' => 'Červená',
'orange' => 'Oranžová'
];
...
public function createComponentEntryForm() {
$form = new Form;
...
$form->addSelect('start_opt', 'Volby', self::$start_options);
...
}
public function renderList($entryid = NULL) {
$this->template->addFilter('startopt', function($s){
return self::$start_options[$s];
});
...
}
}
A v šabloně potom:
...
<tr n:foreach="$entries as $entry">
<td>{$entry->start_opt|startopt}</td>
...
Připadá mi to ale trochu těžkopádné a navíc duplikuju tím klíče toho ENUM – jednou v databázi, podruhé v kódu. Neexistuje nějaké lepší řešení?
Díky za odpověď,
Martin
- greeny
- Člen | 405
já radši řeším enumy v db tak, že místo typu enum dám varchar a enum je to vlastně jen na straně PHPčka, většinou nějak takhle:
class UserStatus
{
const REGISTERED = 'registered';
const BANNED = 'banned';
const VERIFIED = 'verified';
// ...
public static function isValid($stauts)
{
return in_array($status, self::getAll(), TRUE);
}
public static function getAll()
{
return array_keys(self::getPairs());
}
public static function getPairs()
{
return [
self::REGISTERED => 'Registered',
// ...
];
}
}
Všude kde hodnotu nastavuju vyhodím exception pokud mi neprojde isValid (např v Doctrině jen v setteru entity).
Funguje to krásně a když přidám další typ tak se nemusím zabývat migrací DB.
- Tomáš Jacík
- Člen | 147
@horakmar Pokud jde jen o klíč ⇒ hodnota, ukládám to pomocí konstant ve třídě entity a vytvořím si k tomu pole ve static proměnné, např. takto:
class Campaign
{
const STATUS_ACTIVE = 'A',
STATUS_STOPPED = 'S',
STATUS_DELETED = 'D';
public static $states = [
self::STATUS_ACTIVE => 'active',
self::STATUS_STOPPED => 'stopped',
self::STATUS_DELETED => 'deleted',
];
}
Do selectu to pak dostávám raději přes translator, abych měl v aplikaci jen anglické názvy:
foreach (Campaign::$states as $k => $v) {
$this->statusOptions[$k] = $translator->translate("campaign.status.$v");
}
Není to však nutností, stačí selectu nasetovat to pole
Campaign::$states
.
Mnohem častěji ale potřebuji k těm stavům ukládat více informací.
Např. barvu, kterou se zobrazí v datagridu nebo zda se má při změně na
tento stav zaslat informační mail. Pak je lepší mít tabulku
campaign_states
a nacpat to vše do ní.
- Majkl578
- Moderator | 1364
Tomáš Jacík napsal(a):
class Campaign { const STATUS_ACTIVE = 'A', STATUS_STOPPED = 'S', STATUS_DELETED = 'D'; public static $states = [ self::STATUS_ACTIVE => 'active', self::STATUS_STOPPED => 'stopped', self::STATUS_DELETED => 'deleted', ]; }
Tohle bych definoval spíš trochu obecněji (hodnota konstanty stačí, netřeba další mapa překladu) a konstantou. Takhle třeba:
class Campaign
{
const STATE_ACTIVE = 1;
const STATE_STOPPED = 2;
const STATE_DELETED = 3;
const STATES = [
self::STATE_ACTIVE,
self::STATE_STOPPED,
self::STATE_DELETED,
];
}
Jinak souhlasím s nepoužíváním enumu v databázi. Měnit strukturu databáze kvůli přidání nového stavu je tak trochu nic moc…
- studna
- Člen | 181
Jen pozor na použití ENUM a číselných hodnot. Pokud v DB budeš mít
ENUM('3', '2', '1')
a vložíš hodnotu int(1)
, tak
v DB budeš mít uloženou '3'
, nikoliv očekávanou
jedničku.
Edit: Tady si nejsem jistý, jestli klíče ENUMu začínají nulou nebo jedničkou, podstatné je, že to lze velmi snadno přehlédnout a špatně používat.
$row = $row->update('status', Campaign::STATE_ACTIVE);
// ...
// tato podminka bude platit
$row->status == Campaign::STATE_DELETED;
Pro číselné hodnoty je lepší použít běžný integer a ENUM tak uměle držet pouze v kódu.
Tady jen na okraj pár dalších důvodů, proč se ENUM moc nehodí.
Editoval studna (5. 2. 2016 21:59)
- horakmar
- Člen | 16
Pro číselné hodnoty je lepší použít běžný integer a ENUM tak uměle držet pouze v kódu.
Tady jen na okraj pár dalších důvodů, proč se ENUM moc nehodí.
Myslím, že jste mě přesvědčili, že ENUM není dobrá věc a že bude
lepší v DB použít buď INT, nebo číselník. V mém případě
číselník nebude nutný. Také se zdá, že nápad se statickým polem hodnot
v kódu nebyl úplně špatný.
Na ENUM se mi líbilo, že i při procházení databáze je vidět význam
hodnot. Což se dá s trochu menším komfortem asi řešit poznámkou
k tabulce.
Každopádně všem díky!
Martin
- Tomáš Jacík
- Člen | 147
@Majkl578 Nesouhlasím. Takto musíš to pole do selectu vždy vyrobit, nebo na to mít funkci. Mé řešení je imho mnohem jednoduší a ten výčet z něj vždy snadno uděláš přes array_keys.