_prepare(); } /** * @return bool * @throws */ public function save(): bool { return (bool)$this->_prepare(); } /** * @return bool|array * @throws */ public function all(): bool|array { return $this->search('fetchAll'); } /** * @return array|bool|null * @throws */ public function one(): array|null|bool { return $this->search('fetch'); } /** * @return mixed * @throws */ public function fetchColumn(): mixed { return $this->search('fetchColumn'); } /** * @return mixed * @throws */ public function rowCount(): int { return $this->search('rowCount'); } /** * @return bool * @throws Exception */ public function exists(): bool { $total = $this->search('rowCount'); if ($total === false) { throw new Exception('Query data is has error.'); } return $total > 0; } /** * @param string $method * @return mixed * @throws */ protected function search(string $method): mixed { $client = $this->connection->getConnection(); try { if (($prepare = $client->prepare($this->sql)) === false) { throw new Exception('(' . $prepare->errorInfo()[0] . ')' . $client->errorInfo()[2]); } $prepare->execute($this->params); $result = $method == 'rowCount' ? $prepare->rowCount() : $prepare->{$method}(PDO::FETCH_ASSOC); $prepare->closeCursor(); return $result; } catch (Throwable $throwable) { if ($this->isRefresh($throwable)) return $this->search($method); $errorMsg = $throwable->getMessage() . PHP_EOL . ' Sql: ' . $this->sql . '.' . json_encode($this->params); return $this->getLogger()->failure($errorMsg, 'mysql'); } finally { $this->connection->release($client); } } /** * @return bool * @throws */ public function flush(): bool { return (bool)$this->_prepare(); } /** * @return int|bool * @throws */ private function _prepare(): int|bool { $client = $this->connection->getConnection(); try { if (($prepare = $client->prepare($this->sql)) === false) { throw new Exception('(' . $prepare->errorInfo()[0] . ')' . $prepare->errorInfo()[2]); } if ($prepare->execute($this->params) === false) { throw new Exception('(' . $prepare->errorInfo()[0] . ')' . $prepare->errorInfo()[2]); } $prepare->closeCursor(); $result = $client->lastInsertId(); return $result == 0 ? $prepare->rowCount() : (int)$result; } catch (Throwable $throwable) { if ($this->isRefresh($throwable)) return $this->_prepare(); $errorMsg = $throwable->getMessage() . PHP_EOL . ' Sql: ' . $this->sql . '.' . json_encode($this->params); return $this->getLogger()->failure($errorMsg, 'mysql'); } finally { $this->connection->release($client); } } /** * @param Throwable $throwable * @return bool */ protected function isRefresh(Throwable $throwable): bool { if (str_contains($throwable->getMessage(), 'MySQL server has gone away')) { return true; } if (str_contains($throwable->getMessage(), 'Send of 14 bytes failed with errno=32 Broken pipe')) { return true; } if (str_contains($throwable->getMessage(), 'Lost connection to MySQL server during query')) { return true; } return false; } /** * @return bool * @throws */ public function delete(): bool { return (bool)$this->_prepare(); } /** * @return int|bool */ public function exec(): int|bool { return $this->_prepare(); } /** * @param array $data * @return $this */ public function bindValues(array $data = []): static { if (count($data) > 0) { $this->params = array_merge($this->params, $data); } return $this; } }