Completed
Pull Request — master (#16)
by Simon
01:41
created

PartialUserFormController   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 17
dl 0
loc 222
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
B savePartialSubmission() 0 42 7
A createOrUpdateSubmission() 0 19 3
A savePartialFile() 0 18 5
A uploadFile() 0 24 4
A savePartialField() 0 17 4
B partial() 0 36 6
1
<?php
2
3
namespace Firesphere\PartialUserforms\Controllers;
4
5
use Exception;
6
use Firesphere\PartialUserforms\Models\PartialFieldSubmission;
7
use Firesphere\PartialUserforms\Models\PartialFileFieldSubmission;
8
use Firesphere\PartialUserforms\Models\PartialFormSubmission;
9
use SilverStripe\Assets\File;
10
use SilverStripe\Assets\Upload;
11
use SilverStripe\CMS\Controllers\ContentController;
12
use SilverStripe\Control\Controller;
13
use SilverStripe\Control\HTTPRequest;
14
use SilverStripe\Control\HTTPResponse_Exception;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\ORM\FieldType\DBHTMLText;
17
use SilverStripe\ORM\ValidationException;
18
use SilverStripe\ORM\ValidationResult;
19
use SilverStripe\UserForms\Control\UserDefinedFormController;
20
use SilverStripe\UserForms\Model\EditableFormField;
21
use SilverStripe\View\Requirements;
22
23
/**
24
 * Class PartialUserFormController
25
 *
26
 * @package Firesphere\PartialUserforms\Controllers
27
 */
28
class PartialUserFormController extends ContentController
29
{
30
    /**
31
     * Session key name
32
     */
33
    const SESSION_KEY = 'PartialSubmissionID';
34
35
    /**
36
     * @var array
37
     */
38
    private static $url_handlers = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
39
        'save'        => 'savePartialSubmission',
40
        '$Key/$Token' => 'partial',
41
    ];
42
43
    /**
44
     * @var array
45
     */
46
    private static $allowed_actions = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
47
        'savePartialSubmission',
48
        'partial',
49
    ];
50
51
    /**
52
     * @param HTTPRequest $request
53
     * @return int|mixed|void
54
     * @throws ValidationException
55
     * @throws HTTPResponse_Exception
56
     */
57
    public function savePartialSubmission(HTTPRequest $request)
58
    {
59
        if (!$request->isPOST()) {
60
            return $this->httpError(404);
61
        }
62
63
        $postVars = $request->postVars();
64
        $editableField = null;
65
66
        // We don't want SecurityID and/or the process Action stored as a thing
67
        unset($postVars['SecurityID'], $postVars['action_process']);
68
        $submissionID = $request->getSession()->get(self::SESSION_KEY);
69
70
        /** @var PartialFormSubmission $partialSubmission */
71
        $partialSubmission = PartialFormSubmission::get()->byID($submissionID);
72
73
        if (!$submissionID || !$partialSubmission) {
74
            $partialSubmission = PartialFormSubmission::create();
75
            $submissionID = $partialSubmission->write();
76
        }
77
        $request->getSession()->set(self::SESSION_KEY, $submissionID);
78
        foreach ($postVars as $field => $value) {
79
            /** @var EditableFormField $editableField */
80
            $editableField = $this->createOrUpdateSubmission([
81
                'Name'            => $field,
82
                'Value'           => $value,
83
                'SubmittedFormID' => $submissionID
84
            ]);
85
        }
86
87
        if ($editableField instanceof EditableFormField && !$partialSubmission->UserDefinedFormID) {
88
            $partialSubmission->update([
89
                'UserDefinedFormID'    => $editableField->Parent()->ID,
90
                'ParentID'             => $editableField->Parent()->ID,
91
                'ParentClass'          => $editableField->Parent()->ClassName,
92
                'UserDefinedFormClass' => $editableField->Parent()->ClassName
93
            ]);
94
            $partialSubmission->write();
95
        }
96
97
        return $submissionID;
98
    }
99
100
    /**
101
     * @param $formData
102
     * @return DataObject|EditableFormField
103
     * @throws ValidationException
104
     */
105
    protected function createOrUpdateSubmission($formData)
106
    {
107
        $filter = [
108
            'Name'            => $formData['Name'],
109
            'SubmittedFormID' => $formData['SubmittedFormID'],
110
        ];
111
112
        // Set the title
113
        /** @var EditableFormField $editableField */
114
        $editableField = EditableFormField::get()->filter(['Name' => $formData['Name']])->first();
115
        if ($editableField instanceof EditableFormField\EditableFileField) {
116
            $this->savePartialFile($formData, $filter, $editableField);
117
        } elseif ($editableField instanceof EditableFormField) {
118
            $this->savePartialField($formData, $filter, $editableField);
119
        }
120
121
        // Return the ParentID to link the PartialSubmission to it's proper thingy
122
        return $editableField;
123
    }
124
125
    /**
126
     * @param $formData
127
     * @param array $filter
128
     * @param EditableFormField\EditableFileField $editableField
129
     * @throws ValidationException
130
     * @throws Exception
131
     */
132
    protected function savePartialFile($formData, array $filter, EditableFormField\EditableFileField $editableField)
133
    {
134
        $partialFileSubmission = PartialFileFieldSubmission::get()->filter($filter)->first();
135
        $partialData = [];
136
        // Don't overwrite existing uploads
137
        if (!$partialFileSubmission) {
138
            if ($editableField) {
139
                $partialData['Title'] = $editableField->Title;
140
                $partialData['ParentClass'] = $editableField->Parent()->ClassName;
141
            }
142
        }
143
        if (is_array($formData['Value']) && !$partialFileSubmission->UploadedFileID) {
144
            $file = $this->uploadFile($partialData, $editableField);
145
            $formData['UploadedFileID'] = $file->ID ?? 0;
146
            $partialFileSubmission = PartialFileFieldSubmission::create($partialData);
147
        }
148
        $partialFileSubmission->write();
149
    }
150
151
    /**
152
     * @param array $formData
153
     * @param EditableFormField\EditableFileField $field
154
     * @return File|void
155
     * @throws Exception
156
     */
157
    protected function uploadFile($formData, $field)
158
    {
159
        if (!empty($formData['Value']['name'])) {
160
            $foldername = $field->getFormField()->getFolderName();
161
162
            // create the file from post data
163
            $upload = Upload::create();
164
            $file = File::create();
165
            $file->ShowInSearch = 0;
166
            try {
167
                $upload->loadIntoFile($formData['Value'], $file, $foldername);
168
            } catch (ValidationException $e) {
169
                $validationResult = $e->getResult();
170
                foreach ($validationResult->getMessages() as $message) {
171
                    $field->Parent()->sessionMessage($message['message'], ValidationResult::TYPE_ERROR);
172
                }
173
                Controller::curr()->redirectBack();
174
175
                return;
176
            }
177
178
            return $file;
179
        }
180
    }
181
182
    /**
183
     * @param $formData
184
     * @param array $filter
185
     * @param EditableFormField $editableField
186
     * @throws ValidationException
187
     */
188
    protected function savePartialField($formData, array $filter, EditableFormField $editableField)
189
    {
190
        $exists = PartialFieldSubmission::get()->filter($filter)->first();
191
        if (is_array($formData['Value'])) {
192
            $formData['Value'] = implode(', ', $formData['Value']);
193
        }
194
        if ($editableField) {
195
            $formData['Title'] = $editableField->Title;
196
            $formData['ParentClass'] = $editableField->Parent()->ClassName;
197
        }
198
        if (!$exists) {
199
            $exists = PartialFieldSubmission::create($formData);
200
        } else {
201
            $exists->update($formData);
202
        }
203
        $exists->write();
204
    }
205
206
    /**
207
     * Partial form
208
     *
209
     * @param HTTPRequest $request
210
     * @return DBHTMLText|void
211
     * @throws HTTPResponse_Exception
212
     */
213
    public function partial(HTTPRequest $request)
214
    {
215
        $key = $request->param('Key');
216
        $token = $request->param('Token');
217
218
        $partial = PartialFormSubmission::get()->find('Token', $token);
219
        if (!$token || !$partial || !$partial->UserDefinedFormID) {
220
            return $this->httpError(404);
221
        }
222
223
        if ($partial->generateKey($token) === $key) {
224
            // Set the session if the last session has expired
225
            if (!$request->getSession()->get(self::SESSION_KEY)) {
226
                $request->getSession()->set(self::SESSION_KEY, $partial->ID);
227
            }
228
229
            // TODO: Recognize visitor with the password
230
            // TODO: Populate form values
231
232
            $record = DataObject::get_by_id($partial->UserDefinedFormClass, $partial->UserDefinedFormID);
233
            $controller = new UserDefinedFormController($record);
234
            $controller->init();
0 ignored issues
show
Bug introduced by
The method init() cannot be called from this context as it is declared protected in class SilverStripe\UserForms\C...erDefinedFormController.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
235
236
            Requirements::javascript('firesphere/partialuserforms:client/dist/main.js');
237
238
            return $this->customise([
239
                'Title'       => $record->Title,
240
                'Breadcrumbs' => $record->Breadcrumbs(),
241
                'Content'     => $this->obj('Content'),
242
                'Form'        => $controller->Form(),
243
                'Link'        => $partial->getPartialLink()
244
            ])->renderWith(['PartialUserForm', 'Page']);
245
        } else {
246
            return $this->httpError(404);
247
        }
248
    }
249
}
250