From 948ab47c101aef7dcd4239b0051dc7669148d1e1 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:29:48 +0900 Subject: [PATCH 01/21] remove MysqliWrap. #332 --- app/src/Model/MSDB.php | 112 ++--------- app/src/Model/MySqliWrap.php | 351 ----------------------------------- 2 files changed, 17 insertions(+), 446 deletions(-) delete mode 100644 app/src/Model/MySqliWrap.php diff --git a/app/src/Model/MSDB.php b/app/src/Model/MSDB.php index a40b727d..5c551dcc 100644 --- a/app/src/Model/MSDB.php +++ b/app/src/Model/MSDB.php @@ -1,9 +1,4 @@ -master) { - if (DB_CONNECT_LIB === 'PDO') { - $this->master = new PDOWrap( - Config::get('MASTER_DB.HOST'), - Config::get('MASTER_DB.PORT'), - Config::get('MASTER_DB.USER'), - Config::get('MASTER_DB.PASSWORD'), - Config::get('MASTER_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - if (DB_CONNECT_LIB === 'mysqli') { - $this->master = new MySqliWrap( - Config::get('MASTER_DB.HOST'), - Config::get('MASTER_DB.PORT'), - Config::get('MASTER_DB.USER'), - Config::get('MASTER_DB.PASSWORD'), - Config::get('MASTER_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - } - return $this->master; - } - - private function getSlaveDB() - { - if (!$this->slave) { - if (DB_CONNECT_LIB === 'PDO') { - $this->slave = new PDOWrap( - Config::get('SLAVE_DB.HOST'), - Config::get('SLAVE_DB.USER'), - Config::get('SLAVE_DB.PASSWORD'), - Config::get('SLAVE_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - if (DB_CONNECT_LIB === 'mysqli') { - $this->slave = new MySqliWrap( - Config::get('SLAVE_DB.HOST'), - Config::get('SLAVE_DB.USER'), - Config::get('SLAVE_DB.PASSWORD'), - Config::get('SLAVE_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - } - return $this->slave; - } - - /** - * @param bool $isMaster - * @return MySqliWrap|PDOWrap + * @return PDOWrap */ - public function getDB($isMaster = false) + private function getMasterDB(): PDOWrap { - // Master/Slave機能のON/OFF - if (!Config::get('IS_MASTER_SLAVE', true)) { - return $this->getMasterDB(); - } - return $isMaster ? $this->getMasterDB() : $this->getSlaveDB(); + return $this->master = new PDOWrap( + Config::get('MASTER_DB.HOST'), + Config::get('MASTER_DB.PORT'), + Config::get('MASTER_DB.USER'), + Config::get('MASTER_DB.PASSWORD'), + Config::get('MASTER_DB.DATABASE'), + Config::get('DB_CHARSET') + ); } public function close() { - if ($this->master) { - $this->master->close(); - $this->master = null; - } - if ($this->slave) { - $this->slave->close(); - $this->slave = null; - } + $this->master->close(); + $this->master = null; } /** @@ -126,7 +59,7 @@ public function find(string $sql, array $params = [], array $options = []) 'result' => DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... ); $options = array_merge($_options, $options); - $db = $this->getDB($options['master']); + $db = $this->getMasterDB(); return $db->find($sql, $params, $options); } @@ -155,26 +88,15 @@ public function execute(string $sql, array $params = [], array $options = []) */ public function multiExecute($sql) { - return $this->getDB()->multiExecute($sql); + return $this->getMasterDB()->multiExecute($sql); } /** * 接続処理 - * @param bool $is_charset - * @param bool $is_database */ - public function connect($is_charset = true, $is_database = true) + public function connect() { - $this->getDB()->connect($is_charset, $is_database); + $this->getMasterDB()->connect(); } - - /** - * MySQLのバージョンを取得する - */ - public function getVersion() - { - return $this->getDB()->getVersion(); - } - } diff --git a/app/src/Model/MySqliWrap.php b/app/src/Model/MySqliWrap.php deleted file mode 100644 index 8d8cc06f..00000000 --- a/app/src/Model/MySqliWrap.php +++ /dev/null @@ -1,351 +0,0 @@ -host = $host; - $this->port = $port; - $this->user = $user; - $this->password = $password; - $this->database = $database; - $this->charset = $charset; - } - - /** - * 参照系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false|int|mixed - */ - public function find(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (\Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - /** - * 更新系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false|int|mixed - */ - public function execute(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_SUCCESS, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (\Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; - } - return $this->result($stmt, $options['result']); - } - - /** - * 複数の更新系SQL - */ - public function multiExecute($sql) - { - $sql = preg_replace('/^--.*?\n/m', '', $sql); - $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); - $sqls = explode(';', $sql); - $execute_sqls = array(); - foreach ($sqls as $sql) { - if (trim($sql) !== '') { - $execute_sqls[] = $sql; - } - } - - foreach ($execute_sqls as $sql) { - if ($this->execute($sql) === false) { - return false; - } - } - return true; - } - - /** - * SQLの実行 - * @throws \Exception - */ - private function query($sql, $params = array(), $types = '') - { - $mtime = 0; // SQL実行結果時間取得用 - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = microtime(true); - } - - $this->connect(); - - if (!count($params)) { - // SQL文をそのまま実行 - $stmt = $this->db->query($sql); - if (getType($stmt) == 'boolean' && !$stmt) { - throw new \Exception('[query Error]' . print_r($this->db->error, true) . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - // プリペアドステートメント - $stmt = $this->db->prepare($sql); - if (!$stmt) { - throw new \Exception('[prepare Error]' . $sql); - } - $types = count($params) == strlen($types) ? $types : $this->getBindTypes($params); - $bindParams = array($types); - foreach ($params as $key => $value) { - $bindParams[] = &$params[$key]; - } - $res = call_user_func_array(array($stmt, 'bind_param'), $bindParams); - if (!$stmt->execute()) { - throw new \Exception('[execute Error]' . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; - } - - public function connect($is_charset = true, $is_database = true) - { - // TODO Show Warning message on connect failed. but mysqli throw error, not exception... - if ($this->db == null) { - if ($is_database) { - $this->db = new \mysqli($this->host, $this->user, $this->password, $this->database, (int)$this->port); - } else { - $this->db = new \mysqli($this->host, $this->user, $this->password, null, (int)$this->port); - } - $this->errorCheck('Connect Error'); - if ($is_charset) { - $this->db->set_charset($this->charset); - } - } - } - - public function close() - { - if ($this->db != null) { - $this->db->close(); - $this->db = null; - } - } - - private function errorCheck($msg) - { - if (mysqli_connect_error()) { - throw new \Exception('[' . $msg . '] (' . mysqli_connect_errno() . ') ' . mysqli_connect_error()); - } - /* - // PHP 5.2.9 および 5.3.0 より前のバージョンでは $connect_error は動作していない - if ($this->db->connect_errno) { - throw new \Exception('['.$msg . '] (' . $this->db->connect_errno . ') ' . $this->db->connect_error); - } - */ - } - - private function getBindTypes($params) - { - $types = ""; - foreach ($params as $key => $value) { - $type = getType($value); - switch ($type) { - default: - $type = "string"; - case 'boolean': - case 'integer': - case 'double': - case 'string': - $types .= $type[0]; - } - } - return $types; - } - - public function result($stmt, $type) - { - switch ($type) { - // 1カラムのみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ONE : - $one = null; - switch (get_class($stmt)) { - case 'mysqli_stmt': - $one = $this->fetchstatement($stmt, 'one'); - $stmt->close(); - break; - - case 'mysqli_result': - $row = $stmt->fetch_row(); - $one = $row[0]; - $stmt->close(); - break; - } - $one = empty($one) ? 0 : $one; - return $one; - - // 1行のみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ROW : - $row = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $row = $this->fetchstatement($stmt, 'row'); - $stmt->close(); - break; - - case 'mysqli_result': - $row = $stmt->fetch_assoc(); - $stmt->close(); - break; - } - return $row; - - // リスト形式で取得 - case \Fc2blog\Model\DBInterface::RESULT_LIST : - $rows = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $rows = $this->fetchstatement($stmt, 'list'); - $stmt->close(); - break; - - case 'mysqli_result': - while ($row = $stmt->fetch_row()) { - $rows[$row[0]] = $row[1]; - } - $stmt->close(); - break; - } - return $rows; - - - // 全て取得 - case \Fc2blog\Model\DBInterface::RESULT_ALL : - $rows = array(); - switch (get_class($stmt)) { - case 'mysqli_stmt': - $rows = $this->fetchstatement($stmt); - $stmt->close(); - break; - - case 'mysqli_result': - while ($row = $stmt->fetch_assoc()) { - $rows[] = $row; - } - $stmt->close(); - break; - } - return $rows; - - // InsertIDを返却 - case \Fc2blog\Model\DBInterface::RESULT_INSERT_ID : - $insert_id = $this->db->insert_id; - if (getType($stmt) === 'object') { - $stmt->close(); - } - return $insert_id; - - // 影響のあった行数を返却 - case \Fc2blog\Model\DBInterface::RESULT_AFFECTED : - $affected_rows = $this->db->affected_rows; - if (getType($stmt) === 'object') { - $stmt->close(); - } - return $affected_rows; - - // 成功したかどうかを返却 - case \Fc2blog\Model\DBInterface::RESULT_SUCCESS : - return 1; - - case \Fc2blog\Model\DBInterface::RESULT_STAT: - default: - return $stmt; - } - } - - /** - * mysqli_statement用のfetch - */ - private function fetchstatement(&$stmt, $type = 'all') - { - $hits = array(); - $params = array(); - - if (!$stmt->store_result()) { - throw new \Exception('[store_result] error=[' . $stmt->error . ']'); - } - $meta = $stmt->result_metadata(); - while ($field = $meta->fetch_field()) { - $params[] = &$row[$field->name]; - } - call_user_func_array(array($stmt, 'bind_result'), $params); - while ($stmt->fetch()) { - if ($type == 'one') { - return array_shift($row); - } - $c = array(); - foreach ($row as $key => $val) { - $c[$key] = $val; - } - if ($type == 'row') { - return $c; - } - if ($type == 'list') { - $hits[array_shift($c)] = array_shift($c); - } else { - $hits[] = $c; - } - } - return $hits; - } - - public function getVersion() - { - $this->connect(false, false); - $version = explode('-', $this->db->server_info); - return $version[0]; - } -} From 226ffb682606e7759f860a5cf213500d355ed85e Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:30:11 +0900 Subject: [PATCH 02/21] remove unnecessary `getVersion`. #332 --- app/src/Model/DBInterface.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/Model/DBInterface.php b/app/src/Model/DBInterface.php index c3b60638..de0b03b9 100644 --- a/app/src/Model/DBInterface.php +++ b/app/src/Model/DBInterface.php @@ -27,6 +27,4 @@ public function connect(); public function close(); - public function getVersion(); - } From d641d4f8c713eaa0ab873dccda7a34ef14a89bfc Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:30:58 +0900 Subject: [PATCH 03/21] refactoring the PDOWrap class. #332 --- app/src/Model/PDOWrap.php | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/app/src/Model/PDOWrap.php b/app/src/Model/PDOWrap.php index c493afd5..aa3fa8ee 100644 --- a/app/src/Model/PDOWrap.php +++ b/app/src/Model/PDOWrap.php @@ -2,7 +2,6 @@ /** * DB接続クラス - * mysqliのラッピング */ namespace Fc2blog\Model; @@ -151,24 +150,15 @@ private function query($sql, $params = array(), $types = '') return $stmt; } - public function connect($is_charset = true, $is_database = true) + public function connect() { if ($this->db == null) { - $dsn = "mysql:host={$this->host};port={$this->port}"; - if ($is_database) { - $dsn = "mysql:host={$this->host};port={$this->port};dbname={$this->database};"; - } + $dsn = "mysql:host={$this->host};port={$this->port};dbname={$this->database};charset={$this->charset};"; $options = array( + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, \PDO::ATTR_EMULATE_PREPARES => false, ); - if ($is_charset) { - if (version_compare(PHP_VERSION, '5.3.6') < 0) { - $options[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES '" . $this->charset . "';"; - } else { - $dsn .= "charset={$this->charset};"; - } - } $this->db = new \PDO($dsn, $this->user, $this->password, $options); } } @@ -230,14 +220,4 @@ public function result($stmt, $type) return $stmt; } } - - /** - * MySQLのバージョンを取得する - */ - public function getVersion() - { - $this->connect(false, false); - $version = explode('-', $this->db->getAttribute(\PDO::ATTR_SERVER_VERSION)); - return $version[0]; - } } From e941574647908b6f8e37a789929be379623ffae8 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:32:11 +0900 Subject: [PATCH 04/21] Bugfix, Now the getFoundRows method works correctly with PDO. #332 --- app/src/Model/Model.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index 9d99ed80..cc4517a7 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -4,6 +4,7 @@ namespace Fc2blog\Model; use Fc2blog\Util\Log; +use PDOStatement; abstract class Model { @@ -278,6 +279,8 @@ public function isExist(array $options = []): bool */ public function getPaging(array $options = []): array { + $count = $this->getFoundRows($options); + if (!isset($options['page']) || !isset($options['limit'])) { Log::error('getPaging options["page"] or options["limit"]が設定されておりません'); return []; @@ -286,8 +289,6 @@ public function getPaging(array $options = []): array $page = $options['page']; $limit = $options['limit']; - $count = $this->getFoundRows(); - $pages = []; $pages['count'] = $count; $pages['max_page'] = ceil($count / $limit); @@ -301,13 +302,17 @@ public function getPaging(array $options = []): array } /** - * SQL_CALC_FOUND_ROWSで見つかった件数を返却する - * @return array|false + * 指定のOptionでSELECTされる件数を取得 + * @param array $options + * @return int */ - public function getFoundRows() + public function getFoundRows(array $options = []): int { - $sql = 'SELECT FOUND_ROWS()'; - return $this->findSql($sql, [], array('result' => DBInterface::RESULT_ONE)); + unset($options['limit']); + unset($options['offset']); + /** @var PDOStatement $stmt */ + $stmt = $this->find('statement', $options); + return (int)$stmt->rowCount(); } /** From a709a87f6851f757d35e9eccfa58fc09a7a23474 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:32:44 +0900 Subject: [PATCH 05/21] remove auto select feature of mysqli or pdo. #332 --- app/src/include/bootstrap.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/include/bootstrap.php b/app/src/include/bootstrap.php index b0929a64..007be552 100644 --- a/app/src/include/bootstrap.php +++ b/app/src/include/bootstrap.php @@ -4,11 +4,7 @@ define('APP_DIR', realpath(__DIR__ . '/../../') . '/'); // APPディレクトリのパス // DBの接続ライブラリ -if (class_exists('mysqli')) { - define('DB_CONNECT_LIB', 'mysqli'); -} else if (class_exists('PDO')) { - define('DB_CONNECT_LIB', 'PDO'); -} +define('DB_CONNECT_LIB', 'PDO'); // 環境設定読み込み \Fc2blog\Config::read(__DIR__ . '/../config/init_config.php'); From 70f5d0e3592df5485f80d41a9a12034b6be4027d Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:33:46 +0900 Subject: [PATCH 06/21] Remove the installation ext-mysqli in CI. #332 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6817ae50..32b65368 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: '8.0' - extensions: mbstring, gd, gettext, fileinfo, pdo, pdo_mysql, mysqli, zip + extensions: mbstring, gd, gettext, fileinfo, pdo, pdo_mysql, zip - uses: actions/checkout@v2 From fd3b2fd5a7858a2cd300f02d540ca4c8184b947f Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:34:38 +0900 Subject: [PATCH 07/21] Remove the check ext-mysqli available in the installer. #332 --- dist_zip/installer/fc2blog_installer.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/dist_zip/installer/fc2blog_installer.php b/dist_zip/installer/fc2blog_installer.php index 2d919a21..7ce70e51 100644 --- a/dist_zip/installer/fc2blog_installer.php +++ b/dist_zip/installer/fc2blog_installer.php @@ -67,9 +67,6 @@ if (!extension_loaded('PDO')) { $list[] = "PDO notfound. "; } - if (!extension_loaded('mysqli')) { - $list[] = "mysqli notfound. "; - } if (!extension_loaded('mbstring')) { $list[] = "mbstring notfound. "; } From aef47ec918f5d6c67fdff81598def822b2ef9626 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:35:05 +0900 Subject: [PATCH 08/21] Remove the check ext-mysqli available in the installer' test. #332 --- tests/App/Controller/Admin/Common/InstallTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/App/Controller/Admin/Common/InstallTest.php b/tests/App/Controller/Admin/Common/InstallTest.php index 30e9dd3c..d7ad92c9 100644 --- a/tests/App/Controller/Admin/Common/InstallTest.php +++ b/tests/App/Controller/Admin/Common/InstallTest.php @@ -45,7 +45,6 @@ public function testInstallCheck(): void $this->assertTrue($d['is_db_connect_lib']); $this->assertTrue($d['is_connect']); $this->assertEquals(0, strlen($d['connect_message'])); - $this->assertTrue($d['is_character']); $this->assertTrue($d['is_domain']); $this->assertTrue($d['is_gd']); $this->assertTrue($d['is_all_ok']); @@ -82,8 +81,6 @@ public function testInstallFailCheck(): void // 確認がむずかしい $this->assertEquals(0, strlen($d['connect_message'])); // 確認がむずかしい - $this->assertTrue($d['is_character']); - // 確認がむずかしい $this->assertTrue($d['is_domain']); // 確認がむずかしい $this->assertTrue($d['is_gd']); From 7b7032c0ee561089ce88451a7f3a9b01e1686c66 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:35:45 +0900 Subject: [PATCH 09/21] Update text in the installer. #332 --- .../en_US.UTF-8/LC_MESSAGES/messages.mo | Bin 1674 -> 1782 bytes .../en_US.UTF-8/LC_MESSAGES/messages.po | 6 ++--- .../ja_JP.UTF-8/LC_MESSAGES/messages.mo | Bin 38753 -> 38665 bytes .../ja_JP.UTF-8/LC_MESSAGES/messages.po | 8 +++--- .../Web/Controller/Admin/CommonController.php | 25 ++++-------------- app/twig_templates/admin/common/install.twig | 2 +- 6 files changed, 13 insertions(+), 28 deletions(-) diff --git a/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo b/app/locale/en_US.UTF-8/LC_MESSAGES/messages.mo index e5366313a7912165beab483a731df1a748128f9c..b0f49446874e9fee15eb3d2dc7a53d21c37d3ca7 100644 GIT binary patch delta 539 zcmXxgze@sP7{KvY(@M+gG=eDOAfiQsAPAx*k#HzzbS&g5Ax_X+n$&0tEa=B#Q$bKd zHdsMLU{eIGEe$PF`WFNZLEq=J2cGwH&vP&L-t+GGzJ1vbzw1a50dknUCWGXHgN3M~ zyn8}FzF|K$TK!+_qSlJwLUe+g-;yOs~F{v-P6zv2kK<0}4Oi1XF5Td8px1>D9PY{wZE z_NY0OdY;9Lix|N;hVd9f_=55S8u=eGh(vc2#nASUQp&fzv+_jrl5)+QZHL^5gj}s$ zn@qsK_QafHhyUQh@f=>-Fjg{#o-r&vkxHkHgr!^Sh8~SjnkHp3Wy)JCX|81|rnBM< kMkBR+`D^#Aep_suUw)R0wXOYH{;+;}-zXI-ntRjn2SvR|iU0rr delta 447 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 delta 9430 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 B)T96a diff --git a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po index 7a5beb15..8386a47a 100644 --- a/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po +++ b/app/locale/ja_JP.UTF-8/LC_MESSAGES/messages.po @@ -1109,8 +1109,8 @@ msgid "Check connection library with MySQL" msgstr "MySQLとの接続ライブラリチェック" #: shell/../view/admin/common/install.html:78 -msgid "Please enable pdo or mysqli" -msgstr "mysqli または pdoを有効にしてください" +msgid "Please enable pdo" +msgstr "pdoを有効にしてください" #: shell/../view/admin/common/install.html:94 msgid "Check connection to the MySQL" @@ -2545,8 +2545,8 @@ msgstr "ブログに設置されたプラグイン、またはテンプレート msgid "The page you are looking for does not exist." msgstr "お探しのページは存在しません" -msgid "Execute `Create database` failed. Please `Create database` your self." -msgstr "`CREATE DATABASE`のsql実行に失敗しました、事前に`CREATE DATABASE`を実行してください。" +msgid "Please set correct the DB connection settings." +msgstr "DBの接続設定をご確認ください。" msgid "(If not exists, will be try create)" msgstr "(未作成の場合、作成を試行します)" diff --git a/app/src/Web/Controller/Admin/CommonController.php b/app/src/Web/Controller/Admin/CommonController.php index b3f2c3ed..b55a3b63 100644 --- a/app/src/Web/Controller/Admin/CommonController.php +++ b/app/src/Web/Controller/Admin/CommonController.php @@ -170,7 +170,7 @@ public function install(Request $request): string $is_connect = true; $connect_message = ''; try { - MSDB::getInstance()->connect(false, false); + MSDB::getInstance()->connect(); } catch (Exception $e) { $is_connect = false; $connect_message = $e->getMessage(); @@ -178,10 +178,6 @@ public function install(Request $request): string $this->set('is_connect', $is_connect); $this->set('connect_message', $connect_message); - // DB設定確認 - $is_character = version_compare(MSDB::getInstance()->getVersion(), '5.5.0') >= 0 || DB_CHARSET != 'UTF8MB4'; - $this->set('is_character', $is_character); - // ドメイン確認 $is_domain = DOMAIN != 'domain'; $this->set('is_domain', $is_domain); @@ -191,8 +187,8 @@ public function install(Request $request): string $is_gd = function_exists('gd_info'); $this->set('is_gd', $is_gd); - $is_all_ok = $is_write_temp && $is_write_upload && $is_db_connect_lib && $is_connect && $is_character && $is_domain; - $this->set('is_all_ok', $is_all_ok); + $is_all_ok = $is_write_temp && $is_write_upload && $is_db_connect_lib && $is_connect && $is_domain; + $this->set('is_all_ok', $is_all_ok); return 'admin/common/install.twig'; @@ -216,19 +212,8 @@ public function install(Request $request): string // DB接続確認(DATABASEの存在判定含む) $msdb->connect(); } catch (Exception $e) { - // データベースの作成 - $msdb->close(); - $msdb->connect(false, false); - $sql = 'CREATE DATABASE IF NOT EXISTS ' . DB_DATABASE . ' CHARACTER SET ' . DB_CHARSET; - $msdb->execute($sql); - $msdb->close(); - try { - // 作成できたか確認 - $msdb->connect(); - } catch (Exception $e) { - $this->setErrorMessage(__('Execute `Create database` failed. Please `Create database` your self.')); - $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); - } + $this->setErrorMessage(__('Please set correct the DB connection settings.')); + $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); } // テーブルの存在チェック diff --git a/app/twig_templates/admin/common/install.twig b/app/twig_templates/admin/common/install.twig index 8651d810..34eb1f4a 100644 --- a/app/twig_templates/admin/common/install.twig +++ b/app/twig_templates/admin/common/install.twig @@ -78,7 +78,7 @@ {% if not is_db_connect_lib %} NG!
-

