Lean Mapper - přeměňte své mappery v Lego
7. dubna 2018
Mappery v Lean Mapperu poskytují
informace o základních jmenných konvencích, ale také o implicitních
filtrech, o tom jaký repozitář patří k jaké entitě, apod. Pro
základní použití postačuje výchozí třída
LeanMapper\DefaultMapper
, pokud chceme něco složitějšího
obvykle výchozí mapper podědíme. Typicky je to potřeba, když potřebujeme
změnit výchozí namespace pro entity.
Právě neustálé dědění a
psaní dost podobných funkcí stále dokola mě vedlo k vytvoření knihovny
inlm/mappers
. Ta
poskytuje sadu několika mapperů, které je možné poskládat do sebe a
dosáhnout tak požadované funkcionality pomocí kompozice.
Základní konvence
Nejprve si představíme mappery, které nám pokrývají základní konvence pro převod názvu entity na název tabulky.
Inlm\Mappers\DefaultMapper
– poskytuje stejné konvence jakoLeanMapper\DefaultMapper
Inlm\Mappers\CamelCaseMapper
– stejné konvence jako DefaultMapper, ale názvy tabulek jsou konvertovány podle „camelCase“ konvence – entitěOrderItem
tedy bude odpovídat tabulkaorderItem
Inlm\Mappers\UnderScoreMapper
– stejné konvence jako DefaultMapper, ale názvy tabulek a sloupců jsou konvertovány podle „under_score“ konvence – entitěOrderItem
tedy bude odpovídat tabulkaorder_item
a položcecustomerName
sloupeccustomer_name
Změna namespace
Pokud potřebujeme změnit výchozí namespace pro entity, stačí namespace uvést v konstruktoru:
$mapper = new Inlm\Mappers\DefaultMapper('App\Entities');
$mapper = new Inlm\Mappers\CamelCaseMapper('App\Entities');
$mapper = new Inlm\Mappers\UnderScoreMapper('App\Entities');
Pokud se vám takový způsob nastavení výchozího namespace líbí a chtěli byste ho mít přímo v Lean Mapperu, zanechte komentář u tohoto pull requestu.
Dynamicky definované konvence
V případě,
že se nějaká entita výchozím konvencím vymyká, můžeme použít
DynamicMapper
a explicitně uvést správné mapování. Hodí se
třeba do modulárních aplikací, kdy každý modul může dynamicky
specifikovat svoje mapování.
$mapper = new Inlm\Mappers\DynamicMapper;
$mapper->setMapping(
'order_items', // název tabulky (povinný parametr)
'OrderItem', // entita (volitelný parametr)
'OrderItemRepository', // repositář (volitelný parametr)
'item_id' // primární klíč (volitelný parametr)
);
Pokud některý parametr vynecháme, bude zjištěn ze záložního mapperu – ve výchozím nastavení je to DefaultMapper, ale můžeme předat jiný mapper v konstruktoru:
$mapper = new DynamicMapper(new UnderScoreMapper('App\Entities'));
Prefixování tabulek
Ve výjimečných případech se můžeme setkat s požadavkem prefixovat názvy tabulek nějakým řetězcem. V tom přídadě použijeme PrefixMapper:
$mapper = new Inlm\Mappers\PrefixMapper('prefix_');
Všechny ostatní konvence jsou odvozeny ze záložního mapperu – ve výchozím nastavení je to DefaultMapper, ale v konstrukturu můžeme předat vlastní:
$mapper = new Inlm\Mappers\PrefixMapper('prefix_', new Inlm\Mappers\UnderScoreMapper);
$table = $mapper->getTable('OrderItem'); // vrátí 'prefix_order_item'
Příklad
Pokud to naše aplikace vyžaduje, můžeme všechny mappery pěkně poskládat do sebe:
$underscoreMapper = new UnderScoreMapper($defaultEntityNamespace);
$dynamicMapper = new DynamicMapper($underscoreMapper);
$mapper = new PrefixMapper($prefix, $dynamicMapper);
$table = $mapper->getTable('OrderItem');
Pro Nette:
parameters:
defaultEntityNamespace: 'Model\Entity'
prefix: 'prefix_'
services:
-
factory: Inlm\Mappers\CamelCaseMapper(%defaultEntityNamespace%)
autowired: off
-
factory: Inlm\Mappers\DynamicMapper(@Inlm\Mappers\CamelCaseMapper)
autowired: off
setup:
- setMapping('order_items', 'OrderItem', 'OrderItemRepository', 'item_id')
- Inlm\Mappers\PrefixMapper(%prefix%, @Inlm\Mappers\DynamicMapper)
Co dál?
V plánu mám ještě univerzální mapper pro Single Table Inheritance a pak už budou mappery pokrývat snad většinu obvyklých možností.