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

PartialUserFormController::uploadFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 3
nc 3
nop 2
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\HTTPRequest;
13
use SilverStripe\Control\HTTPResponse_Exception;
14
use SilverStripe\ORM\DataObject;
15
use SilverStripe\ORM\FieldType\DBHTMLText;
16
use SilverStripe\ORM\ValidationException;
17
use SilverStripe\UserForms\Control\UserDefinedFormController;
18
use SilverStripe\UserForms\Model\EditableFormField;
19
use SilverStripe\UserForms\Model\UserDefinedForm;
20
use SilverStripe\View\Requirements;
21
22
/**
23
 * Class PartialUserFormController
24
 *
25
 * @package Firesphere\PartialUserforms\Controllers
26
 */
27
class PartialUserFormController extends ContentController
28
{
29
    /**
30
     * Session key name
31
     */
32
    public const SESSION_KEY = 'PartialSubmissionID';
33
34
    /**
35
     * @var array
36
     */
37
    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...
38
        'save'        => 'savePartialSubmission',
39
        '$Key/$Token' => 'partial',
40
    ];
41
42
    /**
43
     * @var array
44
     */
45
    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...
46
        'savePartialSubmission',
47
        'partial',
48
    ];
49
50
    /**
51
     * @param HTTPRequest $request
52
     * @return int|mixed|void
53
     * @throws ValidationException
54
     * @throws HTTPResponse_Exception
55
     */
56
    public function savePartialSubmission(HTTPRequest $request)
57
    {
58
        if (!$request->isPOST()) {
59
            return $this->httpError(404);
60
        }
61
62
        $postVars = $request->postVars();
63
        $editableField = null;
64
65
        // We don't want SecurityID and/or the process Action stored as a thing
66
        unset($postVars['SecurityID'], $postVars['action_process']);
67
        $submissionID = $request->getSession()->get(self::SESSION_KEY);
68
69
        /** @var PartialFormSubmission $partialSubmission */
70
        $partialSubmission = PartialFormSubmission::get()->byID($submissionID);
71
72
        if (!$submissionID || !$partialSubmission) {
73
            $partialSubmission = PartialFormSubmission::create();
74
            $submissionID = $partialSubmission->write();
75
        }
76
        $request->getSession()->set(self::SESSION_KEY, $submissionID);
77
        foreach ($postVars as $field => $value) {
78
            /** @var EditableFormField $editableField */
79
            $editableField = $this->createOrUpdateSubmission([
80
                'Name'            => $field,
81
                'Value'           => $value,
82
                'SubmittedFormID' => $submissionID
83
            ]);
84
        }
85
86
        // @todo this is an ugly hack to get the ID and ClassName out of the Fields.
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
        if (!$partialFileSubmission && $editableField) {
137
            $partialData['Title'] = $editableField->Title;
138
            $partialData['ParentClass'] = $editableField->Parent()->ClassName;
139
        }
140
        // Don't overwrite existing uploads
141
        if (is_array($formData['Value']) && !$partialFileSubmission->UploadedFileID) {
142
            $file = $this->uploadFile($partialData, $editableField);
143
            $formData['UploadedFileID'] = $file->ID ?? 0;
144
            $partialFileSubmission = PartialFileFieldSubmission::create($partialData);
145
        }
146
        $partialFileSubmission->write();
147
    }
148
149
    /**
150
     * @param array $formData
151
     * @param EditableFormField\EditableFileField $field
152
     * @return bool|File
153
     * @throws Exception
154
     */
155
    protected function uploadFile($formData, $field)
156
    {
157
        if (!empty($formData['Value']['name'])) {
158
            $foldername = $field->getFormField()->getFolderName();
159
160
            // create the file from post data
161
            $upload = Upload::create();
162
            $file = File::create();
163
            $file->ShowInSearch = 0;
164
            if ($upload->loadIntoFile($formData['Value'], $file, $foldername)) {
165
                return $file;
166
            }
167
        }
168
169
        return false;
170
    }
171
172
    /**
173
     * @param $formData
174
     * @param array $filter
175
     * @param EditableFormField $editableField
176
     * @throws ValidationException
177
     */
178
    protected function savePartialField($formData, array $filter, EditableFormField $editableField)
179
    {
180
        $exists = PartialFieldSubmission::get()->filter($filter)->first();
181
        if (is_array($formData['Value'])) {
182
            $formData['Value'] = implode(', ', $formData['Value']);
183
        }
184
        if ($editableField) {
185
            $formData['Title'] = $editableField->Title;
186
            $formData['ParentClass'] = $editableField->Parent()->ClassName;
187
        }
188
        if (!$exists) {
189
            $exists = PartialFieldSubmission::create($formData);
190
        } else {
191
            $exists->update($formData);
192
        }
193
        $exists->write();
194
    }
195
196
    /**
197
     * Partial form
198
     *
199
     * @param HTTPRequest $request
200
     * @return DBHTMLText|void
201
     * @throws HTTPResponse_Exception
202
     * @throws Exception
203
     */
204
    public function partial(HTTPRequest $request)
205
    {
206
        $key = $request->param('Key');
207
        $token = $request->param('Token');
208
209
        /** @var PartialFormSubmission $partial */
210
        $partial = PartialFormSubmission::get()->find('Token', $token);
211
        if (!$token || !$partial || !$partial->UserDefinedFormID) {
212
            return $this->httpError(404);
213
        }
214
215
        if ($partial->generateKey($token) === $key) {
216
            // Set the session if the last session has expired
217
            if (!$request->getSession()->get(self::SESSION_KEY)) {
218
                $request->getSession()->set(self::SESSION_KEY, $partial->ID);
219
            }
220
221
            // TODO: Recognize visitor with the password
222
            // TODO: Populate form values
223
224
            // Could be done as $class = $partial->UserDefinedFormClass;$class::get()->byID();
225
            /** @var UserDefinedForm $record */
226
            $record = DataObject::get_by_id($partial->UserDefinedFormClass, $partial->UserDefinedFormID);
0 ignored issues
show
Documentation introduced by
The property UserDefinedFormClass does not exist on object<Firesphere\Partia...\PartialFormSubmission>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
227
            $controller = new UserDefinedFormController($record);
228
            $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...
229
230
            Requirements::javascript('firesphere/partialuserforms:client/dist/main.js');
231
232
            return $this->customise([
233
                'Title'       => $record->Title,
234
                'Breadcrumbs' => $record->Breadcrumbs(),
235
                'Content'     => $this->obj('Content'),
236
                'Form'        => $controller->Form(),
237
                'Link'        => $partial->getPartialLink()
238
            ])->renderWith(['PartialUserForm', 'Page']);
239
        }
240
241
        return $this->httpError(404);
242
    }
243
}
244