Completed
Pull Request — master (#406)
by Damian
02:24
created

RemoteFileFormFactory   B

Complexity

Total Complexity 22

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 16
dl 0
loc 171
rs 8.4614
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getForm() 0 23 3
A getRequiredContext() 0 4 1
B getFormFields() 0 65 6
A getFormActions() 0 21 3
C validateUrl() 0 26 8
A getEmbed() 0 6 1
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Forms;
4
5
use Embed\Exceptions\InvalidUrlException;
6
use InvalidArgumentException;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Core\Config\Configurable;
10
use SilverStripe\Core\Extensible;
11
use SilverStripe\Forms\CompositeField;
12
use SilverStripe\Forms\FieldGroup;
13
use SilverStripe\Forms\FieldList;
14
use SilverStripe\Forms\Form;
15
use SilverStripe\Forms\FormAction;
16
use SilverStripe\Forms\FormFactory;
17
use SilverStripe\Forms\HeaderField;
18
use SilverStripe\Forms\HiddenField;
19
use SilverStripe\Forms\HTMLEditor\HTMLEditorField_Embed;
20
use SilverStripe\Forms\LabelField;
21
use SilverStripe\Forms\LiteralField;
22
use SilverStripe\Forms\OptionsetField;
23
use SilverStripe\Forms\ReadonlyField;
24
use SilverStripe\Forms\RequiredFields;
25
use SilverStripe\Forms\TextField;
26
27
class RemoteFileFormFactory implements FormFactory
28
{
29
    use Extensible;
30
    use Configurable;
31
32
    private static $fileurl_scheme_whitelist = ['http', 'https'];
0 ignored issues
show
Unused Code introduced by
The property $fileurl_scheme_whitelist is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
33
34
    private static $fileurl_domain_whitelist = [];
0 ignored issues
show
Unused Code introduced by
The property $fileurl_domain_whitelist is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
35
36
    /**
37
     * @param Controller $controller
38
     * @param string $name
39
     * @param array $context
40
     * @return Form
41
     */
42
    public function getForm(Controller $controller, $name = self::DEFAULT_NAME, $context = [])
43
    {
44
        // Validate context
45
        foreach ($this->getRequiredContext() as $required) {
46
            if (!isset($context[$required])) {
47
                throw new InvalidArgumentException("Missing required context $required");
48
            }
49
        }
50
51
        $fields = $this->getFormFields($controller, $name, $context);
52
        $actions = $this->getFormActions($controller, $name, $context);
53
54
        $validator = new RequiredFields();
55
        $form = Form::create($controller, $name, $fields, $actions, $validator);
56
        $form->addExtraClass('form--fill-height');
57
        $form->addExtraClass('form--no-dividers');
58
        $form->addExtraClass('insert-embed-modal--'. strtolower($context['type']));
59
60
        // Extend form
61
        $this->invokeWithExtensions('updateForm', $form, $controller, $name, $context);
62
63
        return $form;
64
    }
65
66
    public function getRequiredContext()
67
    {
68
        return ['type'];
69
    }
70
71
    protected function getFormFields($controller, $name, $context)
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
72
    {
73
        $fields = [];
74
        $url = (isset($context['url'])) ? $context['url'] : null;
75
76
        if ($context['type'] === 'create') {
77
            $fields = [
78
                TextField::create('Url',
79
                    _t(
80
                        'RemoteFileForm.UrlDescription',
81
                        'Embed Youtube and Vimeo videos, images and other media directly from the web.'
82
                    )
83
                )
84
                ->addExtraClass('insert-embed-modal__url-create'),
85
            ];
86
        }
87
88
        if ($context['type'] === 'edit' && $url && $this->validateUrl($url)) {
89
            $embed = $this->getEmbed($url);
90
            $alignments = array(
91
                'leftAlone' => _t('AssetAdmin.AlignmentLeftAlone', 'Left'),
92
                'center' => _t('AssetAdmin.AlignmentCenter', 'Center'),
93
                'rightAlone' => _t('AssetAdmin.AlignmentRightAlone', 'Right'),
94
                'left' => _t('AssetAdmin.AlignmentLeft', 'Left wrap'),
95
                'right' => _t('AssetAdmin.AlignmentRight', 'Right wrap'),
96
            );
97
98
            $fields = CompositeField::create([
99
                LiteralField::create(
100
                    'Preview',
101
                    sprintf(
102
                        '<img src="%s" class="%s" />',
103
                        $embed->getPreviewURL(),
104
                        'insert-embed-modal__preview'
105
                    )
106
                )->addExtraClass('insert-embed-modal__preview-container'),
107
                HiddenField::create('PreviewUrl', 'PreviewUrl', $embed->getPreviewURL()),
108
                CompositeField::create([
109
                    TextField::create('UrlPreview', $embed->getName(), $url)
110
                        ->setReadonly(true),
111
                    HiddenField::create('Url', false, $url),
112
                    TextField::create('CaptionText', _t('AssetAdmin.Caption', 'Caption')),
113
                    OptionsetField::create(
114
                        'Placement',
115
                        _t('AssetAdmin.Placement', 'Placement'),
116
                        $alignments
117
                    )
118
                        ->addExtraClass('insert-embed-modal__placement'),
119
                    FieldGroup::create(
120
                        _t('AssetAdmin.ImageSpecs', 'Dimensions'),
121
                        TextField::create('Width', '', $embed->getWidth())
122
                            ->setRightTitle(_t('AssetAdmin.ImageWidth', 'Width'))
123
                            ->setMaxLength(5)
124
                            ->addExtraClass('flexbox-area-grow'),
125
                        TextField::create('Height', '', $embed->getHeight())
126
                            ->setRightTitle(_t('AssetAdmin.ImageHeight', 'Height'))
127
                            ->setMaxLength(5)
128
                            ->addExtraClass('flexbox-area-grow')
129
                    )->addExtraClass('fieldgroup--fill-width')
130
                ])->addExtraClass('flexbox-area-grow'),
131
            ])->addExtraClass('insert-embed-modal__fields--fill-width');
132
        }
133
134
        return FieldList::create($fields);
135
    }
136
137
    protected function getFormActions($controller, $name, $context)
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
138
    {
139
        $actions = [];
140
141
        if ($context['type'] === 'create') {
142
            $actions = [
143
                FormAction::create('addmedia', _t('RemoteFileForm.AddMedia', 'Add media'))
144
                    ->setSchemaData(['data' => ['buttonStyle' => 'primary']]),
145
            ];
146
        }
147
148
        if ($context['type'] === 'edit') {
149
            $actions = [
150
                FormAction::create('insertmedia', _t('RemoteFileForm.InsertMedia', 'Insert media'))
151
                    ->setSchemaData(['data' => ['buttonStyle' => 'primary']]),
152
                FormAction::create('cancel', _t('RemoteFileForm.Cancel', 'Cancel')),
153
            ];
154
        }
155
156
        return FieldList::create($actions);
157
    }
158
159
    /**
160
     * @param $url
161
     * @return bool
162
     * @throws InvalidUrlException
163
     */
164
    protected function validateUrl($url)
165
    {
166
        if (!Director::is_absolute_url($url)) {
167
            throw new InvalidUrlException(_t(
168
                "HTMLEditorField_Toolbar.ERROR_ABSOLUTE",
169
                "Only absolute urls can be embedded"
170
            ));
171
        }
172
        $scheme = strtolower(parse_url($url, PHP_URL_SCHEME));
173
        $allowed_schemes = self::config()->get('fileurl_scheme_whitelist');
174
        if (!$scheme || ($allowed_schemes && !in_array($scheme, $allowed_schemes))) {
175
            throw new InvalidUrlException(_t(
176
                "HTMLEditorField_Toolbar.ERROR_SCHEME",
177
                "This file scheme is not included in the whitelist"
178
            ));
179
        }
180
        $domain = strtolower(parse_url($url, PHP_URL_HOST));
181
        $allowed_domains = self::config()->get('fileurl_domain_whitelist');
182
        if (!$domain || ($allowed_domains && !in_array($domain, $allowed_domains))) {
183
            throw new InvalidUrlException(_t(
184
                "HTMLEditorField_Toolbar.ERROR_HOSTNAME",
185
                "This file hostname is not included in the whitelist"
186
            ));
187
        }
188
        return true;
189
    }
190
191
    protected function getEmbed($url)
192
    {
193
        $embed = new HTMLEditorField_Embed($url);
194
195
        return $embed;
196
    }
197
}
198