Преобразователь Данных (англ. 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);
}
}