_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 bool * @throws Exception */ public function exists(): bool { $data = $this->search('fetch'); if (!$data) { return false; } return true; } /** * @return mixed * @throws */ public function fetchColumn(): mixed { return $this->search('fetchColumn'); } /** * @return mixed * @throws */ public function rowCount(): int { $data = $this->search('fetch'); return !$data ? 0 : +current($data); } /** * @param string $method * @return mixed * @throws */ protected function search(string $method): mixed { $client = $this->connection->getConnection(); try { $startTime = microtime(true); 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(); $this->connection->println($startTime, microtime(true), $this->sql, $this->params); 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 . PHP_EOL, '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 { $startTime = microtime(true); 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(); $this->connection->println($startTime, microtime(true), $this->sql, $this->params); 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 . PHP_EOL, '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; } }