Преобразователь Данных (англ. Data Mapper ) — это шаблон, который выступает в роли посредника для
двунаправленной передачи данных между постоянным хранилищем данных (часто, реляционной базы данных)
и представления данных в памяти (слой домена, то что уже загружено и используется для логической обработки).
Цель шаблона в том, чтобы держать представление данных в памяти и постоянное хранилище данных независимыми друг
от друга и от самого преобразователя данных. Слой состоит из одного или более mapper ‘а (или объектов доступа к данным),
отвечающих за передачу данных. Реализации mapper ‘ов различаются по назначению. Общие mapper ‘ы могут
обрабатывать всевозможные типы сущностей доменов, а выделенные mapper ‘ы будут обрабатывать один или несколько
конкретных типов.
Storage.php
<?php
namespace DesignPatterns\Structural\DataMapper ;
/**
* Class Storage
* @package DesignPatterns\Structural\DataMapper
*/
class Storage
{
/**
* @var array
*/
private $data = [];
/**
* Storage constructor.
*
* @param array $data
*/
public function __construct ( array $data )
{
$this -> data = $data ;
}
/**
* @param int $id
*
* @return array|null
*/
public function find ( int $id )
{
if ( isset ( $this -> data [ $id ])) {
return $this -> data [ $id ];
}
return null ;
}
}
User.php
<?php
namespace DesignPatterns\Structural\DataMapper ;
/**
* Class User
* @package DesignPatterns\Structural\DataMapper
*/
class User
{
/**
* @var string
*/
private $username ;
/**
* @var string
*/
private $email ;
/**
* @param array $state
*
* @return User
*/
public static function fromState ( array $state ): User
{
return new self (
$state [ 'username' ],
$state [ 'email' ]
);
}
/**
* User constructor.
*
* @param string $username
* @param string $email
*/
public function __construct ( string $username , string $email )
{
$this -> username = $username ;
$this -> email = $email ;
}
/**
* @return string
*/
public function getUsername ()
{
return $this -> username ;
}
/**
* @return string
*/
public function getEmail ()
{
return $this -> email ;
}
}
UserMapper.php
<?php
namespace DesignPatterns\Structural\DataMapper ;
use InvalidArgumentException ;
/**
* Class UserMapper
* @package DesignPatterns\Structural\DataMapper
*/
class UserMapper
{
/**
* @var Storage
*/
private $storage ;
/**
* UserMapper constructor.
*
* @param Storage $storage
*/
public function __construct ( Storage $storage )
{
$this -> storage = $storage ;
}
/**
* @param int $id
*
* @return User
*/
public function findById ( int $id ): User
{
$result = $this -> storage -> find ( $id );
if ( $result === null ) {
throw new InvalidArgumentException ( 'User #' . $id . ' not found' );
}
return $this -> mapRowToUser ( $result );
}
/**
* @param array $row
*
* @return User
*/
private function mapRowToUser ( array $row ): User
{
return User :: fromState ( $row );
}
}
Test case:
UserMapperTest.php
<?php
namespace DesignPatterns\Tests\Structural\DataMapper ;
use DesignPatterns\Structural\DataMapper\Storage ;
use DesignPatterns\Structural\DataMapper\UserMapper ;
use InvalidArgumentException ;
use PHPUnit_Framework_TestCase ;
class DataMapperTest extends PHPUnit_Framework_TestCase
{
public function testCanMapUserFromStorage ()
{
$storage = new Storage (
[
1 => [
'username' => 'zyuzka' ,
'email' => 'zyuzka@mail.com' ,
],
]
);
$mapper = new UserMapper ( $storage );
$user = $mapper -> findById ( 1 );
$this -> assertInstanceOf ( 'DesignPatterns\Structural\DataMapper\User' , $user );
}
public function testWillNotMapInvalidData ()
{
$this -> expectException ( InvalidArgumentException :: class );
$storage = new Storage ([]);
$mapper = new UserMapper ( $storage );
$mapper -> findById ( 1 );
}
}