lundi 18 avril 2016

RepositoryPattern without an ORM

I'm trying to learn the Repository pattern, and I have some questions regarding my current understanding of it.

  1. All the examples I've been able to find of database repositories use ORMs, but for a number of reasons, I can't use an ORM in the project I am learning this for. So, when not using an ORM, where should the SQL queries go? My best guess was in the repository class itself, so that's what I did in the example below.
  2. How's my naming convention for the repository's methods? I stuck with the create/update/delete verbiage of SQL as a sort of placeholder, but is there a better way?
  3. Because I'm not using an ORM, I need a setId() method in my repository. I recognize the danger inherent in allowing id's to be changed after object creation. Right now I prevent that by throwing an exception in setId() if id is not null. Is that alright or is there a better way?
  4. Am I doing anything just completely wrong in general?

Here is my current implementation, as far as I understand the concepts.

Product.php

<?php

namespace Vendor\Package\Module\Entities;

class Product
{
    /** @var int $id */
    protected $id;

    /** @var string $name */
    protected $name;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        if ($this->id !== null) {
            throw new Exception('id cannot be reset.');
        }

        $this->id = $id;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }
}

ProductRepositoryInterface.php

<?php

namespace Vendor\Package\Module\Repositories;

use PDO;
use Vendor\Package\Module\Entities\Product;

interface ProductRepositoryInterface
{
    public function findAll();

    public function findById($id);

    public function create(Product $product);

    public function update(Product $product);

    public function delete(Product $product);
}

ProductRepository.php

<?php

namespace Vendor\Package\Module\Repositories;

use PDO;
use Vendor\Package\Module\Entities\Product;

class ProductRepository implements ProductRepositoryInterface
{
    /** @var PDO $db */
    protected $db;

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

    /**
     * @return array
     */
    public function findAll()
    {
        $stmt = $this->db->query(
            'SELECT
                id,
                name
            FROM products
            WHERE active = 1'
        );

        $products = [];
        while ($stmt->fetch(PDO::FETCH_ASSOC)) {
            $product = new Product();
            $product
                ->setId($result['id'])
                ->setName($result['name'])
            ;
        }
        return $products;
    }

    /**
     * @param int $id
     *
     * @return Product
     */
    public function findById($id)
    {
        $stmt = $this->db->prepare(
            'SELECT
                id,
                name
            FROM products
            WHERE id = :id
                AND active = 1
            LIMIT 1'
        );
        $stmt->bindValue(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        $product = new Product();
        $product
            ->setId($result['id'])
            ->setName($result['name'])
        ;
    }

    /**
     * @param Product $product
     *
     * @return int
     */
    public function create(Product $product)
    {
        $stmt = $this->db->prepare(
            'INSERT INTO products (
                name
            ) VALUES (
                :name
            )'
        );
        $stmt->bindValue(':name', $product->getName(), PDO::PARAM_STR);
        $stmt->execute();

        $id = $this->db->lastInsertId();
        $product->setId($id);
        return $id;
    }

    /**
     * @param Product $product
     *
     * @return bool
     */
    public function update(Product $product)
    {
        $stmt = $this->db->prepare(
            'UPDATE products SET
                name = :name
            WHERE id = :id
                AND active = 1'
        );
        $stmt->bindValue(':name', $product->getName(), PDO::PARAM_STR);
        $stmt->bindValue(':id', $product->getId(), PDO::PARAM_INT);
        return $stmt->execute();
    }

    /**
     * @param Product $product
     *
     * @return bool
     */
    public function delete(Product $product)
    {
        $stmt = $this->db->prepare(
            'UPDATE products SET
                active = 0
            WHERE id = :id
                AND active = 1'
        );
        $stmt->bindValue(':id', $product->getId(), PDO::PARAM_INT);
        return $stmt->execute();
    }
}

demo.php

<?php

use Vendor\Package\Module\Entities\Product;
use Vendor\Package\Module\Repositories\ProductRepository;

$repository = new ProductRepository($db);

// Create
if (
    isset($_POST['create'])
    && isset($_POST['name'])
) {
    $product = new Product();
    $product
        ->setName($_POST['name'])
    ;

    $repository->create($product);
}

// Update
if (
    isset($_POST['update'])
    && isset($_POST['id'])
    && isset($_POST['name'])
) {
    $product = new Product();
    $product
        ->setId($_POST['id'])
        ->setName($_POST['name'])
    ;

    $repository->update($product);
}

// Delete
if (
    isset($_POST['delete'])
    && isset($_POST['id'])
) {
    $product = new Product();
    $product
        ->setId($_POST['id'])
    ;

    $repository->delete($product);
}

Aucun commentaire:

Enregistrer un commentaire