GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — 3.0.x ( 7360c0...725db6 )
by Nicolas
04:14
created

contentBlueprintsDatasources::__actionEdit()   C

Complexity

Conditions 7

Size

Total Lines 54
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 19
c 1
b 0
f 0
nop 0
dl 0
loc 54
rs 6.8325

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package content
5
 */
6
/**
7
 * The Datasource Editor page allows a developer to create new datasources
8
 * from the four Symphony types, Section, Authors, Navigation and Static XML
9
 */
10
11
class contentBlueprintsDatasources extends ResourcesPage
12
{
13
    public $_errors = array();
14
15
    public function __viewIndex($resource_type)
16
    {
17
        parent::__viewIndex(ResourceManager::RESOURCE_TYPE_DS);
18
19
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Data Sources'), __('Symphony'))));
20
        $this->appendSubheading(__('Data Sources'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new data source'), 'create button', null, array('accesskey' => 'c')));
21
    }
22
23
    // Both the Edit and New pages need the same form
24
    public function __viewNew()
25
    {
26
        $this->__form();
27
    }
28
29
    public function __viewEdit()
30
    {
31
        $this->__form();
32
    }
33
34
    public function __form()
35
    {
36
        $formHasErrors = (is_array($this->_errors) && !empty($this->_errors));
37
38
        if ($formHasErrors) {
39
            $this->pageAlert(
40
                __('An error occurred while processing this form. See below for details.'),
41
                Alert::ERROR
42
            );
43
44
            // These alerts are only valid if the form doesn't have errors
45
        } elseif (isset($this->_context[2])) {
46
            $time = Widget::Time();
47
48
            switch ($this->_context[2]) {
49
                case 'saved':
50
                    $message = __('Data Source updated at %s.', array($time->generate()));
51
                    break;
52
                case 'created':
53
                    $message = __('Data Source created at %s.', array($time->generate()));
54
            }
55
56
            $this->pageAlert(
57
                $message
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.
Loading history...
58
                . ' <a href="' . SYMPHONY_URL . '/blueprints/datasources/new/" accesskey="c">'
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
59
                . __('Create another?')
60
                . '</a> <a href="' . SYMPHONY_URL . '/blueprints/datasources/" accesskey="a">'
61
                . __('View all Data Sources')
62
                . '</a>',
63
                Alert::SUCCESS
64
            );
65
        }
66
67
        $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::DATASOURCE);
68
        $canonical_link = null;
69
        $isEditing = false;
70
        $about = $handle = null;
71
        $fields = array(
72
            'name' => null,
73
            'source' => null,
74
            'filter'=> null,
75
            'required_url_param' => null,
76
            'negate_url_param' => null,
77
            'param' => null,
78
            'paramxml' => null,
79
        );
80
81
        if (isset($_POST['fields'])) {
82
            $fields = $_POST['fields'];
83
84
            if (
85
                !in_array($fields['source'], array('authors', 'navigation', 'static_xml'))
86
                && !empty($fields['filter']) && is_array($fields['filter'])
87
            ) {
88
                $filters = array();
89
                foreach ($fields['filter'] as $f) {
90
                    foreach ($f as $key => $val) {
91
                        $filters[$key] = $val;
92
                    }
93
                }
94
95
                $fields['filter'][$fields['source']] = $filters;
96
            }
97
98
            if (!isset($fields['xml_elements']) || !is_array($fields['xml_elements'])) {
99
                $fields['xml_elements'] = array();
100
            }
101
102
            if ($this->_context[0] == 'edit') {
103
                $isEditing = true;
104
            }
105
        } elseif ($this->_context[0] == 'edit') {
106
            $isEditing = true;
107
            $handle = $this->_context[1];
108
            $existing = DatasourceManager::create($handle, array(), false);
109
            $order = isset($existing->dsParamORDER) ? stripslashes($existing->dsParamORDER) : 'asc';
110
            $canonical_link = '/blueprints/datasources/edit/' . $handle . '/';
111
112
            if (!$existing->allowEditorToParse()) {
113
                redirect(SYMPHONY_URL . '/blueprints/datasources/info/' . $handle . '/');
114
            }
115
116
            $about = General::array_map_recursive('stripslashes', $existing->about());
117
            $fields['name'] = $about['name'];
118
119
            $fields['order'] = ($order == 'rand') ? 'random' : $order;
120
            $fields['param'] = isset($existing->dsParamPARAMOUTPUT) ? array_map('stripslashes', $existing->dsParamPARAMOUTPUT) : null;
121
            $fields['paramxml'] = isset($existing->dsParamPARAMXML) ? ($existing->dsParamPARAMXML === 'yes' ? 'yes' : 'no') : 'yes';
0 ignored issues
show
Bug introduced by
The property dsParamPARAMXML does not exist on Datasource. Did you mean dsParamPARAMOUTPUT?
Loading history...
122
            $fields['required_url_param'] = isset($existing->dsParamREQUIREDPARAM) ? stripslashes(trim($existing->dsParamREQUIREDPARAM)) : null;
0 ignored issues
show
Bug introduced by
The property dsParamREQUIREDPARAM does not seem to exist on Datasource.
Loading history...
123
            $fields['negate_url_param'] = isset($existing->dsParamNEGATEPARAM) ? stripslashes(trim($existing->dsParamNEGATEPARAM)) : null;
0 ignored issues
show
Bug introduced by
The property dsParamNEGATEPARAM does not seem to exist on Datasource.
Loading history...
124
125
            if (isset($existing->dsParamINCLUDEDELEMENTS) && is_array($existing->dsParamINCLUDEDELEMENTS)) {
126
                $fields['xml_elements'] = array_map('stripslashes', $existing->dsParamINCLUDEDELEMENTS);
127
            } else {
128
                $fields['xml_elements'] = array();
129
            }
130
131
            $fields['sort'] = isset($existing->dsParamSORT) ? stripslashes($existing->dsParamSORT) : null;
132
            $fields['paginate_results'] = isset($existing->dsParamPAGINATERESULTS) ? stripslashes($existing->dsParamPAGINATERESULTS) : 'yes';
0 ignored issues
show
Bug introduced by
The property dsParamPAGINATERESULTS does not seem to exist on Datasource.
Loading history...
133
            $fields['page_number'] = isset($existing->dsParamSTARTPAGE) ? stripslashes($existing->dsParamSTARTPAGE) : '1';
134
            $fields['group'] = isset($existing->dsParamGROUP) ? stripslashes($existing->dsParamGROUP) : null;
0 ignored issues
show
Bug introduced by
The property dsParamGROUP does not exist on Datasource. Did you mean dsParamSORT?
Loading history...
135
            $fields['html_encode'] = isset($existing->dsParamHTMLENCODE) ? stripslashes($existing->dsParamHTMLENCODE) : 'no';
0 ignored issues
show
Bug introduced by
The property dsParamHTMLENCODE does not seem to exist on Datasource.
Loading history...
136
            $fields['associated_entry_counts'] = isset($existing->dsParamASSOCIATEDENTRYCOUNTS) ? stripslashes($existing->dsParamASSOCIATEDENTRYCOUNTS) : 'no';
0 ignored issues
show
Bug introduced by
The property dsParamASSOCIATEDENTRYCOUNTS does not seem to exist on Datasource.
Loading history...
137
            $fields['redirect_on_empty'] = isset($existing->dsParamREDIRECTONEMPTY) ? stripslashes($existing->dsParamREDIRECTONEMPTY) : 'no';
0 ignored issues
show
Bug introduced by
The property dsParamREDIRECTONEMPTY does not seem to exist on Datasource.
Loading history...
138
            $fields['redirect_on_forbidden'] = isset($existing->dsParamREDIRECTONFORBIDDEN) ? stripslashes($existing->dsParamREDIRECTONFORBIDDEN) : 'no';
0 ignored issues
show
Bug introduced by
The property dsParamREDIRECTONFORBIDDEN does not seem to exist on Datasource.
Loading history...
139
            $fields['redirect_on_required'] = isset($existing->dsParamREDIRECTONREQUIRED) ? stripslashes($existing->dsParamREDIRECTONREQUIRED) : 'no';
0 ignored issues
show
Bug introduced by
The property dsParamREDIRECTONREQUIRED does not seem to exist on Datasource.
Loading history...
140
141
            if (!isset($existing->dsParamFILTERS) || !is_array($existing->dsParamFILTERS)) {
142
                $existing->dsParamFILTERS = array();
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamFILTERS does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
143
            }
144
145
            if (!empty($existing->dsParamFILTERS)) {
146
                $existing->dsParamFILTERS = array_map('stripslashes', $existing->dsParamFILTERS);
147
            }
148
149
            $fields['source'] = stripslashes($existing->getSource());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $existing->getSource() targeting Datasource::getSource() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
150
151
            $provided = false;
152
153
            if (!empty($providers)) {
154
                foreach ($providers as $providerClass => $provider) {
155
                    if ($fields['source'] == call_user_func(array($providerClass, 'getClass'))) {
156
                        $fields = array_merge($fields, $existing->settings());
0 ignored issues
show
Bug introduced by
The method settings() does not exist on Datasource. ( Ignorable by Annotation )

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

156
                        $fields = array_merge($fields, $existing->/** @scrutinizer ignore-call */ settings());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
157
                        $provided = true;
158
                        break;
159
                    }
160
                }
161
            }
162
163
            if ($provided === false) {
164
                switch ($fields['source']) {
165
                    case 'authors':
166
                        $fields['filter']['author'] = $existing->dsParamFILTERS;
167
                        break;
168
                    case 'navigation':
169
                        $fields['filter']['navigation'] = $existing->dsParamFILTERS;
170
                        break;
171
                    case 'static_xml':
172
                        $fields['static_xml'] = stripslashes(trim($existing->dsParamSTATIC));
173
                        break;
174
                    default:
175
                        $fields['filter'][$fields['source']] = $existing->dsParamFILTERS;
176
                        $fields['max_records'] = stripslashes($existing->dsParamLIMIT);
177
                        break;
178
                }
179
            }
180
        } else {
181
            $fields['max_records'] = '20';
182
            $fields['page_number'] = '1';
183
            $fields['order'] = 'desc';
184
        }
185
186
        // Handle name on edited changes, or from reading an edited datasource
187
        if (isset($about['name'])) {
188
            $name = $about['name'];
189
        } elseif (isset($fields['name'])) {
190
            $name = $fields['name'];
191
        }
192
193
        $this->setPageType('form');
194
        $this->setTitle(__(($isEditing ? '%1$s &ndash; %2$s &ndash; %3$s' : '%2$s &ndash; %3$s'), array($name, __('Data Sources'), __('Symphony'))));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.
Loading history...
195
        if ($canonical_link) {
196
            $this->addElementToHead(new XMLElement('link', null, array(
197
                'rel' => 'canonical',
198
                'href' => SYMPHONY_URL . $canonical_link,
199
            )));
200
        }
201
        $this->appendSubheading(($isEditing ? $name : __('Untitled')));
202
        $this->insertBreadcrumbs(array(
203
            Widget::Anchor(__('Data Sources'), SYMPHONY_URL . '/blueprints/datasources/'),
204
        ));
205
206
        // Sources
207
        $sources = new XMLElement('div', null, array('class' => 'apply actions'));
208
        $div = new XMLElement('div');
209
        $label = Widget::Label(__('Source'), null, 'apply-label-left');
210
        $sources->appendChild($label);
211
        $sources->appendChild($div);
212
213
        $sections = (new SectionManager)->select()->execute()->rows();
214
215
        $field_groups = array();
216
217
        foreach ($sections as $section) {
218
            $field_groups[$section->get('id')] = array('fields' => $section->fetchFields(), 'section' => $section);
219
        }
220
221
        $options = array(
222
            array('label' => __('System'), 'data-label' => 'system', 'options' => array(
223
                    array('authors', ($fields['source'] == 'authors'), __('Authors'), null, null, array('data-context' => 'authors')),
224
                    array('navigation', ($fields['source'] == 'navigation'), __('Navigation'), null, null, array('data-context' => 'navigation')),
225
            )),
226
            array('label' => __('Custom XML'), 'data-label' => 'custom-xml', 'options' => array(
227
                    array('static_xml', ($fields['source'] == 'static_xml'), __('Static XML'), null, null, array('data-context' => 'static-xml')),
228
            )),
229
        );
230
231
        // Loop over the datasource providers
232
        if (!empty($providers)) {
233
            $p = array('label' => __('From extensions'), 'data-label' => 'from_extensions', 'options' => array());
234
235
            foreach ($providers as $providerClass => $provider) {
236
                $p['options'][] = array(
237
                    $providerClass, ($fields['source'] == $providerClass), $provider, null, null, array('data-context' => Lang::createHandle($provider))
238
                );
239
            }
240
241
            $options[] = $p;
242
        }
243
244
        // Add Sections
245
        if (is_array($sections) && !empty($sections)) {
246
            array_unshift($options, array('label' => __('Sections'), 'data-label' => 'sections', 'options' => array()));
247
248
            foreach ($sections as $s) {
249
                $options[0]['options'][] = array($s->get('id'), ($fields['source'] == $s->get('id')), General::sanitize($s->get('name')));
250
            }
251
        }
252
253
        $div->appendChild(Widget::Select('source', $options, array('id' => 'ds-context')));
254
        $this->Context->prependChild($sources);
255
256
        $this->Form->appendChild(
257
            Widget::Input('fields[source]', null, 'hidden', array('id' => 'ds-source'))
258
        );
259
260
        // Name
261
        $fieldset = new XMLElement('fieldset');
262
        $fieldset->setAttribute('class', 'settings');
263
        $fieldset->appendChild(new XMLElement('legend', __('Essentials')));
264
265
        $group = new XMLElement('div');
266
267
        $label = Widget::Label(__('Name'));
268
        $label->appendChild(Widget::Input('fields[name]', General::sanitize($fields['name'])));
269
270
        if (isset($this->_errors['name'])) {
271
            $group->appendChild(Widget::Error($label, $this->_errors['name']));
272
        } else {
273
            $group->appendChild($label);
274
        }
275
276
        $fieldset->appendChild($group);
277
        $this->Form->appendChild($fieldset);
278
279
        // Conditions
280
        $fieldset = new XMLElement('fieldset');
281
        $this->setContext($fieldset, array('sections', 'system'));
282
        $fieldset->appendChild(new XMLElement('legend', __('Execution Conditions')));
283
        $p = new XMLElement('p', __('Leaving these fields empty will always execute the data source.'));
284
        $p->setAttribute('class', 'help');
285
        $fieldset->appendChild($p);
286
287
        $group = new XMLElement('div');
288
        $group->setAttribute('class', 'two columns');
289
290
        $label = Widget::Label(__('Required Parameter'));
291
        $label->setAttribute('class', 'column ds-param');
292
        $label->appendChild(new XMLElement('i', __('Optional')));
293
        $input = Widget::Input('fields[required_url_param]', General::sanitize(trim($fields['required_url_param'])), 'text', array(
294
            'placeholder' => __('$param'),
295
            'data-search-types' => 'parameters',
296
            'data-trigger' => '$'
297
        ));
298
        $label->appendChild($input);
299
        $group->appendChild($label);
300
301
        $label = Widget::Label(__('Forbidden Parameter'));
302
        $label->setAttribute('class', 'column ds-param');
303
        $label->appendChild(new XMLElement('i', __('Optional')));
304
        $input = Widget::Input('fields[negate_url_param]', General::sanitize(trim($fields['negate_url_param'])), 'text', array(
305
            'placeholder' => __('$param'),
306
            'data-search-types' => 'parameters',
307
            'data-trigger' => '$'
308
        ));
309
        $label->appendChild($input);
310
        $group->appendChild($label);
311
312
        $fieldset->appendChild($group);
313
314
        $this->Form->appendChild($fieldset);
315
316
        $fieldset = new XMLElement('fieldset');
317
        $this->setContext($fieldset, array('sections', 'system'));
318
        $fieldset->appendChild(new XMLElement('legend', __('Error Conditions')));
319
        $p = new XMLElement('p', __('Meeting one of these conditions will cause a <code>404 Not Found</code> response.'));
320
        $p->setAttribute('class', 'help');
321
        $fieldset->appendChild($p);
322
        $group = new XMLElement('div');
323
324
        $label = Widget::Checkbox('fields[redirect_on_required]', $fields['redirect_on_required'], __('The required parameter is missing'));
325
        $group->appendChild($label);
326
327
        $label = Widget::Checkbox('fields[redirect_on_forbidden]', $fields['redirect_on_forbidden'], __('The forbidden parameter is present'));
328
        $group->appendChild($label);
329
330
        $label = Widget::Checkbox('fields[redirect_on_empty]', $fields['redirect_on_empty'], __('No results are found'));
331
        $group->appendChild($label);
332
333
        $fieldset->appendChild($group);
334
335
        $this->Form->appendChild($fieldset);
336
337
        // Filters
338
        $fieldset = new XMLElement('fieldset');
339
        $this->setContext($fieldset, array('sections', 'system'));
340
        $fieldset->appendChild(new XMLElement('legend', __('Filters')));
341
        $p = new XMLElement('p',
342
            __('Use %s syntax to filter by page parameters. A default value can be set using %s.', array(
343
                '<code>{' . __('$param') . '}</code>',
344
                '<code>{' . __('$param:default') . '}</code>'
345
            ))
346
        );
347
        $p->setAttribute('class', 'help');
348
        $fieldset->appendChild($p);
349
350
        foreach ($field_groups as $section_id => $section_data) {
351
            $div = new XMLElement('div');
352
            $div->setAttribute('class', 'contextual frame filters-duplicator');
353
            $div->setAttribute('data-context', 'section-' . $section_id);
354
            $div->setAttribute('data-interactive', 'data-interactive');
355
356
            $ol = new XMLElement('ol');
357
            $ol->setAttribute('class', 'suggestable');
358
            $ol->setAttribute('data-interactive', 'data-interactive');
359
            $ol->setAttribute('data-add', __('Add filter'));
360
            $ol->setAttribute('data-remove', __('Remove filter'));
361
362
            // Add system:id filter
363
            if (
364
                isset($fields['filter'][$section_id]['system:id'])
365
                || isset($fields['filter'][$section_id]['id'])
366
            ) {
367
                $id = isset($fields['filter'][$section_id]['system:id'])
368
                    ? $fields['filter'][$section_id]['system:id']
369
                    : $fields['filter'][$section_id]['id'];
370
371
                $li = new XMLElement('li');
372
                $li->setAttribute('class', 'unique');
373
                $li->setAttribute('data-type', 'system:id');
374
                $li->appendChild(new XMLElement('header', '<h4>' . __('System ID') . '</h4>'));
375
                $label = Widget::Label(__('Value'));
376
                $input = Widget::Input('fields[filter]['.$section_id.'][system:id]', General::sanitize($id));
377
                $input->setAttribute('data-search-types', 'parameters');
378
                $input->setAttribute('data-trigger', '{$');
379
                $label->appendChild($input);
380
                $li->appendChild($label);
381
                $ol->appendChild($li);
382
            }
383
384
            $li = new XMLElement('li');
385
            $li->setAttribute('class', 'unique template');
386
            $li->setAttribute('data-type', 'system:id');
387
            $li->appendChild(new XMLElement('header', '<h4>' . __('System ID') . '</h4>'));
388
            $label = Widget::Label(__('Value'));
389
            $input = Widget::Input('fields[filter]['.$section_id.'][system:id]', General::sanitize($id));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id does not seem to be defined for all execution paths leading up to this point.
Loading history...
390
            $input->setAttribute('data-search-types', 'parameters');
391
            $input->setAttribute('data-trigger', '{$');
392
            $label->appendChild($input);
393
            $li->appendChild($label);
394
            $ol->appendChild($li);
395
396
            // Add system:date filter
397
            if (
398
                isset($fields['filter'][$section_id]['system:creation-date'])
399
                || isset($fields['filter'][$section_id]['system:date'])
400
            ) {
401
                $creation_date = isset($fields['filter'][$section_id]['system:creation-date'])
402
                    ? $fields['filter'][$section_id]['system:creation-date']
403
                    : $fields['filter'][$section_id]['system:date'];
404
405
                $li = new XMLElement('li');
406
                $li->setAttribute('class', 'unique');
407
                $li->setAttribute('data-type', 'system:creation-date');
408
                $li->appendChild(new XMLElement('header', '<h4>' . __('System Creation Date') . '</h4>'));
409
                $label = Widget::Label(__('Value'));
410
                $input = Widget::Input('fields[filter]['.$section_id.'][system:creation-date]', General::sanitize($creation_date));
411
                $input->setAttribute('data-search-types', 'parameters');
412
                $input->setAttribute('data-trigger', '{$');
413
                $label->appendChild($input);
414
                $li->appendChild($label);
415
                $ol->appendChild($li);
416
            }
417
418
            $li = new XMLElement('li');
419
            $li->setAttribute('class', 'unique template');
420
            $li->setAttribute('data-type', 'system:creation-date');
421
            $li->appendChild(new XMLElement('header', '<h4>' . __('System Creation Date') . '</h4>'));
422
            $label = Widget::Label(__('Value'));
423
            $input = Widget::Input('fields[filter]['.$section_id.'][system:creation-date]');
424
            $input->setAttribute('data-search-types', 'parameters');
425
            $input->setAttribute('data-trigger', '{$');
426
            $label->appendChild($input);
427
            $li->appendChild($label);
428
            $ol->appendChild($li);
429
430
            if (isset($fields['filter'][$section_id]['system:modification-date'])) {
431
                $li = new XMLElement('li');
432
                $li->setAttribute('class', 'unique');
433
                $li->setAttribute('data-type', 'system:modification-date');
434
                $li->appendChild(new XMLElement('header', '<h4>' . __('System Modification Date') . '</h4>'));
435
                $label = Widget::Label(__('Value'));
436
                $input = Widget::Input('fields[filter]['.$section_id.'][system:modification-date]', General::sanitize($fields['filter'][$section_id]['system:modification-date']));
437
                $input->setAttribute('data-search-types', 'parameters');
438
                $input->setAttribute('data-trigger', '{$');
439
                $label->appendChild($input);
440
                $li->appendChild($label);
441
                $ol->appendChild($li);
442
            }
443
444
            $li = new XMLElement('li');
445
            $li->setAttribute('class', 'unique template');
446
            $li->setAttribute('data-type', 'system:modification-date');
447
            $li->appendChild(new XMLElement('header', '<h4>' . __('System Modification Date') . '</h4>'));
448
            $label = Widget::Label(__('Value'));
449
            $input = Widget::Input('fields[filter]['.$section_id.'][system:modification-date]');
450
            $input->setAttribute('data-search-types', 'parameters');
451
            $input->setAttribute('data-trigger', '{$');
452
            $label->appendChild($input);
453
            $li->appendChild($label);
454
            $ol->appendChild($li);
455
456
            if (is_array($section_data['fields']) && !empty($section_data['fields'])) {
457
                foreach ($section_data['fields'] as $field) {
458
                    if (!$field->canFilter()) {
459
                        continue;
460
                    }
461
462
                    if (isset($fields['filter'][$section_id], $fields['filter'][$section_id][$field->get('id')])) {
463
                        $wrapper = new XMLElement('li');
464
                        $wrapper->setAttribute('class', 'unique');
465
                        $wrapper->setAttribute('data-type', $field->get('element_name'));
466
                        $errors = isset($this->_errors[$field->get('id')])
467
                            ? $this->_errors[$field->get('id')]
468
                            : array();
469
470
                        $field->displayDatasourceFilterPanel($wrapper, $fields['filter'][$section_id][$field->get('id')], $errors, $section_id);
471
                        $ol->appendChild($wrapper);
472
                    }
473
474
                    $wrapper = new XMLElement('li');
475
                    $wrapper->setAttribute('class', 'unique template');
476
                    $wrapper->setAttribute('data-type', $field->get('element_name'));
477
                    $field->displayDatasourceFilterPanel($wrapper, null, null, $section_id);
478
                    $ol->appendChild($wrapper);
479
                }
480
            }
481
482
            $div->appendChild($ol);
483
484
            $fieldset->appendChild($div);
485
        }
486
487
        $div = new XMLElement('div');
488
        $div->setAttribute('class', 'contextual frame filters-duplicator');
489
        $div->setAttribute('data-context', 'authors');
490
        $div->setAttribute('data-interactive', 'data-interactive');
491
492
        $ol = new XMLElement('ol');
493
        $ol->setAttribute('class', 'suggestable');
494
        $ol->setAttribute('data-interactive', 'data-interactive');
495
        $ol->setAttribute('data-add', __('Add filter'));
496
        $ol->setAttribute('data-remove', __('Remove filter'));
497
498
        if (!isset($fields['filter']['author'])) {
499
            $fields['filter']['author'] = array(
500
                'id' => null,
501
                'username' => null,
502
                'first_name' => null,
503
                'last_name' => null,
504
                'email' => null,
505
                'user_type' => null
506
            );
507
        }
508
509
        $this->__appendAuthorFilter($ol, __('ID'), 'id', $fields['filter']['author']['id'], (!isset($fields['filter']['author']['id'])));
510
        $this->__appendAuthorFilter($ol, __('Username'), 'username', $fields['filter']['author']['username'], (!isset($fields['filter']['author']['username'])));
511
        $this->__appendAuthorFilter($ol, __('First Name'), 'first_name', $fields['filter']['author']['first_name'], (!isset($fields['filter']['author']['first_name'])));
512
        $this->__appendAuthorFilter($ol, __('Last Name'), 'last_name', $fields['filter']['author']['last_name'], (!isset($fields['filter']['author']['last_name'])));
513
        $this->__appendAuthorFilter($ol, __('Email'), 'email', $fields['filter']['author']['email'], (!isset($fields['filter']['author']['email'])));
514
        $this->__appendAuthorFilter($ol, __('User Type'), 'user_type', $fields['filter']['author']['user_type'], (!isset($fields['filter']['author']['user_type'])));
515
516
        $div->appendChild($ol);
517
518
        $fieldset->appendChild($div);
519
520
        $div = new XMLElement('div');
521
        $div->setAttribute('class', 'contextual frame filters-duplicator');
522
        $div->setAttribute('data-context', 'navigation');
523
        $div->setAttribute('data-interactive', 'data-interactive');
524
525
        $ol = new XMLElement('ol');
526
        $ol->setAttribute('class', 'suggestable');
527
        $ol->setAttribute('data-interactive', 'data-interactive');
528
        $ol->setAttribute('data-add', __('Add filter'));
529
        $ol->setAttribute('data-remove', __('Remove filter'));
530
531
        $ul = new XMLElement('ul');
532
        $ul->setAttribute('class', 'tags');
533
        $ul->setAttribute('data-interactive', 'data-interactive');
534
535
        $pages = (new PageManager)
536
            ->select()
537
            ->sort('title')
538
            ->execute()
539
            ->rows();
540
541
        foreach ($pages as $page) {
542
            $ul->appendChild(new XMLElement('li', preg_replace('/\/{2,}/i', '/', '/' . $page['path'] . '/' . $page['handle'])));
543
        }
544
545
        if (isset($fields['filter']['navigation']['parent'])) {
546
            $li = new XMLElement('li');
547
            $li->setAttribute('class', 'unique');
548
            $li->setAttribute('data-type', 'parent');
549
            $li->appendChild(new XMLElement('header', '<h4>' . __('Parent Page') . '</h4>'));
550
            $label = Widget::Label(__('Value'));
551
            $label->appendChild(Widget::Input('fields[filter][navigation][parent]', General::sanitize($fields['filter']['navigation']['parent'])));
552
            $li->appendChild($label);
553
            $li->appendChild($ul);
554
            $ol->appendChild($li);
555
        }
556
557
        $li = new XMLElement('li');
558
        $li->setAttribute('class', 'unique template');
559
        $li->setAttribute('data-type', 'parent');
560
        $li->appendChild(new XMLElement('header', '<h4>' . __('Parent Page') . '</h4>'));
561
        $label = Widget::Label(__('Value'));
562
        $label->appendChild(Widget::Input('fields[filter][navigation][parent]'));
563
        $li->appendChild($label);
564
        $li->appendChild($ul);
565
        $ol->appendChild($li);
566
567
        $ul = new XMLElement('ul');
568
        $ul->setAttribute('class', 'tags');
569
        $ul->setAttribute('data-interactive', 'data-interactive');
570
571
        if ($types = PageManager::fetchAvailablePageTypes()) {
572
            foreach ($types as $type) {
573
                $ul->appendChild(new XMLElement('li', $type));
574
            }
575
        }
576
577
        if (isset($fields['filter']['navigation']['type'])) {
578
            $li = new XMLElement('li');
579
            $li->setAttribute('class', 'unique');
580
            $li->setAttribute('data-type', 'type');
581
            $li->appendChild(new XMLElement('header', '<h4>' . __('Page Type') . '</h4>'));
582
            $label = Widget::Label(__('Value'));
583
            $label->appendChild(Widget::Input('fields[filter][navigation][type]', General::sanitize($fields['filter']['navigation']['type'])));
584
            $li->appendChild($label);
585
            $li->appendChild($ul);
586
            $ol->appendChild($li);
587
        }
588
589
        $li = new XMLElement('li');
590
        $li->setAttribute('class', 'unique template');
591
        $li->appendChild(new XMLElement('header', '<h4>' . __('Page Type') . '</h4>'));
592
        $li->setAttribute('data-type', 'type');
593
        $label = Widget::Label(__('Value'));
594
        $label->appendChild(Widget::Input('fields[filter][navigation][type]'));
595
        $li->appendChild($label);
596
        $li->appendChild($ul);
597
        $ol->appendChild($li);
598
599
        $div->appendChild($ol);
600
601
        $fieldset->appendChild($div);
602
        $this->Form->appendChild($fieldset);
603
604
        // Sorting
605
        $fieldset = new XMLElement('fieldset');
606
        $this->setContext($fieldset, array('sections', 'system'));
607
        $fieldset->appendChild(new XMLElement('legend', __('Sorting')));
608
609
        $p = new XMLElement('p',
610
            __('Use %s syntax to order by page parameters.', array(
611
                '<code>{' . __('$param') . '}</code>'
612
            ))
613
        );
614
        $p->setAttribute('class', 'help');
615
        $fieldset->appendChild($p);
616
617
        $div = new XMLElement('div');
618
619
        $label = Widget::Label(__('Sort By'));
620
621
        $options = array(
622
            array('label' => __('Authors'), 'data-label' => 'authors', 'options' => array(
623
                    array('id', ($fields['source'] == 'authors' && $fields['sort'] == 'id'), __('Author ID')),
624
                    array('username', ($fields['source'] == 'authors' && $fields['sort'] == 'username'), __('Username')),
625
                    array('first-name', ($fields['source'] == 'authors' && $fields['sort'] == 'first-name'), __('First Name')),
626
                    array('last-name', ($fields['source'] == 'authors' && $fields['sort'] == 'last-name'), __('Last Name')),
627
                    array('email', ($fields['source'] == 'authors' && $fields['sort'] == 'email'), __('Email')),
628
                    array('status', ($fields['source'] == 'authors' && $fields['sort'] == 'status'), __('Status')),
629
                )
630
            ),
631
632
            array('label' => __('Navigation'), 'data-label' => 'navigation', 'options' => array(
633
                    array('id', ($fields['source'] == 'navigation' && $fields['sort'] == 'id'), __('Page ID')),
634
                    array('handle', ($fields['source'] == 'navigation' && $fields['sort'] == 'handle'), __('Handle')),
635
                    array('sortorder', ($fields['source'] == 'navigation' && $fields['sort'] == 'sortorder'), __('Sort Order')),
636
                )
637
            ),
638
        );
639
640
        foreach ($field_groups as $section_id => $section_data) {
641
            $optgroup = array('label' => General::sanitize($section_data['section']->get('name')), 'data-label' => 'section-' . $section_data['section']->get('id'), 'options' => array(
642
                array('system:id', ($fields['source'] == $section_id && $fields['sort'] == 'system:id'), __('System ID')),
643
                array('system:creation-date', ($fields['source'] == $section_id && ($fields['sort'] == 'system:creation-date' || $fields['sort'] == 'system:date')), __('System Creation Date')),
644
                array('system:modification-date', ($fields['source'] == $section_id && $fields['sort'] == 'system:modification-date'), __('System Modification Date')),
645
            ));
646
647
            if (is_array($section_data['fields']) && !empty($section_data['fields'])) {
648
                foreach ($section_data['fields'] as $input) {
649
                    if (!$input->isSortable()) {
650
                        continue;
651
                    }
652
653
                    $optgroup['options'][] = array(
654
                        $input->get('element_name'),
655
                        ($fields['source'] == $section_id && $input->get('element_name') == $fields['sort']),
656
                        $input->get('label')
657
                    );
658
                }
659
            }
660
661
            $options[] = $optgroup;
662
        }
663
664
        $label->appendChild(Widget::Select('fields[sort]', $options));
665
        $div->appendChild($label);
666
667
        $label = Widget::Label(__('Sort Order'));
668
        $label->setAttribute('class', 'ds-param');
669
670
        $input = Widget::Input('fields[order]', General::sanitize(trim($fields['order'])), 'text', array(
671
            'placeholder' => __('{$param}'),
672
            'data-search-types' => 'parameters',
673
            'data-trigger' => '{$'
674
        ));
675
        $label->appendChild($input);
676
        $div->appendChild($label);
677
678
        $orders = new XMLElement('ul');
679
        $orders->setAttribute('class', 'tags singular');
680
        $orders->setAttribute('data-interactive', 'data-interactive');
681
        $orders->appendChild(new XMLElement('li', 'asc'));
682
        $orders->appendChild(new XMLElement('li', 'desc'));
683
        $orders->appendChild(new XMLElement('li', 'random'));
684
        $div->appendChild($orders);
685
686
        $fieldset->appendChild($div);
687
        $this->Form->appendChild($fieldset);
688
689
        // Grouping
690
        $fieldset = new XMLElement('fieldset');
691
        $this->setContext($fieldset, array('sections', 'authors'));
692
        $fieldset->appendChild(new XMLElement('legend', __('Grouping')));
693
694
        $label = Widget::Label(__('Group By'));
695
        $options = array(
696
            array('', null, __('None')),
697
        );
698
699
        foreach ($field_groups as $section_id => $section_data) {
700
            $optgroup = array('label' => $section_data['section']->get('name'), 'data-label' => 'section-' . $section_data['section']->get('id'), 'options' => array());
701
702
            if (is_array($section_data['fields']) && !empty($section_data['fields'])) {
703
                foreach ($section_data['fields'] as $input) {
704
                    if (!$input->allowDatasourceOutputGrouping()) {
705
                        continue;
706
                    }
707
708
                    $optgroup['options'][] = array($input->get('id'), ($fields['source'] == $section_id && $fields['group'] == $input->get('id')), $input->get('label'));
709
                }
710
            }
711
712
            $options[] = $optgroup;
713
        }
714
715
        $label->appendChild(Widget::Select('fields[group]', $options));
716
        $fieldset->appendChild($label);
717
718
        $this->Form->appendChild($fieldset);
719
720
        // Pagination
721
        $fieldset = new XMLElement('fieldset');
722
        $this->setContext($fieldset, array('sections'));
723
        $fieldset->appendChild(new XMLElement('legend', __('Pagination')));
724
725
        $p = new XMLElement('p',
726
            __('Use %s syntax to limit by page parameters.', array(
727
                '<code>{' . __('$param') . '}</code>'
728
            ))
729
        );
730
        $p->setAttribute('class', 'help');
731
        $fieldset->appendChild($p);
732
733
        $group = new XMLElement('div');
734
        $group->setAttribute('class', 'two columns pagination');
735
736
        $label = Widget::Label(__('Entries per Page'));
737
        $label->setAttribute('class', 'column ds-param');
738
        $input = Widget::Input('fields[max_records]', isset($fields['max_records']) ? General::sanitize(trim($fields['max_records'])) : '10', 'text', array(
739
            'placeholder' => __('{$param}'),
740
            'data-search-types' => 'parameters',
741
            'data-trigger' => '{$'
742
        ));
743
        $label->appendChild($input);
744
        if (isset($this->_errors['max_records'])) {
745
            $group->appendChild(Widget::Error($label, $this->_errors['max_records']));
746
        } else {
747
            $group->appendChild($label);
748
        }
749
750
        $label = Widget::Label(__('Page Number'));
751
        $label->setAttribute('class', 'column ds-param');
752
        $input = Widget::Input('fields[page_number]', General::sanitize(trim($fields['page_number'])), 'text', array(
753
            'placeholder' => __('{$param}'),
754
            'data-search-types' => 'parameters',
755
            'data-trigger' => '{$'
756
        ));
757
        $label->appendChild($input);
758
        if (isset($this->_errors['page_number'])) {
759
            $group->appendChild(Widget::Error($label, $this->_errors['page_number']));
760
        } else {
761
            $group->appendChild($label);
762
        }
763
764
        $fieldset->appendChild($group);
765
766
        $label = Widget::Checkbox('fields[paginate_results]', $fields['paginate_results'], __('Enable pagination'));
767
        $fieldset->appendChild($label);
768
        $this->Form->appendChild($fieldset);
769
770
        // Content
771
        $fieldset = new XMLElement('fieldset');
772
        $this->setContext($fieldset, array('sections', 'authors'));
773
        $fieldset->appendChild(new XMLElement('legend', __('Content')));
774
775
        // XML
776
        $group = new XMLElement('div', null, array('class' => 'two columns'));
777
        $col = new XMLElement('div', null, array('class' => 'column'));
778
779
        $label = Widget::Label(__('Included Elements'));
780
781
        $options = array(
782
            array('label' => __('Authors'), 'data-label' => 'authors', 'options' => array(
783
                    array('username', ($fields['source'] == 'authors' && in_array('username', $fields['xml_elements'])), 'username'),
784
                    array('name', ($fields['source'] == 'authors' && in_array('name', $fields['xml_elements'])), 'name'),
785
                    array('email', ($fields['source'] == 'authors' && in_array('email', $fields['xml_elements'])), 'email'),
786
                    array('author-token', ($fields['source'] == 'authors' && in_array('author-token', $fields['xml_elements'])), 'author-token'),
787
                    array('default-area', ($fields['source'] == 'authors' && in_array('default-area', $fields['xml_elements'])), 'default-area'),
788
            )),
789
        );
790
791
        foreach ($field_groups as $section_id => $section_data) {
792
            $optgroup = array(
793
                'label' => General::sanitize($section_data['section']->get('name')),
794
                'data-label' => 'section-' . $section_data['section']->get('id'),
795
                'options' => array(
796
                    array(
797
                        'system:id',
798
                        ($fields['source'] == $section_id && in_array('system:id', $fields['xml_elements'])),
799
                        'system: id'
800
                    ),
801
                    array(
802
                        'system:pagination',
803
                        ($fields['source'] == $section_id && in_array('system:pagination', $fields['xml_elements'])),
804
                        'system: pagination'
805
                    ),
806
                    array(
807
                        'system:date',
808
                        ($fields['source'] == $section_id && in_array('system:date', $fields['xml_elements'])),
809
                        'system: date'
810
                    )
811
                )
812
            );
813
814
            if (is_array($section_data['fields']) && !empty($section_data['fields'])) {
815
                foreach ($section_data['fields'] as $field) {
816
                    $elements = $field->fetchIncludableElements();
817
818
                    if (is_array($elements) && !empty($elements)) {
819
                        foreach ($elements as $name) {
820
                            $selected = false;
821
822
                            if ($fields['source'] == $section_id && in_array($name, $fields['xml_elements'])) {
823
                                $selected = true;
824
                            }
825
826
                            $optgroup['options'][] = array($name, $selected, $name);
827
                        }
828
                    }
829
                }
830
            }
831
832
            $options[] = $optgroup;
833
        }
834
835
        $label->appendChild(Widget::Select('fields[xml_elements][]', $options, array('multiple' => 'multiple')));
836
        $col->appendChild($label);
837
838
        // Associations
839
        $label = Widget::Checkbox('fields[associated_entry_counts]', $fields['associated_entry_counts'], __('Include a count of entries in associated sections'));
840
        $this->setContext($label, array('sections'));
841
        $col->appendChild($label);
842
843
        // Encoding
844
        $label = Widget::Checkbox('fields[html_encode]', $fields['html_encode'], __('HTML-encode text'));
845
        $this->setContext($label, array('sections'));
846
        $col->appendChild($label);
847
848
        $group->appendChild($col);
849
        $col = new XMLElement('div', null, array('class' => 'column'));
850
851
        // Support multiple parameters
852
        if (!isset($fields['param'])) {
853
            $fields['param'] = array();
854
        } elseif (!is_array($fields['param'])) {
855
            $fields['param'] = array($fields['param']);
856
        }
857
858
        // Parameters
859
        $label = Widget::Label(__('Output Parameters'));
860
        $prefix = '$ds-' . (isset($this->_context[1]) ? Lang::createHandle($fields['name']) : __('untitled')) . '.';
861
862
        $options = array(
863
            array('label' => __('Authors'), 'data-label' => 'authors', 'options' => array())
864
        );
865
866
        foreach (array('id', 'username', 'name', 'email', 'user_type') as $p) {
867
            $options[0]['options'][] = array(
868
                $p,
869
                ($fields['source'] == 'authors' && in_array($p, $fields['param'])),
870
                $prefix . $p,
871
                null,
872
                null,
873
                array(
874
                    'data-handle' => $p
875
                )
876
            );
877
        }
878
879
        foreach ($field_groups as $section_id => $section_data) {
880
            $optgroup = array('label' => $section_data['section']->get('name'), 'data-label' => 'section-' . $section_data['section']->get('id'), 'options' => array());
881
882
            foreach (array('id', 'creation-date', 'modification-date', 'author') as $p) {
883
                $option = array(
884
                    'system:' . $p,
885
                    ($fields['source'] == $section_id && in_array('system:' . $p, $fields['param'])),
886
                    $prefix . 'system-' . $p,
887
                    null,
888
                    null,
889
                    array(
890
                        'data-handle' => 'system-' . $p
891
                    )
892
                );
893
894
                // Handle 'system:date' as an output paramater (backwards compatibility)
895
                if ($p === 'creation-date') {
896
                    if ($fields['source'] == $section_id && in_array('system:date', $fields['param'])) {
897
                        $option[1] = true;
898
                    }
899
                }
900
901
                $optgroup['options'][] = $option;
902
            }
903
904
            if (is_array($section_data['fields']) && !empty($section_data['fields'])) {
905
                foreach ($section_data['fields'] as $input) {
906
                    if (!$input->allowDatasourceParamOutput()) {
907
                        continue;
908
                    }
909
910
                    $optgroup['options'][] = array(
911
                        $input->get('element_name'),
912
                        ($fields['source'] == $section_id && in_array($input->get('element_name'), $fields['param'])),
913
                        $prefix . $input->get('element_name'),
914
                        null,
915
                        null,
916
                        array(
917
                            'data-handle' => $input->get('element_name')
918
                        )
919
                    );
920
                }
921
            }
922
923
            $options[] = $optgroup;
924
        }
925
926
        $label->appendChild(Widget::Select('fields[param][]', $options, array('multiple' => 'multiple')));
927
        $col->appendChild($label);
928
929
        // Parameters in XML
930
        $label = Widget::Checkbox('fields[paramxml]', $fields['paramxml'], __('Include output parameters in xml'));
931
        $this->setContext($label, array('sections', 'authors'));
932
        $col->appendChild($label);
933
934
        $group->appendChild($col);
935
        $fieldset->appendChild($group);
936
937
        $this->Form->appendChild($fieldset);
938
939
        // Static XML
940
        if (!isset($fields['static_xml'])) {
941
            $fields['static_xml'] = null;
942
        }
943
944
        $fieldset = new XMLElement('fieldset');
945
        $this->setContext($fieldset, array('static-xml'));
946
        $fieldset->appendChild(new XMLElement('legend', __('Static XML')));
947
        $p = new XMLElement('p', __('Enter valid XML, exclude XML declaration'));
948
        $p->setAttribute('class', 'help');
949
        $fieldset->appendChild($p);
950
951
        $label = Widget::Label();
952
        $static_xml = htmlspecialchars(
953
            $fields['static_xml'],
954
            ENT_XML1|ENT_COMPAT,
955
            'UTF-8'
956
        );
957
        $label->appendChild(Widget::Textarea('fields[static_xml]', 12, 50, $static_xml, array('class' => 'code', 'placeholder' => '<static>content</static>')));
958
959
        if (isset($this->_errors['static_xml'])) {
960
            $fieldset->appendChild(Widget::Error($label, $this->_errors['static_xml']));
961
        } else {
962
            $fieldset->appendChild($label);
963
        }
964
965
        $this->Form->appendChild($fieldset);
966
967
        // Connections
968
        $fieldset = new XMLElement('fieldset');
969
        $fieldset->setAttribute('class', 'settings');
970
        $fieldset->appendChild(new XMLElement('legend', __('Attach to Pages')));
971
        $p = new XMLElement('p', __('The data will only be available on the selected pages.'));
972
        $p->setAttribute('class', 'help');
973
        $fieldset->appendChild($p);
974
975
        $div = new XMLElement('div');
976
        $label = Widget::Label(__('Pages'));
977
978
        $pages = (new PageManager)->select()->includeTypes()->execute()->rows();
979
        $ds_handle = str_replace('-', '_', Lang::createHandle($fields['name']));
980
        $connections = ResourceManager::getAttachedPages(ResourceManager::RESOURCE_TYPE_DS, $ds_handle);
981
        $selected = array();
982
983
        foreach ($connections as $connection) {
984
            $selected[] = $connection['id'];
985
        }
986
987
        $options = array();
988
989
        foreach ($pages as $page) {
990
            $options[] = array($page['id'], in_array($page['id'], $selected), PageManager::resolvePageTitle($page['id']));
991
        }
992
993
        $label->appendChild(Widget::Select('fields[connections][]', $options, array('multiple' => 'multiple')));
994
        $div->appendChild($label);
995
996
        $fieldset->appendChild($div);
997
        $this->Form->appendChild($fieldset);
998
999
1000
        // Call the provided datasources to let them inject their filters
1001
        // @todo Ideally when a new Datasource is chosen an AJAX request will fire
1002
        // to get the HTML from the extension. This is hardcoded for now into
1003
        // creating a 'big' page and then hiding the fields with JS
1004
        if (!empty($providers)) {
1005
            foreach ($providers as $providerClass => $provider) {
1006
                call_user_func_array(array($providerClass, 'buildEditor'), array($this->Form, &$this->_errors, $fields, $handle));
1007
            }
1008
        }
1009
1010
        $div = new XMLElement('div');
1011
        $div->setAttribute('class', 'actions');
1012
        $div->appendChild(Widget::Input('action[save]', ($isEditing ? __('Save Changes') : __('Create Data Source')), 'submit', array('accesskey' => 's')));
1013
1014
        if ($isEditing) {
1015
            $button = new XMLElement('button', __('Delete'));
1016
            $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this data source'), 'type' => 'submit', 'accesskey' => 'd', 'data-message' => __('Are you sure you want to delete this data source?')));
1017
            $div->appendChild($button);
1018
        }
1019
1020
        $this->Form->appendChild($div);
1021
    }
1022
1023
    public function __viewInfo()
1024
    {
1025
        $this->setPageType('form');
1026
1027
        $datasource = DatasourceManager::create($this->_context[1], array(), false);
1028
        $about = General::array_map_recursive('stripslashes', $datasource->about());
1029
1030
        $this->setTitle(__('%1$s &ndash; %2$s &ndash; %3$s', array($about['name'], __('Data Source'), __('Symphony'))));
1031
        $this->appendSubheading((($this->_context[0] == 'info') ? $about['name'] : __('Untitled')));
1032
        $this->insertBreadcrumbs(array(
1033
            Widget::Anchor(__('Data Sources'), SYMPHONY_URL . '/blueprints/datasources/'),
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1034
        ));
1035
        $this->Form->setAttribute('id', 'controller');
1036
1037
        $link = $about['author']['name'];
1038
1039
        if (isset($about['author']['website'])) {
1040
            $link = Widget::Anchor($about['author']['name'], General::validateURL($about['author']['website']));
1041
        } elseif (isset($about['author']['email'])) {
1042
            $link = Widget::Anchor($about['author']['name'], 'mailto:' . $about['author']['email']);
1043
        }
1044
1045
        foreach ($about as $key => $value) {
1046
            $fieldset = null;
1047
1048
            switch ($key) {
1049
                case 'author':
1050
                    if ($link) {
1051
                        $fieldset = new XMLElement('fieldset');
1052
                        $fieldset->appendChild(new XMLElement('legend', __('Author')));
1053
                        $fieldset->appendChild(new XMLElement('p', $link->generate(false)));
1054
                    }
1055
                    break;
1056
                case 'version':
1057
                    $fieldset = new XMLElement('fieldset');
1058
                    $fieldset->appendChild(new XMLElement('legend', __('Version')));
1059
                    $release_date = array_key_exists('release-date', $about) ? $about['release-date'] : filemtime(DatasourceManager::__getDriverPath($this->_context[1]));
1060
1061
                    if (preg_match('/^\d+(\.\d+)*$/', $value)) {
1062
                        $fieldset->appendChild(new XMLElement('p', __('%1$s released on %2$s', array($value, DateTimeObj::format($release_date, __SYM_DATE_FORMAT__)))));
0 ignored issues
show
Bug introduced by
The constant __SYM_DATE_FORMAT__ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1063
                    } else {
1064
                        $fieldset->appendChild(new XMLElement('p', __('Created by %1$s at %2$s', array($value, DateTimeObj::format($release_date, __SYM_DATE_FORMAT__)))));
1065
                    }
1066
                    break;
1067
                case 'description':
1068
                    $fieldset = new XMLElement('fieldset');
1069
                    $fieldset->appendChild(new XMLElement('legend', __('Description')));
1070
                    $fieldset->appendChild((is_object($about['description']) ? $about['description'] : new XMLElement('p', $about['description'])));
1071
                    break;
1072
                case 'example':
1073
                    if (is_callable(array($datasource, 'example'))) {
1074
                        $fieldset = new XMLElement('fieldset');
1075
                        $fieldset->appendChild(new XMLElement('legend', __('Example XML')));
1076
1077
                        $example = $datasource->example();
0 ignored issues
show
Bug introduced by
The method example() does not exist on Datasource. ( Ignorable by Annotation )

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

1077
                        /** @scrutinizer ignore-call */ 
1078
                        $example = $datasource->example();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1078
1079
                        if (is_object($example)) {
1080
                            $fieldset->appendChild($example);
1081
                        } else {
1082
                            $p = new XMLElement('p');
1083
                            $p->appendChild(new XMLElement('pre', '<code>' . str_replace('<', '&lt;', $example) . '</code>'));
1084
                            $fieldset->appendChild($p);
1085
                        }
1086
                    }
1087
                    break;
1088
            }
1089
1090
            if ($fieldset) {
1091
                $fieldset->setAttribute('class', 'settings');
1092
                $this->Form->appendChild($fieldset);
1093
            }
1094
        }
1095
1096
        // Display source
1097
        $file = DatasourceManager::__getClassPath($this->_context[1]) . '/data.' . $this->_context[1] . '.php';
1098
1099
        if (file_exists($file)) {
1100
            $fieldset = new XMLElement('fieldset');
1101
            $fieldset->setAttribute('class', 'settings');
1102
            $fieldset->appendChild(new XMLElement('legend', __('Source')));
1103
1104
            $source = file_get_contents($file);
1105
            $code = new XMLElement('code', htmlspecialchars($source));
1106
            $pre = new XMLElement('pre');
1107
            $pre->appendChild($code);
1108
1109
            $fieldset->appendChild($pre);
1110
            $this->Form->appendChild($fieldset);
1111
        }
1112
    }
1113
1114
    public function __actionIndex($resource_type)
1115
    {
1116
        return parent::__actionIndex(ResourceManager::RESOURCE_TYPE_DS);
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::__actionIndex(Re...ager::RESOURCE_TYPE_DS) targeting ResourcesPage::__actionIndex() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1117
    }
1118
1119
    public function __actionEdit()
1120
    {
1121
        if (is_array($_POST['action']) && array_key_exists('save', $_POST['action'])) {
1122
            return $this->__formAction();
1 ignored issue
show
Bug introduced by
Are you sure the usage of $this->__formAction() targeting contentBlueprintsDatasources::__formAction() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1123
        } elseif (is_array($_POST['action']) && array_key_exists('delete', $_POST['action'])) {
1124
            /**
1125
             * Prior to deleting the Datasource file. Target file path is provided.
1126
             *
1127
             * @delegate DatasourcePreDelete
1128
             * @since Symphony 2.2
1129
             * @param string $context
1130
             * '/blueprints/datasources/'
1131
             * @param string $file
1132
             *  The path to the Datasource file
1133
             * @param string $handle
1134
             *  @since Symphony 3.0.0
1135
             *  The handle of the Datasource
1136
             */
1137
            Symphony::ExtensionManager()->notifyMembers('DatasourcePreDelete', '/blueprints/datasources/', array(
1138
                'file' => DATASOURCES . "/data." . $this->_context[1] . ".php",
0 ignored issues
show
Bug introduced by
The constant DATASOURCES was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1139
                'handle' => $this->_context[1],
1140
            ));
1141
1142
            if (!General::deleteFile(DATASOURCES . '/data.' . $this->_context[1] . '.php')) {
1143
                $this->pageAlert(
1144
                    __('Failed to delete %s.', array('<code>' . $this->_context[1] . '</code>'))
1145
                    . ' ' . __('Please check permissions on %s.', array('<code>/workspace/data-sources</code>')),
1146
                    Alert::ERROR
1147
                );
1148
            } else {
1149
                $pages = ResourceManager::getAttachedPages(ResourceManager::RESOURCE_TYPE_DS, $this->_context[1]);
1150
1151
                foreach ($pages as $page) {
1152
                    ResourceManager::detach(ResourceManager::RESOURCE_TYPE_DS, $this->_context[1], $page['id']);
1153
                }
1154
1155
                /**
1156
                 * After deleting the Datasource file. Target file path is provided.
1157
                 *
1158
                 * @delegate DatasourcePostDelete
1159
                 * @since Symphony 3.0.0
1160
                 * @param string $context
1161
                 * '/blueprints/datasources/'
1162
                 * @param string $file
1163
                 *  The path to the Datasource file
1164
                 * @param string $handle
1165
                 *  The handle of the Datasource
1166
                 */
1167
                Symphony::ExtensionManager()->notifyMembers('DatasourcePostDelete', '/blueprints/datasources/', array(
1168
                    'file' => DATASOURCES . "/data." . $this->_context[1] . ".php",
1169
                    'handle' => $this->_context[1],
1170
                ));
1171
1172
                redirect(SYMPHONY_URL . '/blueprints/datasources/');
1 ignored issue
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1173
            }
1174
        }
1175
    }
1176
1177
    public function __actionNew()
1178
    {
1179
        if (is_array($_POST['action']) && array_key_exists('save', $_POST['action'])) {
1180
            return $this->__formAction();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->__formAction() targeting contentBlueprintsDatasources::__formAction() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1181
        }
1182
    }
1183
1184
    public function __formAction()
1185
    {
1186
        $fields = $_POST['fields'];
1187
        $this->_errors = array();
1188
        $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::DATASOURCE);
1189
        $providerClass = null;
1190
1191
        if (trim($fields['name']) == '') {
1192
            $this->_errors['name'] = __('This is a required field');
1193
        } elseif (strpos($fields['name'], '\\') !== false) {
1194
            $this->_errors['name'] = __('This field contains invalid characters') . ' (\\)';
1195
        } elseif (!preg_match('/^[a-z]/i', $fields['name'])) {
1196
            $this->_errors['name'] = __('The name of the data source must begin with a letter.');
1197
        }
1198
1199
        if ($fields['source'] == 'static_xml') {
1200
            if (trim($fields['static_xml']) == '') {
1201
                $this->_errors['static_xml'] = __('This is a required field');
1202
            } else {
1203
                $xml_errors = null;
1204
1205
                General::validateXML($fields['static_xml'], $xml_errors, false, new XsltProcess());
1206
1207
                if (!empty($xml_errors)) {
1208
                    $this->_errors['static_xml'] = __('XML is invalid.');
1209
                }
1210
            }
1211
        } elseif (is_numeric($fields['source'])) {
1212
            if (strlen(trim($fields['max_records'])) == 0 || (is_numeric($fields['max_records']) && $fields['max_records'] < 1)) {
1213
                if ($fields['paginate_results'] === 'yes') {
1214
                    $this->_errors['max_records'] = __('A result limit must be set');
1215
                }
1216
            } elseif (!self::__isValidPageString($fields['max_records'])) {
1217
                $this->_errors['max_records'] = __('Must be a valid number or parameter');
1218
            }
1219
1220
            if (strlen(trim($fields['page_number'])) == 0 || (is_numeric($fields['page_number']) && $fields['page_number'] < 1)) {
1221
                if ($fields['paginate_results'] === 'yes') {
1222
                    $this->_errors['page_number'] = __('A page number must be set');
1223
                }
1224
            } elseif (!self::__isValidPageString($fields['page_number'])) {
1225
                $this->_errors['page_number'] = __('Must be a valid number or parameter');
1226
            }
1227
1228
            // See if a Provided Datasource is saved
1229
        } elseif (!empty($providers)) {
1230
            foreach ($providers as $providerClass => $provider) {
1231
                if ($fields['source'] == call_user_func(array($providerClass, 'getSource'))) {
1232
                    call_user_func_array(array($providerClass, 'validate'), array(&$fields, &$this->_errors));
1233
                    break;
1234
                }
1235
1236
                unset($providerClass);
1237
            }
1238
        }
1239
1240
        $classname = Lang::createHandle($fields['name'], 255, '_', false, true, array('@^[^a-z\d]+@i' => '', '/[^\w-\.]/i' => ''));
1241
        $rootelement = str_replace('_', '-', $classname);
1242
1243
        // Check to make sure the classname is not empty after handlisation.
1244
        if (empty($classname) && !isset($this->_errors['name'])) {
1245
            $this->_errors['name'] = __('Please ensure name contains at least one Latin-based character.', array($classname));
1246
        }
1247
1248
        $file = DATASOURCES . '/data.' . $classname . '.php';
0 ignored issues
show
Bug introduced by
The constant DATASOURCES was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1249
1250
        $isDuplicate = false;
1251
        $queueForDeletion = null;
1252
1253
        if ($this->_context[0] == 'new' && is_file($file)) {
1254
            $isDuplicate = true;
1255
        } elseif ($this->_context[0] == 'edit') {
1256
            $existing_handle = $this->_context[1];
1257
1258
            if ($classname != $existing_handle && is_file($file)) {
1259
                $isDuplicate = true;
1260
            } elseif ($classname != $existing_handle) {
1261
                $queueForDeletion = DATASOURCES . '/data.' . $existing_handle . '.php';
1262
            }
1263
        }
1264
1265
        // Duplicate
1266
        if ($isDuplicate) {
1267
            $this->_errors['name'] = __('A Data source with the name %s already exists', array('<code>' . $classname . '</code>'));
1268
        }
1269
1270
        if (empty($this->_errors)) {
1271
            $filters = array();
1272
            $elements = null;
1273
            $source = $fields['source'];
1274
            $params = array(
1275
                'rootelement' => $rootelement
1276
            );
1277
1278
            $about = array(
1279
                'name' => $fields['name'],
1280
                'version' => 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'),
1281
                'release date' => DateTimeObj::getGMT('c'),
1282
                'author name' => Symphony::Author()->getFullName(),
1283
                'author website' => URL,
0 ignored issues
show
Bug introduced by
The constant URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1284
                'author email' => Symphony::Author()->get('email')
1285
            );
1286
1287
            // If there is a provider, get their template
1288
            if ($providerClass) {
1289
                $dsShell = file_get_contents(call_user_func(array($providerClass, 'getTemplate')));
1290
            } else {
1291
                $dsShell = file_get_contents($this->getTemplate('blueprints.datasource'));
0 ignored issues
show
Bug introduced by
It seems like $this->getTemplate('blueprints.datasource') can also be of type false; however, parameter $filename of file_get_contents() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1291
                $dsShell = file_get_contents(/** @scrutinizer ignore-type */ $this->getTemplate('blueprints.datasource'));
Loading history...
1292
            }
1293
1294
            // Author metadata
1295
            self::injectAboutInformation($dsShell, $about);
1296
1297
            // Do dependencies, the template file must have <!-- CLASS NAME -->
1298
            $dsShell = str_replace('<!-- CLASS NAME -->', $classname, $dsShell);
1299
1300
            // If there is a provider, let them do the prepartion work
1301
            if ($providerClass) {
1302
                $dsShell = call_user_func(array($providerClass, 'prepare'), $fields, $params, $dsShell);
1303
            } else {
1304
                switch ($source) {
1305
                    case 'authors':
1306
                        $extends = 'AuthorDatasource';
1307
                        if (isset($fields['filter']['author'])) {
1308
                            $filters = $fields['filter']['author'];
1309
                        }
1310
1311
                        $elements = $fields['xml_elements'];
1312
1313
                        $params['order'] = $fields['order'];
1314
                        $params['redirectonempty'] = $fields['redirect_on_empty'];
1315
                        $params['redirectonforbidden'] = $fields['redirect_on_forbidden'];
1316
                        $params['redirectonrequired'] = $fields['redirect_on_required'];
1317
                        $params['requiredparam'] = trim($fields['required_url_param']);
1318
                        $params['negateparam'] = trim($fields['negate_url_param']);
1319
                        $params['paramoutput'] = $fields['param'];
1320
                        $params['paramxml'] = $fields['paramxml'];
1321
                        $params['sort'] = $fields['sort'];
1322
1323
                        break;
1324
                    case 'navigation':
1325
                        $extends = 'NavigationDatasource';
1326
                        if (isset($fields['filter']['navigation'])) {
1327
                            $filters = $fields['filter']['navigation'];
1328
                        }
1329
1330
                        $params['order'] = $fields['order'];
1331
                        $params['redirectonempty'] = $fields['redirect_on_empty'];
1332
                        $params['redirectonforbidden'] = $fields['redirect_on_forbidden'];
1333
                        $params['redirectonrequired'] = $fields['redirect_on_required'];
1334
                        $params['requiredparam'] = trim($fields['required_url_param']);
1335
                        $params['negateparam'] = trim($fields['negate_url_param']);
1336
1337
                        break;
1338
                    case 'static_xml':
1339
                        $extends = 'StaticXMLDatasource';
1340
                        $fields['static_xml'] = trim($fields['static_xml']);
1341
1342
                        if (preg_match('/^<\?xml/i', $fields['static_xml']) == true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/^<\?xml/i', $fields['static_xml']) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1343
                            // Need to remove any XML declaration
1344
                            $fields['static_xml'] = preg_replace('/^<\?xml[^>]+>/i', null, $fields['static_xml']);
1345
                        }
1346
1347
                        $params['static'] = sprintf(
1348
                            '%s',
1349
                            trim($fields['static_xml'])
1350
                        );
1351
                        break;
1352
                    default:
1353
                        $extends = 'SectionDatasource';
1354
                        $elements = $fields['xml_elements'];
1355
1356
                        if (is_array($fields['filter']) && !empty($fields['filter'])) {
1357
                            $filters = array();
1358
1359
                            foreach ($fields['filter'] as $f) {
1360
                                foreach ($f as $key => $val) {
1361
                                    $filters[$key] = $val;
1362
                                }
1363
                            }
1364
                        }
1365
1366
                        $params['order'] = $fields['order'];
1367
                        $params['group'] = $fields['group'];
1368
                        $params['paginateresults'] = $fields['paginate_results'];
1369
                        $params['limit'] = $fields['max_records'];
1370
                        $params['startpage'] = $fields['page_number'];
1371
                        $params['redirectonempty'] = $fields['redirect_on_empty'];
1372
                        $params['redirectonforbidden'] = $fields['redirect_on_forbidden'];
1373
                        $params['redirectonrequired'] = $fields['redirect_on_required'];
1374
                        $params['requiredparam'] = trim($fields['required_url_param']);
1375
                        $params['negateparam'] = trim($fields['negate_url_param']);
1376
                        $params['paramoutput'] = $fields['param'];
1377
                        $params['paramxml'] = $fields['paramxml'];
1378
                        $params['sort'] = $fields['sort'];
1379
                        $params['htmlencode'] = $fields['html_encode'];
1380
                        $params['associatedentrycounts'] = $fields['associated_entry_counts'];
1381
1382
                        break;
1383
                }
1384
1385
                $this->__injectVarList($dsShell, $params);
1386
                $this->__injectIncludedElements($dsShell, $elements);
1387
                self::injectFilters($dsShell, $filters);
1388
1389
                if (preg_match_all('@(\$ds-[0-9a-z_\.\-]+)@i', $dsShell, $matches)) {
1390
                    $dependencies = General::array_remove_duplicates($matches[1]);
1391
                    $dependencies = array_map('addslashes', $dependencies);
1392
                    $dsShell = str_replace('<!-- DS DEPENDENCY LIST -->', "'" . implode("', '", $dependencies) . "'", $dsShell);
1393
                }
1394
1395
                $dsShell = str_replace('<!-- CLASS EXTENDS -->', $extends, $dsShell);
1396
                $dsShell = str_replace('<!-- SOURCE -->', addslashes($source), $dsShell);
1397
            }
1398
1399
            if ($this->_context[0] == 'new') {
1400
                /**
1401
                 * Prior to creating the Datasource, the file path where it will be written to
1402
                 * is provided and well as the contents of that file.
1403
                 *
1404
                 * @delegate DatasourcePreCreate
1405
                 * @since Symphony 2.2
1406
                 * @param string $context
1407
                 * '/blueprints/datasources/'
1408
                 * @param string $file
1409
                 *  The path to the Datasource file
1410
                 * @param string $contents
1411
                 *  The contents for this Datasource as a string passed by reference
1412
                 * @param array $params
1413
                 *  An array of all the `$dsParam*` values
1414
                 * @param array $elements
1415
                 *  An array of all the elements included in this datasource
1416
                 * @param array $filters
1417
                 *  An associative array of all the filters for this datasource with the key
1418
                 *  being the `field_id` and the value the filter.
1419
                 * @param array $dependencies
1420
                 *  An array of dependencies that this datasource has
1421
                 * @param string $source
1422
                 *  The source of the datasource's data
1423
                 */
1424
                Symphony::ExtensionManager()->notifyMembers('DatasourcePreCreate', '/blueprints/datasources/', array(
1425
                    'file' => $file,
1426
                    'contents' => &$dsShell,
1427
                    'params' => $params,
1428
                    'elements' => $elements,
1429
                    'filters' => $filters,
1430
                    'dependencies' => $dependencies,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dependencies does not seem to be defined for all execution paths leading up to this point.
Loading history...
1431
                    'source' => $source
1432
                ));
1433
            } else {
1434
                /**
1435
                 * Prior to editing a Datasource, the file path where it will be written to
1436
                 * is provided and well as the contents of that file.
1437
                 *
1438
                 * @delegate DatasourcePreEdit
1439
                 * @since Symphony 2.2
1440
                 * @param string $context
1441
                 * '/blueprints/datasources/'
1442
                 * @param string $file
1443
                 *  The path to the Datasource file
1444
                 * @param string $contents
1445
                 *  The contents for this Datasource as a string passed by reference
1446
                 * @param array $params
1447
                 *  An array of all the `$dsParam*` values
1448
                 * @param array $elements
1449
                 *  An array of all the elements included in this datasource
1450
                 * @param array $filters
1451
                 *  An associative array of all the filters for this datasource with the key
1452
                 *  being the `field_id` and the value the filter.
1453
                 * @param array $dependencies
1454
                 *  An array of dependencies that this datasource has
1455
                 * @param string $source
1456
                 *  The source of the datasource's data
1457
                 */
1458
                Symphony::ExtensionManager()->notifyMembers('DatasourcePreEdit', '/blueprints/datasources/', array(
1459
                    'file' => $file,
1460
                    'contents' => &$dsShell,
1461
                    'params' => $params,
1462
                    'elements' => $elements,
1463
                    'filters' => $filters,
1464
                    'dependencies' => $dependencies,
1465
                    'source' => $source
1466
                ));
1467
            }
1468
1469
            // Remove left over placeholders
1470
            $dsShell = preg_replace(array('/<!--[\w ]++-->/', '/(\t+[\r\n]){2,}/', '/(\r\n){2,}/'), '$1', $dsShell);
1471
1472
            // Write the file
1473
            if (!General::writeFile($file, $dsShell, Symphony::Configuration()->get('write_mode', 'file'), 'w', true)) {
0 ignored issues
show
Bug introduced by
It seems like Symphony::Configuration(...t('write_mode', 'file') can also be of type array; however, parameter $perm of General::writeFile() does only seem to accept integer|string, maybe add an additional type check? ( Ignorable by Annotation )

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

1473
            if (!General::writeFile($file, $dsShell, /** @scrutinizer ignore-type */ Symphony::Configuration()->get('write_mode', 'file'), 'w', true)) {
Loading history...
1474
                $this->pageAlert(
1475
                    __('Failed to write Data source to disk.')
1476
                    . ' ' . __('Please check permissions on %s.', array('<code>/workspace/data-sources</code>')),
1477
                    Alert::ERROR
1478
                );
1479
1480
                // Write successful
1481
            } else {
1482
                if (function_exists('opcache_invalidate')) {
1483
                    opcache_invalidate($file, true);
1484
                }
1485
1486
                // Attach this datasources to pages
1487
                $connections = $fields['connections'];
1488
                ResourceManager::setPages(ResourceManager::RESOURCE_TYPE_DS, is_null($existing_handle) ? $classname : $existing_handle, $connections);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $existing_handle does not seem to be defined for all execution paths leading up to this point.
Loading history...
1489
1490
                // If the datasource has been updated and the name changed, then adjust all the existing pages that have the old datasource name
1491
                if ($queueForDeletion) {
1492
                    General::deleteFile($queueForDeletion);
1493
1494
                    // Update pages that use this DS
1495
                    $pages = (new PageManager)
1496
                        ->select(['data_sources', 'id'])
1497
                        ->where(['data_sources' => ['regexp' => '[[:<:]]' . $existing_handle . '[[:>:]]']])
1498
                        ->execute()
1499
                        ->rows();
1500
1501
                    if (is_array($pages) && !empty($pages)) {
1502
                        foreach ($pages as $page) {
1503
                            $page['data_sources'] = preg_replace('/\b'.$existing_handle.'\b/i', $classname, $page['data_sources']);
1504
1505
                            PageManager::edit($page['id'], $page);
1506
                        }
1507
                    }
1508
                }
1509
1510
                if ($this->_context[0] == 'new') {
1511
                    /**
1512
                     * After creating the Datasource, the path to the Datasource file is provided
1513
                     *
1514
                     * @delegate DatasourcePostCreate
1515
                     * @since Symphony 2.2
1516
                     * @param string $context
1517
                     * '/blueprints/datasources/'
1518
                     * @param string $file
1519
                     *  The path to the Datasource file
1520
                     */
1521
                    Symphony::ExtensionManager()->notifyMembers('DatasourcePostCreate', '/blueprints/datasources/', array(
1522
                        'file' => $file
1523
                    ));
1524
                } else {
1525
                    /**
1526
                     * After editing the Datasource, the path to the Datasource file is provided
1527
                     *
1528
                     * @delegate DatasourcePostEdit
1529
                     * @since Symphony 2.2
1530
                     * @param string $context
1531
                     * '/blueprints/datasources/'
1532
                     * @param string $file
1533
                     *  The path to the Datasource file
1534
                     * @param string $previous_file
1535
                     *  The path of the previous Datasource file in the case where a Datasource may
1536
                     *  have been renamed. To get the handle from this value, see
1537
                     *  `DatasourceManager::__getHandleFromFilename`
1538
                     */
1539
                    Symphony::ExtensionManager()->notifyMembers('DatasourcePostEdit', '/blueprints/datasources/', array(
1540
                        'file' => $file,
1541
                        'previous_file' => ($queueForDeletion) ? $queueForDeletion : null
1542
                    ));
1543
                }
1544
1545
                redirect(SYMPHONY_URL . '/blueprints/datasources/edit/'.$classname.'/'.($this->_context[0] == 'new' ? 'created' : 'saved') . '/');
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1546
            }
1547
        }
1548
    }
1549
1550
    public static function injectFilters(&$shell, array $filters)
1551
    {
1552
        if (!is_array($filters) || empty($filters)) {
0 ignored issues
show
introduced by
The condition is_array($filters) is always true.
Loading history...
1553
            return;
1554
        }
1555
1556
        $placeholder = '<!-- FILTERS -->';
1557
        $string = 'public $dsParamFILTERS = array(' . PHP_EOL;
1558
1559
        foreach ($filters as $key => $val) {
1560
            if (trim($val) == '' || !is_string($val)) {
1561
                continue;
1562
            }
1563
1564
            $string .= "        '" . addslashes($key) . "' => '" . addslashes($val) . "'," . PHP_EOL;
1565
        }
1566
1567
        $string .= "    );" . PHP_EOL . "        " . $placeholder;
1568
1569
        $shell = str_replace($placeholder, trim($string), $shell);
1570
    }
1571
1572
    public static function injectAboutInformation(&$shell, array $details)
1573
    {
1574
        if (!is_array($details) || empty($details)) {
0 ignored issues
show
introduced by
The condition is_array($details) is always true.
Loading history...
1575
            return;
1576
        }
1577
1578
        foreach ($details as $key => $val) {
1579
            if (!is_string($key) || !is_string($val)) {
1580
                continue;
1581
            }
1582
1583
            $shell = str_replace('<!-- ' . strtoupper(addslashes($key)) . ' -->', addslashes($val), $shell);
1584
        }
1585
    }
1586
1587
    public function __injectIncludedElements(&$shell, $elements)
1588
    {
1589
        if (!is_array($elements) || empty($elements)) {
1590
            return;
1591
        }
1592
        $elements = array_map('addslashes', $elements);
1593
        $placeholder = '<!-- INCLUDED ELEMENTS -->';
1594
        $shell = str_replace($placeholder, "public \$dsParamINCLUDEDELEMENTS = array(" . PHP_EOL . "        '" . implode("'," . PHP_EOL . "        '", $elements) . "'" . PHP_EOL . '    );' . PHP_EOL . "    " . $placeholder, $shell);
1595
    }
1596
1597
    public function __injectVarList(&$shell, $vars)
1598
    {
1599
        if (!is_array($vars) || empty($vars)) {
1600
            return;
1601
        }
1602
1603
        $var_list = null;
1604
1605
        foreach ($vars as $key => $val) {
1606
            if (!is_string($key)) {
1607
                continue;
1608
            }
1609
            if (is_array($val)) {
1610
                $val = array_map('addslashes', $val);
1611
                $val = "array(" . PHP_EOL . "        '" . implode("'," . PHP_EOL . "        '", $val) . "'" . PHP_EOL . '        );';
1612
                $var_list .= '    public $dsParam' . strtoupper(addslashes($key)) . ' = ' . $val . PHP_EOL;
1613
            } elseif (trim($val) !== '') {
1614
                $var_list .= '    public $dsParam' . strtoupper(addslashes($key)) . " = '" . addslashes($val) . "';" . PHP_EOL;
1615
            }
1616
        }
1617
1618
        $placeholder = '<!-- VAR LIST -->';
1619
        $shell = str_replace($placeholder, trim($var_list) . PHP_EOL . "    " . $placeholder, $shell);
1620
    }
1621
1622
    public function __appendAuthorFilter(&$wrapper, $h4_label, $name, $value = null, $templateOnly = true)
1623
    {
1624
        if (!$templateOnly) {
1625
            $li = new XMLElement('li');
1626
            $li->setAttribute('class', 'unique');
1627
            $li->setAttribute('data-type', $name);
1628
            $li->appendChild(new XMLElement('header', '<h4>' . $h4_label . '</h4>'));
1629
            $label = Widget::Label(__('Value'));
1630
            $label->appendChild(Widget::Input('fields[filter][author]['.$name.']', General::sanitize($value)));
1631
            $li->appendChild($label);
1632
1633
            $wrapper->appendChild($li);
1634
        }
1635
1636
        $li = new XMLElement('li');
1637
        $li->setAttribute('class', 'unique template');
1638
        $li->setAttribute('data-type', $name);
1639
        $li->appendChild(new XMLElement('header', '<h4>' . $h4_label . '</h4>'));
1640
        $label = Widget::Label(__('Value'));
1641
        $label->appendChild(Widget::Input('fields[filter][author]['.$name.']'));
1642
        $li->appendChild($label);
1643
1644
        $wrapper->appendChild($li);
1645
    }
1646
1647
    private static function __isValidPageString($string)
1648
    {
1649
        return (bool)preg_match('/^\{\$[\w-]+(.[\w]+(-[\w]+)?){0,1}\}|[\d]+$/', $string);
1650
    }
1651
1652
    /**
1653
     * Given a `$url` and `$timeout`, this function will use the `Gateway`
1654
     * class to determine that it is a valid URL and returns successfully
1655
     * before the `$timeout`. If it does not, an error message will be
1656
     * returned, otherwise true.
1657
     *
1658
     * @since Symphony 2.3
1659
     * @param string $url
1660
     * @param integer $timeout
1661
     *  If not provided, this will default to 6 seconds
1662
     * @param string $error
1663
     *  If this function returns false, this variable will be populated with the
1664
     *  error message.
1665
     * @return array|boolean
1666
     *  Returns an array with the 'data' if it is a valid URL, otherwise a string
1667
     *  containing an error message.
1668
     */
1669
    public static function __isValidURL($url, $timeout = 6, &$error)
1670
    {
1671
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
1672
            $error = __('Invalid URL');
1673
            return false;
1674
        }
1675
1676
        // Check that URL was provided
1677
        $gateway = new Gateway;
1678
        $gateway->init($url);
1679
        $gateway->setopt('TIMEOUT', $timeout);
1680
        $data = $gateway->exec();
1681
1682
        $info = $gateway->getInfoLast();
1683
1684
        // 28 is CURLE_OPERATION_TIMEDOUT
1685
        if ($info['curl_errno'] === 28) {
1686
            $error = __('Request timed out. %d second limit reached.', array($timeout));
1687
            return false;
1688
        } elseif ($data === false || $info['http_code'] != 200) {
1689
            $error = __('Failed to load URL, status code %d was returned.', array($info['http_code']));
1690
            return false;
1691
        }
1692
1693
        return array('data' => $data);
1694
    }
1695
1696
    /**
1697
     * Set Data Source context
1698
     *
1699
     * @since Symphony 2.3.3
1700
     * @param XMLElement $element
1701
     * @param array $context
1702
     */
1703
    public function setContext(&$element, $context)
1704
    {
1705
        $element->setAttribute('class', 'settings contextual');
1706
        $element->setAttribute('data-context', implode(' ', (array)$context));
1707
    }
1708
}
1709