Completed
Push — master ( f51fba...3ab835 )
by Ingo
02:20
created

AssetAdmin::getList()   C

Complexity

Conditions 11
Paths 33

Size

Total Lines 57
Code Lines 28

Duplication

Lines 16
Ratio 28.07 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 16
loc 57
rs 6.4824
cc 11
eloc 28
nc 33
nop 0

How to fix   Long Method    Complexity   

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
namespace SilverStripe\AssetAdmin\Controller;
4
5
use SilverStripe\Filesystem\Storage\AssetNameGenerator;
6
use SilverStripe\AssetAdmin\FormField\AssetGalleryField;
7
use SilverStripe\AssetAdmin\FormField\DropzoneUploadField;
8
use LeftAndMain;
9
use PermissionProvider;
10
use DateField;
11
use TabSet;
12
use Tab;
13
use DropdownField;
14
use SS_HTTPResponse_Exception;
15
use Controller;
16
use TextField;
17
use FieldList;
18
use Form;
19
use FormAction;
20
use CheckboxField;
21
use Convert;
22
use ArrayData;
23
use File;
24
use Session;
25
use Requirements;
26
use CMSBatchActionHandler;
27
use HiddenField;
28
use DataObject;
29
use Injector;
30
use Folder;
31
use Security;
32
use CMSForm;
33
use CMSBatchAction;
34
use SS_List;
35
use CompositeField;
36
use SSViewer;
37
use HeaderField;
38
use FieldGroup;
39
use Object;
40
41
/**
42
 * AssetAdmin is the 'file store' section of the CMS.
43
 * It provides an interface for manipulating the File and Folder objects in the system.
44
 *
45
 * @package cms
46
 * @subpackage assets
47
 */
48
class AssetAdmin extends LeftAndMain implements PermissionProvider
49
{
50
    private static $url_segment = 'assets';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $url_segment is not used and could be removed.

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

Loading history...
51
52
    private static $url_rule = '/$Action/$ID';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $url_rule is not used and could be removed.

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

Loading history...
53
54
    private static $menu_title = 'Files';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $menu_title is not used and could be removed.

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

Loading history...
55
56
    private static $tree_class = 'Folder';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $tree_class is not used and could be removed.

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

Loading history...
57
58
59
    private static $url_handlers = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $url_handlers is not used and could be removed.

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

Loading history...
60
        // Legacy redirect for SS3-style detail view
61
        'EditForm/field/File/item/$FileID/$Action' => 'legacyRedirectForEditView',
62
        // Pass all URLs to the index, for React to unpack
63
        'show/$FolderID/edit/$FileID' => 'index',
64
    ];
65
66
    /**
67
     * Amount of results showing on a single page.
68
     *
69
     * @config
70
     * @var int
71
     */
72
    private static $page_length = 15;
0 ignored issues
show
Unused Code introduced by
The property $page_length is not used and could be removed.

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

Loading history...
73
74
    /**
75
     * @config
76
     * @see Upload->allowedMaxFileSize
77
     * @var int
78
     */
79
    private static $allowed_max_file_size;
0 ignored issues
show
Unused Code introduced by
The property $allowed_max_file_size is not used and could be removed.

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

Loading history...
80
81
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

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

Loading history...
82
        'addfolder',
83
        'delete',
84
        'AddForm',
85
        'SearchForm',
86
        'legacyRedirectForEditView',
87
    );
88
89
90
91
	public function getClientConfig() {
92
		return array_merge( parent::getClientConfig(), [
93
            'assetsRoute' => $this->Link() . ':folderAction?/:folderId?/:fileAction?/:fileId?',
94
            'assetsRouteHome' => $this->Link() . 'show/0',
95
        ]);
96
	}
97
98
    public function legacyRedirectForEditView($request)
99
    {
100
        $fileID = $request->param('FileID');
101
        $file = File::get()->byID($fileID);
102
        $link = $this->getFileEditLink($file) ?: $this->Link();
0 ignored issues
show
Documentation introduced by
$file is of type object<DataObject>|null, but the function expects a object<File>.

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...
103
        $this->redirect($link);
104
    }
105
106
    /**
107
     * Given a file return the CMS link to edit it
108
     *
109
     * @param File $file
110
     * @return string
111
     */
112
    public function getFileEditLink($file) {
113
        if(!$file || !$file->isInDB()) {
114
            return null;
115
        }
116
        $fileID = $file->ID;
117
        $folderID = $file->ParentID;
118
        return Controller::join_links(
119
            $this->Link('show'),
120
            $folderID,
121
            'edit',
122
            $fileID
123
        );
124
    }
125
126
    /**
127
     * Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
128
     */
129
    public function currentPageID()
130
    {
131
        if (is_numeric($this->getRequest()->requestVar('ID'))) {
132
            return $this->getRequest()->requestVar('ID');
133
        } elseif (array_key_exists('ID', $this->urlParams) && is_numeric($this->urlParams['ID'])) {
134
            return $this->urlParams['ID'];
135
        } elseif (Session::get("{$this->class}.currentPage")) {
136
            return Session::get("{$this->class}.currentPage");
137
        } else {
138
            return 0;
139
        }
140
    }
141
142
    /**
143
     * Gets the ID of the folder being requested.
144
     *
145
     * @return int
146
     */
147
    public function getCurrentFolderID()
148
    {
149
        $currentFolderID = 0;
150
151
        if ($this->urlParams['Action'] == 'show' && is_numeric($this->urlParams['ID'])) {
152
            $currentFolderID = $this->urlParams['ID'];
153
        }
154
155
        return $currentFolderID;
156
    }
157
158
    /**
159
     * Set up the controller
160
     */
161
    public function init()
162
    {
163
        parent::init();
164
165
        Requirements::javascript(FRAMEWORK_DIR . "/admin/client/dist/js/bundle-lib.js");
166
        Requirements::add_i18n_javascript(ASSET_ADMIN_DIR . '/client/lang', false, true);
167
        Requirements::css(ASSET_ADMIN_DIR . "/client/dist/styles/bundle.css");
168
169
        CMSBatchActionHandler::register('delete', 'SilverStripe\AssetAdmin\BatchAction\DeleteAssets', 'Folder');
170
    }
171
172
    /**
173
     * Returns the files and subfolders contained in the currently selected folder,
174
     * defaulting to the root node. Doubles as search results, if any search parameters
175
     * are set through {@link SearchForm()}.
176
     *
177
     * @return SS_List
178
     */
179
    public function getList()
180
    {
181
        $folder = $this->currentPage();
182
        $context = $this->getSearchContext();
183
        // Overwrite name filter to search both Name and Title attributes
184
        $context->removeFilterByName('Name');
185
        $params = $this->getRequest()->requestVar('q');
186
        $list = $context->getResults($params);
187
188
        // Don't filter list when a detail view is requested,
189
        // to avoid edge cases where the filtered list wouldn't contain the requested
190
        // record due to faulty session state (current folder not always encoded in URL, see #7408).
191
        if (!$folder->ID
192
            && $this->getRequest()->requestVar('ID') === null
193
            && ($this->getRequest()->param('ID') == 'field')
194
        ) {
195
            return $list;
196
        }
197
198
        // Re-add previously removed "Name" filter as combined filter
199
        // TODO Replace with composite SearchFilter once that API exists
200 View Code Duplication
        if (!empty($params['Name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
201
            $list = $list->filterAny(array(
202
                'Name:PartialMatch' => $params['Name'],
203
                'Title:PartialMatch' => $params['Name']
204
            ));
205
        }
206
207
        // Always show folders at the top
208
        $list = $list->sort('(CASE WHEN "File"."ClassName" = \'Folder\' THEN 0 ELSE 1 END), "Name"');
209
210
        // If a search is conducted, check for the "current folder" limitation.
211
        // Otherwise limit by the current folder as denoted by the URL.
212
        if (empty($params) || !empty($params['CurrentFolderOnly'])) {
213
            $list = $list->filter('ParentID', $folder->ID);
214
        }
215
216
        // Category filter
217 View Code Duplication
        if (!empty($params['AppCategory'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
218
            && !empty(File::config()->app_categories[$params['AppCategory']])
219
        ) {
220
            $exts = File::config()->app_categories[$params['AppCategory']];
221
            $list = $list->filter('Name:PartialMatch', $exts);
222
        }
223
224
        // Date filter
225
        if (!empty($params['CreatedFrom'])) {
226
            $fromDate = new DateField(null, null, $params['CreatedFrom']);
227
            $list = $list->filter("Created:GreaterThanOrEqual", $fromDate->dataValue().' 00:00:00');
228
        }
229 View Code Duplication
        if (!empty($params['CreatedTo'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
230
            $toDate = new DateField(null, null, $params['CreatedTo']);
231
            $list = $list->filter("Created:LessThanOrEqual", $toDate->dataValue().' 23:59:59');
232
        }
233
234
        return $list;
235
    }
236
237
    public function getEditForm($id = null, $fields = null)
238
    {
239
        $form = parent::getEditForm($id, $fields);
240
        
241
        // Remove legacy previewable behaviour.
242
        // Can't yet be cleanly removed from JS logic since its loaded via LeftAndMain.ss.
243
        $form->removeExtraClass('cms-previewable');
244
        $form->Fields()->removeByName('SilverStripeNavigator');
245
        
246
        $folder = ($id && is_numeric($id)) ? DataObject::get_by_id('Folder', $id, false) : $this->currentPage();
247
        $title = ($folder && $folder->exists()) ? $folder->Title : _t('AssetAdmin.FILES', 'Files');
0 ignored issues
show
Unused Code introduced by
$title 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...
248
249
        // Override fields, ignore any details from Folder->getCMSFields() since they'll
250
        // be handled by a detail form instead.
251
        $fields = FieldList::create(
252
            HiddenField::create('ID', false, $folder ? $folder->ID : null)
253
        );
254
        $form->setFields($fields);
255
256
        // TODO Re-enable once GridField works with React
257
        // // File listing
258
        // $gridFieldConfig = GridFieldConfig::create()->addComponents(
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
259
        //     new GridFieldToolbarHeader(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
260
        //     new GridFieldSortableHeader(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
261
        //     new GridFieldFilterHeader(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
262
        //     new GridFieldDataColumns(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
263
        //     new GridFieldPaginator(self::config()->page_length),
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
264
        //     new GridFieldEditButton(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
265
        //     new GridFieldDeleteAction(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
266
        //     new GridFieldDetailForm(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
267
        //     GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d')
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
268
        // );
269
        // $gridField = GridField::create('File', $title, $this->getList(), $gridFieldConfig);
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
270
        // $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns');
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
271
        // $columns->setDisplayFields(array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
272
        //     'StripThumbnail' => '',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
273
        //     'Title' => _t('File.Title', 'Title'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
274
        //     'Created' => _t('AssetAdmin.CREATED', 'Date'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
275
        //     'Size' => _t('AssetAdmin.SIZE', 'Size'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
276
        // ));
277
        // $columns->setFieldCasting(array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
278
        //     'Created' => 'SS_Datetime->Nice'
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
279
        // ));
280
        // $gridField->setAttribute(
281
        //     'data-url-folder-template',
282
        //     Controller::join_links($this->Link('show'), '%s')
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
283
        // );
284
285
        // Move existing fields to a "details" tab, unless they've already been tabbed out through extensions.
286
        // Required to keep Folder->getCMSFields() simple and reuseable,
287
        // without any dependencies into AssetAdmin (e.g. useful for "add folder" views).
288
        if (!$fields->hasTabset()) {
289
            $tabs = new TabSet(
290
                'Root',
291
                $tabList = new Tab('ListView', _t('AssetAdmin.ListView', 'List View'))
292
            );
293
            $tabList->addExtraClass("content-listview cms-tabset-icon list");
294
            if ($fields->Count() && $folder->exists()) {
295
                $tabs->push($tabDetails = new Tab('DetailsView', _t('AssetAdmin.DetailsView', 'Details')));
296
                $tabDetails->addExtraClass("content-galleryview cms-tabset-icon edit");
297
                foreach ($fields as $field) {
298
                    $fields->removeByName($field->getName());
299
                    $tabDetails->push($field);
300
                }
301
            }
302
            $fields->push($tabs);
303
        }
304
305
        // Add the upload field for new media
306
        if ($currentPageID = $this->currentPageID()) {
307
            Session::set("{$this->class}.currentPage", $currentPageID);
308
        }
309
310
        $folder = $this->currentPage();
311
312
        if ($folder->exists()) {
313
            $path = $folder->getFilename();
0 ignored issues
show
Unused Code introduced by
$path 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...
314
        }
315
316
        $galleryField = AssetGalleryField::create('Files')
317
            ->setCurrentFolder($this->getCurrentFolderID())
318
            ->setLimit(15);
319
320
        // List view
321
        $fields->addFieldsToTab('Root.ListView', array(
322
            $galleryField,
323
            new DropzoneUploadField('Upload')
324
        ));
325
326
        // Move actions to "details" tab (they don't make sense on list view)
327
        $actions = $form->Actions();
328
        $saveBtn = $actions->fieldByName('action_save');
329
        $deleteBtn = $actions->fieldByName('action_delete');
330
        $actions->removeByName('action_save');
331
        $actions->removeByName('action_delete');
332
        if (($saveBtn || $deleteBtn) && $fields->fieldByName('Root.DetailsView')) {
333
            $fields->addFieldToTab(
334
                'Root.DetailsView',
335
                CompositeField::create($saveBtn, $deleteBtn)->addExtraClass('Actions')
336
            );
337
        }
338
339
        $fields->setForm($form);
0 ignored issues
show
Bug introduced by
It seems like $form defined by parent::getEditForm($id, $fields) on line 239 can be null; however, FieldList::setForm() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
340
        $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
0 ignored issues
show
Documentation introduced by
$this->getTemplatesWithSuffix('_EditForm') is of type array, but the function expects a string.

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...
341
        // TODO Can't merge $FormAttributes in template at the moment
342
        $form->addExtraClass('cms-edit-form ' . $this->BaseCSSClasses());
343
        $form->setAttribute('data-pjax-fragment', 'CurrentForm');
344
        $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
345
346
        $this->extend('updateEditForm', $form);
347
348
        return $form;
349
    }
350
351
    public function addfolder($request)
352
    {
353
        $obj = $this->customise(array(
354
            'EditForm' => $this->AddForm()
355
        ));
356
357
        if ($request->isAjax()) {
358
            // Rendering is handled by template, which will call EditForm() eventually
359
            $content = $obj->renderWith($this->getTemplatesWithSuffix('_Content'));
360
        } else {
361
            $content = $obj->renderWith($this->getViewer('show'));
362
        }
363
364
        return $content;
365
    }
366
367
    public function delete($data, $form)
368
    {
369
        $className = $this->stat('tree_class');
370
371
        $record = DataObject::get_by_id($className, $data['ID']);
372
        if ($record && !$record->canDelete()) {
373
            return Security::permissionFailure();
374
        }
375
        if (!$record || !$record->ID) {
376
            throw new SS_HTTPResponse_Exception("Bad record ID #" . (int) $data['ID'], 404);
377
        }
378
        $parentID = $record->ParentID;
379
        $record->delete();
380
        $this->setCurrentPageID(null);
381
382
        $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.')));
383
        $this->getResponse()->addHeader('X-Pjax', 'Content');
384
385
        return $this->redirect(Controller::join_links($this->Link('show'), $parentID ? $parentID : 0));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->redirect(\Control...ntID ? $parentID : 0)); of type string|null adds the type string to the return on line 385 which is incompatible with the return type of the parent method LeftAndMain::delete of type SS_HTTPResponse|null.
Loading history...
386
    }
387
388
    /**
389
     * Get the search context
390
     *
391
     * @return SearchContext
392
     */
393
    public function getSearchContext()
394
    {
395
        $context = singleton('File')->getDefaultSearchContext();
396
397
        // Namespace fields, for easier detection if a search is present
398
        foreach ($context->getFields() as $field) {
399
            $field->setName(sprintf('q[%s]', $field->getName()));
400
        }
401
        foreach ($context->getFilters() as $filter) {
402
            $filter->setFullName(sprintf('q[%s]', $filter->getFullName()));
403
        }
404
405
        // Customize fields
406
        $dateHeader = HeaderField::create('q[Date]', _t('CMSSearch.FILTERDATEHEADING', 'Date'), 4);
407
        $dateFrom = DateField::create('q[CreatedFrom]', _t('CMSSearch.FILTERDATEFROM', 'From'))
408
        ->setConfig('showcalendar', true);
409
        $dateTo = DateField::create('q[CreatedTo]', _t('CMSSearch.FILTERDATETO', 'To'))
410
        ->setConfig('showcalendar', true);
411
        $dateGroup = FieldGroup::create(
412
            $dateHeader,
413
            $dateFrom,
414
            $dateTo
415
        );
416
        $context->addField($dateGroup);
417
        $appCategories = array(
418
            'archive' => _t('AssetAdmin.AppCategoryArchive', 'Archive', 'A collection of files'),
419
            'audio' => _t('AssetAdmin.AppCategoryAudio', 'Audio'),
420
            'document' => _t('AssetAdmin.AppCategoryDocument', 'Document'),
421
            'flash' => _t('AssetAdmin.AppCategoryFlash', 'Flash', 'The fileformat'),
422
            'image' => _t('AssetAdmin.AppCategoryImage', 'Image'),
423
            'video' => _t('AssetAdmin.AppCategoryVideo', 'Video'),
424
        );
425
        $context->addField(
426
            $typeDropdown = new DropdownField(
427
                'q[AppCategory]',
428
                _t('AssetAdmin.Filetype', 'File type'),
429
                $appCategories
430
            )
431
        );
432
433
        $typeDropdown->setEmptyString(' ');
434
435
        $context->addField(
436
            new CheckboxField('q[CurrentFolderOnly]', _t('AssetAdmin.CurrentFolderOnly', 'Limit to current folder?'))
437
        );
438
        $context->getFields()->removeByName('q[Title]');
439
440
        return $context;
441
    }
442
443
    /**
444
     * Returns a form for filtering of files and assets gridfield.
445
     * Result filtering takes place in {@link getList()}.
446
     *
447
     * @return Form
448
     *              @see AssetAdmin.js
449
     */
450
    public function searchForm()
451
    {
452
        $folder = $this->currentPage();
453
        $context = $this->getSearchContext();
454
455
        $fields = $context->getSearchFields();
456
        $actions = new FieldList(
457
            FormAction::create('doSearch', _t('CMSMain_left_ss.APPLY_FILTER', 'Apply Filter'))
458
                ->addExtraClass('ss-ui-action-constructive'),
459
            Object::create('ResetFormAction', 'clear', _t('CMSMain_left_ss.RESET', 'Reset'))
460
        );
461
462
        $form = new Form($this, 'filter', $fields, $actions);
463
        $form->setFormMethod('GET');
464
        $form->setFormAction(Controller::join_links($this->Link('show'), $folder->ID));
465
        $form->addExtraClass('cms-search-form');
466
        $form->loadDataFrom($this->getRequest()->getVars());
467
        $form->disableSecurityToken();
468
        // This have to match data-name attribute on the gridfield so that the javascript selectors work
469
        $form->setAttribute('data-gridfield', 'File');
470
471
        return $form;
472
    }
473
474
    public function addForm()
475
    {
476
        $form = CMSForm::create(
477
            $this,
478
            'AddForm',
479
            new FieldList(
480
                new TextField("Name", _t('File.Name')),
481
                new HiddenField('ParentID', false, $this->getRequest()->getVar('ParentID'))
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a null|string.

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...
482
            ),
483
            new FieldList(
484
                FormAction::create('doAdd', _t('AssetAdmin_left_ss.GO', 'Go'))
485
                    ->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')
486
                    ->setTitle(_t('AssetAdmin.ActionAdd', 'Add folder'))
487
            )
488
        )->setHTMLID('Form_AddForm');
489
        $form->setResponseNegotiator($this->getResponseNegotiator());
490
        $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
491
        // TODO Can't merge $FormAttributes in template at the moment
492
        $form->addExtraClass('add-form cms-add-form cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses());
493
494
        return $form;
495
    }
496
497
    /**
498
     * Add a new group and return its details suitable for ajax.
499
     *
500
     * @todo Move logic into Folder class, and use LeftAndMain->doAdd() default implementation.
501
     */
502
    public function doAdd($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

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

Loading history...
503
    {
504
        $class = $this->stat('tree_class');
505
506
        // check create permissions
507
        if (!singleton($class)->canCreate()) {
508
            return Security::permissionFailure($this);
509
        }
510
511
        // check addchildren permissions
512
        if (singleton($class)->hasExtension('Hierarchy')
513
            && isset($data['ParentID'])
514
            && is_numeric($data['ParentID'])
515
            && $data['ParentID']
516
        ) {
517
            $parentRecord = DataObject::get_by_id($class, $data['ParentID']);
518
            if ($parentRecord->hasMethod('canAddChildren') && !$parentRecord->canAddChildren()) {
519
                return Security::permissionFailure($this);
520
            }
521
        } else {
522
            $parentRecord = null;
523
        }
524
525
        // Check parent
526
        $parentID = $parentRecord && $parentRecord->ID
527
            ? (int) $parentRecord->ID
528
            : 0;
529
        // Build filename
530
        $filename = isset($data['Name'])
531
            ? basename($data['Name'])
532
            : _t('AssetAdmin.NEWFOLDER', "NewFolder");
533
        if ($parentRecord && $parentRecord->ID) {
534
            $filename = $parentRecord->getFilename() . '/' . $filename;
535
        }
536
537
        // Get the folder to be created
538
539
        // Ensure name is unique
540
        foreach ($this->getNameGenerator($filename) as $filename) {
541
            if (! File::find($filename)) {
542
                break;
543
            }
544
        }
545
546
        // Create record
547
        $record = Folder::create();
548
        $record->ParentID = $parentID;
549
        $record->Name = $record->Title = basename($filename);
550
        $record->write();
551
552
        if ($parentRecord) {
553
            return $this->redirect(Controller::join_links($this->Link('show'), $parentRecord->ID));
554
        } else {
555
            return $this->redirect($this->Link());
556
        }
557
    }
558
559
    /**
560
     * Get an asset renamer for the given filename.
561
     *
562
     * @param  string             $filename Path name
563
     * @return AssetNameGenerator
564
     */
565
    protected function getNameGenerator($filename)
566
    {
567
        return Injector::inst()
568
            ->createWithArgs('AssetNameGenerator', array($filename));
569
    }
570
571
    /**
572
     * Custom currentPage() method to handle opening the 'root' folder
573
     */
574
    public function currentPage()
575
    {
576
        $id = $this->currentPageID();
577
        if ($id && is_numeric($id) && $id > 0) {
578
            $folder = DataObject::get_by_id('Folder', $id);
579
            if ($folder && $folder->exists()) {
580
                return $folder;
581
            }
582
        }
583
        $this->setCurrentPageID(null);
584
585
        return new Folder();
586
    }
587
588
    /**
589
     * @param  bool      $unlinked
590
     * @return ArrayList
591
     */
592
    public function breadcrumbs($unlinked = false)
593
    {
594
        $items = parent::Breadcrumbs($unlinked);
595
596
        // The root element should explicitly point to the root node.
597
        // Uses session state for current record otherwise.
598
        $items[0]->Link = Controller::join_links(singleton(__class__)->Link('show'), 0);
599
600
        // If a search is in progress, don't show the path
601
        if ($this->getRequest()->requestVar('q')) {
602
            $items = $items->limit(1);
603
            $items->push(new ArrayData(array(
604
                'Title' => _t('LeftAndMain.SearchResults', 'Search Results'),
605
                'Link' => Controller::join_links(
606
                    $this->Link(),
607
                    '?' . http_build_query(array('q' => $this->getRequest()->requestVar('q')))
608
                )
609
            )));
610
        }
611
612
        // If we're adding a folder, note that in breadcrumbs as well
613
        if ($this->getRequest()->param('Action') == 'addfolder') {
614
            $items->push(new ArrayData(array(
615
                'Title' => _t('Folder.AddFolderButton', 'Add folder'),
616
                'Link' => false
617
            )));
618
        }
619
620
        return $items;
621
    }
622
623
624
    /**
625
     * Don't include class namespace in auto-generated CSS class
626
     */
627
    public function baseCSSClasses()
628
    {
629
        return 'AssetAdmin LeftAndMain';
630
    }
631
632
    /**
633
     * Don't include class namespace in template names
634
     * @todo Make code in framework more namespace-savvy so that we don't need this duplication
635
     */
636
    public function getTemplatesWithSuffix($suffix)
637
    {
638
        $className = get_class($this);
639
        $baseClass = 'LeftandMain';
640
641
        $templates = array();
642
        $classes = array_reverse(\ClassInfo::ancestry($className));
643
        foreach ($classes as $class) {
644
            $template = (new \ReflectionClass($class))->getShortName() . $suffix;
645
            if (\SSViewer::hasTemplate($template)) {
0 ignored issues
show
Documentation introduced by
$template is of type string, 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...
646
                $templates[] = $template;
647
            }
648
649
            // If the class is "Page_Controller", look for Page.ss
650
            if (stripos($class, '_controller') !== false) {
651
                $template = str_ireplace('_controller', '', $class) . $suffix;
652
                if (\SSViewer::hasTemplate($template)) {
0 ignored issues
show
Documentation introduced by
$template is of type string, 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...
653
                    $templates[] = $template;
654
                }
655
            }
656
657
            if ($baseClass && $class == $baseClass) {
658
                break;
659
            }
660
        }
661
662
        return $templates;
663
    }
664
665
    public function providePermissions()
666
    {
667
        $title = _t("AssetAdmin.MENUTITLE", LeftAndMain::menu_title_for_class($this->class));
0 ignored issues
show
Deprecated Code introduced by
The method LeftAndMain::menu_title_for_class() has been deprecated with message: 5.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
668
669
        return array(
670
            "CMS_ACCESS_AssetAdmin" => array(
671
                'name' => _t('CMSMain.ACCESS', "Access to '{title}' section", array('title' => $title)),
0 ignored issues
show
Documentation introduced by
array('title' => $title) is of type array<string,string,{"title":"string"}>, but the function expects a string.

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...
672
                'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
673
            )
674
        );
675
    }
676
}
677