diff --git a/model/OperationResult.php b/model/OperationResult.php
new file mode 100644
index 000000000..38be1f57a
--- /dev/null
+++ b/model/OperationResult.php
@@ -0,0 +1,83 @@
+
+ *
+ * This file is part of PhpReport.
+ *
+ * PhpReport is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PhpReport is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PhpReport. If not, see .
+ */
+
+
+/** File for OperationResult
+ *
+ * This file just contains {@link OperationResult}.
+ *
+ * @filesource
+ * @package PhpReport
+ * @author Danielle Mayabb
+ */
+
+/** Result returned after CRUD operations
+ *
+ * This is the object returned for all CRUD operations
+ *
+ * @property boolean $isSuccessful Whether the operation was successful or not
+ * @property int $responseCode The http status code
+ * @property int $errorNumber The php error number
+ * @property string $message Error message that is passed up to front end. Can be php error or custom string.
+ */
+class OperationResult
+{
+ private $isSuccessful;
+ private $responseCode;
+ private $errorNumber;
+ private $message;
+
+ function __construct($isSuccessful, $responseCode = null) {
+ $this->isSuccessful = $isSuccessful;
+ $this->responseCode = $responseCode;
+ }
+
+ public function getIsSuccessful(){
+ return $this->isSuccessful;
+ }
+
+ public function setIsSuccessful($isSuccessful){
+ $this->isSuccessful = (boolean) $isSuccessful;
+ }
+
+ public function getResponseCode(){
+ return $this->responseCode;
+ }
+
+ public function setResponseCode($responseCode){
+ $this->responseCode = (int) $responseCode;
+ }
+
+ public function getErrorNumber(){
+ return $this->errorNumber;
+ }
+
+ public function setErrorNumber($errorNumber){
+ $this->errorNumber = (int) $errorNumber;
+ }
+
+ public function getMessage(){
+ return $this->message;
+ }
+
+ public function setMessage($message){
+ $this->message = (string) $message;
+ }
+}
\ No newline at end of file
diff --git a/model/dao/ProjectDAO/PostgreSQLProjectDAO.php b/model/dao/ProjectDAO/PostgreSQLProjectDAO.php
index c29147445..37edd8528 100644
--- a/model/dao/ProjectDAO/PostgreSQLProjectDAO.php
+++ b/model/dao/ProjectDAO/PostgreSQLProjectDAO.php
@@ -37,6 +37,7 @@
include_once(PHPREPORT_ROOT . '/model/dao/ProjectDAO/ProjectDAO.php');
include_once(PHPREPORT_ROOT . '/model/dao/ProjectUserDAO/PostgreSQLProjectUserDAO.php');
include_once(PHPREPORT_ROOT . '/model/dao/TaskDAO/PostgreSQLTaskDAO.php');
+include_once(PHPREPORT_ROOT . '/model/OperationResult.php');
/** DAO for Projects in PostgreSQL
*
@@ -594,36 +595,73 @@ public function update(ProjectVO $projectVO) {
* The internal id of $projectVO will be set after its creation.
*
* @param ProjectVO $projectVO the {@link ProjectVO} with the data we want to insert on database.
- * @return int the number of rows that have been affected (it should be 1).
+ * @return OperationResult the result {@link OperationResult} with information about operation status
* @throws {@link SQLQueryErrorException}
*/
public function create(ProjectVO $projectVO) {
- $affectedRows = 0;
+ $result = new OperationResult(false);
$sql = "INSERT INTO project (activation, init, _end, invoice, est_hours,
- areaid, customerid, type, description, moved_hours, sched_type) VALUES(" .
- DBPostgres::boolToString($projectVO->getActivation()) . ", " .
- DBPostgres::formatDate($projectVO->getInit()) . ", " .
- DBPostgres::formatDate($projectVO->getEnd()) . ", " .
- DBPostgres::checkNull($projectVO->getInvoice()) . ", " .
- DBPostgres::checkNull($projectVO->getEstHours()) . ", " .
- DBPostgres::checkNull($projectVO->getAreaId()) . ", " .
- DBPostgres::checkNull($projectVO->getCustomerId()) . ", " .
- DBPostgres::checkStringNull($projectVO->getType()) . ", " .
- DBPostgres::checkStringNull($projectVO->getDescription()) . ", " .
- DBPostgres::checkNull($projectVO->getMovedHours()) . ", " .
- DBPostgres::checkStringNull($projectVO->getSchedType()) .")";
-
- $res = pg_query($this->connect, $sql);
-
- if ($res == NULL) throw new SQLQueryErrorException(pg_last_error());
-
- $projectVO->setId(DBPostgres::getId($this->connect, "project_id_seq"));
-
- $affectedRows = pg_affected_rows($res);
+ areaid, customerid, type, description, moved_hours, sched_type) VALUES(
+ :activation, :init, :end, :invoice, :est_hours,
+ :areaid, :customerid, :type, :description, :moved_hours, :sched_type)";
+
+ $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(":activation", $projectVO->getActivation(), PDO::PARAM_BOOL);
+ $statement->bindValue(":init", $initDateFormatted, PDO::PARAM_STR);
+ $statement->bindValue(":end", $endDateFormatted, PDO::PARAM_STR);
+ $statement->bindValue(":invoice", $projectVO->getInvoice(), PDO::PARAM_STR);
+ $statement->bindValue(":est_hours", $projectVO->getEstHours(), PDO::PARAM_STR);
+ $statement->bindValue(":areaid", $projectVO->getAreaId(), PDO::PARAM_INT);
+ $statement->bindValue(":customerid", $projectVO->getCustomerId(), PDO::PARAM_INT);
+ $statement->bindValue(":type", $projectVO->getType(), PDO::PARAM_STR);
+ $statement->bindValue(":description", $projectVO->getDescription(), PDO::PARAM_STR);
+ $statement->bindValue(":moved_hours", $projectVO->getMovedHours(), PDO::PARAM_STR);
+ $statement->bindValue(":sched_type", $projectVO->getSchedType(), PDO::PARAM_STR);
+ $statement->execute();
+
+ $projectVO->setId($this->pdo->lastInsertId('project_id_seq'));
+
+ $result->setIsSuccessful(true);
+ $result->setMessage('Project created successfully.');
+ $result->setResponseCode(201);
+ }
+ 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 creation failed: ' . $errorMessage);
+ $result->setErrorNumber($ex->getCode());
+ $resultMessage = "Project creation failed: \n";
+
+ if(strpos($errorMessage, "Foreign key violation")){
+ if(strpos($errorMessage, "customerid")){
+ $resultMessage .= "Customer not yet created. Please create customer first. \n";
+ }
+ if(strpos($errorMessage,"areaid")){
+ $resultMessage .= "Area not yet created. Please create area first.";
+ }
+ }
+ 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 .= $result . $errorMessage;
+ }
- return $affectedRows;
+ $result->setMessage($resultMessage);
+ $result->setIsSuccessful(false);
+ $result->setResponseCode(500);
+ }
+ return $result;
}
/** Project deleter for PostgreSQL.
diff --git a/model/dao/ProjectDAO/ProjectDAO.php b/model/dao/ProjectDAO/ProjectDAO.php
index 66a0acc07..015ecc52b 100644
--- a/model/dao/ProjectDAO/ProjectDAO.php
+++ b/model/dao/ProjectDAO/ProjectDAO.php
@@ -210,7 +210,7 @@ public abstract function update(ProjectVO $projectVO);
* The internal id of $projectVO will be set after its creation.
*
* @param ProjectVO $projectVO the {@link ProjectVO} with the data we want to insert on database.
- * @return int the number of rows that have been affected (it should be 1).
+ * @return OperationResult the result {@link OperationResult} with information about operation status
* @throws {@link OperationErrorException}
*/
public abstract function create(ProjectVO $projectVO);
@@ -220,7 +220,7 @@ public abstract function create(ProjectVO $projectVO);
* This function deletes the data of a Project by its {@link ProjectVO}.
*
* @param ProjectVO $projectVO the {@link ProjectVO} with the data we want to delete from database.
- * @return int the number of rows that have been affected (it should be 1).
+ * @return OperationResult the result {@link OperationResult} with information about operation status
* @throws {@link OperationErrorException}
*/
public abstract function delete(ProjectVO $projectVO);
diff --git a/model/facade/ProjectsFacade.php b/model/facade/ProjectsFacade.php
index e7a42ca3d..dcb98f973 100644
--- a/model/facade/ProjectsFacade.php
+++ b/model/facade/ProjectsFacade.php
@@ -130,7 +130,7 @@ static function GetCustomProject($projectId) {
* This function is used for creating a new Project.
*
* @param ProjectVO $project the Project value object we want to create.
- * @return int it just indicates if there was any error (-1) or not (0).
+ * @return OperationResult the result {@link OperationResult} with information about operation status
* @throws {@link SQLQueryErrorException}
*/
static function CreateProject(ProjectVO $project) {
@@ -147,17 +147,14 @@ static function CreateProject(ProjectVO $project) {
* If an error occurs, it stops creating.
*
* @param array $projects the Project value objects we want to create.
- * @return int it just indicates if there was any error (-1) or not (0).
+ * @return array OperationResult the araray of results {@link OperationResult} with information about operation status
* @throws {@link SQLQueryErrorException}
*/
static function CreateProjects($projects) {
-
- foreach((array)$projects as $project)
- if ((ProjectsFacade::CreateProject($project)) == -1)
- return -1;
-
- return 0;
-
+ $operationResults = [];
+ foreach ((array) $projects as $project)
+ $operationResults[] = ProjectsFacade::CreateProject($project);
+ return $operationResults;
}
/** Delete Project Function
diff --git a/model/facade/action/CreateProjectAction.php b/model/facade/action/CreateProjectAction.php
index 464e70a05..d0a882167 100644
--- a/model/facade/action/CreateProjectAction.php
+++ b/model/facade/action/CreateProjectAction.php
@@ -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');
/** Create Project Action
*
@@ -68,19 +69,13 @@ public function __construct(ProjectVO $project) {
*
* This is the function that contains the code that creates the new Project, storing it persistently.
*
- * @return int it just indicates if there was any error (-1) or not (0).
+ * @return OperationResult the result {@link OperationResult} with information about operation status
* @throws {@link SQLQueryErrorException}
*/
protected function doExecute() {
-
- $dao = DAOFactory::getProjectDAO();
- if ($dao->create($this->project)!=1) {
- return -1;
- }
-
- return 0;
+ $dao = DAOFactory::getProjectDAO();
+ return $dao->create($this->project);
}
-
}
diff --git a/web/js/projectManagement.js b/web/js/projectManagement.js
index bc728d188..32c6e3c9b 100644
--- a/web/js/projectManagement.js
+++ b/web/js/projectManagement.js
@@ -1106,9 +1106,14 @@ Ext.onReady(function(){
projectGrid.getSelectionModel().selectRow(rowIndex);
projectGrid.getView().focusRow(rowIndex);
},
- 'exception': function(){
- App.setAlert(false, "Some Error Occurred While Saving The Changes");
- },
+ 'exception': function(proxy, type, action, eOpts, res){
+ let parser = new DOMParser();
+ let errorDoc = parser.parseFromString(res.responseText, "text/xml");
+ let errorMessage = errorDoc.getElementsByTagName("error")[0].childNodes[0].nodeValue;
+ App.setAlert(false, errorMessage);
+ //if creation fails, reload data store so that "dirty" record from attempt doesn't persist
+ projectsStore.reload();
+ }
}
});
diff --git a/web/services/createProjectsService.php b/web/services/createProjectsService.php
index 1dedc81aa..91c6f54f2 100644
--- a/web/services/createProjectsService.php
+++ b/web/services/createProjectsService.php
@@ -30,6 +30,7 @@
include_once(PHPREPORT_ROOT . '/web/services/WebServicesFunctions.php');
include_once(PHPREPORT_ROOT . '/model/facade/ProjectsFacade.php');
include_once(PHPREPORT_ROOT . '/model/vo/ProjectVO.php');
+ include_once(PHPREPORT_ROOT . '/model/OperationResult.php');
$parser = new XMLReader();
@@ -208,11 +209,34 @@
if (count($createProjects) >= 1)
- if (ProjectsFacade::CreateProjects($createProjects) == -1)
- $string = "There was some error while creating the projects";
+ if(count($createProjects) == 1){
+ $operationResult = ProjectsFacade::CreateProject($createProjects[0]);
+ if (!$operationResult->getIsSuccessful()) {
+ http_response_code($operationResult->getResponseCode());
+ $string = "" . $operationResult->getMessage() . "";
+ }
+ }
+ else {
+ //leaving the possibility to create multiple projects in the future
+ $operationResults = ProjectsFacade::CreateProjects($createProjects);
+ $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 = "";
+ foreach((array) $errors as $result){
+ if (!$result->getIsSuccessful())
+ $string .= "" . $result->getMessage() . "";
+ }
+ $string .= "";
+ }
+ }
+
- if (!$string)
+ if (!isset($string))
{
$string = "Operation Success!";