Как отделить слой операций с базами данных от слоя BaseModel без использования Extend в PHP MVC? - PullRequest
0 голосов
/ 28 сентября 2018

Я работаю над кодом, где все прекрасно работает, но проблема, с которой я сейчас сталкиваюсь, заключается в том, что я хочу сделать его более общим, отделив мой BaseModel Class от моего DbOPerations Class.

.сейчас я делаю это:

Basemodel.php :

class BaseModel extends DbOperatons implements ModelInterface{

    protected $table = 'default';
    protected $db;
    private $OperateOnDb=new DbOperations();

    /**
     * Fetch all records from table
     * @return array
     */
    public function all(){
        return $this->db->select(["*"])->run();
    }

    /**
     * Find record by given id
     * @param int $id
     * @return array
     */
    public function find($id = 1){
        return $this->db->select(["*"])->where(['id'=>$id])->run();
    }

}

DbOperations.php:

<?php

namespace core\others;

use PDO;

class DbOperations {

    protected $pdo;

    protected $selectParams = '*';

    protected $table       = '';

    protected $lastTable       = '';

    protected $groupByColumns       = '';

    protected $where      = '';


    /**
     * DbOperations constructor.
     * @param PDO $pdo
     */
    public function __construct(PDO $pdo) {
        $this->pdo= $pdo;

    }

    /**
     * Setting select parameters
     * @param $params
     * @return $this
     */
    public function select($params){
        $this->selectParams = implode(",",$params);
        return $this;
    }

    /**
     * Set table name as array like ["students","teachers"]
     * @param array $table
     * @return $this
     */
    public function setTable($table = []){
        $this->lastTable = $this->table;
        $this->table = $table;
        if(is_array($table)) {
            $tableNames = '';
            foreach($table as $table)
                $tableNames .=  $table . ", ";
            $this->table = rtrim($tableNames, ", ");
        }
        return $this;
    }

    /**
     * Setting group by clause
     * @param array $columns
     * @return $this
     */
    public function groupBy($columns = []){
        $this->groupByColumns = implode(", ", $columns);
        return $this;
    }

    /**
     * Setting Where clause
     * @param array $whereClause
     * @param string $operator
     * @param string $operand
     * @return $this
     */
    public function where($whereClause = [],$operator = '=', $operand = 'AND'){
        $where = [];
        foreach ($whereClause as $column => $data)
            $where[] =  $column . $operator . $data;
        $where = implode(' ' . $operand . ' ', $where);
        $this->where = $where;
        return $this;
    }

    /**
     * Generate dynamic SQL
     * @return string
     */
    public function generateSQL(){
        $query = "SELECT {$this->selectParams} FROM {$this->table}";
        if ($this->where!='')
            $query .= " WHERE " . $this->where;
        if ($this->groupByColumns!='')
            $query .= " GROUP BY " . $this->groupByColumns;
        return $query;
    }
    /**
     * Returns a result of dynamic query made by select, where, group by functions
     * @return array
     */
    public function run(){
        $query = $this->generateSQL();
        $statement = $this->pdo->prepare($query);
        $statement->execute();
        $this->table = $this->lastTable;
        return $statement->fetchAll(2);
    }


    /**
     * For creating record in DB with key value pair
     * @param array $data
     * @param null $table
     * @return integer Last Inserted id
     */
    public function create($data = ['key'=>'value'],$table = null){
        $this->lastTable = $this->table;
        $table = (isset($table)?$table : $this->table);
        $columns = '';
        $values= '';
        foreach($data as $key => $valuePair){
            $columns .= "{$key},";
            $values .= "?,";
        }
        $columns = substr($columns, 0, -1);
        $values = substr($values, 0, -1);
        $query = "INSERT INTO {$table} ({$columns}) VALUES ({$values})";
        $this->pdo->prepare($query)->execute(array_values($data));
        return $this->pdo->lastInsertId();
    }

    // @codeCoverageIgnoreStart
    /**
     * For updating record in database table
     * @param array $data
     * @return $this
     */
    public function update($data = []){
        $columns = '';
        foreach($data as $key => $valuePair){
            if($key!='id')
                $columns .= "{$key}=?, ";
        }
        $columns = substr($columns, 0, -2);
        $query = "UPDATE {$this->table} SET {$columns} WHERE id=?";
        $this->pdo->prepare($query)->execute(array_values($data));
        return $this;
    }

    /**
     * For deleting record in database table
     * @param $id
     * @param null $table
     * @return $this
     */
    public function delete($id,$table = null){
        $this->lastTable = $this->table;
        $table = (isset($table)?$table : $this->table);
        $query = "DELETE FROM {$table} WHERE id =:id";
        $statement = $this->pdo->prepare( $query);
        $statement->bindParam(':id', $id);
        $statement->execute();
        return $this;
    }
}

Теперь я хочу использовать функциональные возможности моего DBOPerations для работы в basemodel class без расширения.Я пытался объявить объект dboperation в базовом классе, но я не могу этого сделать, пожалуйста, помогите!

