Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Template DAO to use PDO #534

Merged
merged 6 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/admin/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ To install PhpReport in your system, you will need the following software:

* PHP 7.3 or higher

* Support for PostgreSQL
* Support for PDO and PostgreSQL

* Web server (tested with Apache 2.x)

Expand All @@ -23,11 +23,11 @@ Installing dependencies on selected GNU/Linux distros

Run the following command with root privileges:

* Debian, Ubuntu: ``apt-get install postgresql apache2 php php-pgsql php-xml``
* Ubuntu: ``apt install postgresql apache2 php php-pgsql php-xml php-pdo``

* Fedora: ``dnf install postgresql-server httpd php php-pgsql php-xml``
* Debian: ``apt install postgresql apache2 php php-pgsql php-xml``

* RHEL: ``yum install postgresql-server httpd php php-pgsql php-xml``
* Fedora: ``dnf install postgresql-server httpd php php-pgsql php-xml php-pdo``

Install composer to manage the project dependencies. Follow the official
docs for the instructions: https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos
Expand Down
169 changes: 94 additions & 75 deletions model/dao/TemplateDAO/PostgreSQLTemplateDAO.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,49 +40,68 @@
*/
class PostgreSQLTemplateDAO extends TemplateDAO{

/** The connection to DB.
*
* PDO object with an open connection to the database, initialized in the
* class constructor.
*
* @var resource
* @see __construct()
*/
protected PDO $pdo;

/** Template DAO for PostgreSQL constructor.
*
* This is the constructor of the implementation for PostgreSQL of {@link TemplateDAO}, and it just calls its parent's constructor.
* This is the constructor of the implementation for PostgreSQL of
* {@link TemplateDAO}. It sets up everything for database connection, using
* the parameters read from <i>{@link config.php}</i> and saving the open
* connection in <var>{@link $pdo}</var>.
* Notice this DAO connects to the DB through PDO, unlike the rest of the
* application.
*
* @throws {@link DBConnectionErrorException}
* @see TemplateDAO::__construct()
*/
function __construct() {
// Call parent to initialize non-PDO database access, while we don't
// migrate all the methods here.
parent::__construct();

// TODO: EXTRA_DB_CONNECTION_PARAMETERS used to expect pg_connect
// parameters, which were space-separated, but PDO requires semicolons
$connectionString = sprintf("pgsql:host=%s;port=%d;user=%s;dbname=%s;password=%s;%s",
ConfigurationParametersManager::getParameter('DB_HOST'),
ConfigurationParametersManager::getParameter('DB_PORT'),
ConfigurationParametersManager::getParameter('DB_USER'),
ConfigurationParametersManager::getParameter('DB_NAME'),
ConfigurationParametersManager::getParameter('DB_PASSWORD'),
ConfigurationParametersManager::getParameter('EXTRA_DB_CONNECTION_PARAMETERS'));

try {
$this->pdo = new PDO($connectionString);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
error_log('Connection failed: ' . $e->getMessage());
throw new DBConnectionErrorException($connectionString);
}
}

/** Template value object constructor for PostgreSQL.
*
* This function creates a new {@link TemplateVO} with data retrieved from database.
*
* @param array $row an array with the Task values from a row.
* @return TemplateVO a {@link TemplateVO} with its properties set to the values from <var>$row</var>.
* @see TemplateVO
/**
* This method is declared to fulfill TemplateVO as non-abstract, but it should not be used.
* PDO::FETCH_CLASS now takes care of transforming DB rows into VO objects.
*/
protected function setValues($row) {
$templateVO = new TemplateVO();

$templateVO->setId($row['id']);
$templateVO->setName($row['name']);
$templateVO->setStory($row['story']);
$templateVO->setStory($row['story']);
if (strtolower($row['telework']) == "t")
$templateVO->setTelework(True);
elseif (strtolower($row['telework']) == "f")
$templateVO->setTelework(False);
if (strtolower($row['onsite']) == "t")
$templateVO->setOnsite(True);
elseif (strtolower($row['onsite']) == "f")
$templateVO->setOnsite(False);
$templateVO->setText($row['text']);
$templateVO->setTtype($row['ttype']);
$templateVO->setUserId($row['usrid']);
$templateVO->setProjectId($row['projectid']);
$templateVO->setTaskStoryId($row['task_storyid']);
$templateVO->setInitTime($row['init_time']);
$templateVO->setEndTime($row['end_time']);

return $templateVO;
error_log("Unused TemplateVO::setValues() called");
}

protected function runSelectQuery(string $statement, array $data) {
try {
$statement = $this->pdo->prepare($statement);
$statement->execute($data);
return $statement->fetchAll(PDO::FETCH_CLASS, 'TemplateVO');
} catch (PDOException $e) {
error_log('Query failed: ' . $e->getMessage());
throw new SQLQueryErrorException($e->getMessage());
}
}

/** Template retriever by id for PostgreSQL.
Expand All @@ -97,8 +116,9 @@ protected function setValues($row) {
public function getById($templateId) {
if (!is_numeric($templateId))
throw new SQLIncorrectTypeException($templateId);
$sql = "SELECT * FROM template WHERE id=".$templateId;
$result = $this->execute($sql);
$result = $this->runSelectQuery(
"SELECT * FROM template WHERE id=:id",
[':id' => $templateId]);
return $result[0] ?? NULL;
}

Expand All @@ -115,8 +135,9 @@ public function getById($templateId) {
public function getByUserId($userId) {
if (!is_numeric($userId))
throw new SQLIncorrectTypeException($userId);
$sql = "SELECT * FROM template WHERE usrid=$userId";
$result = $this->execute($sql);
$result = $this->runSelectQuery(
"SELECT * FROM template WHERE usrid=:usrid",
[':usrid' => $userId]);
return $result;
}

Expand All @@ -132,30 +153,34 @@ public function getByUserId($userId) {
public function create(TemplateVO $templateVO) {
$affectedRows = 0;

$sql = "INSERT INTO template (name, story, telework, onsite, text, ttype, usrid, projectid, init_time, end_time, task_storyid) VALUES(" .
DBPostgres::checkStringNull($templateVO->getName()) . ", " .
DBPostgres::checkStringNull($templateVO->getStory()) . ", " .
DBPostgres::boolToString($templateVO->isTelework()) . ", " .
DBPostgres::boolToString($templateVO->isOnsite()) . ", " .
DBPostgres::checkStringNull($templateVO->getText()) . ", " .
DBPostgres::checkStringNull($templateVO->getTtype()) . ", " .
DBPostgres::checkNull($templateVO->getUserId()) . ", " .
DBPostgres::checkNull($templateVO->getProjectId()) . ", " .
DBPostgres::checkNull($templateVO->getInitTime()) . ", " .
DBPostgres::checkNull($templateVO->getEndTime()) . ", " .
DBPostgres::checkNull($templateVO->getTaskStoryId()) .")";

$res = pg_query($this->connect, $sql);

if ($res == NULL)
throw new SQLQueryErrorException(pg_last_error());

$templateVO->setId(DBPostgres::getId($this->connect, "template_id_seq"));

$affectedRows = pg_affected_rows($res);

$sql = "INSERT INTO template (name, story, telework, onsite, text, " .
"ttype, usrid, projectid, init_time, end_time, task_storyid) " .
"VALUES(:name, :story, :telework, :onsite, :text, :ttype, " .
":usrid, :projectid, :init_time, :end_time, :task_storyid)";

try {
$statement = $this->pdo->prepare($sql);
$statement->bindValue(":name", $templateVO->getName(), PDO::PARAM_STR);
$statement->bindValue(":story", $templateVO->getStory(), PDO::PARAM_STR);
$statement->bindValue(":telework", $templateVO->isTelework(), PDO::PARAM_BOOL);
$statement->bindValue(":onsite", $templateVO->isOnsite(), PDO::PARAM_BOOL);
$statement->bindValue(":text", $templateVO->getText(), PDO::PARAM_STR);
$statement->bindValue(":ttype", $templateVO->getTtype(), PDO::PARAM_STR);
$statement->bindValue(":usrid", $templateVO->getUserId(), PDO::PARAM_INT);
$statement->bindValue(":projectid", $templateVO->getProjectId(), PDO::PARAM_INT);
$statement->bindValue(":init_time", $templateVO->getInitTime(), PDO::PARAM_INT);
$statement->bindValue(":end_time", $templateVO->getEndTime(), PDO::PARAM_INT);
$statement->bindValue(":task_storyid", $templateVO->getTaskStoryId(), PDO::PARAM_INT);
$statement->execute();

$templateVO->setId($this->pdo->lastInsertId('template_id_seq'));

$affectedRows = $statement->rowCount();
} catch (PDOException $e) {
error_log('Query failed: ' . $e->getMessage());
throw new SQLQueryErrorException($e->getMessage());
}
return $affectedRows;

}

/**
Expand Down Expand Up @@ -186,20 +211,16 @@ public function batchCreate($templates) {
public function delete(TemplateVO $templateVO) {
$affectedRows = 0;

// Check for a task ID.
if($templateVO->getId() >= 0) {
$currTaskVO = $this->getById($templateVO->getId());
}

// Otherwise delete a task.
if($currTaskVO) {
$sql = "DELETE FROM template WHERE id=".$currTaskVO->getId();
$sql = "DELETE FROM template WHERE id=:id";

$res = pg_query($this->connect, $sql);
if ($res == NULL) throw new SQLQueryErrorException(pg_last_error());
$affectedRows = pg_affected_rows($res);
try {
$statement = $this->pdo->prepare($sql);
$statement->execute([':id' => $templateVO->getId()]);
$affectedRows = $statement->rowCount();
} catch (PDOException $e) {
error_log('Query failed: ' . $e->getMessage());
throw new SQLQueryErrorException($e->getMessage());
}

return $affectedRows;
}

Expand All @@ -226,8 +247,6 @@ public function batchDelete($templates){
* @throws SQLQueryErrorException
*/
public function getUserTemplates($userId) {
$sql = "SELECT * FROM template where usrid=$userId";

return $this->execute($sql);
return $this->getByUserId($userId);
}
}
}
45 changes: 24 additions & 21 deletions model/vo/TemplateVO.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,19 @@
*
* This class just stores Templates data.
*
* NOTICE: properties must match column names in the DB, for PDO::FETCH_CLASS
* to work properly.
*
* @property int $id database internal identifier.
* @property string $name name of the template
* @property string $story story of this Task.
* @property boolean $telework says if this Task was made by telework.
* @property boolean $onsite says if this Task was made onsite.
* @property string $text text describing this Task.
* @property string $ttype type of this Task.
* @property int $userId database internal identifier of the associated User.
* @property int $projectId database internal identifier of the associated Project.
* @property int $taskStoryId database internal identifier of the associated Task Story.
* @property int $usrid database internal identifier of the associated User.
* @property int $projectid database internal identifier of the associated Project.
* @property int $task_storyid database internal identifier of the associated Task Story.
*/
class TemplateVO {

Expand All @@ -56,11 +59,11 @@ class TemplateVO {
protected $onsite = NULL;
protected $text = NULL;
protected $ttype = NULL;
protected $userId = NULL;
protected $projectId = NULL;
protected $taskStoryId = NULL;
protected $initTime = NULL;
protected $endTime = NULL;
protected $usrid = NULL;
protected $projectid = NULL;
protected $task_storyid = NULL;
protected $init_time = NULL;
protected $end_time = NULL;
protected $initTimeRaw = NULL;
protected $endTimeRaw = NULL;

Expand Down Expand Up @@ -166,62 +169,62 @@ public function setTtype($ttype) {
* @return int
*/
public function getUserId() {
return $this->userId;
return $this->usrid;
}

/**
* @param int $userId
*/
public function setUserId($userId) {
$this->userId = $userId;
$this->usrid = $userId;
}

/**
* @return int
*/
public function getProjectId() {
return $this->projectId;
return $this->projectid;
}

/**
* @param int $projectId
*/
public function setProjectId($projectId) {
$this->projectId = $projectId;
$this->projectid = $projectId;
}

/**
* @return int
*/
public function getTaskStoryId() {
return $this->taskStoryId;
return $this->task_storyid;
}

/**
* @param int $taskStoryId
*/
public function setTaskStoryId($taskStoryId) {
$this->taskStoryId = $taskStoryId;
$this->task_storyid = $taskStoryId;
}

public function getInitTime(): ?int {
return $this->initTime;
return $this->init_time;
}

public function setInitTime(?int $initTime) {
$this->initTime = $initTime;
$this->init_time = $initTime;
}

public function setInitTimeRaw(?string $initTime) {
$this->initTimeRaw = $initTime;
}

public function getEndTime(): ?int {
return $this->endTime;
return $this->end_time;
}

public function setEndTime(?int $endTime) {
$this->endTime = $endTime;
$this->end_time = $endTime;
}

public function setEndTimeRaw(?string $endTime) {
Expand All @@ -241,9 +244,9 @@ public function toXml() {
$string .= "<onsite>{$this->onsite}</onsite>";
$string .= "<text>{$this->text}</text>";
$string .= "<ttype>{$this->ttype}</ttype>";
$string .= "<userId>{$this->userId}</userId>";
$string .= "<projectId>{$this->projectId}</projectId>";
$string .= "<taskStoryId>{$this->taskStoryId}</taskStoryId>";
$string .= "<userId>{$this->usrid}</userId>";
$string .= "<projectId>{$this->projectid}</projectId>";
$string .= "<taskStoryId>{$this->task_storyid}</taskStoryId>";
$string .= "<initTime>{$this->initTimeRaw}</initTime>";
$string .= "<endTime>{$this->endTimeRaw}</endTime>";
$string .= "</template>";
Expand Down