Save.php 9.49 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 1/30/16
 * Time: 7:59 PM
 */

namespace qfq;

require_once(__DIR__ . '/../qfq/store/Store.php');
require_once(__DIR__ . '/../qfq/Constants.php');
require_once(__DIR__ . '/../qfq/Evaluate.php');
//require_once(__DIR__ . '/../qfq/exceptions/UserException.php');
//require_once(__DIR__ . '/../qfq/exceptions/CodeException.php');
//require_once(__DIR__ . '/../qfq/exceptions/DbException.php');
//require_once(__DIR__ . '/../qfq/Evaluate.php');


class Save {

    private $formSpec = array();  // copy of the loaded form
    private $feSpecAction = array(); // copy of all formElement.class='action' of the loaded form
    private $feSpecNative = array(); // copy of all formElement.class='native' of the loaded form
    /**
     * @var null|Store
     */
    private $store = null;
    private $db = null;

    private $evaluate = null;

    /**
     * @param array $formSpec
     * @param array $feSpecAction
     * @param array $feSpecNative
     */
    public function __construct(array $formSpec, array $feSpecAction, array $feSpecNative) {
        $this->formSpec = $formSpec;
        $this->feSpecAction = $feSpecAction;
        $this->feSpecNative = $feSpecNative;
        $this->store = Store::getInstance();
        $this->db = new Database();
        $this->evaluate = new Evaluate($this->store, $this->db);
    }

    /**
48
49
     * Starts save process. On succcess, returns forwardmode/page.
     *
50
51
     * @throws CodeException
     * @throws DbException
52
     * @throws UserFormException
53
54
     */
    public function process() {
55
        $rc = 0;
56
57
58
59
60
61

        if ($this->formSpec['multiMode'] !== 'none') {

            $parentRecords = $this->db->sql($this->formSpec['multiSql']);
            foreach ($parentRecords as $row) {
                $this->store->setVarArray($row, STORE_PARENT_RECORD, true);
62
                $rc = $this->elements($row['_id']);
63
64
            }
        } else {
65
66
            $recordId = $this->store->getVar(SIP_RECORD_ID, STORE_SIP . STORE_ZERO);
            $rc = $this->elements($recordId);
67
        }
68
69

        return $rc;
70
71
72
73
    }

    /**
     * @param $recordId
74
     * @return int   record id (in case of insert, it's different from $recordId)
75
76
     * @throws CodeException
     * @throws DbException
77
     * @throws UserFormException
78
79
     */
    public function elements($recordId) {
Carsten  Rose's avatar
Carsten Rose committed
80

81
82
83
        $newValues = array();

        $tableColumns = array_keys($this->store->getStore(STORE_TABLE_COLUMN_TYPES));
84
        $formValues = $this->store->getStore(STORE_FORM);
85

86
        $this->processAllUploads($formValues);
87

88
89
        // Iterate over all table.columns. Built an assoc array $newValues.
        foreach ($tableColumns AS $column) {
90

91
            // Never save a predefined 'id': autoincrement values will be given by database..
92
93
94
95
96
97
98
99
            if ($column === 'id')
                continue;

            // Get related formElement.
            $formElement = $this->getFormElementByName($column);
            if ($formElement === false)
                continue;

100
            // Preparation for Log, Debug
101
            $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($formElement), STORE_SYSTEM);
102

103
104
            Support::setIfNotSet($formValues, $column);
            $newValues[$column] = $formValues[$column];
105
106
        }

107
108
109
110
111
112
113
114
        if ($recordId == 0) {
            $rc = $this->insertRecord($this->formSpec['tableName'], $newValues);
        } else {
            $this->updateRecord($this->formSpec['tableName'], $newValues, $recordId);
            $rc = $recordId;
        }

        return $rc;
115
116
    }

117
    /**
118
     * Process all Upload Formelements for the given $recordId. After processing &$formValues will be updated with the final filenames.
119
120
121
     *
     * @param array $formValues
     */
