Completed
Pull Request — master (#168)
by Franco
02:23
created

DMSDocumentAddController   D

Complexity

Total Complexity 32

Size/Duplication

Total Lines 341
Duplicated Lines 0.88 %

Coupling/Cohesion

Components 1
Dependencies 26

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 26
dl 3
loc 341
rs 4.8
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A currentPage() 0 14 4
A currentPageID() 0 4 2
A getCurrentDocumentSet() 0 7 2
A getEditForm() 0 75 1
A Breadcrumbs() 0 22 3
B Backlink() 0 23 4
A documentautocomplete() 0 22 2
B linkdocument() 0 28 2
B documentlist() 0 29 5
A getAllowedExtensions() 0 9 1
B canView() 3 20 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * @package dms
5
 */
6
class DMSDocumentAddController extends LeftAndMain
0 ignored issues
show
Coding Style Compatibility introduced by helpfulrobot
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
7
{
8
    private static $url_segment = 'pages/adddocument';
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
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...
9
    private static $url_priority = 60;
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
The property $url_priority 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...
10
    private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
The property $required_permission_codes 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...
11
    private static $menu_title = 'Edit Page';
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
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...
12
    private static $tree_class = 'SiteTree';
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
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...
13
    private static $session_namespace = 'CMSMain';
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
The property $session_namespace 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...
14
15
    /**
16
     * Allowed file upload extensions, will be merged with `$allowed_extensions` from {@link File}
17
     *
18
     * @config
19
     * @var array
20
     */
21
    private static $allowed_extensions = array();
0 ignored issues
show
Unused Code introduced by Robbie Averill
The property $allowed_extensions 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...
22
23
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by helpfulrobot
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by helpfulrobot
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...
24
        'getEditForm',
25
        'documentautocomplete',
26
        'linkdocument',
27
        'documentlist'
28
    );
29
30
    /**
31
     * Custom currentPage() method to handle opening the 'root' folder
32
     *
33
     * @return SiteTree
0 ignored issues
show
Documentation introduced by Robbie Averill
Should the return type not be SiteTree|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
34
     */
35
    public function currentPage()
36
    {
37
        $id = $this->currentPageID();
38
39
        if ($id && is_numeric($id) && $id > 0) {
40
            return Versioned::get_by_stage('SiteTree', 'Stage', sprintf(
41
                'ID = %s',
42
                (int) $id
43
            ))->first();
44
        } else {
45
            // ID is either '0' or 'root'
46
            return singleton('SiteTree');
47
        }
48
    }
49
50
    /**
51
     * Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
52
     *
53
     * @return int
54
     */
55
    public function currentPageID()
56
    {
57
        return ($result = parent::currentPageID()) === null ? 0 : $result;
58
    }
59
60
    /**
61
     * Get the current document set, if a document set ID was provided
62
     *
63
     * @return DMSDocumentSet
0 ignored issues
show
Documentation introduced by Robbie Averill
Should the return type not be DMSDocumentSet|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
64
     */
65
    public function getCurrentDocumentSet()
66
    {
67
        if ($id = $this->getRequest()->getVar('dsid')) {
68
            return DMSDocumentSet::get()->byId($id);
69
        }
70
        return singleton('DMSDocumentSet');
71
    }
72
73
    /**
74
     * @return Form
75
     * @todo what template is used here? AssetAdmin_UploadContent.ss doesn't seem to be used anymore
76
     */
77
    public function getEditForm($id = null, $fields = null)
78
    {
79
        Requirements::javascript(FRAMEWORK_DIR . '/javascript/AssetUploadField.js');
80
        Requirements::css(FRAMEWORK_DIR . '/css/AssetUploadField.css');
81
        Requirements::css(DMS_DIR . '/dist/css/cmsbundle.css');
82
83
        /** @var SiteTree $page */
84
        $page = $this->currentPage();
0 ignored issues
show
Unused Code introduced by helpfulrobot
$page 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...
85
        /** @var DMSDocumentSet $documentSet */
86
        $documentSet = $this->getCurrentDocumentSet();
87
88
        $uploadField = DMSUploadField::create('AssetUploadField', '');
89
        $uploadField->setConfig('previewMaxWidth', 40);
90
        $uploadField->setConfig('previewMaxHeight', 30);
91
        // Required to avoid Solr reindexing (often used alongside DMS) to
92
        // return 503s because of too many concurrent reindex requests
93
        $uploadField->setConfig('sequentialUploads', 1);
94
        $uploadField->addExtraClass('ss-assetuploadfield');
95
        $uploadField->removeExtraClass('ss-uploadfield');
96
        $uploadField->setTemplate('AssetUploadField');
97
        $uploadField->setRecord($documentSet);
98
99
        $uploadField->getValidator()->setAllowedExtensions($this->getAllowedExtensions());
100
        $exts = $uploadField->getValidator()->getAllowedExtensions();
101
102
        asort($exts);
103
        $backlink = $this->Backlink();
104
        $done = "
105
		<a class=\"ss-ui-button ss-ui-action-constructive cms-panel-link ui-corner-all\" href=\"" . $backlink . "\">
106
			" . _t('UploadField.DONE', 'DONE') . "
107
		</a>";
108
109
        $addExistingField = new DMSDocumentAddExistingField(
110
            'AddExisting',
111
            _t('DMSDocumentAddExistingField.ADDEXISTING', 'Add Existing')
112
        );
113
        $addExistingField->setRecord($documentSet);
114
115
        $form = new Form(
116
            $this,
117
            'getEditForm',
118
            new FieldList(
119
                new TabSet(
120
                    _t('DMSDocumentAddController.MAINTAB', 'Main'),
121
                    new Tab(
122
                        _t('UploadField.FROMCOMPUTER', 'From your computer'),
123
                        $uploadField,
124
                        new LiteralField(
125
                            'AllowedExtensions',
126
                            sprintf(
127
                                '<p>%s: %s</p>',
128
                                _t('AssetAdmin.ALLOWEDEXTS', 'Allowed extensions'),
129
                                implode('<em>, </em>', $exts)
130
                            )
131
                        )
132
                    ),
133
                    new Tab(
134
                        _t('UploadField.FROMCMS', 'From the CMS'),
135
                        $addExistingField
136
                    )
137
                )
138
            ),
139
            new FieldList(
140
                new LiteralField('doneButton', $done)
141
            )
142
        );
143
        $form->addExtraClass('center cms-edit-form ' . $this->BaseCSSClasses());
144
        $form->Backlink = $backlink;
145
        // Don't use AssetAdmin_EditForm, as it assumes a different panel structure
146
        $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
0 ignored issues
show
Documentation introduced by helpfulrobot
$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...
147
        $form->Fields()->push(HiddenField::create('ID', false, $documentSet->ID));
148
        $form->Fields()->push(HiddenField::create('DSID', false, $documentSet->ID));
149
150
        return $form;
151
    }
152
153
    /**
154
     * @return ArrayList
155
     */
156
    public function Breadcrumbs($unlinked = false)
157
    {
158
        $items = parent::Breadcrumbs($unlinked);
159
160
        // The root element should explicitly point to the root node.
161
        $items[0]->Link = Controller::join_links(singleton('CMSPageEditController')->Link('show'), 0);
162
163
        // Enforce linkage of hierarchy to AssetAdmin
164
        foreach ($items as $item) {
165
            $baselink = $this->Link('show');
166
            if (strpos($item->Link, $baselink) !== false) {
167
                $item->Link = str_replace($baselink, singleton('CMSPageEditController')->Link('show'), $item->Link);
168
            }
169
        }
170
171
        $items->push(new ArrayData(array(
172
            'Title' => _t('DMSDocumentSet.ADDDOCUMENTBUTTON', 'Add Document'),
173
            'Link' => $this->Link()
174
        )));
175
176
        return $items;
177
    }
178
179
    /**
180
     * Returns the link to be used to return the user after uploading a document. If a document set ID (dsid) is present
181
     * then it will be redirected back to that document set in a page.
182
     *
183
     * If no document set ID is present then we assume that it has been added from the model admin, so redirect back to
184
     * that instead.
185
     *
186
     * @return string
187
     */
188
    public function Backlink()
189
    {
190
        if (!$this->getRequest()->getVar('dsid') || !$this->currentPageID()) {
191
            $modelAdmin = new DMSDocumentAdmin;
192
            $modelAdmin->init();
193
194
            if ($this->getRequest()->getVar('dsid')) {
195
                return Controller::join_links(
196
                    $modelAdmin->Link('DMSDocumentSet'),
197
                    'EditForm/field/DMSDocumentSet/item',
198
                    $this->getRequest()->getVar('dsid'),
199
                    'edit'
200
                );
201
            }
202
            return $modelAdmin->Link('DMSDocumentSet');
203
        }
204
205
        return Controller::join_links(
206
            singleton('CMSPagesController')->Link(),
207
            'edit/EditForm/field/Document%20Sets/item',
208
            $this->getRequest()->getVar('dsid')
209
        );
210
    }
211
212
    public function documentautocomplete()
213
    {
214
        $term = (string) $this->getRequest()->getVar('term');
215
        $termSql = Convert::raw2sql($term);
216
        $data = DMSDocument::get()
217
            ->where(
218
                '("ID" LIKE \'%' . $termSql . '%\' OR "Filename" LIKE \'%' . $termSql . '%\''
219
                . ' OR "Title" LIKE \'%' . $termSql . '%\')'
220
            )
221
            ->sort('ID ASC')
222
            ->limit(20);
223
224
        $return = array();
225
        foreach ($data as $doc) {
226
            $return[] = array(
227
                'label' => $doc->ID . ' - ' . $doc->Title,
228
                'value' => $doc->ID
229
            );
230
        }
231
232
        return Convert::raw2json($return);
233
    }
234
235
    /**
236
     * Link an existing document to the given document set ID
237
     * @return string JSON
238
     */
239
    public function linkdocument()
240
    {
241
        $return = array('error' => _t('UploadField.FIELDNOTSET', 'Could not add document to page'));
242
        $documentSet = $this->getCurrentDocumentSet();
243
        if (!empty($documentSet)) {
244
            $document = DMSDocument::get()->byId($this->getRequest()->getVar('documentID'));
245
            $documentSet->Documents()->add($document);
0 ignored issues
show
Bug introduced by Robbie Averill
The method Documents() does not exist on DMSDocumentSet. Did you maybe mean getDocuments()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
246
247
            $buttonText = '<button class="ss-uploadfield-item-edit ss-ui-button ui-corner-all"'
248
                . ' title="' . _t('DMSDocument.EDITDOCUMENT', 'Edit this document') . '" data-icon="pencil">'
249
                . _t('DMSDocument.EDIT', 'Edit') . '<span class="toggle-details">'
250
                . '<span class="toggle-details-icon"></span></span></button>';
251
252
            // Collect all output data.
253
            $return = array(
254
                'id' => $document->ID,
255
                'name' => $document->getTitle(),
256
                'thumbnail_url' => $document->Icon($document->getExtension()),
0 ignored issues
show
Bug introduced by helpfulrobot
The method getExtension() does not exist on DataObject. Did you maybe mean getExtensionInstance()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
257
                'edit_url' => $this->getEditForm()->Fields()->fieldByName('Main.From your computer.AssetUploadField')
258
                    ->getItemHandler($document->ID)->EditLink(),
259
                'size' => $document->getFileSizeFormatted(),
260
                'buttons' => $buttonText,
261
                'showeditform' => true
262
            );
263
        }
264
265
        return Convert::raw2json($return);
266
    }
267
268
    /**
269
     * Returns HTML representing a list of documents that are associated with the given page ID, across all document
270
     * sets.
271
     *
272
     * @return string HTML
273
     */
274
    public function documentlist()
275
    {
276
        if (!$this->getRequest()->getVar('pageID')) {
277
            return $this->httpError(400);
278
        }
279
280
        $page = SiteTree::get()->byId($this->getRequest()->getVar('pageID'));
281
282
        if ($page && $page->getAllDocuments()->count() > 0) {
283
            $list = '<ul>';
284
285
            foreach ($page->getAllDocuments() as $document) {
286
                $list .= sprintf(
287
                    '<li><a class="add-document" data-document-id="%s">%s</a></li>',
288
                    $document->ID,
289
                    $document->ID . ' - '. Convert::raw2xml($document->Title)
290
                );
291
            }
292
293
            $list .= '</ul>';
294
295
            return $list;
296
        }
297
298
        return sprintf(
299
            '<p>%s</p>',
300
            _t('DMSDocumentAddController.NODOCUMENTS', 'There are no documents attached to the selected page.')
301
        );
302
    }
303
304
    /**
305
     * Get an array of allowed file upload extensions, merged with {@link File} and extra configuration from this
306
     * class
307
     *
308
     * @return array
309
     */
310
    public function getAllowedExtensions()
311
    {
312
        return array_filter(
313
            array_merge(
314
                (array) Config::inst()->get('File', 'allowed_extensions'),
315
                (array) $this->config()->get('allowed_extensions')
316
            )
317
        );
318
    }
319
320
    /**
321
     * Overrides the parent method to allow access to this controller if user has access to document admin
322
     *
323
     * @param Member $member
0 ignored issues
show
Documentation introduced by Franco Springveldt
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
324
     * @return bool
325
     */
326
    public function canView($member = null)
327
    {
328 View Code Duplication
        if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
0 ignored issues
show
Duplication introduced by helpfulrobot
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...
329
            $member = Member::currentUser();
330
        }
331
332
        // Do early admin check
333
        if ($member &&
334
            Permission::checkMember(
335
                $member,
336
                array(
337
                    'CMS_ACCESS_DMSDocumentAdmin',
338
                )
339
            )
340
        ) {
341
            return true;
342
        }
343
344
        return parent::canView($member);
0 ignored issues
show
Bug introduced by Franco Springveldt
It seems like $member defined by \Member::currentUser() on line 329 can also be of type object<DataObject>; however, LeftAndMain::canView() does only seem to accept object<Member>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
345
    }
346
}
347