Completed
Pull Request — master (#12)
by Simon
01:30
created

PartialFormSubmission::canDelete()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Firesphere\PartialUserforms\Models;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Forms\FieldList;
8
use SilverStripe\Forms\GridField\GridField;
9
use SilverStripe\Forms\GridField\GridFieldButtonRow;
10
use SilverStripe\Forms\GridField\GridFieldConfig;
11
use SilverStripe\Forms\GridField\GridFieldDataColumns;
12
use SilverStripe\Forms\GridField\GridFieldExportButton;
13
use SilverStripe\Forms\GridField\GridFieldPrintButton;
14
use SilverStripe\Forms\ReadonlyField;
15
use SilverStripe\ORM\DataList;
16
use SilverStripe\ORM\DataObject;
17
use SilverStripe\Security\Member;
18
use SilverStripe\Security\RandomGenerator;
19
use SilverStripe\UserForms\Model\Submission\SubmittedForm;
20
use SilverStripe\UserForms\Model\UserDefinedForm;
21
22
/**
23
 * Class \Firesphere\PartialUserforms\Models\PartialFormSubmission
24
 *
25
 * @property boolean $IsSend
26
 * @property string $Password
27
 * @property int $UserDefinedFormID
28
 * @method DataObject UserDefinedForm()
29
 * @method DataList|PartialFieldSubmission[] PartialFields()
30
 */
31
class PartialFormSubmission extends SubmittedForm
32
{
33
    private static $table_name = 'PartialFormSubmission';
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...
34
35
    /**
36
     * @var array
37
     */
38
    private static $db = [
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
        'IsSend'    => 'Boolean(false)',
40
        'TokenSalt' => 'Varchar(16)',
41
        'Token'     => 'Varchar(16)',
42
        'Password' => 'Varchar(64)',
43
    ];
44
45
    /**
46
     * @var array
47
     */
48
    private static $has_one = [
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...
49
        'UserDefinedForm' => DataObject::class
50
    ];
51
52
    /**
53
     * @var array
54
     */
55
    private static $has_many = [
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...
56
        'PartialFields' => PartialFieldSubmission::class
57
    ];
58
59
    private static $cascade_deletes = [
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...
60
        'PartialFields'
61
    ];
62
63
    /**
64
     * @var array
65
     */
66
    private static $summary_fields = [
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...
67
        'ID'            => 'ID',
68
        'PartialLink'   => 'Link',
69
        'Created'       => 'Created',
70
        'LastEdited'    => 'Last Edited',
71
    ];
72
73
    private static $special_characters = [
74
        '!',
75
        '@',
76
        '#',
77
        '$',
78
        '%',
79
        '^',
80
        '&',
81
        '*',
82
        '(',
83
        ')',
84
        '_',
85
        '-',
86
        '=',
87
        '+',
88
        ';',
89
        ':',
90
        ',',
91
        '.',
92
        '?'
93
    ];
94
95
    /**
96
     * @return FieldList
97
     */
98
    public function getCMSFields()
99
    {
100
        /** @var FieldList $fields */
101
        $fields = parent::getCMSFields();
102
        $fields->removeByName(['Values', 'IsSend', 'PartialFields', 'TokenSalt', 'Token', 'UserDefinedFormID', 'Submitter']);
103
104
        $partialFields = GridField::create(
105
            'PartialFields',
106
            _t(static::class . '.PARTIALFIELDS', 'Partial fields'),
107
            $this->PartialFields()->sort('Created', 'ASC')
108
        );
109
110
        $exportColumns =[
111
            'Title'       => 'Title',
112
            'ExportValue' => 'Value'
113
        ];
114
115
        $config = new GridFieldConfig();
116
        $config->addComponent(new GridFieldDataColumns());
117
        $config->addComponent(new GridFieldButtonRow('after'));
118
        $config->addComponent(new GridFieldExportButton('buttons-after-left', $exportColumns));
119
        $config->addComponent(new GridFieldPrintButton('buttons-after-left'));
120
        $partialFields->setConfig($config);
121
122
        $fields->addFieldsToTab(
123
            'Root.Main',
124
            [
125
                ReadonlyField::create('ReadonlyPartialLink', 'Partial Link', $this->getPartialLink()),
126
                $partialFields
127
            ]
128
        );
129
130
        return $fields;
131
    }
132
133
    /**
134
     * @return DataObject|UserDefinedForm
135
     */
136
    public function getParent()
137
    {
138
        return $this->UserDefinedForm();
139
    }
140
141
    /**
142
     * If the submission is password protected, generate a password.
143
     */
144
    public function onBeforeWrite()
145
    {
146
        parent::onBeforeWrite();
147
        if (!$this->Password &&
148
            $this->getParent() &&
149
            $this->getParent()->PasswordProtected
150
        ) {
151
            $chars = range('A', 'Z');
152
            $chars = array_merge($chars, range('a', 'z'));
153
            $chars = array_merge($chars, range(0, 9));
154
            $chars = array_merge($chars, self::$special_characters);
155
            shuffle($chars);
156
            $pwd = implode(array_slice($chars, 0, 10));
157
            $this->Password = hash('SHA256', $pwd);
158
            Controller::curr()->getRequest()->getSession()->set('FormPassword', $pwd);
159
        }
160
    }
161
162
    /**
163
     * @param Member
164
     *
165
     * @return boolean|string
166
     */
167
    public function canCreate($member = null, $context = [])
168
    {
169
        if ($this->UserDefinedForm()) {
170
            return $this->UserDefinedForm()->canCreate($member, $context);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()...ate($member, $context); of type boolean|string adds the type string to the return on line 170 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...ubmittedForm::canCreate of type boolean.
Loading history...
171
        }
172
173
        return parent::canCreate($member);
174
    }
175
176
    /**
177
     * @param Member
178
     *
179
     * @return boolean|string
180
     */
181
    public function canView($member = null)
182
    {
183
        if ($this->UserDefinedForm()) {
184
            return $this->UserDefinedForm()->canView($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canView($member); of type boolean|string adds the type string to the return on line 184 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...\SubmittedForm::canView of type boolean.
Loading history...
185
        }
186
187
        return parent::canView($member);
188
    }
189
190
    /**
191
     * @param Member
192
     *
193
     * @return boolean|string
194
     */
195
    public function canEdit($member = null)
196
    {
197
        if ($this->UserDefinedForm()) {
198
            return $this->UserDefinedForm()->canEdit($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canEdit($member); of type boolean|string adds the type string to the return on line 198 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...\SubmittedForm::canEdit of type boolean.
Loading history...
199
        }
200
201
        return parent::canEdit($member);
202
    }
203
204
    /**
205
     * @param Member
206
     *
207
     * @return boolean|string
208
     */
209
    public function canDelete($member = null)
210
    {
211
        if ($this->UserDefinedForm()) {
212
            return $this->UserDefinedForm()->canDelete($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canDelete($member); of type boolean|string adds the type string to the return on line 212 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...ubmittedForm::canDelete of type boolean.
Loading history...
213
        }
214
215
        return parent::canDelete($member);
216
    }
217
218
    /**
219
     * Get the share link of the form
220
     *
221
     * @return string
222
     * @throws \Exception
223
     */
224
    public function getPartialLink()
225
    {
226
        if (!$this->isInDB()) {
227
            return '(none)';
228
        }
229
230
        $token = $this->getPartialToken();
231
232
        return Controller::join_links(
233
            Director::absoluteBaseURL(),
234
            'partial',
235
            $this->generateKey($token),
0 ignored issues
show
Bug introduced by
It seems like $token defined by $this->getPartialToken() on line 230 can also be of type boolean or null; however, Firesphere\PartialUserfo...bmission::generateKey() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
236
            $token
237
        );
238
    }
239
240
    /**
241
     * Get the unique token for the share link
242
     *
243
     * @return bool|string|null
244
     * @throws \Exception
245
     */
246
    protected function getPartialToken()
247
    {
248
        if (!$this->TokenSalt) {
0 ignored issues
show
Documentation introduced by
The property TokenSalt 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...
249
            $this->TokenSalt = $this->generateToken();
0 ignored issues
show
Documentation introduced by
The property TokenSalt does not exist on object<Firesphere\Partia...\PartialFormSubmission>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
250
            $this->Token = $this->generateToken();
0 ignored issues
show
Documentation introduced by
The property Token does not exist on object<Firesphere\Partia...\PartialFormSubmission>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
251
            $this->write();
252
        }
253
254
        return $this->Token;
0 ignored issues
show
Documentation introduced by
The property Token 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...
255
    }
256
257
    /**
258
     * Generate a new token
259
     *
260
     * @return bool|string
261
     * @throws \Exception
262
     */
263
    protected function generateToken()
264
    {
265
        $generator = new RandomGenerator();
266
267
        return substr($generator->randomToken('sha256'), 0, 16);
268
    }
269
270
    /**
271
     * Generate a key based on the share token salt
272
     *
273
     * @param string $token
274
     * @return mixed
275
     */
276
    public function generateKey($token)
277
    {
278
        return hash_pbkdf2('sha256', $token, $this->TokenSalt, 1000, 16);
0 ignored issues
show
Documentation introduced by
The property TokenSalt 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...
279
    }
280
}
281