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
Pull Request — master (#2606)
by
unknown
05:01
created

FieldUpload::getCurrentValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 12
rs 9.4285
1
<?php
2
3
/**
4
 * @package toolkit
5
 */
6
7
/**
8
 * A simple Upload field that essentially maps to HTML's `<input type='file '/>`.
9
 */
10
class FieldUpload extends Field implements ExportableField, ImportableField
11
{
12
    protected static $imageMimeTypes = array(
13
        'image/gif',
14
        'image/jpg',
15
        'image/jpeg',
16
        'image/pjpeg',
17
        'image/png',
18
        'image/x-png'
19
    );
20
21 View Code Duplication
    public function __construct()
22
    {
23
        parent::__construct();
24
25
        $this->_name = __('File Upload');
0 ignored issues
show
Bug introduced by
The property _name does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
26
        $this->_required = true;
27
28
        $this->set('location', 'sidebar');
29
        $this->set('required', 'no');
30
    }
31
32
    /*-------------------------------------------------------------------------
33
        Definition:
34
    -------------------------------------------------------------------------*/
35
36
    public function canFilter()
37
    {
38
        return true;
39
    }
40
41
    public function canPrePopulate()
42
    {
43
        return true;
44
    }
45
46
    public function isSortable()
47
    {
48
        return true;
49
    }
50
51
    public function fetchFilterableOperators()
52
    {
53
        return array(
54
            array(
55
                'title' => 'is',
56
                'filter' => ' ',
57
                'help' => __('Find files that are an exact match for the given string.')
58
            ),
59
            array(
60
                'title' => 'contains',
61
                'filter' => 'regexp: ',
62
                'help' => __('Find files that match the given <a href="%s">MySQL regular expressions</a>.', array(
63
                    'http://dev.mysql.com/doc/mysql/en/regexp.html'
64
                ))
65
            ),
66
            array(
67
                'title' => 'does not contain',
68
                'filter' => 'not-regexp: ',
69
                'help' => __('Find files that do not match the given <a href="%s">MySQL regular expressions</a>.', array(
70
                    'http://dev.mysql.com/doc/mysql/en/regexp.html'
71
                ))
72
            ),
73
            array(
74
                'title' => 'file type is',
75
                'filter' => 'mimetype: ',
76
                'help' => __('Find files that match the given mimetype.')
77
            ),
78
            array(
79
                'title' => 'size is',
80
                'filter' => 'size: ',
81
                'help' => __('Find files that match the given size.')
82
            )
83
        );
84
    }
85
86
    /*-------------------------------------------------------------------------
87
        Setup:
88
    -------------------------------------------------------------------------*/
89
90
    public function createTable()
91
    {
92
        return Symphony::Database()->query(
93
            "CREATE TABLE IF NOT EXISTS `tbl_entries_data_" . $this->get('id') . "` (
94
              `id` int(11) unsigned NOT null auto_increment,
95
              `entry_id` int(11) unsigned NOT null,
96
              `file` varchar(255) default null,
97
              `size` int(11) unsigned null,
98
              `mimetype` varchar(100) default null,
99
              `meta` varchar(255) default null,
100
              PRIMARY KEY  (`id`),
101
              UNIQUE KEY `entry_id` (`entry_id`),
102
              KEY `file` (`file`),
103
              KEY `mimetype` (`mimetype`)
104
            ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"
105
        );
106
    }
107
108
    /*-------------------------------------------------------------------------
109
        Utilities:
110
    -------------------------------------------------------------------------*/
111
112
    public function entryDataCleanup($entry_id, $data = null)
113
    {
114
        $file_location = $this->getFilePath($data['file']);
115
116
        if (is_file($file_location)) {
117
            General::deleteFile($file_location);
118
        }
119
120
        parent::entryDataCleanup($entry_id);
121
122
        return true;
123
    }
124
125
    public static function getMetaInfo($file, $type)
126
    {
127
        $meta = array();
128
129
        if (!file_exists($file) || !is_readable($file)) {
130
            return $meta;
131
        }
132
133
        $meta['creation'] = DateTimeObj::get('c', filemtime($file));
134
135
        if (General::in_iarray($type, fieldUpload::$imageMimeTypes) && $array = @getimagesize($file)) {
136
            $meta['width'] = $array[0];
137
            $meta['height'] = $array[1];
138
        }
139
140
        return $meta;
141
    }
142
143
    public function getFilePath($filename)
144
    {
145
        /**
146
         * Ensure the file exists in the `WORKSPACE` directory
147
         * @link http://getsymphony.com/discuss/issues/view/610/
148
         */
149
        $file = WORKSPACE . preg_replace(array('%/+%', '%(^|/)\.\./%', '%\/workspace\/%'), '/', $this->get('destination') . '/' . $filename);
150
151
        return $file;
152
    }
153
154
    /*-------------------------------------------------------------------------
155
        Settings:
156
    -------------------------------------------------------------------------*/
157
158
    public function displaySettingsPanel(XMLElement &$wrapper, $errors = null)
159
    {
160
        parent::displaySettingsPanel($wrapper, $errors);
161
162
        // Destination Folder
163
        $ignore = array(
164
            '/workspace/events',
165
            '/workspace/data-sources',
166
            '/workspace/text-formatters',
167
            '/workspace/pages',
168
            '/workspace/utilities'
169
        );
170
        $directories = General::listDirStructure(WORKSPACE, null, true, DOCROOT, $ignore);
171
172
        $label = Widget::Label(__('Destination Directory'));
173
174
        $options = array();
175
        $options[] = array('/workspace', false, '/workspace');
176
177
        if (!empty($directories) && is_array($directories)) {
178
            foreach ($directories as $d) {
179
                $d = '/' . trim($d, '/');
180
181
                if (!in_array($d, $ignore)) {
182
                    $options[] = array($d, ($this->get('destination') == $d), $d);
183
                }
184
            }
185
        }
186
187
        $label->appendChild(Widget::Select('fields['.$this->get('sortorder').'][destination]', $options));
188
189 View Code Duplication
        if (isset($errors['destination'])) {
190
            $wrapper->appendChild(Widget::Error($label, $errors['destination']));
191
        } else {
192
            $wrapper->appendChild($label);
193
        }
194
195
        // Validation rule
196
        $this->buildValidationSelect($wrapper, $this->get('validator'), 'fields['.$this->get('sortorder').'][validator]', 'upload', $errors);
197
198
        // Requirements and table display
199
        $this->appendStatusFooter($wrapper);
200
    }
201
202
    public function checkFields(array &$errors, $checkForDuplicates = true)
203
    {
204
        if (is_dir(DOCROOT . $this->get('destination') . '/') === false) {
205
            $errors['destination'] = __('The destination directory, %s, does not exist.', array(
206
                '<code>' . $this->get('destination') . '</code>'
207
            ));
208 View Code Duplication
        } elseif (is_writable(DOCROOT . $this->get('destination') . '/') === false) {
209
            $errors['destination'] = __('The destination directory is not writable.')
210
                . ' '
211
                . __('Please check permissions on %s.', array(
212
                    '<code>' . $this->get('destination') . '</code>'
213
                ));
214
        }
215
216
        parent::checkFields($errors, $checkForDuplicates);
217
    }
218
219 View Code Duplication
    public function commit()
220
    {
221
        if (!parent::commit()) {
222
            return false;
223
        }
224
225
        $id = $this->get('id');
226
227
        if ($id === false) {
228
            return false;
229
        }
230
231
        $fields = array();
232
233
        $fields['destination'] = $this->get('destination');
234
        $fields['validator'] = ($fields['validator'] == 'custom' ? null : $this->get('validator'));
235
236
        return FieldManager::saveSettings($id, $fields);
237
    }
238
239
    /*-------------------------------------------------------------------------
240
        Publish:
241
    -------------------------------------------------------------------------*/
242
243
    public function displayPublishPanel(XMLElement &$wrapper, $data = null, $flagWithError = null, $fieldnamePrefix = null, $fieldnamePostfix = null, $entry_id = null)
244
    {
245
        if (is_dir(DOCROOT . $this->get('destination') . '/') === false) {
246
            $flagWithError = __('The destination directory, %s, does not exist.', array(
247
                '<code>' . $this->get('destination') . '</code>'
248
            ));
249 View Code Duplication
        } elseif ($flagWithError && is_writable(DOCROOT . $this->get('destination') . '/') === false) {
250
            $flagWithError = __('Destination folder is not writable.')
251
                . ' '
252
                . __('Please check permissions on %s.', array(
253
                    '<code>' . $this->get('destination') . '</code>'
254
                ));
255
        }
256
257
        $label = Widget::Label($this->get('label'));
258
        $label->setAttribute('class', 'file');
259
260
        if ($this->get('required') !== 'yes') {
261
            $label->appendChild(new XMLElement('i', __('Optional')));
262
        }
263
264
        $span = new XMLElement('span', null, array('class' => 'frame'));
265
266
        if (isset($data['file'])) {
267
            $filename = $this->get('destination') . '/' . basename($data['file']);
268
            $file = $this->getFilePath($data['file']);
269
            if (file_exists($file) === false || !is_readable($file)) {
270
                $flagWithError = __('The file uploaded is no longer available. Please check that it exists, and is readable.');
271
            }
272
273
            $span->appendChild(new XMLElement('span', Widget::Anchor(preg_replace("![^a-z0-9]+!i", "$0&#8203;", $filename), URL . $filename)));
274
        } else {
275
            $filename = null;
276
        }
277
278
        $span->appendChild(Widget::Input('fields'.$fieldnamePrefix.'['.$this->get('element_name').']'.$fieldnamePostfix, $filename, ($filename ? 'hidden' : 'file')));
279
280
        $label->appendChild($span);
281
282
        if ($flagWithError != null) {
283
            $wrapper->appendChild(Widget::Error($label, $flagWithError));
284
        } else {
285
            $wrapper->appendChild($label);
286
        }
287
    }
288
289
    public function validateFilename($file, &$message)
290
    {
291
        if ($this->get('validator') != null) {
292
            $rule = $this->get('validator');
293
294 View Code Duplication
            if (General::validateString($file, $rule) === false) {
295
                $message = __('File chosen in ‘%s’ does not match allowable file types for that field.', array(
296
                    $this->get('label')
297
                ));
298
299
                return self::__INVALID_FIELDS__;
300
            }
301
        }
302
        // If the developer did not specified any validator, check for the
303
        // blacklisted file types instead
304
        else {
305
            $blacklist = Symphony::Configuration()->get('upload_blacklist', 'admin');
306
307 View Code Duplication
            if (!empty($blacklist) && General::validateString($file, $blacklist)) {
308
                $message = __('File chosen in ‘%s’ is blacklisted for that field.', array(
309
                    $this->get('label')
310
                ));
311
312
                return self::__INVALID_FIELDS__;
313
            }
314
        }
315
316
        return self::__OK__;
317
    }
318
319
    public function checkPostFieldData($data, &$message, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
checkPostFieldData uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
320
    {
321
        /**
322
         * For information about PHPs upload error constants see:
323
         * @link http://php.net/manual/en/features.file-upload.errors.php
324
         */
325
        $message = null;
326
327
        if (
328
            empty($data)
329
            || (
330
                is_array($data)
331
                && isset($data['error'])
332
                && $data['error'] == UPLOAD_ERR_NO_FILE
333
            )
334
        ) {
335 View Code Duplication
            if ($this->get('required') === 'yes') {
336
                $message = __('‘%s’ is a required field.', array($this->get('label')));
337
338
                return self::__MISSING_FIELDS__;
339
            }
340
341
            return self::__OK__;
342
        }
343
344
        // Its not an array, so just retain the current data and return
345
        if (is_array($data) === false) {
346
            $file = $this->getFilePath(basename($data));
347
            if (file_exists($file) === false || !is_readable($file)) {
348
                $message = __('The file uploaded is no longer available. Please check that it exists, and is readable.');
349
350
                return self::__INVALID_FIELDS__;
351
            }
352
353
            // Ensure that the file still matches the validator and hasn't
354
            // changed since it was uploaded.
355
            return $this->validateFilename($file, $message);
356
        }
357
358
        if (is_dir(DOCROOT . $this->get('destination') . '/') === false) {
359
            $message = __('The destination directory, %s, does not exist.', array(
360
                '<code>' . $this->get('destination') . '</code>'
361
            ));
362
363
            return self::__ERROR__;
364 View Code Duplication
        } elseif (is_writable(DOCROOT . $this->get('destination') . '/') === false) {
365
            $message = __('Destination folder is not writable.')
366
                . ' '
367
                . __('Please check permissions on %s.', array(
368
                    '<code>' . $this->get('destination') . '</code>'
369
                ));
370
371
            return self::__ERROR__;
372
        }
373
374
        if ($data['error'] != UPLOAD_ERR_NO_FILE && $data['error'] != UPLOAD_ERR_OK) {
375
            switch ($data['error']) {
376
                case UPLOAD_ERR_INI_SIZE:
377
                    $message = __('File chosen in ‘%1$s’ exceeds the maximum allowed upload size of %2$s specified by your host.', array($this->get('label'), (is_numeric(ini_get('upload_max_filesize')) ? General::formatFilesize(ini_get('upload_max_filesize')) : ini_get('upload_max_filesize'))));
378
                    break;
379
                case UPLOAD_ERR_FORM_SIZE:
380
                    $message = __('File chosen in ‘%1$s’ exceeds the maximum allowed upload size of %2$s, specified by Symphony.', array($this->get('label'), General::formatFilesize($_POST['MAX_FILE_SIZE'])));
381
                    break;
382
                case UPLOAD_ERR_PARTIAL:
383
                case UPLOAD_ERR_NO_TMP_DIR:
384
                    $message = __('File chosen in ‘%s’ was only partially uploaded due to an error.', array($this->get('label')));
385
                    break;
386
                case UPLOAD_ERR_CANT_WRITE:
387
                    $message = __('Uploading ‘%s’ failed. Could not write temporary file to disk.', array($this->get('label')));
388
                    break;
389
                case UPLOAD_ERR_EXTENSION:
390
                    $message = __('Uploading ‘%s’ failed. File upload stopped by extension.', array($this->get('label')));
391
                    break;
392
            }
393
394
            return self::__ERROR_CUSTOM__;
395
        }
396
397
        // Sanitize the filename
398
        $data['name'] = Lang::createFilename($data['name']);
399
400
        // Validate the filename
401
        return $this->validateFilename($data['name'], $message);
402
    }
403
404
    public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null)
405
    {
406
        $status = self::__OK__;
407
408
        // No file given, save empty data:
409
        if ($data === null) {
410
            return array(
411
                'file' =>       null,
412
                'mimetype' =>   null,
413
                'size' =>       null,
414
                'meta' =>       null
415
            );
416
        }
417
418
        // Its not an array, so just retain the current data and return:
419
        if (is_array($data) === false) {
420
            $file = $this->getFilePath(basename($data));
421
422
            $result = array(
423
                'file' =>       $data,
424
                'mimetype' =>   null,
425
                'size' =>       null,
426
                'meta' =>       null
427
            );
428
429
            // Grab the existing entry data to preserve the MIME type and size information
430
            if (isset($entry_id)) {
431
                $row = $this->getCurrentValues($entry_id);
432
433
                if (empty($row) === false) {
434
                    $result = $row;
435
                }
436
            }
437
438
            // Found the file, add any missing meta information:
439
            if (file_exists($file) && is_readable($file)) {
440
                if (empty($result['mimetype'])) {
441
                    $result['mimetype'] = General::getMimeType($file);
442
                }
443
444
                if (empty($result['size'])) {
445
                    $result['size'] = filesize($file);
446
                }
447
448
                if (empty($result['meta'])) {
449
                    $result['meta'] = serialize(static::getMetaInfo($file, $result['mimetype']));
450
                }
451
452
                // The file was not found, or is unreadable:
453
            } else {
454
                $message = __('The file uploaded is no longer available. Please check that it exists, and is readable.');
455
                $status = self::__INVALID_FIELDS__;
456
            }
457
458
            return $result;
459
        }
460
461
        if ($simulate && is_null($entry_id)) {
462
            return $data;
463
        }
464
465
        // Check to see if the entry already has a file associated with it:
466
        if (is_null($entry_id) === false) {
467
            $row = $this->getCurrentValues($entry_id);
468
469
            $existing_file = isset($row['file']) ? $this->getFilePath($row['file']) : null;
470
471
            // File was removed:
472
            if (
473
                $data['error'] == UPLOAD_ERR_NO_FILE
474
                && !is_null($existing_file)
475
                && is_file($existing_file)
476
            ) {
477
                General::deleteFile($existing_file);
478
            }
479
        }
480
481
        // Do not continue on upload error:
482
        if ($data['error'] == UPLOAD_ERR_NO_FILE || $data['error'] != UPLOAD_ERR_OK) {
483
            return false;
484
        }
485
486
        // Where to upload the new file?
487
        $abs_path = DOCROOT . '/' . trim($this->get('destination'), '/');
488
        $rel_path = str_replace('/workspace', '', $this->get('destination'));
489
490
        // Sanitize the filename
491
        $data['name'] = Lang::createFilename($data['name']);
492
493
        // If a file already exists, then rename the file being uploaded by
494
        // adding `_1` to the filename. If `_1` already exists, the logic
495
        // will keep adding 1 until a filename is available (#672)
496
        if (file_exists($abs_path . '/' . $data['name'])) {
497
            $extension = General::getExtension($data['name']);
498
            $new_file = substr($abs_path . '/' . $data['name'], 0, -1 - strlen($extension));
499
            $renamed_file = $new_file;
0 ignored issues
show
Unused Code introduced by
$renamed_file is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
500
            $count = 1;
501
502
            do {
503
                $renamed_file = $new_file . '_' . $count . '.' . $extension;
504
                $count++;
505
            } while (file_exists($renamed_file));
506
507
            // Extract the name filename from `$renamed_file`.
508
            $data['name'] = str_replace($abs_path . '/', '', $renamed_file);
509
        }
510
511
        $file = $this->getFilePath($data['name']);
512
513
        // Attempt to upload the file:
514
        $uploaded = General::uploadFile(
515
            $abs_path,
516
            $data['name'],
517
            $data['tmp_name'],
518
            Symphony::Configuration()->get('write_mode', 'file')
0 ignored issues
show
Documentation introduced by
\Symphony::Configuration...t('write_mode', 'file') is of type array|string, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
519
        );
520
521
        if ($uploaded === false) {
522
            $message = __(
523
                __('There was an error while trying to upload the file %1$s to the target directory %2$s.'),
524
                array(
525
                    '<code>' . $data['name'] . '</code>',
526
                    '<code>workspace/' . ltrim($rel_path, '/') . '</code>'
527
                )
528
            );
529
            $status = self::__ERROR_CUSTOM__;
530
531
            return false;
532
        }
533
534
        // File has been replaced:
535
        if (
536
            isset($existing_file)
537
            && $existing_file !== $file
538
            && is_file($existing_file)
539
        ) {
540
            General::deleteFile($existing_file);
541
        }
542
543
        // Get the mimetype, don't trust the browser. RE: #1609
544
        $data['type'] = General::getMimeType($file);
545
546
        return array(
547
            'file' =>       basename($file),
548
            'size' =>       $data['size'],
549
            'mimetype' =>   $data['type'],
550
            'meta' =>       serialize(static::getMetaInfo($file, $data['type']))
551
        );
552
    }
553
554
    protected function getCurrentValues($entry_id)
555
    {
556
        return Symphony::Database()->fetchRow(0, sprintf(
557
            "SELECT `file`, `mimetype`, `size`, `meta`
558
                FROM `tbl_entries_data_%d`
559
                WHERE `entry_id` = %d
560
                LIMIT 1
561
            ",
562
            $this->get('id'),
563
            $entry_id
564
        ));
565
    }
566
567
    /*-------------------------------------------------------------------------
568
        Output:
569
    -------------------------------------------------------------------------*/
570
571
    public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null)
572
    {
573
        // It is possible an array of null data will be passed in. Check for this.
574
        if (!is_array($data) || !isset($data['file']) || is_null($data['file'])) {
575
            return;
576
        }
577
578
        $file = $this->getFilePath($data['file']);
579
        $filesize = (file_exists($file) && is_readable($file)) ? filesize($file) : null;
580
        $item = new XMLElement($this->get('element_name'));
581
        $item->setAttributeArray(array(
582
            'size' =>   !is_null($filesize) ? General::formatFilesize($filesize) : 'unknown',
583
            'bytes' =>  !is_null($filesize) ? $filesize : 'unknown',
584
            'path' =>   General::sanitize(
585
                str_replace(WORKSPACE, null, dirname($file))
586
            ),
587
            'type' =>   $data['mimetype']
588
        ));
589
590
        $item->appendChild(new XMLElement('filename', General::sanitize(basename($file))));
591
592
        $m = unserialize($data['meta']);
593
594
        if (is_array($m) && !empty($m)) {
595
            $item->appendChild(new XMLElement('meta', null, $m));
596
        }
597
598
        $wrapper->appendChild($item);
599
    }
600
601
    public function prepareTableValue($data, XMLElement $link = null, $entry_id = null)
602
    {
603
        if (isset($data['file']) === false || !$file = $data['file']) {
604
            return parent::prepareTableValue(null, $link, $entry_id);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
605
        }
606
607
        if ($link) {
608
            $link->setValue(basename($file));
609
            $link->setAttribute('data-path', $this->get('destination'));
610
611
            return $link->generate();
612
        } else {
613
            $link = Widget::Anchor(basename($file), URL . $this->get('destination') . '/' . $file);
614
            $link->setAttribute('data-path', $this->get('destination'));
615
616
            return $link->generate();
617
        }
618
    }
619
    
620
    public function prepareTextValue($data, $entry_id = null)
621
    {
622
        if (isset($data['file'])) {
623
            return $data['file'];
624
        }
625
        return null;
626
    }
627
628
    public function prepareAssociationsDrawerXMLElement(Entry $e, array $parent_association, $prepopulate = '')
629
    {
630
        $li = parent::prepareAssociationsDrawerXMLElement($e, $parent_association);
631
        $a = $li->getChild(0);
632
        $a->setAttribute('data-path', $this->get('destination'));
633
634
        return $li;
635
    }
636
637
    /*-------------------------------------------------------------------------
638
        Import:
639
    -------------------------------------------------------------------------*/
640
641
    public function getImportModes()
642
    {
643
        return array(
644
            'getValue' =>       ImportableField::STRING_VALUE,
645
            'getPostdata' =>    ImportableField::ARRAY_VALUE
646
        );
647
    }
648
649 View Code Duplication
    public function prepareImportValue($data, $mode, $entry_id = null)
650
    {
651
        $message = $status = null;
652
        $modes = (object)$this->getImportModes();
653
654
        if ($mode === $modes->getValue) {
655
            return $data;
656
        } elseif ($mode === $modes->getPostdata) {
657
            return $this->processRawFieldData($data, $status, $message, true, $entry_id);
658
        }
659
660
        return null;
661
    }
662
663
    /*-------------------------------------------------------------------------
664
        Export:
665
    -------------------------------------------------------------------------*/
666
667
    /**
668
     * Return a list of supported export modes for use with `prepareExportValue`.
669
     *
670
     * @return array
671
     */
672
    public function getExportModes()
673
    {
674
        return array(
675
            'getFilename' =>    ExportableField::VALUE,
676
            'getObject' =>      ExportableField::OBJECT,
677
            'getPostdata' =>    ExportableField::POSTDATA
678
        );
679
    }
680
681
    /**
682
     * Give the field some data and ask it to return a value using one of many
683
     * possible modes.
684
     *
685
     * @param mixed $data
686
     * @param integer $mode
687
     * @param integer $entry_id
688
     * @return array|string|null
689
     */
690
    public function prepareExportValue($data, $mode, $entry_id = null)
691
    {
692
        $modes = (object)$this->getExportModes();
693
694
        $filepath = $this->getFilePath($data['file']);
695
696
        // No file, or the file that the entry is meant to have no
697
        // longer exists.
698
        if (!isset($data['file']) || !is_file($filepath)) {
699
            return null;
700
        }
701
702
        if ($mode === $modes->getFilename) {
703
            return $data['file'];
704
        }
705
706
        if ($mode === $modes->getObject) {
707
            $object = (object)$data;
708
709
            if (isset($object->meta)) {
710
                $object->meta = unserialize($object->meta);
711
            }
712
713
            return $object;
714
        }
715
716
        if ($mode === $modes->getPostdata) {
717
            return $data['file'];
718
        }
719
    }
720
721
    /*-------------------------------------------------------------------------
722
        Filtering:
723
    -------------------------------------------------------------------------*/
724
725
    public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = false)