122
    private function processAllUploads(array &$formValues) {
123
124
125

        foreach ($this->feSpecNative AS $formElement) {
            // skip non upload formElements
126
            if ($formElement[FE_TYPE] != 'upload') {
127
128
129
                continue;
            }

130
131
132
            // Preparation for Log, Debug
            $this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($formElement), STORE_SYSTEM);

133
            $column = $formElement['name'];
134
            $file = $this->doUpload($formElement, $formValues[$column]);
135
136
137
138
139
140
141
            if ($file !== false) {
                $formValues[$column] = $file;
            }
        }
    }

    /**
142
143
144
     * 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.
     *
145
146
147
148
149
150
151
152
153
     * @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) {

154
155

        // Status information about upload file
156
157
158
159
160
        $statusUpload = $this->store->getVar($sipUpload, STORE_EXTRA);
        if ($statusUpload === false) {
            return false;
        }

161
162
163
164
165
166
167
        // 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);
        }

168
169
170
171
172
        // 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)) {
173
                    throw new UserFormException('Unlink file failed: ' . $oldFile, ERROR_IO_UNLINK);
174
175
176
177
                }
            }
        }

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
        $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])) {
200

201
202
203
204
205
            // 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]);
206
207
        }

208
209
        if ($pathFileName === '') {
            throw new UserFormException("Upload failed, no target '" . FE_PATH_FILE_NAME . "' specified.", ERROR_NO_TARGET_PATH_FILE_NAME);
210
211
        }

212
213
214
        if (file_exists($pathFileName)) {
            throw new UserFormException('Copy upload failed - file already exist: ' . $pathFileName, ERROR_IO_FILE_EXIST);
        }
215

216
        Support::mkDirParent($pathFileName);
217

218
219
220
221
        $srcFile = Support::extendFilename($statusUpload[FILES_TMP_NAME], UPLOAD_CACHED);
        if (!rename($srcFile, $pathFileName)) {
            throw new UserFormException("Rename file: '$srcFile' > '$pathFileName'", ERROR_IO_RENAME);
        }
222

223
224
        return $pathFileName;
    }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
    /**
     * 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;
    }

    /**
     * Insert new record in table $this->formSpec['tableName'].
     *
     * @param array $values
243
     * @return int  last insert id
244
245
246
247
248
     * @throws DbException
     */
    public function insertRecord($tableName, array $values) {

        if (count($values) === 0)
249
            return 0; // nothing to write, last insert id=0
250
251
252
253
254
255
256

        $paramList = str_repeat('?, ', count($values));
        $paramList = substr($paramList, 0, strlen($paramList) - 2);
        $columnList = '`' . implode('`, `', array_keys($values)) . '`';

        $sql = 'INSERT INTO ' . $tableName . ' ( ' . $columnList . ' ) VALUES ( ' . $paramList . ' )';

257
        $rc = $this->db->sql($sql, ROW_REGULAR, array_values($values));
258

259
        return $rc;
260
261
262
    }

    /**
263
     * @param string $tableName
264
     * @param array $values
265
     * @param int $recordId
266
     * @return bool|int     false if $values is empty, else affectedrows
267
     * @throws CodeException
268
269
270
271
272
     * @throws DbException
     */
    public function updateRecord($tableName, array $values, $recordId) {

        if (count($values) === 0)
273
            return 0; // nothing to write, 0 rows affected
274
275
276
277

        if ($recordId === 0)
            throw new CodeException('RecordId=0 - this is not possible for update.', ERROR_RECORDID_0_FORBIDDEN);

278
279
//        $paramList = str_repeat('?, ', count($values));
//        $paramList = substr($paramList, 0, strlen($paramList) - 2);
280
281
282
283

        $sql = 'UPDATE `' . $tableName . '` SET ';

        foreach ($values as $column => $value) {
284

285
286
287
288
289
290
            $sql .= '`' . $column . '` = ?, ';
        }

        $sql = substr($sql, 0, strlen($sql) - 2) . ' WHERE id = ?';
        $values[] = $recordId;

291
292
293
        $rc = $this->db->sql($sql, ROW_REGULAR, array_values($values));

        return $rc;
294
295
296
    }

}