Skip to content

Commit

Permalink
[#496,#513] Return more specific errors on project update.
Browse files Browse the repository at this point in the history
Also rewrite the operation in PDO terms, addressing #513.
  • Loading branch information
jaragunde committed Feb 24, 2023
1 parent dd38f87 commit d4829c9
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 60 deletions.
127 changes: 97 additions & 30 deletions model/dao/ProjectDAO/PostgreSQLProjectDAO.php
Original file line number Diff line number Diff line change
Expand Up @@ -482,70 +482,137 @@ public function getByDescription(string $desc): ?int
*
* @param ProjectVO $projectVO the {@link ProjectVO} with the data we want to update on database.
* @param array $update an array with flags for updating or not the different fields.
* @return int the number of rows that have been affected (it should be 1).
* @throws {@link SQLQueryErrorException}
* @return OperationResult the result {@link OperationResult} with information about operation status
*/
public function partialUpdate(ProjectVO $projectVO, $update) {
$affectedRows = 0;
$result = new OperationResult(false);

if($projectVO->getId() != "") {
$currProjectVO = $this->getById($projectVO->getId());
$sql = "UPDATE project SET ";

if ($update['activation'])
$sql .= "activation=:activation, ";

if ($update['init'])
$sql .= "init=:init, ";

if ($update['end'])
$sql .= "_end=:end, ";

if ($update['invoice'])
$sql .= "invoice=:invoice, ";

if ($update['estHours'])
$sql .= "est_hours=:est_hours, ";

if ($update['areaId'])
$sql .= "areaid=:areaid, ";

if ($update['customerId'])
$sql .= "customerid=:customerid, ";

if ($update['description'])
$sql .= "description=:description, ";

if ($update['type'])
$sql .= "type=:type, ";

if ($update['movHours'])
$sql .= "moved_hours=:moved_hours, ";

if ($update['schedType'])
$sql .= "sched_type=:sched_type, ";

if (strlen($sql) == strlen("UPDATE project SET ")) {
$result->setIsSuccessful(true);
$result->setMessage('No changes.');
$result->setResponseCode(200);

return $result;
}

// If the query returned a row then update
if (!is_null($currProjectVO)) {
// remove the last comma
$sql = substr($sql, 0, -2);

$sql .= " WHERE id=:id";

$sql = "UPDATE project SET ";
$initDateFormatted = (is_null($projectVO->getInit())) ? null : DBPostgres::formatDate($projectVO->getInit());
$endDateFormatted = (is_null($projectVO->getEnd())) ? null : DBPostgres::formatDate($projectVO->getEnd());

try {
$statement = $this->pdo->prepare($sql);
$statement->bindValue(":id", $projectVO->getId(), PDO::PARAM_INT);

if ($update['activation'])
$sql .= "activation=" . DBPostgres::boolToString($projectVO->getActivation()) . ", ";
$statement->bindValue(":activation", $projectVO->getActivation(), PDO::PARAM_BOOL);

if ($update['init'])
$sql .= "init=" . DBPostgres::formatDate($projectVO->getInit()) . ", ";
$statement->bindValue(":init", $initDateFormatted, PDO::PARAM_STR);

if ($update['end'])
$sql .= "_end=" . DBPostgres::formatDate($projectVO->getEnd()) . ", ";
$statement->bindValue(":end", $endDateFormatted, PDO::PARAM_STR);

if ($update['invoice'])
$sql .= "invoice=" . DBPostgres::checkNull($projectVO->getInvoice()) . ", ";
$statement->bindValue(":invoice", $projectVO->getInvoice(), PDO::PARAM_STR);

if ($update['estHours'])
$sql .= "est_hours=" . DBPostgres::checkNull($projectVO->getEstHours()) . ", ";
$statement->bindValue(":est_hours", $projectVO->getEstHours(), PDO::PARAM_STR);

if ($update['areaId'])
$sql .= "areaid=" . DBPostgres::checkNull($projectVO->getAreaId()) . ", ";
$statement->bindValue(":areaid", $projectVO->getAreaId(), PDO::PARAM_INT);

if ($update['customerId'])
$sql .= "customerid=" . DBPostgres::checkNull($projectVO->getCustomerId()) . ", ";
$statement->bindValue(":customerid", $projectVO->getCustomerId(), PDO::PARAM_INT);

if ($update['description'])
$sql .= "description=" . DBPostgres::checkStringNull($projectVO->getDescription()) . ", ";
$statement->bindValue(":description", $projectVO->getDescription(), PDO::PARAM_STR);

if ($update['type'])
$sql .= "type=" . DBPostgres::checkStringNull($projectVO->getType()) . ", ";
$statement->bindValue(":type", $projectVO->getType(), PDO::PARAM_STR);

if ($update['movHours'])
$sql .= "moved_hours=" . DBPostgres::checkNull($projectVO->getMovedHours()) . ", ";
$statement->bindValue(":moved_hours", $projectVO->getMovedHours(), PDO::PARAM_STR);

if ($update['schedType'])
$sql .= "sched_type=" . DBPostgres::checkStringNull($projectVO->getSchedType());

if (strlen($sql) == strlen("UPDATE project SET "))
return NULL;
$statement->bindValue(":sched_type", $projectVO->getSchedType(), PDO::PARAM_STR);

$last = strrpos($sql, ",");
$statement->execute();

if ($last == (strlen($sql) - 2))
$sql = substr($sql, 0, -2);
$result->setIsSuccessful(true);
$result->setMessage('Project created successfully.');
$result->setResponseCode(200);
}
catch (PDOException $ex) {
//make sure to log the error as a failure, but return the OperationResult object
//successfully so that front end can see error and fail gracefully
$errorMessage = $ex->getMessage();
error_log('Project update failed: ' . $errorMessage);
$result->setErrorNumber($ex->getCode());
$resultMessage = "Project update failed: \n";

$sql .= " WHERE id=".$projectVO->getId();
if (strpos($errorMessage, "Foreign key violation")){
if (strpos($errorMessage, "customerid")) {
$resultMessage .= "Assigned customer does not exist.";
}
else if (strpos($errorMessage,"areaid")) {
$resultMessage .= "Assigned area does not exist.";
}
}
else if (strpos($errorMessage, "Not null violation")) {
if (strpos($errorMessage,"areaid")) {
$resultMessage .= "Area is null. Please choose area.";
}
}
else {
//if not a predictable error like FK/null violation, just return the native error code and message
$resultMessage .= $errorMessage;
}

$res = pg_query($this->connect, $sql);
if ($res == NULL) throw new SQLQueryErrorException(pg_last_error());
$affectedRows = pg_affected_rows($res);
$result->setMessage($resultMessage);
$result->setIsSuccessful(false);
$result->setResponseCode(500);
}

return $affectedRows;
return $result;
}

/** Project updater for PostgreSQL.
Expand Down
24 changes: 8 additions & 16 deletions model/facade/ProjectsFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,11 @@ static function UpdateProject(ProjectVO $project) {
*
* @param ProjectVO $task the Project value object we want to update.
* @param array $update the updating flags of the Project VO.
* @return int it just indicates if there was any error (<i>-1</i>) or not (<i>0</i>).
* @throws {@link SQLQueryErrorException}
* @return OperationResult the result {@link OperationResult} with information about operation status
*/
static function PartialUpdateProject(ProjectVO $project, $update) {

$action = new PartialUpdateProjectAction($project, $update);

return $action->execute();

$action = new PartialUpdateProjectAction($project, $update);
return $action->execute();
}

/** Partial Update Projects Function
Expand All @@ -302,17 +298,13 @@ static function PartialUpdateProject(ProjectVO $project, $update) {
*
* @param array $projects the Project value objects we want to update.
* @param array $updates the updating flag arrays of the Project VOs.
* @return int it just indicates if there was any error (<i>-1</i>) or not (<i>0</i>).
* @throws {@link SQLQueryErrorException}
* @return array OperationResult the array of results {@link OperationResult} with information about operation status.
*/
static function PartialUpdateProjects($projects, $updates) {

foreach((array)$projects as $i=>$project)
if ((ProjectsFacade::PartialUpdateProject($project, $updates[$i])) == -1)
return -1;

return 0;

$operationResults = [];
foreach ((array) $projects as $i=>$project)
$operationResults[] = ProjectsFacade::PartialUpdateProject($project, $updates[$i]);
return $operationResults;
}

/** GetProjectsByCustomerUserLogin Function
Expand Down
11 changes: 3 additions & 8 deletions model/facade/action/PartialUpdateProjectAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
include_once(PHPREPORT_ROOT . '/model/facade/action/Action.php');
include_once(PHPREPORT_ROOT . '/model/dao/DAOFactory.php');
include_once(PHPREPORT_ROOT . '/model/vo/ProjectVO.php');
include_once(PHPREPORT_ROOT . '/model/OperationResult.php');

/** Partial Update Project Action
*
Expand Down Expand Up @@ -77,17 +78,11 @@ public function __construct(ProjectVO $project, $update) {
*
* This is the function that contains the code that updates the Project on persistent storing.
*
* @return int it just indicates if there was any error (<i>-1</i>) or not (<i>0</i>).
* @return OperationResult the result {@link OperationResult} with information about operation status
*/
protected function doExecute() {

$dao = DAOFactory::getProjectDAO();

if ($dao->partialUpdate($this->project, $this->update)!=1) {
return -1;
}

return 0;
return $dao->partialUpdate($this->project, $this->update);
}

}
Expand Down
32 changes: 26 additions & 6 deletions web/services/updateProjectsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@

$projectVO = new ProjectVO();

$update = array();
$update = array(
"activation" => false,
"init" => false,
"end" => false,
"invoice" => false,
"estHours" => false,
"description" => false,
"areaId" => false,
"customerId" => false,
"type" => false,
"movedHours" => false,
"schedType" => false
);

$parser->read();

Expand Down Expand Up @@ -226,11 +238,19 @@

}


if (count($updateProjects) >= 1)
if (ProjectsFacade::PartialUpdateProjects($updateProjects, $updates) == -1)
$string = "<return service='updateProjects'><error id='1'>There was some error while updating the projects</error></return>";

$operationResults = ProjectsFacade::PartialUpdateProjects($updateProjects, $updates);
$errors = array_filter($operationResults, function ($item) {
return (!$item->getIsSuccessful());
});
if ($errors) {
//if multiple failures, let's just return a 500
http_response_code(500);
$string = "<return service='updateProjects'><errors>";
foreach ($errors as $result) {
$string .= "<error id='" . $result->getErrorNumber() . "'>" . $result->getMessage() . "</error>";
}
$string .= "</errors></return>";
}

if (!isset($string))
$string = "<return service='updateProjects'><ok>Operation Success!</ok></return>";
Expand Down

0 comments on commit d4829c9

Please sign in to comment.