Select Git revision
RunSQLProcess.php
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
RunSQLProcess.php 5.17 KiB
<?php
namespace UnicaenApp\Service\SQL;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Exception;
use UnicaenApp\Exception\RuntimeException;
use Zend\Log\Logger;
use Zend\Log\LoggerAwareTrait;
class RunSQLProcess
{
use LoggerAwareTrait;
/**
* @var string
*/
private $scriptPath;
/**
* @var string
*/
private $logFilePath;
/**
* @var Connection
*/
private $connection;
/**
* @var RunSQLQueryStack
*/
private $queryStack;
/**
* @param string $scriptPath
* @return self
*/
public function setScriptPath($scriptPath)
{
$this->scriptPath = $scriptPath;
return $this;
}
/**
* @param Connection $connection
* @return RunSQLProcess
*/
public function setConnection(Connection $connection)
{
$this->connection = $connection;
return $this;
}
/**
* @param null|string $logFilePath
* @return self
*/
public function setLogFilePath($logFilePath = null)
{
$this->logFilePath = $logFilePath;
return $this;
}
/**
* Exécute dans la transaction courante toutes les instructions d'un script SQL.
*
* @return RunSQLResult
*/
public function executeScript()
{
$this->validateScriptPath();
$queries = $this->extractQueriesFromScript();
$this->logger->info("+ Exécution du script '$this->scriptPath'.");
$this->logger->info(sprintf("'--> Requêtes trouvées : %d", count($queries)));
$result = $this->executeQueries($queries);
$logFilePath = $this->logQueries();
$this->logger->info("'--> Logs : " . $logFilePath);
return $result;
}
/**
* Exécute dans la transaction courante toutes les instructions d'un script SQL.
*
* @param string $query
* @return RunSQLResult
*/
public function executeQuery($query)
{
$this->logger->info("+ Exécution d'une requête.");
$result = $this->executeQueries([$query]);
$logFilePath = $this->logQueries();
$this->logger->info("'--> Logs : " . $logFilePath);
return $result;
}
private function validateScriptPath()
{
if (is_dir($this->scriptPath)) {
throw new RuntimeException("Le fichier '$this->scriptPath' spécifié est un répertoire");
}
if (!is_readable($this->scriptPath)) {
throw new RuntimeException("Le fichier '$this->scriptPath' n'est pas accessible");
}
}
/**
* Extrait les requêtes contenues dans le script.
*
* @return string[]
*/
protected function extractQueriesFromScript()
{
$parts = preg_split("#^/$#m", file_get_contents($this->scriptPath));
$queries = array_filter(array_map('trim', $parts));
if (count($queries) === 0) {
throw new RuntimeException("Aucune requête trouvée dans le script '$this->scriptPath'");
}
return $queries;
}
/**
* Exécute dans la transaction courante les requêtes spécifiées.
*
* @param string[] $queries
* @return RunSQLResult
*/
private function executeQueries($queries)
{
$result = new RunSQLResult();
$result->attachLogger($this->logger);
$result->setIsSuccess(true);
$this->queryStack = new RunSQLQueryStack();
try {
foreach ($queries as $q) {
$this->queryStack->startQuery($q);
$this->connection->executeQuery($q);
$this->queryStack->stopQuery();
}
} catch (DBALException $e) {
$result->setIsSuccess(false);
$result->setException($e);
$this->queryStack->stopQueryWithException($e);
}
$result->setEndMicrotime();
return $result;
}
/**
* @return string
*/
private function logQueries()
{
$logFilePath = $this->generateLogFilePath();
$logger = new Logger();
$logger->addWriter('stream', null, ['stream' => $logFilePath]);
foreach ($this->queryStack->getQueries() as $query) {
$logger->info("Requête : " . $query['sql']);
if (isset($query['exception'])) {
/** @var Exception $exception */
$exception = $query['exception'];
$logger->info($exception->getMessage());
$logger->info($exception->getTraceAsString());
}
$logger->info("Temps d'exécution : " . $query['executionMS'] . " sec");
$logger->info("---------------------------------------------------------------------------------------");
}
return $logFilePath;
}
/**
* @return string
*/
private function generateLogFilePath()
{
if ($this->logFilePath !== null) {
return $this->logFilePath;
}
if ($this->scriptPath) {
$this->logFilePath = sys_get_temp_dir() . '/' . basename($this->scriptPath) . '.log';
} else {
$this->logFilePath = sys_get_temp_dir() . '/' . uniqid('unicaen-app-run-sql-') . '.log';
}
return $this->logFilePath;
}
}