这是域映射模型的常见结构吗?

希望我在正确的堆栈交换论坛上提出这个问题。 如果不是,请让我知道,我会问别的地方。 我也问过Code Review,但社区看起来不太活跃。

由于我自学了PHP和所有编程,我最近才发现了'数据映射器',它允许数据传入类中,而不需要所述类知道数据来自哪里。 我已经阅读了一些使用映射器的积极因素,以及为什么他们更容易在后来执行升级,但是我非常努力地找出在目录结构中使用映射器及其布局的建议方式。

假设我们有一个简单的应用程序,其目的是回显用户的名字和姓氏。

我一直在使用/创建映射器的方式(以及文件结构如下):

的index.php

include 'classes/usermapper.php';
include 'classes/user.php';

$user = new User;
$userMapper = new userMapper;

try {
  $user->setData([
    $userMapper->fetchData([
      'username'=>'peter1'
    ])
  ]);
} catch (Exception $e) {
  die('Error occurred');
}

if ($user->hasData()) {
  echo $user->fullName();
}

类/ user.php的

class User {
  private $_data;

  public function __construct() { }

  public function setData($userObject = null) {
    if (!$userObject) { throw new InvalidArgumentException('No Data Set'); }
    $this->_data = $dataObject;
  }

  public function hasData() {
    return (!$this->_data) ? false : true;
  }

  public function fullName() {
    return ucwords($this->_data->firstname.' '.$this->_data->lastname);
  }
}

类/ usermapper.php

class userMapper {
  private $_db;

  public function __construct() { $this->_db = DB::getInstance(); }

  public function fetchData($where = null) {
    if (!is_array($where)) { 
      throw new InvalidArgumentException('Invalid Params Supplied'); 
    }

    $toFill = null;
    foreach($where as $argument=>$value) {
      $toFill .= $argument.' = '.$value AND ;
    }

    $query = sprintf("SELECT * FROM `users` WHERE %s ", substr(rtrim($toFill), 0, -3));


    $result = $this->_db->query($query); //assume this is just a call to a database which returns the results of the query

    return $result;
  }
}

了解用户表包含用户名,名字和姓氏,并且还缺少很多消毒检查,为什么mappers便于使用?

在获取数据方面这是一个非常漫长的过程,假设用户不是所有的东西,而是订单,支付,票据,公司等等都有他们相应的映射器,看起来不是创建一个映射器并实现它每个班都到处都是。 这允许文件夹结构看起来更好,也意味着代码不会经常重复。

示例映射器在每种情况下看起来都是相同的,即从数据表中抽取数据。

所以我的问题是。 这是'域模型映射器'下的数据映射器应该是什么样子,如果不是我的代码如何改进? 其次,在需要从数据库中提取数据的所有情况下,无论类的大小如何,都需要使用此模型,还是仅在本例中的user.php类非常大时使用此模型?

提前感谢您的帮助。


Data Mapper将域对象与永久性存储(数据库)完全分开,并提供特定于域级操作的方法。 用它将数据从域传输到数据库,反之亦然。 在一个方法中,通常会执行数据库查询,然后将结果映射(水合)到域对象或域对象列表。

例:

基类: Mapper.php

abstract class Mapper
{
    protected $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
}

该文件: BookMapper.php

class BookMapper extends Mapper
{
    public function findAll(): array
    {
        $sql = "SELECT id, title, price, book_category_id FROM books;";
        $statement = $this->db->query($sql);

        $items = [];
        while ($row = $statement->fetch()) {
            $items[] = new BookEntity($row);
        }

        return $items;
    }

    public function findByBookCategoryId(int $bookCategoryId): array
    {
        $sql = "SELECT id, title, price, book_category_id 
                FROM books
                WHERE book_category_id = :book_category_id;";

        $statement = $this->db->prepare($sql);
        $statement->execute(["book_category_id" => $bookCategoryId]);

        $items = [];
        while ($row = $statement->fetch()) {
            $items[] = new BookEntity($row);
        }

        return $items;
    }

    /**
     * Get one Book by its ID
     *
     * @param int $bookId The ID of the book
     * @return BookEntity The book
     * @throws RuntimeException
     */
    public function getById(int $bookId): BookEntity
    {
        $sql = "SELECT id, title, price, book_category_id FROM books 
                WHERE id = :id;";

        $statement = $this->db->prepare($sql);

        if (!$result = $statement->execute(["id" => $bookId])) {
            throw new DomainException(sprintf('Book-ID not found: %s', $bookId));
        }

        return new BookEntity($statement->fetch());
    }

