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

code/cms/DMSDocumentAddController.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @package dms
5
 */
6
class DMSDocumentAddController extends LeftAndMain
7
{
8
    private static $url_segment = 'pages/adddocument';
9
    private static $url_priority = 60;
10
    private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
11
    private static $menu_title = 'Edit Page';
12
    private static $tree_class = 'SiteTree';
13
    private static $session_namespace = 'CMSMain';
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();
22
23
    private static $allowed_actions = array(
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
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
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();
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'));
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();
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);
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()),
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 users with access to DMS admin to access this controller
322
     *
323
     * @param Member $member
0 ignored issues
show
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
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
        if ($member &&
333
            Permission::checkMember(
334
                $member,
335
                array(
336
                    'CMS_ACCESS_DMSDocumentAdmin',
337
                )
338
            )
339
        ) {
340
            return true;
341
        }
342
        return parent::canView($member);
0 ignored issues
show
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...
343
    }
344
}
345