726
    {
727
        $field_id = $this->get('id');
728
729
        if (preg_match('/^mimetype:/', $data[0])) {
730
            $data[0] = str_replace('mimetype:', '', $data[0]);
731
            $column = 'mimetype';
732
        } elseif (preg_match('/^size:/', $data[0])) {
733
            $data[0] = str_replace('size:', '', $data[0]);
734
            $column = 'size';
735
        } else {
736
            $column = 'file';
737
        }
738
739
        if (self::isFilterRegex($data[0])) {
740
            $this->buildRegexSQL($data[0], array($column), $joins, $where);
741
        } elseif ($andOperation) {
742
            foreach ($data as $value) {
743
                $this->_key++;
744
                $value = $this->cleanValue($value);
745
                $joins .= "
746
                    LEFT JOIN
747
                        `tbl_entries_data_{$field_id}` AS t{$field_id}_{$this->_key}
748
                        ON (e.id = t{$field_id}_{$this->_key}.entry_id)
749
                ";
750
                $where .= "
751
                    AND t{$field_id}_{$this->_key}.{$column} = '{$value}'
752
                ";
753
            }
754
        } else {
755
            if (!is_array($data)) {
756
                $data = array($data);
757
            }
758
759
            foreach ($data as &$value) {
760
                $value = $this->cleanValue($value);
761
            }
762
763
            $this->_key++;
764
            $data = implode("', '", $data);
765
            $joins .= "
766
                LEFT JOIN
767
                    `tbl_entries_data_{$field_id}` AS t{$field_id}_{$this->_key}
768
                    ON (e.id = t{$field_id}_{$this->_key}.entry_id)
769
            ";
770
            $where .= "
771
                AND t{$field_id}_{$this->_key}.{$column} IN ('{$data}')
772
            ";
773
        }
774
775
        return true;
776
    }
777
778
    /*-------------------------------------------------------------------------
779
        Sorting:
780
    -------------------------------------------------------------------------*/
781
782
    public function buildSortingSQL(&$joins, &$where, &$sort, $order = 'ASC')
783
    {
784
        if (in_array(strtolower($order), array('random', 'rand'))) {
785
            $sort = 'ORDER BY RAND()';
786
        } else {
787
            $sort = sprintf(
788
                'ORDER BY (
789
                    SELECT %s
790
                    FROM tbl_entries_data_%d AS `ed`
791
                    WHERE entry_id = e.id
792
                ) %s',
793
                '`ed`.file',
794
                $this->get('id'),
795
                $order
796
            );
797
        }
798
    }
799
800
    /*-------------------------------------------------------------------------
801
        Events:
802
    -------------------------------------------------------------------------*/
803
804 View Code Duplication
    public function getExampleFormMarkup()
805
    {
806
        $label = Widget::Label($this->get('label'));
807
        $label->appendChild(Widget::Input('fields['.$this->get('element_name').']', null, 'file'));
808
809
        return $label;
810
    }
811
}
812