Skip to content

Commit 09a5efa

Browse files
authored
[#513] Port Template DAO to use PDO.
Merge pull request #534 from Igalia/i513-pdo-for-template-table
2 parents 3725d71 + 9460159 commit 09a5efa

File tree

3 files changed

+122
-100
lines changed

3 files changed

+122
-100
lines changed

docs/admin/installation.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To install PhpReport in your system, you will need the following software:
1212

1313
* PHP 7.3 or higher
1414

15-
* Support for PostgreSQL
15+
* Support for PDO and PostgreSQL
1616

1717
* Web server (tested with Apache 2.x)
1818

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

2424
Run the following command with root privileges:
2525

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

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

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

3232
Install composer to manage the project dependencies. Follow the official
3333
docs for the instructions: https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos

model/dao/TemplateDAO/PostgreSQLTemplateDAO.php

+94-75
Original file line numberDiff line numberDiff line change
@@ -40,49 +40,68 @@
4040
*/
4141
class PostgreSQLTemplateDAO extends TemplateDAO{
4242

43+
/** The connection to DB.
44+
*
45+
* PDO object with an open connection to the database, initialized in the
46+
* class constructor.
47+
*
48+
* @var resource
49+
* @see __construct()
50+
*/
51+
protected PDO $pdo;
52+
4353
/** Template DAO for PostgreSQL constructor.
4454
*
45-
* This is the constructor of the implementation for PostgreSQL of {@link TemplateDAO}, and it just calls its parent's constructor.
55+
* This is the constructor of the implementation for PostgreSQL of
56+
* {@link TemplateDAO}. It sets up everything for database connection, using
57+
* the parameters read from <i>{@link config.php}</i> and saving the open
58+
* connection in <var>{@link $pdo}</var>.
59+
* Notice this DAO connects to the DB through PDO, unlike the rest of the
60+
* application.
4661
*
4762
* @throws {@link DBConnectionErrorException}
48-
* @see TemplateDAO::__construct()
4963
*/
5064
function __construct() {
65+
// Call parent to initialize non-PDO database access, while we don't
66+
// migrate all the methods here.
5167
parent::__construct();
68+
69+
// TODO: EXTRA_DB_CONNECTION_PARAMETERS used to expect pg_connect
70+
// parameters, which were space-separated, but PDO requires semicolons
71+
$connectionString = sprintf("pgsql:host=%s;port=%d;user=%s;dbname=%s;password=%s;%s",
72+
ConfigurationParametersManager::getParameter('DB_HOST'),
73+
ConfigurationParametersManager::getParameter('DB_PORT'),
74+
ConfigurationParametersManager::getParameter('DB_USER'),
75+
ConfigurationParametersManager::getParameter('DB_NAME'),
76+
ConfigurationParametersManager::getParameter('DB_PASSWORD'),
77+
ConfigurationParametersManager::getParameter('EXTRA_DB_CONNECTION_PARAMETERS'));
78+
79+
try {
80+
$this->pdo = new PDO($connectionString);
81+
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
82+
} catch (PDOException $e) {
83+
error_log('Connection failed: ' . $e->getMessage());
84+
throw new DBConnectionErrorException($connectionString);
85+
}
5286
}
5387

54-
/** Template value object constructor for PostgreSQL.
55-
*
56-
* This function creates a new {@link TemplateVO} with data retrieved from database.
57-
*
58-
* @param array $row an array with the Task values from a row.
59-
* @return TemplateVO a {@link TemplateVO} with its properties set to the values from <var>$row</var>.
60-
* @see TemplateVO
88+
/**
89+
* This method is declared to fulfill TemplateVO as non-abstract, but it should not be used.
90+
* PDO::FETCH_CLASS now takes care of transforming DB rows into VO objects.
6191
*/
6292
protected function setValues($row) {
63-
$templateVO = new TemplateVO();
64-
65-
$templateVO->setId($row['id']);
66-
$templateVO->setName($row['name']);
67-
$templateVO->setStory($row['story']);
68-
$templateVO->setStory($row['story']);
69-
if (strtolower($row['telework']) == "t")
70-
$templateVO->setTelework(True);
71-
elseif (strtolower($row['telework']) == "f")
72-
$templateVO->setTelework(False);
73-
if (strtolower($row['onsite']) == "t")
74-
$templateVO->setOnsite(True);
75-
elseif (strtolower($row['onsite']) == "f")
76-
$templateVO->setOnsite(False);
77-
$templateVO->setText($row['text']);
78-
$templateVO->setTtype($row['ttype']);
79-
$templateVO->setUserId($row['usrid']);
80-
$templateVO->setProjectId($row['projectid']);
81-
$templateVO->setTaskStoryId($row['task_storyid']);
82-
$templateVO->setInitTime($row['init_time']);
83-
$templateVO->setEndTime($row['end_time']);
84-
85-
return $templateVO;
93+
error_log("Unused TemplateVO::setValues() called");
94+
}
95+
96+
protected function runSelectQuery(string $statement, array $data) {
97+
try {
98+
$statement = $this->pdo->prepare($statement);
99+
$statement->execute($data);
100+
return $statement->fetchAll(PDO::FETCH_CLASS, 'TemplateVO');
101+
} catch (PDOException $e) {
102+
error_log('Query failed: ' . $e->getMessage());
103+
throw new SQLQueryErrorException($e->getMessage());
104+
}
86105
}
87106

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

@@ -115,8 +135,9 @@ public function getById($templateId) {
115135
public function getByUserId($userId) {
116136
if (!is_numeric($userId))
117137
throw new SQLIncorrectTypeException($userId);
118-
$sql = "SELECT * FROM template WHERE usrid=$userId";
119-
$result = $this->execute($sql);
138+
$result = $this->runSelectQuery(
139+
"SELECT * FROM template WHERE usrid=:usrid",
140+
[':usrid' => $userId]);
120141
return $result;
121142
}
122143

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

135-
$sql = "INSERT INTO template (name, story, telework, onsite, text, ttype, usrid, projectid, init_time, end_time, task_storyid) VALUES(" .
136-
DBPostgres::checkStringNull($templateVO->getName()) . ", " .
137-
DBPostgres::checkStringNull($templateVO->getStory()) . ", " .
138-
DBPostgres::boolToString($templateVO->isTelework()) . ", " .
139-
DBPostgres::boolToString($templateVO->isOnsite()) . ", " .
140-
DBPostgres::checkStringNull($templateVO->getText()) . ", " .
141-
DBPostgres::checkStringNull($templateVO->getTtype()) . ", " .
142-
DBPostgres::checkNull($templateVO->getUserId()) . ", " .
143-
DBPostgres::checkNull($templateVO->getProjectId()) . ", " .
144-
DBPostgres::checkNull($templateVO->getInitTime()) . ", " .
145-
DBPostgres::checkNull($templateVO->getEndTime()) . ", " .
146-
DBPostgres::checkNull($templateVO->getTaskStoryId()) .")";
147-
148-
$res = pg_query($this->connect, $sql);
149-
150-
if ($res == NULL)
151-
throw new SQLQueryErrorException(pg_last_error());
152-
153-
$templateVO->setId(DBPostgres::getId($this->connect, "template_id_seq"));
154-
155-
$affectedRows = pg_affected_rows($res);
156-
156+
$sql = "INSERT INTO template (name, story, telework, onsite, text, " .
157+
"ttype, usrid, projectid, init_time, end_time, task_storyid) " .
158+
"VALUES(:name, :story, :telework, :onsite, :text, :ttype, " .
159+
":usrid, :projectid, :init_time, :end_time, :task_storyid)";
160+
161+
try {
162+
$statement = $this->pdo->prepare($sql);
163+
$statement->bindValue(":name", $templateVO->getName(), PDO::PARAM_STR);
164+
$statement->bindValue(":story", $templateVO->getStory(), PDO::PARAM_STR);
165+
$statement->bindValue(":telework", $templateVO->isTelework(), PDO::PARAM_BOOL);
166+
$statement->bindValue(":onsite", $templateVO->isOnsite(), PDO::PARAM_BOOL);
167+
$statement->bindValue(":text", $templateVO->getText(), PDO::PARAM_STR);
168+
$statement->bindValue(":ttype", $templateVO->getTtype(), PDO::PARAM_STR);
169+
$statement->bindValue(":usrid", $templateVO->getUserId(), PDO::PARAM_INT);
170+
$statement->bindValue(":projectid", $templateVO->getProjectId(), PDO::PARAM_INT);
171+
$statement->bindValue(":init_time", $templateVO->getInitTime(), PDO::PARAM_INT);
172+
$statement->bindValue(":end_time", $templateVO->getEndTime(), PDO::PARAM_INT);
173+
$statement->bindValue(":task_storyid", $templateVO->getTaskStoryId(), PDO::PARAM_INT);
174+
$statement->execute();
175+
176+
$templateVO->setId($this->pdo->lastInsertId('template_id_seq'));
177+
178+
$affectedRows = $statement->rowCount();
179+
} catch (PDOException $e) {
180+
error_log('Query failed: ' . $e->getMessage());
181+
throw new SQLQueryErrorException($e->getMessage());
182+
}
157183
return $affectedRows;
158-
159184
}
160185

161186
/**
@@ -186,20 +211,16 @@ public function batchCreate($templates) {
186211
public function delete(TemplateVO $templateVO) {
187212
$affectedRows = 0;
188213

189-
// Check for a task ID.
190-
if($templateVO->getId() >= 0) {
191-
$currTaskVO = $this->getById($templateVO->getId());
192-
}
193-
194-
// Otherwise delete a task.
195-
if($currTaskVO) {
196-
$sql = "DELETE FROM template WHERE id=".$currTaskVO->getId();
214+
$sql = "DELETE FROM template WHERE id=:id";
197215

198-
$res = pg_query($this->connect, $sql);
199-
if ($res == NULL) throw new SQLQueryErrorException(pg_last_error());
200-
$affectedRows = pg_affected_rows($res);
216+
try {
217+
$statement = $this->pdo->prepare($sql);
218+
$statement->execute([':id' => $templateVO->getId()]);
219+
$affectedRows = $statement->rowCount();
220+
} catch (PDOException $e) {
221+
error_log('Query failed: ' . $e->getMessage());
222+
throw new SQLQueryErrorException($e->getMessage());
201223
}
202-
203224
return $affectedRows;
204225
}
205226

@@ -226,8 +247,6 @@ public function batchDelete($templates){
226247
* @throws SQLQueryErrorException
227248
*/
228249
public function getUserTemplates($userId) {
229-
$sql = "SELECT * FROM template where usrid=$userId";
230-
231-
return $this->execute($sql);
250+
return $this->getByUserId($userId);
232251
}
233-
}
252+
}

model/vo/TemplateVO.php

+24-21
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,19 @@
3333
*
3434
* This class just stores Templates data.
3535
*
36+
* NOTICE: properties must match column names in the DB, for PDO::FETCH_CLASS
37+
* to work properly.
38+
*
3639
* @property int $id database internal identifier.
3740
* @property string $name name of the template
3841
* @property string $story story of this Task.
3942
* @property boolean $telework says if this Task was made by telework.
4043
* @property boolean $onsite says if this Task was made onsite.
4144
* @property string $text text describing this Task.
4245
* @property string $ttype type of this Task.
43-
* @property int $userId database internal identifier of the associated User.
44-
* @property int $projectId database internal identifier of the associated Project.
45-
* @property int $taskStoryId database internal identifier of the associated Task Story.
46+
* @property int $usrid database internal identifier of the associated User.
47+
* @property int $projectid database internal identifier of the associated Project.
48+
* @property int $task_storyid database internal identifier of the associated Task Story.
4649
*/
4750
class TemplateVO {
4851

@@ -56,11 +59,11 @@ class TemplateVO {
5659
protected $onsite = NULL;
5760
protected $text = NULL;
5861
protected $ttype = NULL;
59-
protected $userId = NULL;
60-
protected $projectId = NULL;
61-
protected $taskStoryId = NULL;
62-
protected $initTime = NULL;
63-
protected $endTime = NULL;
62+
protected $usrid = NULL;
63+
protected $projectid = NULL;
64+
protected $task_storyid = NULL;
65+
protected $init_time = NULL;
66+
protected $end_time = NULL;
6467
protected $initTimeRaw = NULL;
6568
protected $endTimeRaw = NULL;
6669

@@ -166,62 +169,62 @@ public function setTtype($ttype) {
166169
* @return int
167170
*/
168171
public function getUserId() {
169-
return $this->userId;
172+
return $this->usrid;
170173
}
171174

172175
/**
173176
* @param int $userId
174177
*/
175178
public function setUserId($userId) {
176-
$this->userId = $userId;
179+
$this->usrid = $userId;
177180
}
178181

179182
/**
180183
* @return int
181184
*/
182185
public function getProjectId() {
183-
return $this->projectId;
186+
return $this->projectid;
184187
}
185188

186189
/**
187190
* @param int $projectId
188191
*/
189192
public function setProjectId($projectId) {
190-
$this->projectId = $projectId;
193+
$this->projectid = $projectId;
191194
}
192195

193196
/**
194197
* @return int
195198
*/
196199
public function getTaskStoryId() {
197-
return $this->taskStoryId;
200+
return $this->task_storyid;
198201
}
199202

200203
/**
201204
* @param int $taskStoryId
202205
*/
203206
public function setTaskStoryId($taskStoryId) {
204-
$this->taskStoryId = $taskStoryId;
207+
$this->task_storyid = $taskStoryId;
205208
}
206209

207210
public function getInitTime(): ?int {
208-
return $this->initTime;
211+
return $this->init_time;
209212
}
210213

211214
public function setInitTime(?int $initTime) {
212-
$this->initTime = $initTime;
215+
$this->init_time = $initTime;
213216
}
214217

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

219222
public function getEndTime(): ?int {
220-
return $this->endTime;
223+
return $this->end_time;
221224
}
222225

223226
public function setEndTime(?int $endTime) {
224-
$this->endTime = $endTime;
227+
$this->end_time = $endTime;
225228
}
226229

227230
public function setEndTimeRaw(?string $endTime) {
@@ -241,9 +244,9 @@ public function toXml() {
241244
$string .= "<onsite>{$this->onsite}</onsite>";
242245
$string .= "<text>{$this->text}</text>";
243246
$string .= "<ttype>{$this->ttype}</ttype>";
244-
$string .= "<userId>{$this->userId}</userId>";
245-
$string .= "<projectId>{$this->projectId}</projectId>";
246-
$string .= "<taskStoryId>{$this->taskStoryId}</taskStoryId>";
247+
$string .= "<userId>{$this->usrid}</userId>";
248+
$string .= "<projectId>{$this->projectid}</projectId>";
249+
$string .= "<taskStoryId>{$this->task_storyid}</taskStoryId>";
247250
$string .= "<initTime>{$this->initTimeRaw}</initTime>";
248251
$string .= "<endTime>{$this->endTimeRaw}</endTime>";
249252
$string .= "</template>";

0 commit comments

Comments
 (0)