2019-11-27 22:19:20 +08:00
|
|
|
<?php
|
|
|
|
|
2020-10-19 22:10:28 +08:00
|
|
|
namespace App\Utils;
|
2019-11-27 22:19:20 +08:00
|
|
|
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
use PDO;
|
|
|
|
use PDOException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Real basic to interface with an importer
|
|
|
|
*/
|
|
|
|
class ImporterDB
|
|
|
|
{
|
2019-12-02 22:57:35 +08:00
|
|
|
/**
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
public $batchSize;
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
/**
|
|
|
|
* @var PDO
|
|
|
|
*/
|
|
|
|
private $conn;
|
|
|
|
|
2019-12-02 22:57:35 +08:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2019-11-27 22:19:20 +08:00
|
|
|
private $dsn;
|
2019-12-02 22:57:35 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2019-11-27 22:19:20 +08:00
|
|
|
private $creds;
|
|
|
|
|
|
|
|
public function __construct($creds)
|
|
|
|
{
|
|
|
|
$this->creds = $creds;
|
|
|
|
$this->dsn = 'mysql:'.implode(';', [
|
|
|
|
'host='.$this->creds['host'],
|
|
|
|
'port='.$this->creds['port'],
|
|
|
|
'dbname='.$this->creds['name'],
|
2020-01-07 02:44:43 +08:00
|
|
|
]);
|
2019-11-27 22:19:20 +08:00
|
|
|
|
|
|
|
Log::info('Using DSN: '.$this->dsn);
|
|
|
|
|
2019-12-02 22:57:35 +08:00
|
|
|
$this->batchSize = config('installer.importer.batch_size', 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
$this->close();
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public function connect()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
$this->conn = new PDO($this->dsn, $this->creds['user'], $this->creds['pass']);
|
|
|
|
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
|
|
|
} catch (PDOException $e) {
|
|
|
|
Log::error($e);
|
2019-12-02 22:57:35 +08:00
|
|
|
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function close()
|
|
|
|
{
|
|
|
|
if ($this->conn) {
|
|
|
|
$this->conn = null;
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the table name with the prefix
|
|
|
|
*
|
|
|
|
* @param $table
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function tableName($table)
|
|
|
|
{
|
|
|
|
if ($this->creds['table_prefix'] !== false) {
|
|
|
|
return $this->creds['table_prefix'].$table;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $table;
|
|
|
|
}
|
|
|
|
|
2020-02-26 03:45:23 +08:00
|
|
|
/**
|
|
|
|
* Does a table exist? Try to get the column information on it.
|
|
|
|
* The result will be 'false' if that table isn't there
|
|
|
|
*
|
|
|
|
* @param $table
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function tableExists($table): bool
|
|
|
|
{
|
|
|
|
$this->connect();
|
|
|
|
|
|
|
|
$sql = 'SHOW COLUMNS FROM '.$this->tableName($table);
|
|
|
|
$result = $this->conn->query($sql);
|
|
|
|
if (!$result) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
/**
|
|
|
|
* Get the names of the columns for a particular table
|
|
|
|
*
|
|
|
|
* @param $table
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function getColumns($table)
|
|
|
|
{
|
|
|
|
$this->connect();
|
|
|
|
|
|
|
|
$sql = 'SHOW COLUMNS FROM '.$this->tableName($table);
|
|
|
|
$result = $this->conn->query($sql)->fetchAll();
|
|
|
|
|
|
|
|
$rows = [];
|
|
|
|
foreach ($result as $row) {
|
|
|
|
$rows[] = $row->Field;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $rows;
|
|
|
|
}
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
/**
|
|
|
|
* @param $table
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function getTotalRows($table)
|
|
|
|
{
|
|
|
|
$this->connect();
|
|
|
|
|
|
|
|
$sql = 'SELECT COUNT(*) FROM '.$this->tableName($table);
|
|
|
|
$rows = $this->conn->query($sql)->fetchColumn();
|
|
|
|
|
|
|
|
Log::info('Found '.$rows.' rows in '.$table);
|
|
|
|
|
|
|
|
return (int) $rows;
|
|
|
|
}
|
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
/**
|
|
|
|
* Read rows from a table with a given assoc array. Simple
|
|
|
|
*
|
|
|
|
* @param string $table
|
|
|
|
* @param array $attrs
|
|
|
|
*
|
|
|
|
* @return false|\PDOStatement
|
|
|
|
*/
|
|
|
|
public function findBy($table, array $attrs)
|
|
|
|
{
|
|
|
|
$this->connect();
|
|
|
|
|
|
|
|
$where = [];
|
|
|
|
foreach ($attrs as $col => $value) {
|
|
|
|
$where[] = $col.'=\''.$value.'\'';
|
|
|
|
}
|
|
|
|
|
|
|
|
$where = implode(' AND ', $where);
|
|
|
|
|
|
|
|
$sql = implode(' ', [
|
|
|
|
'SELECT',
|
|
|
|
'*',
|
|
|
|
'FROM',
|
|
|
|
$this->tableName($table),
|
|
|
|
'WHERE',
|
|
|
|
$where,
|
|
|
|
]);
|
|
|
|
|
|
|
|
return $this->conn->query($sql);
|
|
|
|
}
|
|
|
|
|
2019-11-27 22:19:20 +08:00
|
|
|
/**
|
|
|
|
* Read all the rows in a table, but read them in a batched manner
|
|
|
|
*
|
2020-02-24 08:48:28 +08:00
|
|
|
* @param string $table The name of the table
|
|
|
|
* @param string $order_by Column to order by
|
|
|
|
* @param int $start_offset
|
|
|
|
* @param string $fields
|
2019-11-27 22:19:20 +08:00
|
|
|
*
|
2020-02-24 08:48:28 +08:00
|
|
|
* @return array
|
2019-11-27 22:19:20 +08:00
|
|
|
*/
|
2020-02-24 08:48:28 +08:00
|
|
|
public function readRows($table, $order_by = 'id', $start_offset = 0, $fields = '*')
|
2019-11-27 22:19:20 +08:00
|
|
|
{
|
|
|
|
$this->connect();
|
|
|
|
|
|
|
|
$offset = $start_offset;
|
2020-02-24 08:48:28 +08:00
|
|
|
// $total_rows = $this->getTotalRows($table);
|
2019-11-27 22:19:20 +08:00
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
$rows = [];
|
|
|
|
$result = $this->readRowsOffset($table, $this->batchSize, $offset, $order_by, $fields);
|
2020-03-23 23:50:15 +08:00
|
|
|
if ($result === false || $result === null) {
|
2020-02-24 08:48:28 +08:00
|
|
|
return [];
|
|
|
|
}
|
2019-11-27 22:19:20 +08:00
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
try {
|
|
|
|
foreach ($result as $row) {
|
|
|
|
$rows[] = $row;
|
|
|
|
}
|
2020-03-23 23:50:15 +08:00
|
|
|
} catch (\Exception $e) {
|
2020-02-24 08:48:28 +08:00
|
|
|
Log::error('foreach rows error: '.$e->getMessage());
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
2020-02-24 08:48:28 +08:00
|
|
|
|
|
|
|
return $rows;
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $table
|
2020-02-24 08:48:28 +08:00
|
|
|
* @param int $limit Number of rows to read
|
|
|
|
* @param int $offset Where to start from
|
|
|
|
* @param $order_by
|
|
|
|
* @param string $fields
|
2019-11-27 22:19:20 +08:00
|
|
|
*
|
2020-02-24 08:48:28 +08:00
|
|
|
* @return false|\PDOStatement|void
|
2019-11-27 22:19:20 +08:00
|
|
|
*/
|
2020-02-24 08:48:28 +08:00
|
|
|
public function readRowsOffset($table, $limit, $offset, $order_by, $fields = '*')
|
2019-11-27 22:19:20 +08:00
|
|
|
{
|
2019-12-02 22:57:35 +08:00
|
|
|
if (is_array($fields)) {
|
|
|
|
$fields = implode(',', $fields);
|
|
|
|
}
|
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
$sql = implode(' ', [
|
|
|
|
'SELECT',
|
|
|
|
$fields,
|
|
|
|
'FROM',
|
|
|
|
$this->tableName($table),
|
|
|
|
'ORDER BY '.$order_by.' ASC',
|
|
|
|
'LIMIT '.$limit,
|
|
|
|
'OFFSET '.$offset,
|
|
|
|
]);
|
2019-11-27 22:19:20 +08:00
|
|
|
|
|
|
|
try {
|
|
|
|
$result = $this->conn->query($sql);
|
2019-12-02 22:57:35 +08:00
|
|
|
if (!$result || $result->rowCount() === 0) {
|
|
|
|
return;
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
|
|
|
|
2020-02-24 08:48:28 +08:00
|
|
|
return $result;
|
2019-11-27 22:19:20 +08:00
|
|
|
} catch (PDOException $e) {
|
|
|
|
// Without incrementing the offset, it should re-run the same query
|
|
|
|
Log::error('Error readRowsOffset: '.$e->getMessage());
|
|
|
|
|
|
|
|
if (strpos($e->getMessage(), 'server has gone away') !== false) {
|
|
|
|
$this->connect();
|
|
|
|
}
|
2020-02-24 08:48:28 +08:00
|
|
|
} catch (\Exception $e) {
|
|
|
|
Log::error('Error readRowsOffset: '.$e->getMessage());
|
2019-11-27 22:19:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|