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\DefaultMapperInlm\Mappers\CamelCaseMapper– stejné konvence jako DefaultMapper, ale názvy tabulek jsou konvertovány podle „camelCase“ konvence – entitěOrderItemtedy bude odpovídat tabulkaorderItemInlm\Mappers\UnderScoreMapper– stejné konvence jako DefaultMapper, ale názvy tabulek a sloupců jsou konvertovány podle „under_score“ konvence – entitěOrderItemtedy bude odpovídat tabulkaorder_itema položcecustomerNamesloupeccustomer_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í.