Advertisement
Guest User

Untitled

a guest
Jul 3rd, 2017
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.58 KB | None | 0 0
  1. <?php
  2.  
  3. define('DS', DIRECTORY_SEPARATOR);
  4. define('BASE_PATH', __DIR__);
  5. define('CLASS_PATH', BASE_PATH . DS . 'classes' );
  6. define('TEMPLATE_PATH', BASE_PATH . DS . 'templates');
  7.  
  8.  
  9. function writeln($s) {
  10.   echo $s . '<br>';
  11. }
  12.  
  13.  
  14. function dump($v) {
  15.   echo '<pre>' . print_r($v, 1) . '</pre>';
  16. }
  17.  
  18.  
  19. function array_get($array, $key, $default = null) {
  20.   return array_key_exists($key, $array) ? $array[$key] : $default;
  21. }
  22.  
  23.  
  24. function registry($k, $v = null) {
  25.   static $r = [];
  26.   return func_num_args() > 1 ? $r[$k] = $v : array_get($r, $k);
  27. }
  28.  
  29.  
  30. function template($filename, $data = []) {
  31.   extract($data);
  32.   ob_start();
  33.   require TEMPLATE_PATH . DS . $filename . '.php';
  34.   return ob_end_clean();
  35. }
  36.  
  37.  
  38. class Set implements Countable, IteratorAggregate {
  39.  
  40.   protected $data = [];
  41.  
  42.   public function __construct($data = []) {
  43.     $this->update($data);
  44.   }
  45.  
  46.   public function has($v) {
  47.     return in_array($v, $this->data, true);
  48.   }
  49.  
  50.   public function add($v) {
  51.     if (!$this->has($v)) {
  52.       $this->data[] = $v;
  53.     }
  54.   }
  55.  
  56.   public function update(array $data) {
  57.     foreach ($data as $v) {
  58.       $this->add($v);
  59.     }
  60.   }
  61.  
  62.   public function remove($v) {
  63.     $i = array_search($v, $this->data, true);
  64.     if (false !== $i) {
  65.       unset($this->data[$i]);
  66.       // Можно закомментировать, если не нужны индексы, идущие по порядку
  67.       $this->reindex();
  68.     }
  69.   }
  70.  
  71.   public function clear() {
  72.     $this->data = [];
  73.   }
  74.  
  75.   public function toArray() {
  76.     return $this->data;
  77.   }
  78.  
  79.   public function count() {
  80.     return count($this->data);
  81.   }
  82.  
  83.   public function getIterator() {
  84.     $obj = new ArrayObject($this->data);
  85.     return $obj->getIterator();
  86.   }
  87.  
  88.   protected function reindex() {
  89.     $this->data = array_values($this->data);
  90.   }
  91. }
  92.  
  93.  
  94. // ...
  95.  
  96. /* (s => {
  97.   let m = s.match(/\$(\w+)/g)
  98.   return m.reduce((a, b) => a + '  protected ' + b + ';\n', '')
  99.     + m.reduce((a, b) => a + '    $this->' + b.slice(1) + ' = ' + b + ';\n', '')
  100. })(`$dbname, $user = 'root', $password = '',
  101.       $host = 'localhost', $port = 3306, $charset = 'utf8'`) */
  102.  
  103. // Column is collection of cells aligned vertically in a table.
  104. // Field is an element in which one piece of information is stored
  105.  
  106. // Table = Relation
  107. // Row = Tuple
  108. // Column = Attribute
  109. // Domain = Data Type
  110.  
  111.  
  112. class DB {
  113.   protected $connection;
  114.   protected $dbname;
  115.   protected $user;
  116.   protected $password;
  117.   protected $host;
  118.   protected $port;
  119.   protected $charset;
  120.  
  121.   public function __construct($dbname, $user = 'root', $password = '',
  122.       $host = 'localhost', $port = 3306, $charset = 'utf8') {
  123.     $this->dbname = $dbname;
  124.     $this->user = $user;
  125.     $this->password = $password;
  126.     $this->host = $host;
  127.     $this->port = $port;
  128.     $this->charset = $charset;
  129.     $this->connect();
  130.   }
  131.  
  132.   public function connect() {
  133.     if ($this->connection) {
  134.       return;
  135.     }
  136.     $dsn = sprintf(
  137.       'mysql:dbname=%s;host=%s;port=%d;charset=%s',
  138.       $this->dbname,
  139.       $this->host,
  140.       $this->port,
  141.       $this->charset
  142.     );
  143.     $this->connection = new PDO($dsn, $this->user, $this->password, [
  144.       PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  145.       PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
  146.     ]);
  147.   }
  148.  
  149.   public function disconnect() {
  150.     $this->connection = null;
  151.   }
  152.  
  153.   public function __destruct() {
  154.     $this->disconnect();
  155.   }
  156.  
  157.   public function query($sql, $bind = []) {
  158.     $s = $this->connection->prepare($sql);
  159.     $s->execute($bind);
  160.     return $s;
  161.   }
  162.  
  163.   public function exec($sql, $bind = []) {
  164.     return $this->query($sql, $bind)->rowCount();
  165.   }
  166.  
  167.   public function lastInsertId() {
  168.     return $this->connection->lastInsertId();
  169.   }
  170.  
  171.   function find(string $table, int $id, string $key = 'id') {
  172.     $sql = sprintf(
  173.       'SELECT * FROM %s WHERE %s = ?;',
  174.       $this->quoteIdent($table),
  175.       $key
  176.     );
  177.     return $this->query($sql, [$id])->fetch();
  178.   }
  179.  
  180.   function findAll(string $table) {
  181.     $sql = sprintf(
  182.       'SELECT * FROM %s;',
  183.       $this->quoteIdent($table),
  184.     );
  185.     return $this->query($sql)->fetchAll();
  186.   }
  187.  
  188.   public function insert($table, array $data) {
  189.     $sql = sprintf(
  190.       'INSERT INTO %s (%s) VALUES (%s);',
  191.       $this->quoteIdent($table),
  192.       implode(', ', array_map([$this, 'qouteIdent'], array_keys($data))),
  193.       substr(str_repeat('?, ', count($data)), 0, -2)
  194.     );
  195.     $this->exec($sql, array_values($data));
  196.     return $this->lastInsertId();
  197.   }
  198.  
  199.   public function update(string $table, array $data, int $id, string $key = 'id') {
  200.     $set = [];
  201.     foreach (array_keys($data) as $column) {
  202.       $set[] = $this->quoteIdent($column) . ' = ?';
  203.     }
  204.     $sql = sprintf(
  205.       'UPDATE %s SET %s WHERE %s = ?;',
  206.       $this->quoteIdent($table),
  207.       implode(', ', $set),
  208.       $key
  209.     );
  210.     $bind = array_values($data);
  211.     $bind[] = $id;
  212.     return $this->exec($sql, $bind);
  213.   }
  214.  
  215.   public function delete(string $table, int $int, string $key = 'id') {
  216.     $sql = sprintf(
  217.       'DELETE FROM %s WHERE %s = ?;',
  218.       $this->quoteIdent($table),
  219.       $key
  220.     );
  221.     return $this->exec($sql, [$id]);
  222.   }
  223.  
  224.   // Транзакции
  225.   public function beginTransaction() {
  226.     return $this->connection->beginTransaction();
  227.   }
  228.  
  229.   public function commit() {
  230.     return $this->connection->commit();
  231.   }
  232.  
  233.   public function rollBack() {
  234.     return $this->connection->rollBack();
  235.   }
  236.  
  237.   public function quoteIdent($name) {
  238.     return '`' . str_replace('`', '``', $name) . '`';
  239.   }
  240. }
  241.  
  242. // http://qiita.com/asaokamei/items/d0957a51e4b943006997
  243.  
  244.  
  245. // Ведет себя как объект и как массив.
  246. // http://ideone.com/2j2Dwi
  247. // $m->data возвращвет null
  248. abstract class AbstractModel implements ArrayAccess, Countable,
  249.     IteratorAggregate {
  250.  
  251.   protected $data;
  252.  
  253.   public function __construct(array $data = []) {
  254.     $this->data = $data;
  255.   }
  256.  
  257.   public function toArray() {
  258.     return $this->data;
  259.   }
  260.  
  261.   public function set($key, $value) {
  262.     $this->data[$key] = $value;
  263.   }
  264.  
  265.   public function has($key) {
  266.     return array_key_exists($key, $this->data);
  267.   }
  268.  
  269.   public function get($key, $default = null) {
  270.     return $this->has($key) ? $this->data[$key] : $default;
  271.   }
  272.  
  273.   public function remove($key) {
  274.     unset($this->data[$key]);
  275.   }
  276.  
  277.   public function keys() {
  278.     return array_keys($this->data);
  279.   }
  280.  
  281.   public function values() {
  282.     return array_values($this->data);
  283.   }
  284.  
  285.   public function __set($property, $value) {
  286.     $this->set($property, $value);
  287.   }
  288.  
  289.   public function __get($property) {
  290.     return $this->get($property);
  291.   }
  292.  
  293.   public function __isset($property) {
  294.     return $this->has($property);
  295.   }
  296.  
  297.   public function __unset($property) {
  298.     $this->remove($property);
  299.   }
  300.  
  301.   public function offsetSet($key, $value) {
  302.     // $obj[] = $value;
  303.     if (!is_null($key)) {
  304.       $this->set($key, $value);
  305.     }
  306.   }
  307.  
  308.   public function offsetExists($key) {
  309.     return $this->has($key);
  310.   }
  311.  
  312.   public function offsetUnset($key) {
  313.     $this->remove($key);
  314.   }
  315.  
  316.   public function offsetGet($key) {
  317.     return $this->get($key);
  318.   }
  319.  
  320.   public function count() {
  321.     return count($this->data);
  322.   }
  323.  
  324.   public function getIterator() {
  325.     $obj = new ArrayObject($this->data);
  326.     return $obj->getIterator();
  327.   }
  328. }
  329.  
  330.  
  331. abstract class AbstractMapper {
  332.  
  333.   protected $adapter;
  334.   protected $primaryKey;
  335.   protected $fields = [];
  336.   // Эти свойства переопределяются в классах наследниках
  337.   protected $table;
  338.   protected $modelClass;
  339.  
  340.   public function __construct($adapter) {
  341.     $this->adapter = $adapter;
  342.     $this->describe();
  343.   }
  344.  
  345.   public function find($id) {
  346.     $row = $this->adapter->find($this->table, $id, $this->primaryKey);
  347.     return $row ? $this->createObject($row) : null;
  348.   }
  349.   public function findAll() {
  350.     $rows = $this->adapter->findAll($this->table);
  351.     return $this->createObjects($rows);
  352.   }
  353.  
  354.   public function save(AbstractModel $o) {
  355.     return $o->{$this->primaryKey} ? $this->update($o) : $this->insert($o);
  356.   }
  357.  
  358.   public function update(AbstractModel $o) {
  359.     $data = $this->getModelData($o);
  360.     $affected_rows = $this->adapter->update(
  361.       $this->table,
  362.       $data,
  363.       $o->{$this->primaryKey},
  364.       $this->primaryKey
  365.     );
  366.   }
  367.  
  368.   public function insert(AbstractModel $o) {
  369.     $data = $this->getModelData($o);
  370.     $id = $this->adapter->insert($this->table, $data);
  371.     return $o->{$this->primaryKey} = $id;
  372.   }
  373.  
  374.   public function remove(AbstractModel $o) {
  375.     $affected_rows = $this->adapter->delete(
  376.       $this->table,
  377.       $o->{$this->primaryKey},
  378.       $this->primaryKey
  379.     );
  380.     if ($affected_rows) {
  381.       $o->{$this->primaryKey} = null;
  382.       return true;
  383.     }
  384.     return false;
  385.   }
  386.  
  387.   protected function describe() {
  388.     $rows = $this->adapter->describe($this->table);
  389.     foreach ($rows as $row) {
  390.       $this->fields[] = $row['Field'];
  391.       if ($row['Key'] === 'PRI') {
  392.         $this->primaryKey = $row['Field'];
  393.       }
  394.     }
  395.   }
  396.  
  397.   protected function createObject($row) {
  398.     return new $this->modelClass($row);
  399.   }
  400.  
  401.   protected function createObjects($rows) {
  402.     return array_map([$this, 'createObject'], $rows);
  403.   }
  404.  
  405.   // TODO: придумать более подходящее имя
  406.   protected function getModelData(AbstractModel $o) {
  407.     $ret = [];
  408.     // Выбираем только те ключи, которые совпадают с именами колонок таблицы
  409.     $keys = array_intersect($this->fields, $o->keys());
  410.     foreach ($keys as $k) {
  411.       $ret[$k] = $o[$k];
  412.     }
  413.     return $ret;
  414.   }
  415. }
  416.  
  417.  
  418. class User extends AbstractModel {
  419.   // Add some methods
  420. }
  421.  
  422.  
  423. class UserMapper extends AbstractMapper {
  424.   protected $table = 'users';
  425.   protected $modelClass = 'User';
  426. }
  427.  
  428. /*
  429.  
  430. CREATE TABLE `users` (
  431.  `id` int(11) NOT NULL AUTO_INCREMENT,
  432.  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  433.  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  434.  `password` varchar(20) NOT NULL,
  435.  PRIMARY KEY (`id`),
  436.  UNIQUE KEY `username` (`username`),
  437.  UNIQUE KEY `email` (`email`)
  438. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  439.  
  440. */
  441.  
  442. $db = new MySQLAdapter(['dbname' => 'test']);
  443. $userMapper = new UserMapper($db);
  444.  
  445. $user = new User([
  446.   'username' => 'r00t',
  447.   'email' => 'root@localhost',
  448.   'password' => '1'
  449. ]);
  450.  
  451. $userMapper->save($user);
  452. dump($user);
  453. $user->password = '123456';
  454. $userMapper->save($user);
  455. dump($user);
  456. $userMapper->remove($user);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement