Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- define('DS', DIRECTORY_SEPARATOR);
- define('BASE_PATH', __DIR__);
- define('CLASS_PATH', BASE_PATH . DS . 'classes' );
- define('TEMPLATE_PATH', BASE_PATH . DS . 'templates');
- function writeln($s) {
- echo $s . '<br>';
- }
- function dump($v) {
- echo '<pre>' . print_r($v, 1) . '</pre>';
- }
- function array_get($array, $key, $default = null) {
- return array_key_exists($key, $array) ? $array[$key] : $default;
- }
- function registry($k, $v = null) {
- static $r = [];
- return func_num_args() > 1 ? $r[$k] = $v : array_get($r, $k);
- }
- function template($filename, $data = []) {
- extract($data);
- ob_start();
- require TEMPLATE_PATH . DS . $filename . '.php';
- return ob_end_clean();
- }
- class Set implements Countable, IteratorAggregate {
- protected $data = [];
- public function __construct($data = []) {
- $this->update($data);
- }
- public function has($v) {
- return in_array($v, $this->data, true);
- }
- public function add($v) {
- if (!$this->has($v)) {
- $this->data[] = $v;
- }
- }
- public function update(array $data) {
- foreach ($data as $v) {
- $this->add($v);
- }
- }
- public function remove($v) {
- $i = array_search($v, $this->data, true);
- if (false !== $i) {
- unset($this->data[$i]);
- // Можно закомментировать, если не нужны индексы, идущие по порядку
- $this->reindex();
- }
- }
- public function clear() {
- $this->data = [];
- }
- public function toArray() {
- return $this->data;
- }
- public function count() {
- return count($this->data);
- }
- public function getIterator() {
- $obj = new ArrayObject($this->data);
- return $obj->getIterator();
- }
- protected function reindex() {
- $this->data = array_values($this->data);
- }
- }
- // ...
- interface AdapterInterface {
- public function connect();
- public function disconnect();
- public function beginTransaction();
- public function commit();
- public function rollBack();
- public function query($sql, $bind = []);
- public function exec($sql, $bind = []);
- public function lastInsertId();
- public function quoteIdentifier($name);
- public function find($table, $id, $key = 'id');
- public function findAll($table);
- public function insert($table, array $data);
- public function update($table, array $data, $id, $key = 'id');
- public function delete($table, $id, $key = 'id');
- public function describe($table);
- }
- interface ResultInterface {
- public function fetch();
- public function fetchAll();
- public function fetchColumn();
- public function affectedRows();
- }
- class DBException extends Exception {}
- class MySQLAdapter implements AdapterInterface {
- protected $pdo;
- protected $hostname = 'localhost';
- protected $port = 3306;
- protected $user = 'root';
- protected $password;
- protected $dbname;
- protected $charset = 'utf8';
- public function __construct(array $options) {
- $this->hostname = array_get($options, 'hostname', $this->hostname);
- $this->port = array_get($options, 'port', $this->port);
- $this->user = array_get($options, 'user', $this->user);
- $this->password = array_get($options, 'password', $this->password);
- $this->dbname = array_get($options, 'dbname', $this->dbname);
- $this->charset = array_get($options, 'charset', $this->charset);
- $this->connect();
- }
- public function connect() {
- $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=%s',
- $this->hostname,
- $this->port,
- $this->dbname,
- $this->charset
- );
- $this->pdo = new PDO(
- $dsn,
- $this->user,
- $this->password,
- [
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
- ]
- );
- }
- public function disconnect() {
- $this->pdo = null;
- }
- public function __destruct() {
- $this->disconnect();
- }
- public function beginTransaction() {
- return $this->pdo->beginTransaction();
- }
- public function commit() {
- return $this->pdo->commit();
- }
- public function rollBack() {
- return $this->pdo->rollBack();
- }
- public function query($sql, $bind = []) {
- $s = $this->pdo->prepare($sql);
- $s->execute($bind);
- return new MySQlResult($s);
- }
- // Возвращает количество модифицированных запросом рядов
- public function exec($sql, $bind = []) {
- return $this->query($sql, $bind)->affectedRows();
- }
- public function lastInsertId() {
- return $this->pdo->lastInsertId();
- }
- public function quoteIdentifier($name) {
- return '`' . str_replace('`', '``', $name) . '`';
- }
- public function find($table, $id, $key = 'id') {
- $sql = sprintf(
- 'SELECT * FROM %s WHERE %s = ?;',
- $this->quoteIdentifier($table),
- $this->quoteIdentifier($key)
- );
- writeln($sql);
- return $this->query($sql, [$id])->fetch();
- }
- public function findAll($table) {
- $sql = sprintf(
- 'SELECT * FROM %s;',
- $this->quoteIdentifier($table)
- );
- writeln($sql);
- return $this->query($sql)->fetchAll();
- }
- public function insert($table, array $data) {
- $sql = sprintf(
- 'INSERT INTO %s (%s) VALUES (%s);',
- $this->quoteIdentifier($table),
- implode(', ', array_map([$this, 'quoteIdentifier'], array_keys($data))),
- substr(str_repeat('?, ', count($data)), 0, -2)
- );
- writeln($sql);
- $affected_rows = $this->exec($sql, array_values($data));
- return $affected_rows ? $this->lastInsertId() : false;
- }
- public function update($table, array $data, $id, $key = 'id') {
- $set = [];
- foreach (array_keys($data) as $column) {
- $set[] = sprintf('%s = ?', $this->quoteIdentifier($column));
- }
- $bind = array_values($data);
- $bind[] = $id;
- $sql = sprintf(
- 'UPDATE %s SET %s WHERE %s = ?;',
- $this->quoteIdentifier($table),
- implode(', ', $set),
- $this->quoteIdentifier($key)
- );
- writeln($sql);
- return $this->exec($sql, $bind);
- }
- public function delete($table, $id, $key = 'id') {
- $sql = sprintf(
- 'DELETE FROM %s WHERE %s = ?;',
- $this->quoteIdentifier($table),
- $this->quoteIdentifier($key)
- );
- writeln($sql);
- return $this->exec($sql, [$id]);
- }
- public function describe($table) {
- $sql = sprintf(
- 'DESCRIBE %s;',
- $this->quoteIdentifier($table)
- );
- return $this->query($sql)->fetchAll();
- }
- }
- class MySQlResult implements ResultInterface {
- protected $statement;
- public function __construct(PDOStatement $statement) {
- $this->statement = $statement;
- }
- public function fetch() {
- return $this->statement->fetch();
- }
- public function fetchAll() {
- return $this->statement->fetchAll();
- }
- public function fetchColumn() {
- return $this->statement->fetchColumn();
- }
- public function affectedRows() {
- return $this->statement->rowCount();
- }
- }
- // Ведет себя как объект и как массив.
- // http://ideone.com/2j2Dwi
- // $m->data возвращвет null
- abstract class AbstractModel implements ArrayAccess, Countable,
- IteratorAggregate {
- protected $data;
- public function __construct(array $data = []) {
- $this->data = $data;
- }
- public function toArray() {
- return $this->data;
- }
- public function set($key, $value) {
- $this->data[$key] = $value;
- }
- public function has($key) {
- return array_key_exists($key, $this->data);
- }
- public function get($key, $default = null) {
- return $this->has($key) ? $this->data[$key] : $default;
- }
- public function remove($key) {
- unset($this->data[$key]);
- }
- public function keys() {
- return array_keys($this->data);
- }
- public function values() {
- return array_values($this->data);
- }
- public function __set($property, $value) {
- $this->set($property, $value);
- }
- public function __get($property) {
- return $this->get($property);
- }
- public function __isset($property) {
- return $this->has($property);
- }
- public function __unset($property) {
- $this->remove($property);
- }
- public function offsetSet($key, $value) {
- // $obj[] = $value;
- if (!is_null($key)) {
- $this->set($key, $value);
- }
- }
- public function offsetExists($key) {
- return $this->has($key);
- }
- public function offsetUnset($key) {
- $this->remove($key);
- }
- public function offsetGet($key) {
- return $this->get($key);
- }
- public function count() {
- return count($this->data);
- }
- public function getIterator() {
- $obj = new ArrayObject($this->data);
- return $obj->getIterator();
- }
- }
- abstract class AbstractMapper {
- protected $adapter;
- protected $primaryKey;
- protected $fields = [];
- // Эти свойства переопределяются в классах наследниках
- protected $table;
- protected $modelClass;
- public function __construct($adapter) {
- $this->adapter = $adapter;
- $this->describe();
- }
- public function find($id) {
- $row = $this->adapter->find($this->table, $id, $this->primaryKey);
- return $row ? $this->createObject($row) : null;
- }
- public function findAll() {
- $rows = $this->adapter->findAll($this->table);
- return $this->createObjects($rows);
- }
- public function save(AbstractModel $o) {
- return $o->{$this->primaryKey} ? $this->update($o) : $this->insert($o);
- }
- public function update(AbstractModel $o) {
- $data = $this->getModelData($o);
- $affected_rows = $this->adapter->update(
- $this->table,
- $data,
- $o->{$this->primaryKey},
- $this->primaryKey
- );
- }
- public function insert(AbstractModel $o) {
- $data = $this->getModelData($o);
- $id = $this->adapter->insert($this->table, $data);
- return $o->{$this->primaryKey} = $id;
- }
- public function remove(AbstractModel $o) {
- $affected_rows = $this->adapter->delete(
- $this->table,
- $o->{$this->primaryKey},
- $this->primaryKey
- );
- if ($affected_rows) {
- $o->{$this->primaryKey} = null;
- return true;
- }
- return false;
- }
- protected function describe() {
- $rows = $this->adapter->describe($this->table);
- foreach ($rows as $row) {
- $this->fields[] = $row['Field'];
- if ($row['Key'] === 'PRI') {
- $this->primaryKey = $row['Field'];
- }
- }
- }
- protected function createObject($row) {
- return new $this->modelClass($row);
- }
- protected function createObjects($rows) {
- return array_map([$this, 'createObject'], $rows);
- }
- // TODO: придумать более подходящее имя
- protected function getModelData(AbstractModel $o) {
- $ret = [];
- // Выбираем только те ключи, которые совпадают с именами колонок таблицы
- $keys = array_intersect($this->fields, $o->keys());
- foreach ($keys as $k) {
- $ret[$k] = $o[$k];
- }
- return $ret;
- }
- }
- class User extends AbstractModel {
- // Add some methods
- }
- class UserMapper extends AbstractMapper {
- protected $table = 'users';
- protected $modelClass = 'User';
- }
- /*
- CREATE TABLE `users` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
- `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
- `password` varchar(20) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `username` (`username`),
- UNIQUE KEY `email` (`email`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8
- */
- $db = new MySQLAdapter(['dbname' => 'test']);
- $userMapper = new UserMapper($db);
- $user = new User([
- 'username' => 'r00t',
- 'email' => 'root@localhost',
- 'password' => '1'
- ]);
- $userMapper->save($user);
- dump($user);
- $user->password = '123456';
- $userMapper->save($user);
- dump($user);
- $userMapper->remove($user);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement