Как проверить, какие свойства существуют в классе после того, как метод __call используется для их загрузки? - PullRequest
1 голос
/ 16 мая 2019

PDO имеет предопределенные режимы выборки, которые можно передавать в методы fetch и fetchAll. Я в основном концентрируюсь на FETCH_CLASS в моем номере.

Чтобы загрузить свойства и значения в мой класс, я создал черту, позволяющую использовать магические методы __set.

trait Entity {
  public function __construct() {
    $this->_attributes = func_get_args();
  }

  public function __set($prop, $value) {
    if (in_array($prop, $this->_attributes))
        $this->$prop = $value;
  }
}

Это можно легко использовать в приложении, используя черту в классе.

class UserModel {
    use Entity;

    public function save() {

    }
}

Проблема, с которой я столкнулся сейчас, заключается в реализации магического метода __get, чтобы теперь иметь возможность сохранять данные, основанные на свойствах и значениях класса. Чтобы загрузить данные в UserModel, я могу просто создать экземпляр PDO и выполнить запрос следующим образом:

$pdo = new PDO();
$stmt = $pdo->prepare('SELECT user_id, email, username, hash FROM app_users WHERE user_id = 1');
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_CLASS, 'UserModel');

Я попытался сгенерировать дополнительный метод __get в моей черте, например:

public function __get($prop) {
    if(isset($this->$prop)) return $this->$prop;
}

Но теперь я застрял в том, как использовать экземпляр для обновления строки, когда экземпляр PDO находится за пределами своей области видимости. Я попытался реализовать одноэлементную черту для PDO следующим образом:

trait Singleton
{
  private static $instance;

  public static function getInstance()
  {
    if(self::$instance) return self::$instance;
    self::$instance = new self();
    return self::$instance;
  }  

  protected function __construct() {}
  private function __clone() {}
}

И действительно быстрое расширение PDO для базовой реализации на данный момент.

class PDOWrapper extends PDO
{
  use Singleton;

  protected function __construct()
  {
    parent::_construct('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', array(
      PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
      PDO::ATTR_EMULATE_PREPARES   => false,
    ));
  }

  public function query($sql)
  {
    return parent::prepare($sql);
  }
}

Что затем меняет весь мой подход к извлечению строки в класс, чтобы он выглядел примерно так:

$stmt = PDOWrapper::getInstance()->query('SELECT user_id, email, username, hash FROM app_users WHERE user_id = 1');
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_CLASS, 'UserModel');

Теперь внутри моего метода save() у меня есть доступ к тому же экземпляру PDO, используя PDOWrapper::getInstance(). У меня проблема в том, что вам нужно знать , какие свойства были загружены из SQL-запроса, чтобы получить необходимые значения.

Например, ранее я загружал в класс столбцы email, user_id и username. Я хочу обновить пароль для этого пользователя. Это свойство не существует в первой выборке. Как я могу проверить, какие свойства существуют в классе?

// Won't work
public function save() {
    $stmt = PDOWrapper::getInstance()->query('UPDATE app_users SET hash = ? WHERE user_id = ?');
    $stmt->execute(array($this->__get('hash'), $this->__get('user_id')));
}

Мне нужно решение, которое является динамическим для набора свойств, например, которое, вероятно, должно быть пакетным обновлением:

// Sudo code
PDOWrapper::getInstance()->beginTransaction(); // Will need to be added
foreach($this->props as $prop)
    PDOWrapper::getInstance()->query('UPDATE table SET prop = value where user_id = value')->execute(array($this->$prop, $this->user_id));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...