formSpec = $formSpec; $this->feSpecAction = $feSpecAction; $this->feSpecNative = $feSpecNative; $this->store = Store::getInstance(); $this->db = new Database(); $this->evaluate = new Evaluate($this->store, $this->db); } /** * Starts save process. On succcess, returns forwardmode/page. * * @throws CodeException * @throws DbException * @throws UserFormException */ public function process() { $rc = 0; if ($this->formSpec['multiMode'] !== 'none') { $parentRecords = $this->db->sql($this->formSpec['multiSql']); foreach ($parentRecords as $row) { $this->store->setVarArray($row, STORE_PARENT_RECORD, true); $rc = $this->elements($row['_id']); } } else { $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_ZERO); $rc = $this->elements($recordId); } return $rc; } /** * @param $recordId * @return int record id (in case of insert, it's different from $recordId) * @throws CodeException * @throws DbException * @throws UserFormException */ public function elements($recordId) { $newValues = array(); $tableColumns = array_keys($this->store->getStore(STORE_TABLE_COLUMN_TYPES)); $formValues = $this->store->getStore(STORE_FORM); $this->processAllUploads($formValues); // Iterate over all table.columns. Built an assoc array $newValues. foreach ($tableColumns AS $column) { // Never save a predefined 'id': autoincrement values will be given by database.. if ($column === 'id') { continue; } // Is there a value? Do not forget SIP values. Those do not have necessarily a FormElement. if (!isset($formValues[$column])) { continue; } $this->store->setVar(SYSTEM_FORM_ELEMENT, "Column: $column", STORE_SYSTEM); Support::setIfNotSet($formValues, $column); $newValues[$column] = $formValues[$column]; } if ($recordId == 0) { $rc = $this->insertRecord($this->formSpec['tableName'], $newValues); } else { $this->updateRecord($this->formSpec['tableName'], $newValues, $recordId); $rc = $recordId; } return $rc; } /** * Process all Upload Formelements for the given $recordId. After processing &$formValues will be updated with the final filenames. * * @param array $formValues */ private function processAllUploads(array &$formValues) { foreach ($this->feSpecNative AS $formElement) { // skip non upload formElements if ($formElement[FE_TYPE] != 'upload') { continue; } // Preparation for Log, Debug $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($formElement), STORE_SYSTEM); $column = $formElement['name']; $file = $this->doUpload($formElement, $formValues[$column]); if ($file !== false) { $formValues[$column] = $file; } } } /** * Process upload for the given Formelement. If necessary, delete a previous uploaded file. * Calculate the final path/filename and move the file to the new location. * * @param $formElement * @param $sipUpload * @return string|false New filename or false on error * @throws CodeException * @throws UserFormException * @internal param $recordId */ private function doUpload($formElement, $sipUpload) { // Status information about upload file $statusUpload = $this->store->getVar($sipUpload, STORE_EXTRA); if ($statusUpload === false) { return false; } // Take care the necessary target directories exist. $cwd = getcwd(); $sitePath = $this->store->getVar(SYSTEM_SITE_PATH, STORE_SYSTEM); if ($cwd === false || $sitePath === false || !chdir($sitePath)) { throw new UserFormException("getcwd() failed or SITE_PATH undefined or chdir('$sitePath') failed.", ERROR_IO_CHDIR); } // Delete existing old file. if (isset($statusUpload[FILES_FLAG_DELETE]) && $statusUpload[FILES_FLAG_DELETE] == '1') { $oldFile = $this->store->getVar($formElement['name'], STORE_RECORD); if (file_exists($oldFile)) { if (!unlink($oldFile)) { throw new UserFormException('Unlink file failed: ' . $oldFile, ERROR_IO_UNLINK); } } } $pathFileName = $this->copyUploadFile($formElement, $statusUpload); chdir($cwd); // Delete current used uniq SIP $this->store->setVar($sipUpload, array(), STORE_EXTRA); return $pathFileName; } /** * @param array $formElement * @param array $statusUpload * @return array|mixed|null|string * @throws CodeException * @throws UserFormException */ private function copyUploadFile(array $formElement, array $statusUpload) { $pathFileName = ''; if (isset($formElement[FE_PATH_FILE_NAME])) { // Provide variable '_filename'. Might be substituted in $formElement[FE_PATH_FILE_NAME]. $origFilename = Sanitize::safeFilename($statusUpload[FILES_NAME]); $this->store->setVar(CLIENT_UPLOAD_FILENAME, $origFilename, STORE_FORM); $pathFileName = $this->evaluate->parse($formElement[FE_PATH_FILE_NAME]); } if ($pathFileName === '') { throw new UserFormException("Upload failed, no target '" . FE_PATH_FILE_NAME . "' specified.", ERROR_NO_TARGET_PATH_FILE_NAME); } if (file_exists($pathFileName)) { throw new UserFormException('Copy upload failed - file already exist: ' . $pathFileName, ERROR_IO_FILE_EXIST); } Support::mkDirParent($pathFileName); $srcFile = Support::extendFilename($statusUpload[FILES_TMP_NAME], UPLOAD_CACHED); if (!rename($srcFile, $pathFileName)) { throw new UserFormException("Rename file: '$srcFile' > '$pathFileName'", ERROR_IO_RENAME); } return $pathFileName; } /** * Insert new record in table $this->formSpec['tableName']. * * @param array $values * @return int last insert id * @throws DbException */ public function insertRecord($tableName, array $values) { if (count($values) === 0) return 0; // nothing to write, last insert id=0 $paramList = str_repeat('?, ', count($values)); $paramList = substr($paramList, 0, strlen($paramList) - 2); $columnList = '`' . implode('`, `', array_keys($values)) . '`'; $sql = 'INSERT INTO ' . $tableName . ' ( ' . $columnList . ' ) VALUES ( ' . $paramList . ' )'; $rc = $this->db->sql($sql, ROW_REGULAR, array_values($values)); return $rc; } /** * @param string $tableName * @param array $values * @param int $recordId * @return bool|int false if $values is empty, else affectedrows * @throws CodeException * @throws DbException */ public function updateRecord($tableName, array $values, $recordId) { if (count($values) === 0) return 0; // nothing to write, 0 rows affected if ($recordId === 0) throw new CodeException('RecordId=0 - this is not possible for update.', ERROR_RECORDID_0_FORBIDDEN); // $paramList = str_repeat('?, ', count($values)); // $paramList = substr($paramList, 0, strlen($paramList) - 2); $sql = 'UPDATE `' . $tableName . '` SET '; foreach ($values as $column => $value) { $sql .= '`' . $column . '` = ?, '; } $sql = substr($sql, 0, strlen($sql) - 2) . ' WHERE id = ?'; $values[] = $recordId; $rc = $this->db->sql($sql, ROW_REGULAR, array_values($values)); return $rc; } /** * Get the complete FormElement for $name * * @param $name * @return bool|array if found the FormElement, else false. */ private function getFormElementByName($name) { foreach ($this->feSpecNative as $formElement) { if ($formElement['name'] === $name) return $formElement; } return false; } }