Passed
Pull Request — master (#688)
by Robbie
03:46
created

EditableCustomRule::getCanCreateContext()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 5

Duplication

Lines 13
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 3
nop 1
dl 13
loc 13
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\UserForms\Model;
4
5
use LogicException;
6
use SilverStripe\CMS\Controllers\CMSMain;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Core\Convert;
9
use SilverStripe\ORM\DataObject;
10
use Silverstripe\Versioned\Versioned;
11
12
/**
13
 * A custom rule for showing / hiding an EditableFormField
14
 * based the value of another EditableFormField.
15
 *
16
 * @method EditableFormField Parent()
17
 * @package userforms
18
 *
19
 * @property string Display
20
 * @property string ConditionOption
21
 * @property string FieldValue
22
 */
23
class EditableCustomRule extends DataObject
24
{
25
    private static $condition_options = [
0 ignored issues
show
introduced by
The private property $condition_options is not used, and could be removed.
Loading history...
26
        'IsBlank' => 'Is blank',
27
        'IsNotBlank' => 'Is not blank',
28
        'HasValue' => 'Equals',
29
        'ValueNot' => 'Doesn\'t equal',
30
        'ValueLessThan' => 'Less than',
31
        'ValueLessThanEqual' => 'Less than or equal',
32
        'ValueGreaterThan' => 'Greater than',
33
        'ValueGreaterThanEqual' => 'Greater than or equal'
34
    ];
35
36
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
37
        'Display' => 'Enum("Show,Hide")',
38
        'ConditionOption' => 'Enum("IsBlank,IsNotBlank,HasValue,ValueNot,ValueLessThan,ValueLessThanEqual,ValueGreaterThan,ValueGreaterThanEqual")',
39
        'FieldValue' => 'Varchar(255)'
40
    ];
41
42
    private static $has_one = [
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
43
        'Parent' => EditableFormField::class,
44
        'ConditionField' => EditableFormField::class
45
    ];
46
47
    /**
48
     * Built in extensions required
49
     *
50
     * @config
51
     * @var array
52
     */
53
    private static $extensions = [
0 ignored issues
show
introduced by
The private property $extensions is not used, and could be removed.
Loading history...
54 1
        Versioned::class . "('Stage', 'Live')"
55
    ];
56 1
57 1
    private static $table_name = 'EditableCustomRule';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
58
59
    /**
60
     * @param Member $member
0 ignored issues
show
Bug introduced by
The type SilverStripe\UserForms\Model\Member was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
61
     * @return bool
62
     */
63
    public function canDelete($member = null)
64
    {
65
        return $this->canEdit($member);
66
    }
67
68
    /**
69
     * @param Member $member
70
     * @return bool
71
     */
72
    public function canEdit($member = null)
73
    {
74
        return $this->Parent()->canEdit($member);
75
    }
76
77
    /**
78
     * @param Member $member
79
     * @return bool
80
     */
81
    public function canView($member = null)
82
    {
83
        return $this->Parent()->canView($member);
84
    }
85
86
    /**
87
     * Return whether a user can create an object of this type
88
     *
89
     * @param Member $member
90
     * @param array $context Virtual parameter to allow context to be passed in to check
91
     * @return bool
92
     */
93 View Code Duplication
    public function canCreate($member = null, $context = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
94
    {
95
        // Check parent page
96
        $parent = $this->getCanCreateContext(func_get_args());
97
        if ($parent) {
98
            return $parent->canEdit($member);
99
        }
100
101
        // Fall back to secure admin permissions
102
        return parent::canCreate($member);
103
    }
104
105
    /**
106
     * Helper method to check the parent for this object
107
     *
108
     * @param array $args List of arguments passed to canCreate
109
     * @return DataObject Some parent dataobject to inherit permissions from
110
     */
111 View Code Duplication
    protected function getCanCreateContext($args)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
112
    {
113
        // Inspect second parameter to canCreate for a 'Parent' context
114
        if (isset($args[1]['Parent'])) {
115
            return $args[1]['Parent'];
116
        }
117
        // Hack in currently edited page if context is missing
118
        if (Controller::has_curr() && Controller::curr() instanceof CMSMain) {
119
            return Controller::curr()->currentPage();
120
        }
121
122
        // No page being edited
123
        return null;
124
    }
125
126
    /**
127
     * @param Member $member
128
     * @return bool
129
     */
130
    public function canPublish($member = null)
131
    {
132
        return $this->canEdit($member);
133
    }
134
135
    /**
136
     * @param Member $member
137
     * @return bool
138
     */
139
    public function canUnpublish($member = null)
140
    {
141
        return $this->canDelete($member);
142
    }
143
144
    /**
145
     * Substitutes configured rule logic with it's JS equivalents and returns them as array elements
146
     *
147
     * @return array
148
     * @throws LogicException If the provided condition option was not able to be handled
149
     */
150
    public function buildExpression()
151
    {
152
        /** @var EditableFormField $formFieldWatch */
153
        $formFieldWatch = $this->ConditionField();
0 ignored issues
show
Bug introduced by
The method ConditionField() does not exist on SilverStripe\UserForms\Model\EditableCustomRule. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

153
        /** @scrutinizer ignore-call */ 
154
        $formFieldWatch = $this->ConditionField();
Loading history...
154
        //Encapsulated the action to the object
155
        $action = $formFieldWatch->getJsEventHandler();
156
157
        // is this field a special option field
158
        $checkboxField = $formFieldWatch->isCheckBoxField();
159 2
        $radioField = $formFieldWatch->isRadioField();
160
        $target = sprintf('$("%s")', $formFieldWatch->getSelectorFieldOnly());
161
        $fieldValue = Convert::raw2js($this->FieldValue);
162 2
163
        $conditionOptions = [
164 2
            'ValueLessThan'         => '<',
165
            'ValueLessThanEqual'    => '<=',
166
            'ValueGreaterThan'      => '>',
167 2
            'ValueGreaterThanEqual' => '>='
168 2
        ];
169 2
170 2
        // and what should we evaluate
171
        switch ($this->ConditionOption) {
172
            case 'IsNotBlank':
173 2
            case 'IsBlank':
174 2
                $expression = ($checkboxField || $radioField) ? "!{$target}.is(\":checked\")" : "{$target}.val() == ''";
175 2
                if ($this->ConditionOption == 'IsNotBlank') {
176
                    //Negate
177 2
                    $expression = "!({$expression})";
178
                }
179 2
                break;
180 2
            case 'HasValue':
181 2
            case 'ValueNot':
182
                if ($checkboxField) {
183
                    if ($formFieldWatch->isCheckBoxGroupField()) {
184
                        $expression = sprintf(
185
                            "$.inArray('%s', %s.filter(':checked').map(function(){ return $(this).val();}).get()) > -1",
186
                            $fieldValue,
187
                            $target
188 2
                        );
189 2
                    } else {
190 2
                        $expression = "{$target}.prop('checked')";
191
                    }
192
                } elseif ($radioField) {
193
                    // We cannot simply get the value of the radio group, we need to find the checked option first.
194
                    $expression = sprintf(
195
                        '%s.closest(".field, .control-group").find("input:checked").val() == "%s"',
196
                        $target,
197
                        $fieldValue
198
                    );
199
                } else {
200 2
                    $expression = sprintf('%s.val() == "%s"', $target, $fieldValue);
201
                }
202
203
                if ($this->ConditionOption == 'ValueNot') {
204
                    //Negate
205
                    $expression = "!({$expression})";
206
                }
207
                break;
208 2
            case 'ValueLessThan':
209
            case 'ValueLessThanEqual':
210
            case 'ValueGreaterThan':
211 2
            case 'ValueGreaterThanEqual':
212
                $expression = sprintf(
213
                    '%s.val() %s parseFloat("%s")',
214
                    $target,
215 2
                    $conditionOptions[$this->ConditionOption],
216 1
                    $fieldValue
217 1
                );
218 1
                break;
219 1
            default:
220 1
                throw new LogicException("Unhandled rule {$this->ConditionOption}");
221 1
                break;
222 1
        }
223 1
224
        $result = [
225 1
            'operation' => $expression,
226 1
            'event'     => $action,
227
        ];
228
229
        return $result;
230 2
    }
231
232
    /**
233 2
     * Returns the opposite visibility function for the value of the initial visibility field, e.g. show/hide. This
234 2
     * will toggle the "hide" class either way, which is handled by CSS.
235 2
     *
236
     * @param string $text
237 2
     * @return string
238
     */
239
    public function toggleDisplayText($text)
240
    {
241
        return (strtolower($text) === 'hide') ? 'removeClass("hide")' : 'addClass("hide")';
242
    }
243
}
244