1 Ответ

0 голосов
/ 29 сентября 2018

Действительно, создание экземпляра с использованием new и присвоение ему свойства не допускается.Вы можете сделать это назначение внутри конструктора, но вы получите нежелательную тесную связь между двумя классами.Правильные решения включают внедрение зависимости.Поэтому вы должны либо внедрить уже созданный экземпляр в конструктор (и назначить его внутри конструктора), либо внедрить его через метод установки (и назначить его внутри метода).Конструктор инъекций лучше.Основываясь на вашем коде, вот как вы можете разделить обязанности.

core / others / DatabaseAdapter.php

<?php

namespace core\others;

interface DatabaseAdapter {

    public function select($params);
    public function setTable($table = []);
    public function groupBy($columns = []);
    public function where($whereClause = [], $operator = '=', $operand = 'AND');
    public function generateSQL();
    public function run();
    public function create($data = ['key' => 'value'], $table = null);
    public function update($data = []);
    public function delete($id, $table = null);
}

core / others / PdoAdapter.php

<?php

namespace core\others;

use core\others\DatabaseAdapter;

class PdoAdapter implements DatabaseAdapter {

    private $connection;
    private $selectParams = '*';
    protected $table = '';
    protected $lastTable = '';
    protected $groupByColumns = '';
    protected $where = '';

    /**
     * @param \PDO $connection Database connection.
     */
    public function __construct(\PDO $connection) {
        $this->connection = $connection;
    }

    /**
     * Setting select parameters
     * @param $params
     * @return $this
     */
    public function select($params) {
        $this->selectParams = implode(",", $params);
        return $this;
    }

    /* ... */

}

core / models / BaseModel.php

<?php

namespace core\models;

use core\others\DatabaseAdapter;

/**
 * Class BaseModel
 * @package core\models
 */
class BaseModel {

    /**
     * Database adapter.
     *
     * @var DatabaseAdapter
     */
    protected $dbAdapter;

    /**
     * Table name.
     *
     * @var string|array
     */
    protected $table = 'default';

    /**
     * @param DatabaseAdapter $dbAdapter Database adapter.
     */
    public function __construct(DatabaseAdapter $dbAdapter) {
        $this->dbAdapter = $dbAdapter;
    }

    /**
     * Fetch all records from table.
     *
     * @return array
     */
    public function all() {
        return $this->dbAdapter
                        ->setTable($this->table)
                        ->select(["*"])
                        ->run()
        ;
    }

    /**
     * Find record by given id
     * @param int $id
     * @return array
     */
    public function find($id = 1) {
        return $this->dbAdapter
                        ->setTable($this->table)
                        ->select(["*"])
                        ->where(['id' => $id])
                        ->run()
        ;
    }

    /**
     * Create a new record.
     *
     * @param array $columns (optional) The list of column name/value pairs, like:
     *  array(
     *      'name' => 'example name',
     *      'phone' => 'example phone number',
     *  )
     * @return int Last insert id.
     */
    public function create($columns = []) {
        return $this->dbAdapter->create($columns, $this->table);
    }

    /**
     * Update a record.
     *
     * @param array $columns (optional) The list of column name/value pairs, like:
     *  array(
     *      'id' => 123,
     *      'name' => 'example name',
     *      'phone' => 'example phone number',
     *  )
     * @return $this
     */
    public function update($columns = []) {
        $this->dbAdapter
                ->setTable($this->table)
                ->update($columns)
        ;
        return $this;
    }

    /**
     * Remove a record.
     *
     * @param int $id Record id.
     * @return $this
     */
    public function delete($id) {
        $this->dbAdapter->delete($id, $this->table);
        return $this;
    }

    /**
     * Get table name.
     *
     * @return string|array
     */
    public function getTable() {
        return $this->table;
    }

    /**
     * Set table name.
     *
     * @param string|array $table
     * @return $this
     */
    public function setTable($table = []) {
        $this->table = $table;

        if (is_array($table)) {
            $tableNames = '';
            foreach ($table as $table) {
                $tableNames .= $table . ", ";
            }
            $this->table = rtrim($tableNames, ", ");
        }

        return $this;
    }

}

core / models / ModelFactory.php

<?php

namespace core\models;

use core\others\PdoAdapter;
use app\models\DefaultModel;
use core\others\DependencyContainer;

/**
 * Class ModelFactory
 * @package core\models
 */
class ModelFactory {

    /**
     * @param $model
     * @param null $pdo
     * @return DefaultModel
     */
    public static function build($model, $pdo = null) {
        $model = 'app\models\\' . ucfirst($model) . 'Model';

        $dbInstance = ($pdo) ? $pdo : DependencyContainer::getInstance("Database");
        $pdoAdapterInstance = new PdoAdapter($dbInstance);

        if (class_exists($model)) {
            return new $model($pdoAdapterInstance);
        }

        return new DefaultModel($pdoAdapterInstance);
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...