{{ _('Please enable pdo or mysqli') }}

+

{{ _('Please enable pdo') }}

{% endif %} From 3ba7fd5c5748fd4aa534ff8ed33627ebd88aa4c4 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:41:18 +0900 Subject: [PATCH 10/21] Chore, set correct types. --- app/src/Model/Model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index cc4517a7..9971f08a 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -19,7 +19,7 @@ abstract class Model /** * @return static */ - public static function getInstance() + public static function getInstance(): Model { if (!isset(static::$instance)) { static::$instance = new static(); @@ -312,7 +312,7 @@ public function getFoundRows(array $options = []): int unset($options['offset']); /** @var PDOStatement $stmt */ $stmt = $this->find('statement', $options); - return (int)$stmt->rowCount(); + return $stmt->rowCount(); } /** From 228d47a34e7632cbc30b6187a541f6a1c6e35c40 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:54:11 +0900 Subject: [PATCH 11/21] use PDOWrap instead of DBInterface, update the (base) Model class, remove MSDB. #332 --- app/src/Model/DBInterface.php | 30 ---------- app/src/Model/MSDB.php | 102 ---------------------------------- app/src/Model/Model.php | 33 +++++------ app/src/Model/PDOWrap.php | 47 ++++++++++++---- 4 files changed, 51 insertions(+), 161 deletions(-) delete mode 100644 app/src/Model/DBInterface.php delete mode 100644 app/src/Model/MSDB.php diff --git a/app/src/Model/DBInterface.php b/app/src/Model/DBInterface.php deleted file mode 100644 index de0b03b9..00000000 --- a/app/src/Model/DBInterface.php +++ /dev/null @@ -1,30 +0,0 @@ -master = new PDOWrap( - Config::get('MASTER_DB.HOST'), - Config::get('MASTER_DB.PORT'), - Config::get('MASTER_DB.USER'), - Config::get('MASTER_DB.PASSWORD'), - Config::get('MASTER_DB.DATABASE'), - Config::get('DB_CHARSET') - ); - } - - public function close() - { - $this->master->close(); - $this->master = null; - } - - /** - * 参照系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return array|false - */ - public function find(string $sql, array $params = [], array $options = []) - { - $_options = array( - 'master' => false, // Masterから取得するかどうか - 'types' => '', // paramsの型設定(sdi) - 'result' => DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); - $db = $this->getMasterDB(); - return $db->find($sql, $params, $options); - } - - /** - * 更新系SQL - * @param string $sql - * @param array $params - * @param array $options - * @return false|int|mixed - */ - public function execute(string $sql, array $params = [], array $options = []) - { - $default_options = [ - 'types' => '', // paramsの型設定(sdi) - 'result' => DBInterface::RESULT_AFFECTED, // 戻り値 one/row/all/statement... - ]; - $options = array_merge($default_options, $options); - $db = $this->getMasterDB(); - return $db->execute($sql, $params, $options); - } - - /** - * 複数の更新系SQL - * @param $sql - * @return bool - */ - public function multiExecute($sql) - { - return $this->getMasterDB()->multiExecute($sql); - } - - /** - * 接続処理 - */ - public function connect() - { - $this->getMasterDB()->connect(); - } -} - diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index 9971f08a..18b0fc0c 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -16,10 +16,7 @@ abstract class Model /** @var static */ public static $instance; - /** - * @return static - */ - public static function getInstance(): Model + public static function getInstance() { if (!isset(static::$instance)) { static::$instance = new static(); @@ -36,11 +33,11 @@ protected function getAutoIncrementCompositeKey(): string } /** - * @return MSDB|null + * @return PDOWrap */ - public function getDB(): ?MSDB + public function getDB(): PDOWrap { - return MSDB::getInstance(); + return PDOWrap::getInstance(); } public function close(): void @@ -156,25 +153,25 @@ public function find(string $type, array $options = []) case 'count': $options['fields'] = 'COUNT(*)'; $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ONE; + $options['options']['result'] = PDOWrap::RESULT_ONE; break; case 'one': $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ONE; + $options['options']['result'] = PDOWrap::RESULT_ONE; break; case 'row': $options['limit'] = 1; - $options['options']['result'] = DBInterface::RESULT_ROW; + $options['options']['result'] = PDOWrap::RESULT_ROW; break; case 'list': - $options['options']['result'] = DBInterface::RESULT_LIST; + $options['options']['result'] = PDOWrap::RESULT_LIST; break; case 'all': - $options['options']['result'] = DBInterface::RESULT_ALL; + $options['options']['result'] = PDOWrap::RESULT_ALL; break; case 'statement': default: - $options['options']['result'] = DBInterface::RESULT_STAT; + $options['options']['result'] = PDOWrap::RESULT_STAT; break; } $fields = '*'; @@ -369,7 +366,7 @@ public function insert(array $values, array $options = []) $values = array_values($values); } if (!isset($options['result'])) { - $options['result'] = DBInterface::RESULT_INSERT_ID; + $options['result'] = PDOWrap::RESULT_INSERT_ID; } return $this->executeSql($sql, $values, $options); } @@ -392,7 +389,7 @@ public function update(array $values, string $where, array $params = [], array $ } $sql = 'UPDATE ' . $this->getTableName() . ' SET ' . implode(',', $sets) . ' WHERE ' . $where; $params = array_merge(array_values($values), $params); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -433,7 +430,7 @@ public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $ public function delete(string $where, array $params = [], array $options = []) { $sql = 'DELETE FROM ' . $this->getTableName() . ' WHERE ' . $where; - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -488,7 +485,7 @@ public function multipleInsert(array $columns = [], array $params = [], array $o $sql_array[] = '(' . implode(',', array_fill(0, count($columns), '?')) . ')'; } $sql .= implode(',', $sql_array); - $options['result'] = DBInterface::RESULT_INSERT_ID; + $options['result'] = PDOWrap::RESULT_INSERT_ID; return $this->executeSql($sql, $params, $options); } @@ -496,7 +493,7 @@ public function multipleInsert(array $columns = [], array $params = [], array $o * @param string $sql * @param array $params * @param array $options - * @return mixed|false 失敗時False、成功時はOptionにより不定 + * @return array|false|int 失敗時False、成功時はOptionにより不定 */ public function executeSql(string $sql, array $params = [], array $options = []) { diff --git a/app/src/Model/PDOWrap.php b/app/src/Model/PDOWrap.php index aa3fa8ee..18230e86 100644 --- a/app/src/Model/PDOWrap.php +++ b/app/src/Model/PDOWrap.php @@ -9,8 +9,16 @@ use Exception; use PDOStatement; -class PDOWrap implements DBInterface +class PDOWrap { + const RESULT_ONE = 'one'; // 1カラムのみ取得 + const RESULT_ROW = 'row'; // 1行のみ取得 + const RESULT_LIST = 'list'; // リスト形式で取得 + const RESULT_ALL = 'all'; // 全て取得 + const RESULT_STAT = 'statement'; // 結果ステートメントを返却する + const RESULT_INSERT_ID = 'insert_id'; // AUTO_INCREMENTの値を返却 + const RESULT_AFFECTED = 'affected'; // 変更のあった行数を返却 + const RESULT_SUCCESS = 'success'; // SQLの実行結果が成功かどうかを返却 // DB情報 private $host = null; @@ -33,6 +41,23 @@ function __construct($host, $port, $user, $password, $database, $charset) $this->charset = $charset; } + private static $instance; + + public static function getInstance(bool $rebuild = false): self + { + if (!isset(self::$instance) || $rebuild) { + self::$instance = new self( + DB_HOST, + DB_PORT, + DB_USER, + DB_PASSWORD, + DB_DATABASE, + DB_CHARSET, + ); + } + return self::$instance; + } + /** * 参照系SQL * @param string $sql @@ -44,7 +69,7 @@ public function find(string $sql, array $params = [], array $options = []) { $_options = array( 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_ALL, // 戻り値 one/row/all/statement... + 'result' => \Fc2blog\Model\PDOWrap::RESULT_ALL, // 戻り値 one/row/all/statement... ); $options = array_merge($_options, $options); try { @@ -70,7 +95,7 @@ public function execute(string $sql, array $params = [], array $options = []) { $_options = array( 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\DBInterface::RESULT_SUCCESS, // 戻り値 one/row/all/statement... + 'result' => \Fc2blog\Model\PDOWrap::RESULT_SUCCESS, // 戻り値 one/row/all/statement... ); $options = array_merge($_options, $options); try { @@ -183,15 +208,15 @@ public function result($stmt, $type) switch ($type) { // 1カラムのみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ONE : + case \Fc2blog\Model\PDOWrap::RESULT_ONE : return $stmt->fetchColumn(); // 1行のみ取得 - case \Fc2blog\Model\DBInterface::RESULT_ROW : + case \Fc2blog\Model\PDOWrap::RESULT_ROW : return $stmt->fetch(); // リスト形式で取得 - case \Fc2blog\Model\DBInterface::RESULT_LIST : + case \Fc2blog\Model\PDOWrap::RESULT_LIST : $rows = array(); $stmt->setFetchMode(\PDO::FETCH_NUM); foreach ($stmt as $value) { @@ -200,22 +225,22 @@ public function result($stmt, $type) return $rows; // 全て取得 - case \Fc2blog\Model\DBInterface::RESULT_ALL : + case \Fc2blog\Model\PDOWrap::RESULT_ALL : return $stmt->fetchAll(); // InsertIDを返却 - case \Fc2blog\Model\DBInterface::RESULT_INSERT_ID : + case \Fc2blog\Model\PDOWrap::RESULT_INSERT_ID : return $this->db->lastInsertId(); // 影響のあった行数を返却 - case \Fc2blog\Model\DBInterface::RESULT_AFFECTED : + case \Fc2blog\Model\PDOWrap::RESULT_AFFECTED : return $stmt->rowCount(); // 成功したかどうかを返却 - case \Fc2blog\Model\DBInterface::RESULT_SUCCESS : + case \Fc2blog\Model\PDOWrap::RESULT_SUCCESS : return 1; - case \Fc2blog\Model\DBInterface::RESULT_STAT: + case \Fc2blog\Model\PDOWrap::RESULT_STAT: default: return $stmt; } From 267620219299d06a0a0f807b12e5d4fdced0658b Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 18:55:56 +0900 Subject: [PATCH 12/21] Use directly to the PDOWrap class instead of the DBInterface. #332 --- app/src/Model/BlogsModel.php | 2 +- app/src/Model/CategoriesModel.php | 8 ++++---- app/src/Model/CommentsModel.php | 2 +- app/src/Model/EntriesModel.php | 6 +++--- app/src/Model/TagsModel.php | 8 ++++---- app/src/Web/Controller/Admin/CommonController.php | 12 ++++++------ 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/Model/BlogsModel.php b/app/src/Model/BlogsModel.php index bebbc22f..f4f4ad6d 100644 --- a/app/src/Model/BlogsModel.php +++ b/app/src/Model/BlogsModel.php @@ -349,7 +349,7 @@ public function insert(array $data, array $options = []) { // 主キーがauto_incrementじゃないのでreturn値の受け取り方を変更 $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s'); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; if (!parent::insert($data, $options)) { return false; } diff --git a/app/src/Model/CategoriesModel.php b/app/src/Model/CategoriesModel.php index 9b867355..dd335ee8 100644 --- a/app/src/Model/CategoriesModel.php +++ b/app/src/Model/CategoriesModel.php @@ -183,7 +183,7 @@ public function getEntryCategories($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOWrap::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -210,7 +210,7 @@ public function getEntriesCategories($blog_id, $entry_ids = array()) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOWrap::RESULT_ALL; $categories = $this->findSql($sql, $params, $options); $entries_categories = array(); @@ -253,7 +253,7 @@ public function increaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -270,7 +270,7 @@ public function decreaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count-1 WHERE blog_id=? AND count>0 AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/CommentsModel.php b/app/src/Model/CommentsModel.php index 536a20c3..d571de7d 100644 --- a/app/src/Model/CommentsModel.php +++ b/app/src/Model/CommentsModel.php @@ -594,7 +594,7 @@ public function updateApproval($blog_id, $comment_id = null) $params[] = $comment_id; } $sql .= ' AND open_status=' . Config::get('COMMENT.OPEN_STATUS.PENDING'); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/EntriesModel.php b/app/src/Model/EntriesModel.php index 815ce29a..24c375ba 100644 --- a/app/src/Model/EntriesModel.php +++ b/app/src/Model/EntriesModel.php @@ -136,7 +136,7 @@ public function getArchives($blog_id) ORDER BY concat(year, month) DESC; SQL; $params = array($blog_id); - $options = array('result' => DBInterface::RESULT_ALL); + $options = array('result' => PDOWrap::RESULT_ALL); return $this->findSql($sql, $params, $options); } @@ -387,7 +387,7 @@ public function increaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count+1 WHERE blog_id=? AND id=?'; $params = array($blog_id, $entry_id); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -401,7 +401,7 @@ public function decreaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count-1 WHERE blog_id=? AND id=? AND comment_count>0'; $params = array($blog_id, $entry_id); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/TagsModel.php b/app/src/Model/TagsModel.php index 3b163015..c80c41f8 100644 --- a/app/src/Model/TagsModel.php +++ b/app/src/Model/TagsModel.php @@ -184,7 +184,7 @@ public function getEntryTags($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOWrap::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -211,7 +211,7 @@ public function getEntriesTags($blog_id, $entry_ids) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = DBInterface::RESULT_ALL; + $options['result'] = PDOWrap::RESULT_ALL; $tags = $this->findSql($sql, $params, $options); $entries_tags = array(); @@ -237,7 +237,7 @@ public function increaseCount(string $blog_id, array $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -256,7 +256,7 @@ public function decreaseCount($blog_id, array $ids = []) ' SET count=count-1 WHERE blog_id=? AND count>0 AND id ' . ' IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge([$blog_id], $ids); - $options['result'] = DBInterface::RESULT_SUCCESS; + $options['result'] = PDOWrap::RESULT_SUCCESS; return # 有効タグ数の数え直し $this->executeSql($sql, $params, $options) && diff --git a/app/src/Web/Controller/Admin/CommonController.php b/app/src/Web/Controller/Admin/CommonController.php index b55a3b63..9ec28277 100644 --- a/app/src/Web/Controller/Admin/CommonController.php +++ b/app/src/Web/Controller/Admin/CommonController.php @@ -9,7 +9,7 @@ use Fc2blog\Model\BlogSettingsModel; use Fc2blog\Model\BlogsModel; use Fc2blog\Model\CommentsModel; -use Fc2blog\Model\MSDB; +use Fc2blog\Model\PDOWrap; use Fc2blog\Model\PluginsModel; use Fc2blog\Model\UsersModel; use Fc2blog\Web\Cookie; @@ -170,7 +170,7 @@ public function install(Request $request): string $is_connect = true; $connect_message = ''; try { - MSDB::getInstance()->connect(); + PDOWrap::getInstance()->connect(); } catch (Exception $e) { $is_connect = false; $connect_message = $e->getMessage(); @@ -207,7 +207,7 @@ public function install(Request $request): string } // DB接続確認 - $msdb = MSDB::getInstance(true); + $msdb = PDOWrap::getInstance(true); try { // DB接続確認(DATABASEの存在判定含む) $msdb->connect(); @@ -218,7 +218,7 @@ public function install(Request $request): string // テーブルの存在チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = MSDB::getInstance()->find($sql); + $table = PDOWrap::getInstance()->find($sql); if (is_countable($table) && count($table)) { // 既にDB登録完了 @@ -231,7 +231,7 @@ public function install(Request $request): string if (DB_CHARSET != 'UTF8MB4') { $sql = str_replace('utf8mb4', strtolower(DB_CHARSET), $sql); } - $res = MSDB::getInstance()->multiExecute($sql); + $res = PDOWrap::getInstance()->multiExecute($sql); if ($res === false) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); @@ -239,7 +239,7 @@ public function install(Request $request): string // DBセットアップ成功チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = MSDB::getInstance()->find($sql); + $table = PDOWrap::getInstance()->find($sql); if (!is_countable($table)) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); From fefed24f59718f095d51d09e0b563a508db22b91 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:03:44 +0900 Subject: [PATCH 13/21] Remove check for UTF8MB4 support (too old mysql). --- app/twig_templates/admin/common/install.twig | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/app/twig_templates/admin/common/install.twig b/app/twig_templates/admin/common/install.twig index 34eb1f4a..050a2434 100644 --- a/app/twig_templates/admin/common/install.twig +++ b/app/twig_templates/admin/common/install.twig @@ -121,24 +121,6 @@ - {% if is_connect %} -
  • - {{ _('Character code check of MySQL') }} . . . - {% if is_character %} - OK - {% endif %} - {% if not is_character %} - NG! -
    -

    - {{ _('You can not use the character code of UTF8MB4 because the version of MySQL is older') }}
    - {{ _('Please change to UTF8 DB_CHARSET') }}
    - {{ _('Example') }}) define('DB_CHARSET', 'UTF8'); -

    - {% endif %} -
  • - {% endif %} -
  • {{ _('Check the configuration of the domain') }} . . . {% if is_domain %} From 25d4b17be695959b949b87633e300dfda7676143 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:05:37 +0900 Subject: [PATCH 14/21] Refactoring PDOWrap. #332 --- app/src/Model/Model.php | 28 +++--- app/src/Model/PDOWrap.php | 199 ++++++++++++++------------------------ 2 files changed, 89 insertions(+), 138 deletions(-) diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index 18b0fc0c..6a69fe37 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -16,6 +16,9 @@ abstract class Model /** @var static */ public static $instance; + /** + * @return static + */ public static function getInstance() { if (!isset(static::$instance)) { @@ -40,11 +43,6 @@ public function getDB(): PDOWrap return PDOWrap::getInstance(); } - public function close(): void - { - $this->getDB()->close(); - } - /** * 入力チェック処理 * @param array $data 入力データ @@ -139,7 +137,8 @@ public function is_numeric_array(array $array): bool /** * @param string $type * @param array $options - * @return array|false + * @return array + * @throw PDOException */ public function find(string $type, array $options = []) { @@ -247,7 +246,7 @@ public function findByIdAndBlogId($id, ?string $blog_id, array $options = []) * @param $id * @param int $user_id * @param array $options - * @return array|false + * @return array */ public function findByIdAndUserId($id, int $user_id, array $options = []) { @@ -331,7 +330,8 @@ public static function getPageList(array $paging): array * @param string $sql * @param array $params * @param array $options - * @return array|false + * @return array + * @throw PDOException */ public function findSql(string $sql, array $params = [], array $options = []) { @@ -376,7 +376,7 @@ public function insert(array $values, array $options = []) * @param string $where * @param array $params * @param array $options - * @return false|int 失敗時:false, 成功時:1 + * @return array|int 失敗時:false, 成功時:1 */ public function update(array $values, string $where, array $params = [], array $options = []) { @@ -425,7 +425,7 @@ public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $ * @param string $where * @param array $params * @param array $options - * @return int|false 失敗時:false, 成功時:1 + * @return array|int 失敗時:false, 成功時:1 */ public function delete(string $where, array $params = [], array $options = []) { @@ -474,7 +474,7 @@ public function deleteByIdAndUserId($id, int $user_id, array $options = []) * @param array $columns * @param array $params * @param array $options - * @return string|int|false false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい + * @return array|int false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい */ public function multipleInsert(array $columns = [], array $params = [], array $options = []) { @@ -493,7 +493,7 @@ public function multipleInsert(array $columns = [], array $params = [], array $o * @param string $sql * @param array $params * @param array $options - * @return array|false|int 失敗時False、成功時はOptionにより不定 + * @return array|int 失敗時False、成功時はOptionにより不定 */ public function executeSql(string $sql, array $params = [], array $options = []) { @@ -503,7 +503,7 @@ public function executeSql(string $sql, array $params = [], array $options = []) /** * 階層構造の一覧取得 * @param array $options - * @return array|false + * @return array */ public function findNode(array $options) { @@ -705,7 +705,7 @@ public function updateNodeById(array $data, string $id, string $where = '', arra * @param string $where * @param array $params * @param array $options - * @return array|false|int|mixed + * @return array|false|int */ public function deleteNodeById($id, string $where = '', array $params = [], array $options = []) { diff --git a/app/src/Model/PDOWrap.php b/app/src/Model/PDOWrap.php index 18230e86..1914b211 100644 --- a/app/src/Model/PDOWrap.php +++ b/app/src/Model/PDOWrap.php @@ -1,16 +1,17 @@ -host = $host; - $this->port = $port; - $this->user = $user; - $this->password = $password; - $this->database = $database; - $this->charset = $charset; - } + /** @var PDO */ + private $pdo; private static $instance; public static function getInstance(bool $rebuild = false): self { if (!isset(self::$instance) || $rebuild) { - self::$instance = new self( - DB_HOST, - DB_PORT, - DB_USER, - DB_PASSWORD, - DB_DATABASE, - DB_CHARSET, - ); + self::$instance = new self(); } return self::$instance; } + public static function createNewConnection(): PDO + { + $host = DB_HOST; + $port = DB_PORT; + $user = DB_USER; + $password = DB_PASSWORD; + $database = DB_DATABASE; + $charset = DB_CHARSET; + + return new PDO( + "mysql:host={$host};port={$port};dbname={$database};charset={$charset};", + $user, + $password, + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ] + ); + } + /** * 参照系SQL * @param string $sql * @param array $params * @param array $options - * @return mixed + * @return array|int + * @throw PDOException */ public function find(string $sql, array $params = [], array $options = []) { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\PDOWrap::RESULT_ALL, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); + $options = array_merge(['result' => static::RESULT_ALL], $options); try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; + $stmt = $this->query($sql, $params); + } catch (PDOException $e) { + Log::error("DB find error " . $e->getMessage() . " {$sql}", [$params]); + throw $e; } return $this->result($stmt, $options['result']); } @@ -89,22 +81,16 @@ public function find(string $sql, array $params = [], array $options = []) * @param string $sql * @param array $params * @param array $options - * @return array|false|int + * @return array|int */ public function execute(string $sql, array $params = [], array $options = []) { - $_options = array( - 'types' => '', // paramsの型設定(sdi) - 'result' => \Fc2blog\Model\PDOWrap::RESULT_SUCCESS, // 戻り値 one/row/all/statement... - ); - $options = array_merge($_options, $options); + $options = array_merge(['result' => static::RESULT_SUCCESS], $options); try { - $stmt = $this->query($sql, $params, $options['types']); - } catch (Exception $e) { - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - \Fc2blog\Util\Log::old_log($e->getMessage(), $params, 'error', __FILE__, __LINE__); - } - return false; + $stmt = $this->query($sql, $params); + } catch (PDOException $e) { + Log::error("DB execute error " . $e->getMessage() . " {$sql}", [$params]); + throw $e; } return $this->result($stmt, $options['result']); } @@ -112,22 +98,14 @@ public function execute(string $sql, array $params = [], array $options = []) /** * 複数の更新系SQL */ - public function multiExecute($sql) + public function multiExecute($sql): bool { $sql = preg_replace('/^--.*?\n/m', '', $sql); $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); - $sqls = explode(';', $sql); - $execute_sqls = array(); - foreach ($sqls as $sql) { - if (trim($sql) !== '') { - $execute_sqls[] = $sql; - } - } - - foreach ($execute_sqls as $sql) { - if ($this->execute($sql) === false) { - return false; - } + $sql_list = explode(';', $sql); + foreach ($sql_list as $sql) { + if (trim($sql) === '') continue; // 空クエリならスキップ + $this->execute($sql); } return true; } @@ -136,63 +114,36 @@ public function multiExecute($sql) * SQLの実行 * @param $sql * @param array $params - * @param string $types - * @return PDOStatement|mixed 成功時PDOStatement - * @throws Exception + * @return false|PDOStatement 成功時PDOStatement */ - private function query($sql, $params = array(), $types = '') + private function query($sql, array $params = []) { - $mtime = 0; // SQL実行結果時間取得用 - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { + if (Config::get('SQL_DEBUG', 0)) { $mtime = microtime(true); } - $this->connect(); + $pdo = $this->getPdo(); if (!count($params)) { - // SQL文をそのまま実行 - $stmt = $this->db->query($sql); - if (getType($stmt) == 'boolean' && !$stmt) { - throw new Exception('[query Error]' . print_r($this->db->errorInfo(), true) . $sql); - } - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { - $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); - } - return $stmt; + $stmt = $pdo->query($sql); + } else { + $stmt = $pdo->prepare($sql); + $stmt->execute($params); } - // プリペアドステートメント - $stmt = $this->db->prepare($sql); - if (!$stmt) { - throw new Exception('[prepare Error]' . $sql); - } - $stmt->execute($params); - if (\Fc2blog\Config::get('SQL_DEBUG', 0)) { + if (isset($mtime) && Config::get('SQL_DEBUG', 0)) { $mtime = sprintf('%0.2fms', (microtime(true) - $mtime) * 1000); - \Fc2blog\Util\Log::old_log('実行時間:' . $mtime . ' ' . $sql, $params, 'sql', __FILE__, __LINE__); + Log::debug_log("SQL {$mtime} {$sql}", ['params' => $params]); } return $stmt; } - public function connect() - { - if ($this->db == null) { - $dsn = "mysql:host={$this->host};port={$this->port};dbname={$this->database};charset={$this->charset};"; - $options = array( - \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, - \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, - \PDO::ATTR_EMULATE_PREPARES => false, - ); - $this->db = new \PDO($dsn, $this->user, $this->password, $options); - } - } - - public function close() + public function getPdo(bool $forceNew = false): PDO { - if ($this->db != null) { - $this->db = null; + if ($forceNew || !isset($this->pdo)) { + $this->pdo = static::createNewConnection(); } + return $this->pdo; } /** @@ -203,44 +154,44 @@ public function close() public function result($stmt, $type) { if ($stmt === false) { - return array(); + return []; } switch ($type) { // 1カラムのみ取得 - case \Fc2blog\Model\PDOWrap::RESULT_ONE : + case static::RESULT_ONE : return $stmt->fetchColumn(); // 1行のみ取得 - case \Fc2blog\Model\PDOWrap::RESULT_ROW : + case static::RESULT_ROW : return $stmt->fetch(); // リスト形式で取得 - case \Fc2blog\Model\PDOWrap::RESULT_LIST : - $rows = array(); - $stmt->setFetchMode(\PDO::FETCH_NUM); + case static::RESULT_LIST : + $rows = []; + $stmt->setFetchMode(PDO::FETCH_NUM); foreach ($stmt as $value) { $rows[$value[0]] = $value[1]; } return $rows; // 全て取得 - case \Fc2blog\Model\PDOWrap::RESULT_ALL : + case static::RESULT_ALL : return $stmt->fetchAll(); // InsertIDを返却 - case \Fc2blog\Model\PDOWrap::RESULT_INSERT_ID : - return $this->db->lastInsertId(); + case static::RESULT_INSERT_ID : + return $this->pdo->lastInsertId(); // 影響のあった行数を返却 - case \Fc2blog\Model\PDOWrap::RESULT_AFFECTED : + case static::RESULT_AFFECTED : return $stmt->rowCount(); // 成功したかどうかを返却 - case \Fc2blog\Model\PDOWrap::RESULT_SUCCESS : + case static::RESULT_SUCCESS : return 1; - case \Fc2blog\Model\PDOWrap::RESULT_STAT: + case static::RESULT_STAT: default: return $stmt; } From faacfbf39b336dffcab8ffcaf13cac90f063ea9a Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:06:10 +0900 Subject: [PATCH 15/21] Bugfix, query failed in install. #332 --- app/src/Model/BlogsModel.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/Model/BlogsModel.php b/app/src/Model/BlogsModel.php index f4f4ad6d..be586e1c 100644 --- a/app/src/Model/BlogsModel.php +++ b/app/src/Model/BlogsModel.php @@ -8,6 +8,7 @@ use Fc2blog\Web\Request; use InvalidArgumentException; use OutOfBoundsException; +use PDOException; class BlogsModel extends Model { @@ -233,16 +234,21 @@ public static function getTemplateIds($blog): array /** * ブログの一覧(SelectBox用) * @param $user_id - * @return mixed + * @return array */ - public function getSelectList($user_id) + public function getSelectList($user_id): array { - return $this->find('list', array( - 'fields' => array('id', 'name'), - 'where' => 'user_id=?', - 'params' => array($user_id), - 'order' => 'created_at DESC', - )); + try { + return $this->find('list', array( + 'fields' => array('id', 'name'), + 'where' => 'user_id=?', + 'params' => array($user_id), + 'order' => 'created_at DESC', + )); + } catch (PDOException $e) { + // インストール前や初期化前など、クエリが出来ないケースがある + return []; + } } /** From 9c56b01529fdf698ede1a5a49ad907370eb0b326 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:06:16 +0900 Subject: [PATCH 16/21] Bugfix --- app/src/Web/Controller/Admin/CommonController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/Web/Controller/Admin/CommonController.php b/app/src/Web/Controller/Admin/CommonController.php index 9ec28277..6fbe7581 100644 --- a/app/src/Web/Controller/Admin/CommonController.php +++ b/app/src/Web/Controller/Admin/CommonController.php @@ -170,7 +170,7 @@ public function install(Request $request): string $is_connect = true; $connect_message = ''; try { - PDOWrap::getInstance()->connect(); + PDOWrap::createNewConnection(); } catch (Exception $e) { $is_connect = false; $connect_message = $e->getMessage(); @@ -207,10 +207,9 @@ public function install(Request $request): string } // DB接続確認 - $msdb = PDOWrap::getInstance(true); try { // DB接続確認(DATABASEの存在判定含む) - $msdb->connect(); + PDOWrap::createNewConnection(); } catch (Exception $e) { $this->setErrorMessage(__('Please set correct the DB connection settings.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); From 79d501574a76f17e82522b8251b7562d24daee94 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:11:37 +0900 Subject: [PATCH 17/21] Now unnecessary old_log method. removed. --- app/src/Util/Log.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/app/src/Util/Log.php b/app/src/Util/Log.php index 7af9b991..5112b202 100644 --- a/app/src/Util/Log.php +++ b/app/src/Util/Log.php @@ -32,20 +32,6 @@ public static function getLogger(): LoggerInterface return static::$logger; } - /** - * 過去のDebug::logと互換性を持ったメソッド - * @param string $message - * @param mixed $context - * @param string $class - * @param string $filename - * @param int $line - */ - public static function old_log(string $message, $context, string $class = 'log', string $filename = "-", int $line = 0): void - { - $logger = static::getLogger(); - $logger->debug("[{$class}]{$filename}:{$line} {$message}", [$context]); - } - /** * @param string $message * @param array $context From 5ccd10c8eb55cf5f3083b5910fee94511c49e937 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 20:59:52 +0900 Subject: [PATCH 18/21] Decouple PDO connection and query feature. #322 --- app/src/Model/PDOConnection.php | 45 +++++++++++ app/src/Model/{PDOWrap.php => PDOQuery.php} | 85 ++++++--------------- 2 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 app/src/Model/PDOConnection.php rename app/src/Model/{PDOWrap.php => PDOQuery.php} (68%) diff --git a/app/src/Model/PDOConnection.php b/app/src/Model/PDOConnection.php new file mode 100644 index 00000000..fc0bbaa1 --- /dev/null +++ b/app/src/Model/PDOConnection.php @@ -0,0 +1,45 @@ +pdo = static::createConnection(); + } + return self::$instance; + } + + /** @var PDO */ + public $pdo; + + public static function createConnection(): PDO + { + $host = DB_HOST; + $port = DB_PORT; + $user = DB_USER; + $password = DB_PASSWORD; + $database = DB_DATABASE; + $charset = DB_CHARSET; + + return new PDO( + "mysql:host={$host};port={$port};dbname={$database};charset={$charset};", + $user, + $password, + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ] + ); + } +} diff --git a/app/src/Model/PDOWrap.php b/app/src/Model/PDOQuery.php similarity index 68% rename from app/src/Model/PDOWrap.php rename to app/src/Model/PDOQuery.php index 1914b211..5f12c68f 100644 --- a/app/src/Model/PDOWrap.php +++ b/app/src/Model/PDOQuery.php @@ -9,7 +9,7 @@ use PDOException; use PDOStatement; -class PDOWrap +class PDOQuery { // find等の挙動選択肢 TODO 削除し、別々のメソッドへ const RESULT_ONE = 'one'; // 1カラムのみ取得 @@ -21,109 +21,78 @@ class PDOWrap const RESULT_AFFECTED = 'affected'; // 変更のあった行数を返却 const RESULT_SUCCESS = 'success'; // SQLの実行結果が成功かどうかを返却 - /** @var PDO */ - private $pdo; - - private static $instance; - - public static function getInstance(bool $rebuild = false): self - { - if (!isset(self::$instance) || $rebuild) { - self::$instance = new self(); - } - return self::$instance; - } - - public static function createNewConnection(): PDO - { - $host = DB_HOST; - $port = DB_PORT; - $user = DB_USER; - $password = DB_PASSWORD; - $database = DB_DATABASE; - $charset = DB_CHARSET; - - return new PDO( - "mysql:host={$host};port={$port};dbname={$database};charset={$charset};", - $user, - $password, - [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, - ] - ); - } - /** - * 参照系SQL + * 参照系SQLの実行 + * @param PDO $pdo * @param string $sql * @param array $params * @param array $options * @return array|int * @throw PDOException */ - public function find(string $sql, array $params = [], array $options = []) + public static function find(PDO $pdo, string $sql, array $params = [], array $options = []) { $options = array_merge(['result' => static::RESULT_ALL], $options); try { - $stmt = $this->query($sql, $params); + $stmt = static::query($pdo, $sql, $params); } catch (PDOException $e) { Log::error("DB find error " . $e->getMessage() . " {$sql}", [$params]); throw $e; } - return $this->result($stmt, $options['result']); + return static::result($pdo, $stmt, $options['result']); } - /** - * 更新系SQL + * 更新系SQLの実行 + * @param PDO $pdo * @param string $sql * @param array $params * @param array $options * @return array|int */ - public function execute(string $sql, array $params = [], array $options = []) + public static function execute(PDO $pdo, string $sql, array $params = [], array $options = []) { $options = array_merge(['result' => static::RESULT_SUCCESS], $options); try { - $stmt = $this->query($sql, $params); + $stmt = static::query($pdo, $sql, $params); } catch (PDOException $e) { Log::error("DB execute error " . $e->getMessage() . " {$sql}", [$params]); throw $e; } - return $this->result($stmt, $options['result']); + return static::result($pdo, $stmt, $options['result']); } /** - * 複数の更新系SQL + * 複数行となるSQLの実行 + * @param PDO $pdo + * @param $sql + * @return bool */ - public function multiExecute($sql): bool + public static function multiExecute(PDO $pdo, $sql): bool { $sql = preg_replace('/^--.*?\n/m', '', $sql); $sql = preg_replace('/\/\*.*?\*\//s', '', $sql); $sql_list = explode(';', $sql); foreach ($sql_list as $sql) { if (trim($sql) === '') continue; // 空クエリならスキップ - $this->execute($sql); + static::execute($pdo, $sql); } return true; } /** - * SQLの実行 + * PDOでSQLの実行 + * @param PDO $pdo * @param $sql * @param array $params * @return false|PDOStatement 成功時PDOStatement */ - private function query($sql, array $params = []) + private static function query(PDO $pdo, $sql, array $params = []) { if (Config::get('SQL_DEBUG', 0)) { $mtime = microtime(true); } - $pdo = $this->getPdo(); - if (!count($params)) { $stmt = $pdo->query($sql); } else { @@ -138,20 +107,14 @@ private function query($sql, array $params = []) return $stmt; } - public function getPdo(bool $forceNew = false): PDO - { - if ($forceNew || !isset($this->pdo)) { - $this->pdo = static::createNewConnection(); - } - return $this->pdo; - } - /** + * 結果内容の変換 TODO いつか削除する + * @param PDO $pdo * @param $stmt * @param $type * @return array|int $typeによって様々な意味の返り値となる */ - public function result($stmt, $type) + public static function result(PDO $pdo, $stmt, $type) { if ($stmt === false) { return []; @@ -181,7 +144,7 @@ public function result($stmt, $type) // InsertIDを返却 case static::RESULT_INSERT_ID : - return $this->pdo->lastInsertId(); + return $pdo->lastInsertId(); // 影響のあった行数を返却 case static::RESULT_AFFECTED : From 7bac97140a8b0412ccde277cb6d156fcf3a274fd Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 21:00:55 +0900 Subject: [PATCH 19/21] Decouple Model and Sql builder feature. #322 --- app/src/Model/Model.php | 596 +---------------------------------- app/src/Model/QueryTrait.php | 592 ++++++++++++++++++++++++++++++++++ 2 files changed, 593 insertions(+), 595 deletions(-) create mode 100644 app/src/Model/QueryTrait.php diff --git a/app/src/Model/Model.php b/app/src/Model/Model.php index 6a69fe37..8eea27eb 100644 --- a/app/src/Model/Model.php +++ b/app/src/Model/Model.php @@ -4,11 +4,10 @@ namespace Fc2blog\Model; use Fc2blog\Util\Log; -use PDOStatement; abstract class Model { - const LIKE_WILDCARD = '\\_%'; // MySQL用 + use QueryTrait; private static $loaded = []; public $validates = []; @@ -35,14 +34,6 @@ protected function getAutoIncrementCompositeKey(): string return ""; } - /** - * @return PDOWrap - */ - public function getDB(): PDOWrap - { - return PDOWrap::getInstance(); - } - /** * 入力チェック処理 * @param array $data 入力データ @@ -98,18 +89,6 @@ public static function load(string $model) return self::$loaded[$model]; } - - /** - * LIKE検索用にワイルドカードのエスケープ - * @param string $str - * @return string - */ - public static function escape_wildcard(string $str): string - { - return addcslashes($str, self::LIKE_WILDCARD); - } - - /** * 配列内が全て数値型かチェック * @param array $array @@ -134,140 +113,6 @@ public function is_numeric_array(array $array): bool return true; } - /** - * @param string $type - * @param array $options - * @return array - * @throw PDOException - */ - public function find(string $type, array $options = []) - { - if (!isset($options['options'])) { - $options['options'] = []; - } - if (!isset($options['params'])) { - $options['params'] = []; - } - switch ($type) { - case 'count': - $options['fields'] = 'COUNT(*)'; - $options['limit'] = 1; - $options['options']['result'] = PDOWrap::RESULT_ONE; - break; - case 'one': - $options['limit'] = 1; - $options['options']['result'] = PDOWrap::RESULT_ONE; - break; - case 'row': - $options['limit'] = 1; - $options['options']['result'] = PDOWrap::RESULT_ROW; - break; - case 'list': - $options['options']['result'] = PDOWrap::RESULT_LIST; - break; - case 'all': - $options['options']['result'] = PDOWrap::RESULT_ALL; - break; - case 'statement': - default: - $options['options']['result'] = PDOWrap::RESULT_STAT; - break; - } - $fields = '*'; - if (isset($options['fields'])) { - $fields = is_array($options['fields']) ? implode(',', $options['fields']) : $options['fields']; - } - if (!empty($options['limit']) && isset($options['page'])) { - $fields = 'SQL_CALC_FOUND_ROWS ' . $fields; - } - $sql = 'SELECT ' . $fields . ' FROM ' . $this->getTableName(); - if (!empty($options['from'])) { - if (is_array($options['from'])) { - $sql .= ', ' . implode(',', $options['from']); - } else { - $sql .= ', ' . $options['from']; - } - } - if (isset($options['where']) && $options['where'] != "") { - $sql .= ' WHERE ' . $options['where']; - } - if (isset($options['group']) && $options['group'] != "") { - $sql .= ' GROUP BY ' . $options['group']; - } - if (isset($options['order']) && $options['order'] != "") { - $sql .= ' ORDER BY ' . $options['order']; - } - if (!empty($options['limit'])) { - $sql .= ' LIMIT ' . $options['limit']; - if (isset($options['page'])) { - $sql .= ' OFFSET ' . $options['limit'] * $options['page']; - } else if (isset($options['offset'])) { - $sql .= ' OFFSET ' . $options['offset']; - } - } - return $this->findSql($sql, $options['params'], $options['options']); - } - - /** - * 主キーをキーにしてデータを取得 - * @param int|string|null $id - * @param array $options - * @return array|false - */ - public function findById($id, array $options = []) - { - if (empty($id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'id=? AND ' . $options['where'] : 'id=?'; - $options['params'] = isset($options['params']) ? array_merge([$id], $options['params']) : [$id]; - return $this->find('row', $options); - } - - /** - * idとblog_idの複合キーからデータを取得 - * @param int|string|null $id - * @param string|null $blog_id - * @param array $options - * @return array|false - */ - public function findByIdAndBlogId($id, ?string $blog_id, array $options = []) - { - if (empty($id) || empty($blog_id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'blog_id=? AND id=? AND ' . $options['where'] : 'blog_id=? AND id=?'; - $options['params'] = isset($options['params']) ? array_merge([$blog_id, $id], $options['params']) : [$blog_id, $id]; - return $this->find('row', $options); - } - - /** - * idとuser_idのキーからデータを取得 - * @param $id - * @param int $user_id - * @param array $options - * @return array - */ - public function findByIdAndUserId($id, int $user_id, array $options = []) - { - if (empty($id) || empty($user_id)) { - return []; - } - $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; - $options['params'] = isset($options['params']) ? array_merge([$id, $user_id], $options['params']) : [$id, $user_id]; - return $this->find('row', $options); - } - - /** - * 存在するかどうかを取得 - * @param array $options - * @return bool - */ - public function isExist(array $options = []): bool - { - return !!$this->find('row', $options); - } - /** * ページング用のデータ取得 * @param array $options @@ -297,20 +142,6 @@ public function getPaging(array $options = []): array return $pages; } - /** - * 指定のOptionでSELECTされる件数を取得 - * @param array $options - * @return int - */ - public function getFoundRows(array $options = []): int - { - unset($options['limit']); - unset($options['offset']); - /** @var PDOStatement $stmt */ - $stmt = $this->find('statement', $options); - return $stmt->rowCount(); - } - /** * ページングのリストを表示する * @param array $paging @@ -325,429 +156,4 @@ public static function getPageList(array $paging): array } return $pages; } - - /** - * @param string $sql - * @param array $params - * @param array $options - * @return array - * @throw PDOException - */ - public function findSql(string $sql, array $params = [], array $options = []) - { - return $this->getDB()->find($sql, $params, $options); - } - - /** - * @param array $values - * @param array $options - * @return string|int|false 失敗時:false, 成功時 last insert id - */ - public function insert(array $values, array $options = []) - { - if (!count($values)) { - return 0; - } - $tableName = $this->getTableName(); - $compositeKey = $this->getAutoIncrementCompositeKey(); - if ($compositeKey && empty($values['id']) && !empty($values[$compositeKey])) { - // 複合キーのauto_increment対応 - /** @noinspection SqlResolve */ - /** @noinspection SqlInsertValues */ - $sql = 'INSERT INTO ' . $tableName . ' (id, ' . implode(',', array_keys($values)) . ') ' - . 'VALUES ((SELECT LAST_INSERT_ID(COALESCE(MAX(id), 0)+1) FROM ' . $tableName . ' as auto_increment_temp ' - . 'WHERE ' . $compositeKey . '=?), ' . implode(',', array_fill(0, count($values), '?')) . ')'; - $value = $values[$compositeKey]; - $values = array_values($values); - array_unshift($values, $value); - } else { - // 通常のINSERT - $sql = 'INSERT INTO ' . $tableName . ' (' . implode(',', array_keys($values)) . ') VALUES (' . implode(',', array_fill(0, count($values), '?')) . ')'; - $values = array_values($values); - } - if (!isset($options['result'])) { - $options['result'] = PDOWrap::RESULT_INSERT_ID; - } - return $this->executeSql($sql, $values, $options); - } - - /** - * @param array $values - * @param string $where - * @param array $params - * @param array $options - * @return array|int 失敗時:false, 成功時:1 - */ - public function update(array $values, string $where, array $params = [], array $options = []) - { - if (count($values) === 0) { - return 0; - } - $sets = []; - foreach ($values as $key => $value) { - $sets[] = $key . '=?'; - } - $sql = 'UPDATE ' . $this->getTableName() . ' SET ' . implode(',', $sets) . ' WHERE ' . $where; - $params = array_merge(array_values($values), $params); - $options['result'] = PDOWrap::RESULT_SUCCESS; - return $this->executeSql($sql, $params, $options); - } - - - /** - * idをキーとした更新 - * @param array $values - * @param $id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function updateById(array $values, $id, array $options = []) - { - return $this->update($values, 'id=?', [$id], $options); - } - - - /** - * idとblog_idをキーとした更新 - * @param array $values - * @param $id - * @param string $blog_id - * @param array $options - * @return false|int 失敗時 False 、成功時1 - */ - public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $options = []) - { - return $this->update($values, 'id=? AND blog_id=?', [$id, $blog_id], $options); - } - - - /** - * @param string $where - * @param array $params - * @param array $options - * @return array|int 失敗時:false, 成功時:1 - */ - public function delete(string $where, array $params = [], array $options = []) - { - $sql = 'DELETE FROM ' . $this->getTableName() . ' WHERE ' . $where; - $options['result'] = PDOWrap::RESULT_SUCCESS; - return $this->executeSql($sql, $params, $options); - } - - /** - * idをキーとした削除 - * @param $id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteById($id, array $options = []) - { - return $this->delete('id=?', [$id], $options); - } - - /** - * idとblog_idをキーとした削除 - * @param $id - * @param string $blog_id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteByIdAndBlogId($id, string $blog_id, array $options = []) - { - return $this->delete('blog_id=? AND id=?', [$blog_id, $id], $options); - } - - /** - * idとuser_idをキーとした削除 - * @param $id - * @param int $user_id - * @param array $options - * @return false|int 失敗時:false, 成功時:1 - */ - public function deleteByIdAndUserId($id, int $user_id, array $options = []) - { - return $this->delete('id=? AND user_id=?', [$id, $user_id], $options); - } - - /** - * バルクインサート - * @param array $columns - * @param array $params - * @param array $options - * @return array|int false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい - */ - public function multipleInsert(array $columns = [], array $params = [], array $options = []) - { - $sql = 'INSERT INTO ' . $this->getTableName() . ' (' . implode(',', $columns) . ') VALUES '; - $len = count($params) / count($columns); - $sql_array = []; - for ($i = 0; $i < $len; $i++) { - $sql_array[] = '(' . implode(',', array_fill(0, count($columns), '?')) . ')'; - } - $sql .= implode(',', $sql_array); - $options['result'] = PDOWrap::RESULT_INSERT_ID; - return $this->executeSql($sql, $params, $options); - } - - /** - * @param string $sql - * @param array $params - * @param array $options - * @return array|int 失敗時False、成功時はOptionにより不定 - */ - public function executeSql(string $sql, array $params = [], array $options = []) - { - return $this->getDB()->execute($sql, $params, $options); - } - - /** - * 階層構造の一覧取得 - * @param array $options - * @return array - */ - public function findNode(array $options) - { - $options['order'] = 'lft ASC'; - $nodes = $this->find('all', $options); - - // levelを付与 - $level = 0; - $levels = []; - foreach ($nodes as $key => $value) { - // 最初のノード - if ($level == 0) { - $levels[] = $value; - $nodes[$key]['level'] = $level = count($levels); - continue; - } - // left=left+1であれば子供ノードとして解釈 - if ($value['lft'] == $levels[$level - 1]['lft'] + 1) { - $levels[] = $value; - $nodes[$key]['level'] = $level = count($levels); - continue; - } - // left=right+1であれば兄弟ノードとして解釈 - if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { - $levels[$level - 1] = $value; - $nodes[$key]['level'] = $level; - continue; - } - // 兄弟ノードになるまで階層を遡る - while (array_pop($levels)) { - $level = count($levels); - if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { - $levels[$level - 1] = $value; - $nodes[$key]['level'] = $level; - break; - } - } - } - return $nodes; - } - - /** - * 階層構造の追加 - * @param array $data 追加するノード情報 - * @param string $where 親ノード検索時のwhere句 - * @param array $params 親ノード検索時のバインドデータ - * @param array $options - * @return string|int|false falseか、Last insert id - */ - public function addNode(array $data = [], string $where = '', array $params = [], array $options = []) - { - // 親として末尾に追加する場合 - if (empty($data['parent_id'])) { - $max_right = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)); - // 親として末尾に追加 - $data['lft'] = $max_right + 1; - $data['rgt'] = $max_right + 2; - return $this->insert($data); - } - - // 親の子供として末尾に追加する場合 - $parent = $this->findById($data['parent_id'], array('fields' => 'rgt', 'where' => $where, 'params' => $params, 'options' => $options)); - if (!$parent) { - return false; - } - $right = $parent['rgt']; - - // 挿入する場所を確保する - $table = $this->getTableName(); - if ($where != "") { - $where .= ' AND '; - } - /** @noinspection SqlResolve */ - /** @noinspection SqlCaseVsIf */ - $updateSql = << {$right} THEN lft + 2 ELSE lft END, - rgt = CASE WHEN rgt >= {$right} THEN rgt + 2 ELSE rgt END - WHERE {$where} rgt >= {$right} - SQL; - - if (!$this->executeSql($updateSql, $params)) { - return false; - } - - // 子供として末尾に追加 - $data['lft'] = $right; - $data['rgt'] = $right + 1; - return $this->insert($data); - } - - /** - * 階層構造の更新 - * @param array $data - * @param string|int $id - * @param string $where - * @param array $params - * @param array $options - * @return false|int - */ - public function updateNodeById(array $data, string $id, string $where = '', array $params = [], array $options = []) - { - $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; - - // 自身取得 - $self_params = array_merge(array($id), $params); - $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); - if (!$self) { - return false; - } - - // 親が変更されていない場合そのまま更新 - if ($self['parent_id'] == $data['parent_id']) { - return $this->update($data, $idWhere, $self_params, $options); - } - - if ($self['parent_id'] && empty($data['parent_id'])) { - // 親から外れた時 - $parent = []; - $parent['lft'] = $parent['rgt'] = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)) + 1; - } else { - // 変更先の親を取得 - $parent_params = array_merge(array($data['parent_id']), $params); - $parent = $this->find('row', array('where' => $idWhere, 'params' => $parent_params, 'options' => $options)); - if (!$parent) { - return false; - } - } - - // 変更先の親が自身や自分の子供の場合はエラー - if ($self['lft'] <= $parent['lft'] && $parent['rgt'] <= $self['rgt']) { - return false; - } - - // ノードの変更位置計算 - $self_lft = $self['lft']; - $self_rgt = $self['rgt']; - $parent_rgt = $parent['rgt']; - $space = $self_rgt - $self_lft + 1; - - $table = $this->getTableName(); - $where = $where ? $where . ' AND ' : ''; - if ($self_rgt > $parent_rgt) { - // 自身を左へ移動 - $move = $parent_rgt - $self_lft; - /** @noinspection SqlResolve */ - $sql = << $parent_rgt AND lft < $self_lft - THEN lft + $space - WHEN lft >= $self_lft AND lft < $self_rgt - THEN lft + $move - ELSE lft END, - rgt = CASE - WHEN rgt >= $parent_rgt AND rgt < $self_lft - THEN rgt + $space - WHEN rgt > $self_lft AND rgt <= $self_rgt - THEN rgt + $move - ELSE rgt END - WHERE $where - rgt >= $parent_rgt AND lft < $self_rgt - SQL; - } else { - // 自身を右へ移動 - $move = $parent_rgt - $self_rgt - 1; - /** @noinspection SqlResolve */ - $sql = << $self_rgt AND lft < $parent_rgt - THEN lft - $space - WHEN lft >= $self_lft AND lft < $self_rgt - THEN lft + $move - ELSE lft END, - rgt = CASE - WHEN rgt > $self_rgt AND rgt < $parent_rgt - THEN rgt - $space - WHEN rgt > $self_lft AND rgt <= $self_rgt - THEN rgt + $move - ELSE rgt END - WHERE $where - rgt > $self_lft AND lft < $parent_rgt - SQL; - } - - // 親の位置変更処理 - if (!$this->executeSql($sql, $params, $options)) { - return false; - } - - // 自身の更新処理 - return $this->update($data, $idWhere, $self_params, $options); - } - - /** - * 階層構造のノード削除 - * @param $id - * @param string $where - * @param array $params - * @param array $options - * @return array|false|int - */ - public function deleteNodeById($id, string $where = '', array $params = [], array $options = []) - { - // 自身取得 - $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; - $self_params = array_merge(array($id), $params); - $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); - - if (!$self) { - return false; - } - - $self_lft = $self['lft']; - $self_rgt = $self['rgt']; - $space = $self_rgt - $self_lft + 1; - - $table = $this->getTableName(); - $where = $where ? $where . ' AND ' : ''; - - // 削除処理 - $sql = 'DELETE FROM ' . $table . ' WHERE ' . $where . ' lft >= ' . $self_lft . ' AND rgt <= ' . $self_rgt; - if (!$this->executeSql($sql, $params, $options)) { - return false; - } - - // 詰める処理 - /** @noinspection SqlResolve */ - /** @noinspection SqlCaseVsIf */ - $sql = << $self_rgt - THEN lft - $space - ELSE lft END, - rgt = CASE - WHEN rgt > $self_rgt - THEN rgt - $space - ELSE rgt END - WHERE - $where - rgt > $self_rgt - SQL; - return $this->executeSql($sql, $params, $options); - } } diff --git a/app/src/Model/QueryTrait.php b/app/src/Model/QueryTrait.php new file mode 100644 index 00000000..b835d6c2 --- /dev/null +++ b/app/src/Model/QueryTrait.php @@ -0,0 +1,592 @@ +execute(PDOConnection::getInstance()->pdo, $sql, $params, $options); + } + + /** + * @param string $sql + * @param array $params + * @param array $options + * @return array + * @throw PDOException + */ + public function findSql(string $sql, array $params = [], array $options = []) + { + return (new PDOQuery())->find(PDOConnection::getInstance()->pdo, $sql, $params, $options); + } + + /** + * 指定のOptionでSELECTされる件数を取得 + * @param array $options + * @return int + */ + public function getFoundRows(array $options = []): int + { + unset($options['limit']); + unset($options['offset']); + /** @var PDOStatement $stmt */ + $stmt = $this->find('statement', $options); + return $stmt->rowCount(); + } + + /** + * @param string $type + * @param array $options + * @return array + * @throw PDOException + */ + public function find(string $type, array $options = []) + { + if (!isset($options['options'])) { + $options['options'] = []; + } + if (!isset($options['params'])) { + $options['params'] = []; + } + switch ($type) { + case 'count': + $options['fields'] = 'COUNT(*)'; + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ONE; + break; + case 'one': + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ONE; + break; + case 'row': + $options['limit'] = 1; + $options['options']['result'] = PDOQuery::RESULT_ROW; + break; + case 'list': + $options['options']['result'] = PDOQuery::RESULT_LIST; + break; + case 'all': + $options['options']['result'] = PDOQuery::RESULT_ALL; + break; + case 'statement': + default: + $options['options']['result'] = PDOQuery::RESULT_STAT; + break; + } + $fields = '*'; + if (isset($options['fields'])) { + $fields = is_array($options['fields']) ? implode(',', $options['fields']) : $options['fields']; + } + if (!empty($options['limit']) && isset($options['page'])) { + $fields = 'SQL_CALC_FOUND_ROWS ' . $fields; + } + $sql = 'SELECT ' . $fields . ' FROM ' . $this->getTableName(); + if (!empty($options['from'])) { + if (is_array($options['from'])) { + $sql .= ', ' . implode(',', $options['from']); + } else { + $sql .= ', ' . $options['from']; + } + } + if (isset($options['where']) && $options['where'] != "") { + $sql .= ' WHERE ' . $options['where']; + } + if (isset($options['group']) && $options['group'] != "") { + $sql .= ' GROUP BY ' . $options['group']; + } + if (isset($options['order']) && $options['order'] != "") { + $sql .= ' ORDER BY ' . $options['order']; + } + if (!empty($options['limit'])) { + $sql .= ' LIMIT ' . $options['limit']; + if (isset($options['page'])) { + $sql .= ' OFFSET ' . $options['limit'] * $options['page']; + } else if (isset($options['offset'])) { + $sql .= ' OFFSET ' . $options['offset']; + } + } + return $this->executeSql($sql, $options['params'], $options['options']); + } + + /** + * 主キーをキーにしてデータを取得 + * @param int|string|null $id + * @param array $options + * @return array|false + */ + public function findById($id, array $options = []) + { + if (empty($id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'id=? AND ' . $options['where'] : 'id=?'; + $options['params'] = isset($options['params']) ? array_merge([$id], $options['params']) : [$id]; + return $this->find('row', $options); + } + + /** + * idとblog_idの複合キーからデータを取得 + * @param int|string|null $id + * @param string|null $blog_id + * @param array $options + * @return array|false + */ + public function findByIdAndBlogId($id, ?string $blog_id, array $options = []) + { + if (empty($id) || empty($blog_id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'blog_id=? AND id=? AND ' . $options['where'] : 'blog_id=? AND id=?'; + $options['params'] = isset($options['params']) ? array_merge([$blog_id, $id], $options['params']) : [$blog_id, $id]; + return $this->find('row', $options); + } + + /** + * idとuser_idのキーからデータを取得 + * @param $id + * @param int $user_id + * @param array $options + * @return array + */ + public function findByIdAndUserId($id, int $user_id, array $options = []) + { + if (empty($id) || empty($user_id)) { + return []; + } + $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; + $options['params'] = isset($options['params']) ? array_merge([$id, $user_id], $options['params']) : [$id, $user_id]; + return $this->find('row', $options); + } + + /** + * 存在するかどうかを取得 + * @param array $options + * @return bool + */ + public function isExist(array $options = []): bool + { + return !!$this->find('row', $options); + } + + + /** + * @param array $values + * @param array $options + * @return string|int|false 失敗時:false, 成功時 last insert id + */ + public function insert(array $values, array $options = []) + { + if (!count($values)) { + return 0; + } + $tableName = $this->getTableName(); + $compositeKey = $this->getAutoIncrementCompositeKey(); + if ($compositeKey && empty($values['id']) && !empty($values[$compositeKey])) { + // 複合キーのauto_increment対応 + /** @noinspection SqlResolve */ + /** @noinspection SqlInsertValues */ + $sql = 'INSERT INTO ' . $tableName . ' (id, ' . implode(',', array_keys($values)) . ') ' + . 'VALUES ((SELECT LAST_INSERT_ID(COALESCE(MAX(id), 0)+1) FROM ' . $tableName . ' as auto_increment_temp ' + . 'WHERE ' . $compositeKey . '=?), ' . implode(',', array_fill(0, count($values), '?')) . ')'; + $value = $values[$compositeKey]; + $values = array_values($values); + array_unshift($values, $value); + } else { + // 通常のINSERT + $sql = 'INSERT INTO ' . $tableName . ' (' . implode(',', array_keys($values)) . ') VALUES (' . implode(',', array_fill(0, count($values), '?')) . ')'; + $values = array_values($values); + } + if (!isset($options['result'])) { + $options['result'] = PDOQuery::RESULT_INSERT_ID; + } + return $this->executeSql($sql, $values, $options); + } + + /** + * @param array $values + * @param string $where + * @param array $params + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function update(array $values, string $where, array $params = [], array $options = []) + { + if (count($values) === 0) { + return 0; + } + $sets = []; + foreach ($values as $key => $value) { + $sets[] = $key . '=?'; + } + $sql = 'UPDATE ' . $this->getTableName() . ' SET ' . implode(',', $sets) . ' WHERE ' . $where; + $params = array_merge(array_values($values), $params); + $options['result'] = PDOQuery::RESULT_SUCCESS; + return $this->executeSql($sql, $params, $options); + } + + /** + * idをキーとした更新 + * @param array $values + * @param $id + * @param array $options + * @return false|int 失敗時:false, 成功時:1 + */ + public function updateById(array $values, $id, array $options = []) + { + return $this->update($values, 'id=?', [$id], $options); + } + + /** + * idとblog_idをキーとした更新 + * @param array $values + * @param $id + * @param string $blog_id + * @param array $options + * @return false|int 失敗時 False 、成功時1 + */ + public function updateByIdAndBlogId(array $values, $id, string $blog_id, array $options = []) + { + return $this->update($values, 'id=? AND blog_id=?', [$id, $blog_id], $options); + } + + /** + * @param string $where + * @param array $params + * @param array $options + * @return array|int 失敗時:false, 成功時:1 + */ + public function delete(string $where, array $params = [], array $options = []) + { + $sql = 'DELETE FROM ' . $this->getTableName() . ' WHERE ' . $where; + $options['result'] = PDOQuery::RESULT_SUCCESS; + return $this->executeSql($sql, $params, $options); + } + + /** + * idをキーとした削除 + * @param $id + * @param array $options + * @return false|int 失敗時:false, 成功時:1 + */ + public function deleteById($id, array $options = []) + { + return $this->delete('id=?', [$id], $options); + } + + /** + * idとblog_idをキーとした削除 + * @param $id + * @param string $blog_id + * @param array $options + * @return false|int 失敗時:false, 成功時:1 + */ + public function deleteByIdAndBlogId($id, string $blog_id, array $options = []) + { + return $this->delete('blog_id=? AND id=?', [$blog_id, $id], $options); + } + + /** + * idとuser_idをキーとした削除 + * @param $id + * @param int $user_id + * @param array $options + * @return false|int 失敗時:false, 成功時:1 + */ + public function deleteByIdAndUserId($id, int $user_id, array $options = []) + { + return $this->delete('id=? AND user_id=?', [$id, $user_id], $options); + } + + /** + * バルクインサート + * @param array $columns + * @param array $params + * @param array $options + * @return array|int false時失敗, 成功時はlast insert idだが、複数INSERTなので活用は難しい + */ + public function multipleInsert(array $columns = [], array $params = [], array $options = []) + { + $sql = 'INSERT INTO ' . $this->getTableName() . ' (' . implode(',', $columns) . ') VALUES '; + $len = count($params) / count($columns); + $sql_array = []; + for ($i = 0; $i < $len; $i++) { + $sql_array[] = '(' . implode(',', array_fill(0, count($columns), '?')) . ')'; + } + $sql .= implode(',', $sql_array); + $options['result'] = PDOQuery::RESULT_INSERT_ID; + return $this->executeSql($sql, $params, $options); + } + + + /** + * 階層構造の一覧取得 + * @param array $options + * @return array + */ + public function findNode(array $options) + { + $options['order'] = 'lft ASC'; + $nodes = $this->find('all', $options); + + // levelを付与 + $level = 0; + $levels = []; + foreach ($nodes as $key => $value) { + // 最初のノード + if ($level == 0) { + $levels[] = $value; + $nodes[$key]['level'] = $level = count($levels); + continue; + } + // left=left+1であれば子供ノードとして解釈 + if ($value['lft'] == $levels[$level - 1]['lft'] + 1) { + $levels[] = $value; + $nodes[$key]['level'] = $level = count($levels); + continue; + } + // left=right+1であれば兄弟ノードとして解釈 + if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { + $levels[$level - 1] = $value; + $nodes[$key]['level'] = $level; + continue; + } + // 兄弟ノードになるまで階層を遡る + while (array_pop($levels)) { + $level = count($levels); + if ($value['lft'] == $levels[$level - 1]['rgt'] + 1) { + $levels[$level - 1] = $value; + $nodes[$key]['level'] = $level; + break; + } + } + } + return $nodes; + } + + /** + * 階層構造の追加 + * @param array $data 追加するノード情報 + * @param string $where 親ノード検索時のwhere句 + * @param array $params 親ノード検索時のバインドデータ + * @param array $options + * @return string|int|false falseか、Last insert id + */ + public function addNode(array $data = [], string $where = '', array $params = [], array $options = []) + { + // 親として末尾に追加する場合 + if (empty($data['parent_id'])) { + $max_right = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)); + // 親として末尾に追加 + $data['lft'] = $max_right + 1; + $data['rgt'] = $max_right + 2; + return $this->insert($data); + } + + // 親の子供として末尾に追加する場合 + $parent = $this->findById($data['parent_id'], array('fields' => 'rgt', 'where' => $where, 'params' => $params, 'options' => $options)); + if (!$parent) { + return false; + } + $right = $parent['rgt']; + + // 挿入する場所を確保する + $table = $this->getTableName(); + if ($where != "") { + $where .= ' AND '; + } + /** @noinspection SqlResolve */ + /** @noinspection SqlCaseVsIf */ + $updateSql = << {$right} THEN lft + 2 ELSE lft END, + rgt = CASE WHEN rgt >= {$right} THEN rgt + 2 ELSE rgt END + WHERE {$where} rgt >= {$right} + SQL; + + if (!$this->executeSql($updateSql, $params)) { + return false; + } + + // 子供として末尾に追加 + $data['lft'] = $right; + $data['rgt'] = $right + 1; + return $this->insert($data); + } + + /** + * 階層構造の更新 + * @param array $data + * @param string|int $id + * @param string $where + * @param array $params + * @param array $options + * @return false|int + */ + public function updateNodeById(array $data, string $id, string $where = '', array $params = [], array $options = []) + { + $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; + + // 自身取得 + $self_params = array_merge(array($id), $params); + $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); + if (!$self) { + return false; + } + + // 親が変更されていない場合そのまま更新 + if ($self['parent_id'] == $data['parent_id']) { + return $this->update($data, $idWhere, $self_params, $options); + } + + if ($self['parent_id'] && empty($data['parent_id'])) { + // 親から外れた時 + $parent = []; + $parent['lft'] = $parent['rgt'] = $this->find('one', array('fields' => 'MAX(rgt)', 'where' => $where, 'params' => $params, 'options' => $options)) + 1; + } else { + // 変更先の親を取得 + $parent_params = array_merge(array($data['parent_id']), $params); + $parent = $this->find('row', array('where' => $idWhere, 'params' => $parent_params, 'options' => $options)); + if (!$parent) { + return false; + } + } + + // 変更先の親が自身や自分の子供の場合はエラー + if ($self['lft'] <= $parent['lft'] && $parent['rgt'] <= $self['rgt']) { + return false; + } + + // ノードの変更位置計算 + $self_lft = $self['lft']; + $self_rgt = $self['rgt']; + $parent_rgt = $parent['rgt']; + $space = $self_rgt - $self_lft + 1; + + $table = $this->getTableName(); + $where = $where ? $where . ' AND ' : ''; + if ($self_rgt > $parent_rgt) { + // 自身を左へ移動 + $move = $parent_rgt - $self_lft; + /** @noinspection SqlResolve */ + $sql = << $parent_rgt AND lft < $self_lft + THEN lft + $space + WHEN lft >= $self_lft AND lft < $self_rgt + THEN lft + $move + ELSE lft END, + rgt = CASE + WHEN rgt >= $parent_rgt AND rgt < $self_lft + THEN rgt + $space + WHEN rgt > $self_lft AND rgt <= $self_rgt + THEN rgt + $move + ELSE rgt END + WHERE $where + rgt >= $parent_rgt AND lft < $self_rgt + SQL; + } else { + // 自身を右へ移動 + $move = $parent_rgt - $self_rgt - 1; + /** @noinspection SqlResolve */ + $sql = << $self_rgt AND lft < $parent_rgt + THEN lft - $space + WHEN lft >= $self_lft AND lft < $self_rgt + THEN lft + $move + ELSE lft END, + rgt = CASE + WHEN rgt > $self_rgt AND rgt < $parent_rgt + THEN rgt - $space + WHEN rgt > $self_lft AND rgt <= $self_rgt + THEN rgt + $move + ELSE rgt END + WHERE $where + rgt > $self_lft AND lft < $parent_rgt + SQL; + } + + // 親の位置変更処理 + if (!$this->executeSql($sql, $params, $options)) { + return false; + } + + // 自身の更新処理 + return $this->update($data, $idWhere, $self_params, $options); + } + + /** + * 階層構造のノード削除 + * @param $id + * @param string $where + * @param array $params + * @param array $options + * @return array|false|int + */ + public function deleteNodeById($id, string $where = '', array $params = [], array $options = []) + { + // 自身取得 + $idWhere = $where ? 'id=? AND ' . $where : 'id=?'; + $self_params = array_merge(array($id), $params); + $self = $this->find('row', array('where' => $idWhere, 'params' => $self_params, 'options' => $options)); + + if (!$self) { + return false; + } + + $self_lft = $self['lft']; + $self_rgt = $self['rgt']; + $space = $self_rgt - $self_lft + 1; + + $table = $this->getTableName(); + $where = $where ? $where . ' AND ' : ''; + + // 削除処理 + $sql = 'DELETE FROM ' . $table . ' WHERE ' . $where . ' lft >= ' . $self_lft . ' AND rgt <= ' . $self_rgt; + if (!$this->executeSql($sql, $params, $options)) { + return false; + } + + // 詰める処理 + /** @noinspection SqlResolve */ + /** @noinspection SqlCaseVsIf */ + $sql = << $self_rgt + THEN lft - $space + ELSE lft END, + rgt = CASE + WHEN rgt > $self_rgt + THEN rgt - $space + ELSE rgt END + WHERE + $where + rgt > $self_rgt + SQL; + return $this->executeSql($sql, $params, $options); + } +} \ No newline at end of file From 8c9eda197bfbb5f4e7c2153726cfdbb5b5f83d0d Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 21:02:49 +0900 Subject: [PATCH 20/21] Apply PDOQuery. --- app/src/Model/BlogsModel.php | 2 +- app/src/Model/CategoriesModel.php | 9 +++--- app/src/Model/CommentsModel.php | 2 +- app/src/Model/EntriesModel.php | 6 ++-- app/src/Model/TagsModel.php | 28 ++++++++++--------- .../Web/Controller/Admin/CommonController.php | 14 ++++++---- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/app/src/Model/BlogsModel.php b/app/src/Model/BlogsModel.php index be586e1c..a4eba168 100644 --- a/app/src/Model/BlogsModel.php +++ b/app/src/Model/BlogsModel.php @@ -355,7 +355,7 @@ public function insert(array $data, array $options = []) { // 主キーがauto_incrementじゃないのでreturn値の受け取り方を変更 $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s'); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; if (!parent::insert($data, $options)) { return false; } diff --git a/app/src/Model/CategoriesModel.php b/app/src/Model/CategoriesModel.php index dd335ee8..c101b393 100644 --- a/app/src/Model/CategoriesModel.php +++ b/app/src/Model/CategoriesModel.php @@ -71,6 +71,7 @@ public function validate(array $data, ?array &$valid_data = [], array $white_lis * @param $data * @param $model * @return bool|string + * @noinspection PhpUnusedParameterInspection */ public static function uniqueName($value, $option, $key, $data, $model) { @@ -183,7 +184,7 @@ public function getEntryCategories($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = PDOWrap::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -210,7 +211,7 @@ public function getEntriesCategories($blog_id, $entry_ids = array()) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = PDOWrap::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; $categories = $this->findSql($sql, $params, $options); $entries_categories = array(); @@ -253,7 +254,7 @@ public function increaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -270,7 +271,7 @@ public function decreaseCount($blog_id, $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count-1 WHERE blog_id=? AND count>0 AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/CommentsModel.php b/app/src/Model/CommentsModel.php index d571de7d..25c4bf89 100644 --- a/app/src/Model/CommentsModel.php +++ b/app/src/Model/CommentsModel.php @@ -594,7 +594,7 @@ public function updateApproval($blog_id, $comment_id = null) $params[] = $comment_id; } $sql .= ' AND open_status=' . Config::get('COMMENT.OPEN_STATUS.PENDING'); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/EntriesModel.php b/app/src/Model/EntriesModel.php index 24c375ba..49c253a3 100644 --- a/app/src/Model/EntriesModel.php +++ b/app/src/Model/EntriesModel.php @@ -136,7 +136,7 @@ public function getArchives($blog_id) ORDER BY concat(year, month) DESC; SQL; $params = array($blog_id); - $options = array('result' => PDOWrap::RESULT_ALL); + $options = array('result' => PDOQuery::RESULT_ALL); return $this->findSql($sql, $params, $options); } @@ -387,7 +387,7 @@ public function increaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count+1 WHERE blog_id=? AND id=?'; $params = array($blog_id, $entry_id); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -401,7 +401,7 @@ public function decreaseCommentCount($blog_id, $entry_id) { $sql = 'UPDATE ' . $this->getTableName() . ' SET comment_count=comment_count-1 WHERE blog_id=? AND id=? AND comment_count>0'; $params = array($blog_id, $entry_id); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } diff --git a/app/src/Model/TagsModel.php b/app/src/Model/TagsModel.php index c80c41f8..d2bb84dd 100644 --- a/app/src/Model/TagsModel.php +++ b/app/src/Model/TagsModel.php @@ -61,6 +61,7 @@ public function validate(array $data, ?array &$valid_data = [], array $white_lis * @param $data * @param $model * @return bool|string + * @noinspection PhpUnusedParameterInspection */ public static function uniqueName($value, $option, $key, $data, $model) { @@ -125,9 +126,10 @@ public function getListByNames(string $blog_id, array $tags = []): array * @param $name * @param $blog_id * @param array $options - * @return mixed + * @return array + * @noinspection PhpUnused */ - public function findByNameAndBlogId($name, $blog_id, $options = array()) + public function findByNameAndBlogId($name, $blog_id, array $options = array()) { $options['where'] = isset($options['where']) ? 'name=? AND blog_id=? AND ' . $options['where'] : 'name=? AND blog_id=?'; $options['params'] = isset($options['params']) ? array_merge(array($name, $blog_id), $options['params']) : array($name, $blog_id); @@ -138,9 +140,9 @@ public function findByNameAndBlogId($name, $blog_id, $options = array()) * 良く使用するタグ一覧を取得する * @param $blog_id * @param array $options - * @return mixed + * @return array */ - public function getWellUsedTags($blog_id, $options = array()) + public function getWellUsedTags($blog_id, array $options = array()) { $options['fields'] = 'id, name'; $options['where'] = (isset($options['where']) && $options['where'] != "") ? 'blog_id=? AND ' . $options['where'] : 'blog_id=?'; @@ -170,7 +172,7 @@ public function getEntryTagNames($blog_id, $entry_id) * 記事のタグを取得する * @param $blog_id * @param $entry_id - * @return mixed + * @return array */ public function getEntryTags($blog_id, $entry_id) { @@ -184,7 +186,7 @@ public function getEntryTags($blog_id, $entry_id) SQL; $params = array($blog_id, $entry_id, $blog_id); $options = array(); - $options['result'] = PDOWrap::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; return $this->findSql($sql, $params, $options); } @@ -211,7 +213,7 @@ public function getEntriesTags($blog_id, $entry_ids) SQL; $params = array_merge(array($blog_id), $entry_ids, array($blog_id)); $options = array(); - $options['result'] = PDOWrap::RESULT_ALL; + $options['result'] = PDOQuery::RESULT_ALL; $tags = $this->findSql($sql, $params, $options); $entries_tags = array(); @@ -228,7 +230,7 @@ public function getEntriesTags($blog_id, $entry_ids) * 件数を増加させる処理 * @param string $blog_id * @param array $ids - * @return int|false + * @return array|int */ public function increaseCount(string $blog_id, array $ids = array()) { @@ -237,7 +239,7 @@ public function increaseCount(string $blog_id, array $ids = array()) } $sql = 'UPDATE ' . $this->getTableName() . ' SET count=count+1 WHERE blog_id=? AND id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge(array($blog_id), $ids); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return $this->executeSql($sql, $params, $options); } @@ -256,7 +258,7 @@ public function decreaseCount($blog_id, array $ids = []) ' SET count=count-1 WHERE blog_id=? AND count>0 AND id ' . ' IN (' . implode(',', array_fill(0, count($ids), '?')) . ')'; $params = array_merge([$blog_id], $ids); - $options['result'] = PDOWrap::RESULT_SUCCESS; + $options['result'] = PDOQuery::RESULT_SUCCESS; return # 有効タグ数の数え直し $this->executeSql($sql, $params, $options) && @@ -269,9 +271,9 @@ public function decreaseCount($blog_id, array $ids = []) * @param $tag_id * @param $blog_id * @param array $options - * @return array|false|int|mixed + * @return array|false|int */ - public function deleteByIdAndBlogId($tag_id, $blog_id, $options = array()) + public function deleteByIdAndBlogId($tag_id, $blog_id, array $options = array()) { // タグの紐付け情報削除 Model::load('EntryTags')->delete('blog_id=? AND tag_id=?', array($blog_id, $tag_id)); @@ -287,7 +289,7 @@ public function deleteByIdAndBlogId($tag_id, $blog_id, $options = array()) * @param array $options * @return bool */ - public function deleteByIdsAndBlogId($ids, $blog_id, $options = array()) + public function deleteByIdsAndBlogId($ids, $blog_id, array $options = array()) { // 単体ID対応 if (is_numeric($ids)) { diff --git a/app/src/Web/Controller/Admin/CommonController.php b/app/src/Web/Controller/Admin/CommonController.php index 6fbe7581..26dd31b1 100644 --- a/app/src/Web/Controller/Admin/CommonController.php +++ b/app/src/Web/Controller/Admin/CommonController.php @@ -9,7 +9,8 @@ use Fc2blog\Model\BlogSettingsModel; use Fc2blog\Model\BlogsModel; use Fc2blog\Model\CommentsModel; -use Fc2blog\Model\PDOWrap; +use Fc2blog\Model\PDOConnection; +use Fc2blog\Model\PDOQuery; use Fc2blog\Model\PluginsModel; use Fc2blog\Model\UsersModel; use Fc2blog\Web\Cookie; @@ -170,7 +171,7 @@ public function install(Request $request): string $is_connect = true; $connect_message = ''; try { - PDOWrap::createNewConnection(); + PDOConnection::createConnection(); } catch (Exception $e) { $is_connect = false; $connect_message = $e->getMessage(); @@ -209,15 +210,16 @@ public function install(Request $request): string // DB接続確認 try { // DB接続確認(DATABASEの存在判定含む) - PDOWrap::createNewConnection(); + $pdo = PDOConnection::createConnection(); } catch (Exception $e) { $this->setErrorMessage(__('Please set correct the DB connection settings.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=db_create'); + return ""; } // テーブルの存在チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = PDOWrap::getInstance()->find($sql); + $table = PDOQuery::find($pdo, $sql); if (is_countable($table) && count($table)) { // 既にDB登録完了 @@ -230,7 +232,7 @@ public function install(Request $request): string if (DB_CHARSET != 'UTF8MB4') { $sql = str_replace('utf8mb4', strtolower(DB_CHARSET), $sql); } - $res = PDOWrap::getInstance()->multiExecute($sql); + $res = PDOQuery::multiExecute($pdo, $sql); if ($res === false) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); @@ -238,7 +240,7 @@ public function install(Request $request): string // DBセットアップ成功チェック $sql = "SHOW TABLES LIKE 'users'"; - $table = PDOWrap::getInstance()->find($sql); + $table = PDOQuery::find($pdo, $sql); if (!is_countable($table)) { $this->setErrorMessage(__('Create' . ' table failed.')); $this->redirect($request, $request->baseDirectory . 'common/install?state=0&error=table_insert'); From 80ae2d3f133b48fe9347093f07286d345cabc445 Mon Sep 17 00:00:00 2001 From: uzulla Date: Sun, 13 Jun 2021 21:08:02 +0900 Subject: [PATCH 21/21] Chore, suppress warns, add type defs. --- app/src/Model/BlogsModel.php | 29 ++++++++++++++++------------- app/src/Model/QueryTrait.php | 20 ++++++++++---------- app/src/Model/TagsModel.php | 14 ++++++++------ 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/app/src/Model/BlogsModel.php b/app/src/Model/BlogsModel.php index a4eba168..5534ef73 100644 --- a/app/src/Model/BlogsModel.php +++ b/app/src/Model/BlogsModel.php @@ -72,6 +72,7 @@ public static function isPasswordRegistered($blog_id): bool * ディレクトリとして使用済みかどうか * @param string $value * @return bool|string + * @noinspection PhpUnused */ public static function usableDirectory(string $value) { @@ -253,15 +254,15 @@ public function getSelectList($user_id): array /** * ブログIDをキーにユーザーIDを条件としてブログを取得 - * @param $blog_id + * @param $id * @param $user_id * @param array $options * @return mixed */ - public function findByIdAndUserId($blog_id, $user_id, array $options = []): array + public function findByIdAndUserId($id, $user_id, array $options = []): array { $options['where'] = isset($options['where']) ? 'id=? AND user_id=? AND ' . $options['where'] : 'id=? AND user_id=?'; - $options['params'] = isset($options['params']) ? array_merge(array($blog_id, $user_id), $options['params']) : array($blog_id, $user_id); + $options['params'] = isset($options['params']) ? array_merge(array($id, $user_id), $options['params']) : array($id, $user_id); return $this->find('row', $options); } @@ -269,9 +270,9 @@ public function findByIdAndUserId($blog_id, $user_id, array $options = []): arra * ユーザーIDをキーにしてブログを取得 * @param $user_id * @param array $options - * @return mixed + * @return array */ - public function findByUserId($user_id, $options = array()) + public function findByUserId($user_id, array $options = array()) { $options['where'] = isset($options['where']) ? 'user_id=? AND ' . $options['where'] : 'user_id=?'; $options['params'] = isset($options['params']) ? array_merge(array($user_id), $options['params']) : array($user_id); @@ -292,7 +293,7 @@ public function findByRandom() /** * ログイン後最初に表示するブログを取得する * @param $user - * @return mixed + * @return array */ public function getLoginBlog($user) { @@ -317,7 +318,7 @@ public function getLoginBlog($user) /** * ユーザーIDをキーにブログのリストを取得 * @param int $user_id - * @return mixed + * @return array */ public function getListByUserId(int $user_id) { @@ -502,7 +503,7 @@ public static function regeneratePluginPhpByBlogId(string $blog_id): void * @param array $values * @param $id * @param array $options - * @return array|false|int|mixed + * @return array|int */ public function updateById(array $values, $id, array $options = []) { @@ -513,7 +514,8 @@ public function updateById(array $values, $id, array $options = []) /** * 最終投稿日時更新 * @param $id - * @return array|false|int|mixed + * @return array|int + * @noinspection PhpUnused */ public function updateLastPostedAt($id) { @@ -525,7 +527,7 @@ public function updateLastPostedAt($id) * テンプレートの切り替え * @param array $blog_template * @param string $blog_id - * @return array|false|int|mixed + * @return array|int */ public function switchTemplate(array $blog_template, string $blog_id) { @@ -539,13 +541,12 @@ public function switchTemplate(array $blog_template, string $blog_id) $reply_type = strstr($blog_template['html'], '<%comment_reply_body>') ? Config::get('BLOG_TEMPLATE.COMMENT_TYPE.REPLY') : Config::get('BLOG_TEMPLATE.COMMENT_TYPE.AFTER'); // コメントの表示タイプを更新 - Model::load('BlogSettings')->updateReplyType($device_type, $reply_type, $blog_id); + (new BlogSettingsModel())->updateReplyType($device_type, $reply_type, $blog_id); $ret = $this->updateById($data, $blog_id); if ($ret) { // 更新に成功した場合 現在のテンプレートを削除 - Model::load('BlogTemplates'); $template_path = BlogTemplatesModel::getTemplateFilePath($blog_id, $device_type); is_file($template_path) && unlink($template_path); $css_path = BlogTemplatesModel::getCssFilePath($blog_id, $device_type); @@ -562,7 +563,7 @@ public function switchTemplate(array $blog_template, string $blog_id) * @param array $options * @return bool|int */ - public function deleteByIdAndUserId($blog_id, int $user_id, $options = array()) + public function deleteByIdAndUserId($blog_id, int $user_id, array $options = array()) { if (!parent::deleteById($blog_id, array('where' => 'user_id=?', 'params' => array($user_id)))) { return 0; @@ -641,6 +642,7 @@ static public function isCorrectHttpSchemaByBlog(Request $request, Blog $blog): * @param Request $request * @param string $blog_id * @return bool + * @noinspection PhpUnused */ static public function isCorrectHttpSchemaByBlogId(Request $request, string $blog_id): bool { @@ -768,6 +770,7 @@ static public function getDefaultBlogId(): ?string /** * @param Request $request * @return string|null + * @noinspection PhpUnused */ static public function getBlogIdByRequestOrDefault(Request $request): ?string { diff --git a/app/src/Model/QueryTrait.php b/app/src/Model/QueryTrait.php index b835d6c2..32c7f6bf 100644 --- a/app/src/Model/QueryTrait.php +++ b/app/src/Model/QueryTrait.php @@ -1,4 +1,4 @@ -delete('blog_id=? AND tag_id=?', array($blog_id, $tag_id)); + (new EntryTagsModel())->delete('blog_id=? AND tag_id=?', array($blog_id, $id)); // 記事本体削除 - return parent::deleteByIdAndBlogId($tag_id, $blog_id, $options); + return parent::deleteByIdAndBlogId($id, $blog_id, $options); } /** * idとblog_idをキーとした削除 + 付随情報も削除 - * @param array $ids + * @param array|int $ids * @param $blog_id * @param array $options * @return bool + * @noinspection PhpUnused */ public function deleteByIdsAndBlogId($ids, $blog_id, array $options = array()) {