php mapper model dao,PHP 设计模式 - 结构型 - 数据映射模式(Data Mapper)

1. 模式定义

数据映射:是持久化数据存储层(通常是关系型数据库)和驻于内存得数据表现层直接进行双向数据传输得数据访问层。

数据映射模式的目的:让持久化数据存储层、驻于内存的数据表现层、以及数据映射本身三者相互独立、互不依赖。

这个数据访问层由一个或多个映射器(或者数据访问对象)组成,用于实现数据传输。通用的数据访问层可以处理不同的实体类型,而专用的则处理一个或几个。

2. 数据映射模式 ( Data Mapper ) VS 活动记录模式(Active Record)

首先我们将 ORM 模型拆分开来就是两个功能

数据操作 - 对数据对象做变更,就是我们常说的业务逻辑。

数据持久化 - 将数据落地,比如存储到 MySQL,MongoDB 等不同的数据库。

数据映射模式 ( Data Mapper ):主张两个功能必须分开,扩展灵活,逼格高,数据模型遵循单一职责原则(Single Responsibility Principle)。使用Data Mappers的框架数量相比ActiveRecord要少很多,主要有Java Hibernate,PHP Doctrine,SQLAlchemy in Python,EntityFramework for Microsoft .NET。

$model = new User();

$model->setId(1);

$model->setAccount('it2048');

$model->setPassword('123456');

$result = (new UserMapper())->save($user);

$model 对象属性的修改属于业务逻辑,UserMapper涵括持久化逻辑。

活动记录模式 (Active Record) : 主张把两个功能合在一起,简单方便,易上手。用ActiveRecord ORM的PHP框架有Laravel, Yii, CodeIgniter, CakePHP等。其他语言用的有 Ruby on Rails,Django等。

$model = new User();

$model->user_id = 1;

$model->name = 'Sylvia';

$model->save();

对 $model 属性的修改属于业务逻辑,调用save()方法属于持久化逻辑。使用者完全不用关心save()方法执行后数据是存储到MySQL还是MongoDB,在开发过程中可以将精力全部放到业务逻辑,开发速度非常快。

3. UML类图

85caa1609172

image.png

4. 示例代码

业务逻辑 User

namespace DesignPattern\Structural\DataMapper;

/**

* 数据库记录在内存的表现层

*/

class User

{

/**

* @var int

*/

protected $userId;

/**

* @var string

*/

protected $name;

/**

* @param null $id

* @param null $name

*/

public function __construct($id = null, $name = null)

{

$this->userId = $id;

$this->name = $name;

}

/**

* @return int

*/

public function getUserId()

{

return $this->userId;

}

/**

* @param int $userId

*/

public function setUserID($userId)

{

$this->userId = $userId;

}

/**

* @return string

*/

public function getName()

{

return $this->name;

}

/**

* @param string $name

*/

public function setName($name)

{

$this->name = $name;

}

}

持久化逻辑 UserMapper

namespace DesignPattern\Structural\DataMapper;

use Doctrine\DBAL\DBALException;

use Doctrine\DBAL\DriverManager;

/**

* 数据映射类

* 数据库的连接与修改,这里用的是扩展包DBAL适配器,用于连接各种数据库并进行操作 composer require doctrine/dbal:3.0.0 进行下载安装

*/

class UserMapper

{

protected $table = 'users';

protected $adapter;

/**

* UserMapper constructor.

* @throws DBALException

*/

public function __construct()

{

$connectionParams = array(

'dbname' => 'design_pattern',

'user' => 'root',

'password' => '123456',

'host' => '127.0.0.1:3316',

'driver' => 'pdo_mysql',

);

$adapter = DriverManager::getConnection($connectionParams);

$this->adapter = $adapter;

}

/**

* 将用户对象保存到数据库

*

* @param User $user

* @return bool

* @throws DBALException

*/

public function save(User $user)

{

// $data的键名对应数据库表字段

$data = array(

'user_id' => $user->getUserId(),

'name' => $user->getName(),

);

// 如果没有指定ID则在数据库中创建新纪录,否则更新已有记录

if (null === ($id = $user->getUserId())) {

unset($data['user_id']);

$this->adapter->insert($this->table, $data);

return true;

} else {

$this->adapter->update($this->table, $data, array('user_id ' => $id));

return true;

}

}

/**

* 基于ID在数据库中查找用户并返回用户实例

* @param $id

* @return mixed

* @throws DBALException

* @throws \InvalidArgumentException

*/

public function findById($id)

{

$result = $this->adapter->executeQuery("select * from ".$this->table." where user_id = ".$id)->fetch();

if (empty($result)) {

throw new \InvalidArgumentException("User #$id not found");

}

return $this->mapObject($result);

}

/**

* 获取数据库所有记录并返回用户实例数组

* @return array

* @throws DBALException

*/

public function findAll()

{

$resultSet = $this->adapter->executeQuery("select * from ".$this->table)->fetchAll();

$entries = array();

foreach ($resultSet as $row) {

$entries[] = $this->mapObject($row);

}

return $entries;

}

/**

* 映射表记录到对象

*

* @param array $row

*

* @return User

*/

protected function mapObject(array $row)

{

$entry = new User();

$entry->setUserID((int)$row['user_id']);

$entry->setName($row['name']);

return $entry;

}

}

单元测试:

namespace DesignPattern\Tests;

use DesignPattern\Structural\DataMapper\User;

use DesignPattern\Structural\DataMapper\UserMapper;

use PHPUnit\Framework\InvalidArgumentException;

use PHPUnit\Framework\TestCase;

/**

* 测试数据映射模式

* Class DataMapperTest

* @package Creational\Singleton\Tests

*/

class DataMapperTest extends TestCase

{

public function getNewUser()

{

return array(array(new User(null, 'Sylvia')));

}

public function getExistingUser()

{

return array(array(new User(1, 'Sylvia1')));

}

/**

* @param User $user

*

* @dataProvider getNewUser

*

* @throws \Doctrine\DBAL\DBALException

*/

public function testCreate(User $user)

{

$result = (new UserMapper())->save($user);

$this->assertIsBool($result);

}

/**

* @param User $user

* @dataProvider getExistingUser

* @throws \Doctrine\DBAL\DBALException

*/

public function testUpdate(User $user)

{

$updateResult = (new UserMapper())->save($user);

$this->assertIsBool($updateResult);

}

/**

* @param User $existing

* @dataProvider getExistingUser

* @throws \Doctrine\DBAL\DBALException

*/

public function testFindById(User $existing)

{

$user = (new UserMapper())->findById(1);

$this->assertEquals($existing, $user);

}

/**

* @dataProvider getExistingUser

* @throws \Doctrine\DBAL\DBALException

*/

public function testFindAll()

{

$users = (new UserMapper())->findAll();

$this->assertIsArray($users);

foreach ($users as $user) {

$this->assertIsObject($user);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值