    public function insert(BookEntity $book): int
    {
        $sql = "INSERT INTO books SET title=:title, price=:price, book_category_id=:book_category_id";
        $statement = $this->db->prepare($sql);

        $result = $statement->execute([
            'title' => $book->getTitle(),
            'price' => $book->getPrice(),
            'book_category_id' => $book->getBookCategoryId(),
        ]);

        if (!$result) {
            throw new RuntimeException('Could not save record');
        }

        return (int)$this->db->lastInsertId();
    }
}

该文件: BookEntity.php

class BookEntity
{
    /** @var int|null */
    protected $id;

    /** @var string|null */
    protected $title;

    /** @var float|null */
    protected $price;

    /** @var int|null */
    protected $bookCategoryId;

    /**
     * Accept an array of data matching properties of this class
     * and create the class
     *
     * @param array|null $data The data to use to create
     */
    public function __construct(array $data = null)
    {
        // Hydration (manually)
        if (isset($data['id'])) {
            $this->setId($data['id']);
        }
        if (isset($data['title'])) {
            $this->setTitle($data['title']);
        }
        if (isset($data['price'])) {
            $this->setPrice($data['price']);
        }
        if (isset($data['book_category_id'])) {
            $this->setBookCategoryId($data['book_category_id']);
        }
    }

    /**
     * Get Id.
     *
     * @return int|null
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * Set Id.
     *
     * @param int|null $id
     * @return void
     */
    public function setId(?int $id): void
    {
        $this->id = $id;
    }

    /**
     * Get Title.
     *
     * @return null|string
     */
    public function getTitle(): ?string
    {
        return $this->title;
    }

    /**
     * Set Title.
     *
     * @param null|string $title
     * @return void
     */
    public function setTitle(?string $title): void
    {
        $this->title = $title;
    }

    /**
     * Get Price.
     *
     * @return float|null
     */
    public function getPrice(): ?float
    {
        return $this->price;
    }

    /**
     * Set Price.
     *
     * @param float|null $price
     * @return void
     */
    public function setPrice(?float $price): void
    {
        $this->price = $price;
    }

    /**
     * Get BookCategoryId.
     *
     * @return int|null
     */
    public function getBookCategoryId(): ?int
    {
        return $this->bookCategoryId;
    }

    /**
     * Set BookCategoryId.
     *
     * @param int|null $bookCategoryId
     * @return void
     */
    public function setBookCategoryId(?int $bookCategoryId): void
    {
        $this->bookCategoryId = $bookCategoryId;
    }
}

该文件:BookCategoryEntity.php

class BookCategoryEntity
{
    const FANTASY = 1;
    const ADVENTURE = 2;
    const COMEDY = 3;

    // here you can add the setter and getter methods
}

表结构:schema.sql

CREATE TABLE `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `price` decimal(19,2) DEFAULT NULL,
  `book_category_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `book_category_id` (`book_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `book_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

/*Data for the table `book_categories` */

insert  into `book_categories`(`id`,`title`) values (1,'Fantasy');
insert  into `book_categories`(`id`,`title`) values (2,'Adventure');
insert  into `book_categories`(`id`,`title`) values (3,'Comedy');

用法

// Create the database connection
$host = '127.0.0.1';
$dbname = 'test';
$username = 'root';
$password = '';
$charset = 'utf8';
$collate = 'utf8_unicode_ci';
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_PERSISTENT => false,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset COLLATE $collate"
];

$db = new PDO($dsn, $username, $password, $options);

// Create the data mapper instance
$bookMapper = new BookMapper($db);

// Create a new book entity
$book = new BookEntity();
$book->setTitle('Harry Potter');
$book->setPrice(29.99);
$book->setBookCategoryId(BookCategoryEntity::FANTASY);

// Insert the book entity
$bookId = $bookMapper->insert($book);

// Get the saved book
$newBook = $bookMapper->getById($bookId);
var_dump($newBook);

// Find all fantasy books
$fantasyBooks = $bookMapper->findByBookCategoryId(BookCategoryEntity::FANTASY);
var_dump($fantasyBooks);
链接地址: http://www.djcxy.com/p/56225.html

上一篇: Is this the common structure for the domain mapper model?

下一篇: PHP MVC: Data Mapper pattern: class design