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 jako LeanMapper\DefaultMapper
  • Inlm\Mappers\CamelCaseMapper – stejné konvence jako DefaultMapper, ale názvy tabulek jsou konvertovány podle „camelCase“ konvence – entitě OrderItem tedy bude odpovídat tabulka orderItem
  • 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 tabulka order_item a položce customerName sloupec customer_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í.

Líbí se vám tato stránka?