Completed
Push — master ( 23423a...b8da20 )
by Damian
14s
created

RemoteFileFormFactory::getFormFields()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 3
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Forms;
4
5
use Embed\Exceptions\InvalidUrlException;
6
use InvalidArgumentException;
7
use SilverStripe\AssetAdmin\Model\EmbedResource;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Control\RequestHandler;
10
use SilverStripe\Core\Config\Configurable;
11
use SilverStripe\Core\Extensible;
12
use SilverStripe\Forms\CompositeField;
13
use SilverStripe\Forms\FieldGroup;
14
use SilverStripe\Forms\FieldList;
15
use SilverStripe\Forms\Form;
16
use SilverStripe\Forms\FormAction;
17
use SilverStripe\Forms\FormFactory;
18
use SilverStripe\Forms\HiddenField;
19
use SilverStripe\Forms\LiteralField;
20
use SilverStripe\Forms\OptionsetField;
21
use SilverStripe\Forms\RequiredFields;
22
use SilverStripe\Forms\TextField;
23
24
class RemoteFileFormFactory implements FormFactory
25
{
26
    use Extensible;
27
    use Configurable;
28
29
    /**
30
     * Force whitelist for resource protocols to the given list
31
     *
32
     * @config
33
     * @var array
34
     */
35
    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...
36
37
    /**
38
     * Force whitelist for resource domains to the given list
39
     *
40
     * @config
41
     * @var array
42
     */
43
    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...
44
45
    /**
46
     * @param RequestHandler $controller
47
     * @param string $name
48
     * @param array $context
49
     * @return Form
50
     */
51
    public function getForm(RequestHandler $controller = null, $name = self::DEFAULT_NAME, $context = [])
52
    {
53
        // Validate context
54
        foreach ($this->getRequiredContext() as $required) {
55
            if (!isset($context[$required])) {
56
                throw new InvalidArgumentException("Missing required context $required");
57
            }
58
        }
59
60
        $fields = $this->getFormFields($controller, $name, $context);
61
        $actions = $this->getFormActions($controller, $name, $context);
62
63
        $validator = new RequiredFields();
64
        $form = Form::create($controller, $name, $fields, $actions, $validator);
65
        $form->addExtraClass('form--fill-height');
66
        $form->addExtraClass('form--no-dividers');
67
        $form->addExtraClass('insert-embed-modal--'. strtolower($context['type']));
68
69
        // Extend form
70
        $this->invokeWithExtensions('updateForm', $form, $controller, $name, $context);
71
72
        return $form;
73
    }
74
75
    public function getRequiredContext()
76
    {
77
        return ['type'];
78
    }
79
80
    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...
81
    {
82
        $formType = $context['type'];
83
        switch ($formType) {
84
            case 'create':
85
                return $this->getCreateFormFields();
86
            case 'edit':
87
                return $this->getEditFormFields($context);
88
            default:
89
                throw new InvalidArgumentException("Unknown media form type: {$formType}");
90
        }
91
    }
92
93
    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...
94
    {
95
        $actions = [];
96
97
        if ($context['type'] === 'create') {
98
            $actions = [
99
                FormAction::create('addmedia', _t(__CLASS__.'.AddMedia', 'Add media'))
100
                    ->setSchemaData(['data' => ['buttonStyle' => 'primary']]),
101
            ];
102
        }
103
104
        if ($context['type'] === 'edit') {
105
            $actions = [
106
                FormAction::create('insertmedia', _t(__CLASS__.'.InsertMedia', 'Insert media'))
107
                    ->setSchemaData(['data' => ['buttonStyle' => 'primary']]),
108
                FormAction::create('cancel', _t(__CLASS__.'.Cancel', 'Cancel')),
109
            ];
110
        }
111
112
        return FieldList::create($actions);
113
    }
114
115
    /**
116
     * @param string $url
117
     * @return bool
118
     * @throws InvalidUrlException
119
     */
120
    protected function validateUrl($url)
121
    {
122
        if (!Director::is_absolute_url($url)) {
123
            throw new InvalidUrlException(_t(
124
                __CLASS__.'.ERROR_ABSOLUTE',
125
                'Only absolute urls can be embedded'
126
            ));
127
        }
128
        $scheme = strtolower(parse_url($url, PHP_URL_SCHEME));
129
        $allowed_schemes = self::config()->get('fileurl_scheme_whitelist');
130
        if (!$scheme || ($allowed_schemes && !in_array($scheme, $allowed_schemes))) {
131
            throw new InvalidUrlException(_t(
132
                __CLASS__.'.ERROR_SCHEME',
133
                'This file scheme is not included in the whitelist'
134
            ));
135
        }
136
        $domain = strtolower(parse_url($url, PHP_URL_HOST));
137
        $allowed_domains = self::config()->get('fileurl_domain_whitelist');
138
        if (!$domain || ($allowed_domains && !in_array($domain, $allowed_domains))) {
139
            throw new InvalidUrlException(_t(
140
                __CLASS__.'.ERROR_HOSTNAME',
141
                'This file hostname is not included in the whitelist'
142
            ));
143
        }
144
        return true;
145
    }
146
147
    /**
148
     * Get form fields for create new embed
149
     *
150
     * @return FieldList
151
     */
152
    protected function getCreateFormFields()
153
    {
154
        return FieldList::create([
155
            TextField::create(
156
                'Url',
157
                _t(
158
                    __CLASS__.'.UrlDescription',
159
                    'Embed Youtube and Vimeo videos, images and other media directly from the web.'
160
                )
161
            )
162
                ->addExtraClass('insert-embed-modal__url-create'),
163
        ]);
164
    }
165
166
    /**
167
     * Get form fields for edit form
168
     *
169
     * @param array $context
170
     * @return FieldList
171
     */
172
    protected function getEditFormFields($context)
173
    {
174
        // Check if the url is valid
175
        $url = (isset($context['url'])) ? $context['url'] : null;
176
        if (empty($url)) {
177
            return $this->getCreateFormFields();
178
        }
179
180
        // Get embed
181
        $this->validateUrl($url);
182
        $embed = new EmbedResource($url);
183
184
        // Build form
185
        $alignments = array(
186
            'leftAlone' => _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.AlignmentLeftAlone', 'Left'),
187
            'center' => _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.AlignmentCenter', 'Center'),
188
            'rightAlone' => _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.AlignmentRightAlone', 'Right'),
189
            'left' => _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.AlignmentLeft', 'Left wrap'),
190
            'right' => _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.AlignmentRight', 'Right wrap'),
191
        );
192
193
        $width = $embed->getWidth();
194
        $height = $embed->getHeight();
195
196
        $fields = CompositeField::create([
197
            LiteralField::create(
198
                'Preview',
199
                sprintf(
200
                    '<img src="%s" class="%s" />',
201
                    $embed->getPreviewURL(),
202
                    'insert-embed-modal__preview'
203
                )
204
            )->addExtraClass('insert-embed-modal__preview-container'),
205
            HiddenField::create('PreviewUrl', 'PreviewUrl', $embed->getPreviewURL()),
206
            CompositeField::create([
207
                TextField::create('UrlPreview', $embed->getName(), $url)
208
                    ->setReadonly(true),
209
                HiddenField::create('Url', false, $url),
210
                TextField::create(
211
                    'CaptionText',
212
                    _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.Caption', 'Caption')
213
                ),
214
                OptionsetField::create(
215
                    'Placement',
216
                    _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.Placement', 'Placement'),
217
                    $alignments
218
                )
219
                    ->addExtraClass('insert-embed-modal__placement'),
220
                $dimensions = FieldGroup::create(
221
                    _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ImageSpecs', 'Dimensions'),
222
                    TextField::create('Width', '', $width)
223
                        ->setRightTitle(_t(
224
                            'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ImageWidth',
225
                            'Width'
226
                        ))
227
                        ->setMaxLength(5)
228
                        ->addExtraClass('flexbox-area-grow'),
229
                    TextField::create('Height', '', $height)
230
                        ->setRightTitle(_t(
231
                            'SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.ImageHeight',
232
                            'Height'
233
                        ))
234
                        ->setMaxLength(5)
235
                        ->addExtraClass('flexbox-area-grow')
236
                )->addExtraClass('fieldgroup--fill-width')
237
                    ->setName('Dimensions')
238
            ])->addExtraClass('flexbox-area-grow'),
239
        ])->addExtraClass('insert-embed-modal__fields--fill-width');
240
241 View Code Duplication
        if ($dimensions && $width && $height) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
242
            $ratio = $width / $height;
243
244
            $dimensions->setSchemaComponent('ProportionConstraintField');
245
            $dimensions->setSchemaState([
246
                'data' => [
247
                    'ratio' => $ratio
248
                ]
249
            ]);
250
        }
251
        return FieldList::create($fields);
252
    }
253
}
254