Completed
Push — master ( e5c7d1...b4e5c2 )
by Daniel
18s
created

code/model/DMSDocumentSet.php (1 issue)

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
 * A document set is attached to Pages, and contains many DMSDocuments
4
 *
5
 * @property Varchar Title
6
 * @property  Text KeyValuePairs
7
 * @property  Enum SortBy
8
 * @property Enum SortByDirection
9
 */
10
class DMSDocumentSet extends DataObject
11
{
12
    private static $db = array(
13
        'Title' => 'Varchar(255)',
14
        'KeyValuePairs' => 'Text',
15
        'SortBy' => "Enum('LastEdited,Created,Title')')",
16
        'SortByDirection' => "Enum('DESC,ASC')')",
17
    );
18
19
    private static $has_one = array(
20
        'Page' => 'SiteTree',
21
    );
22
23
    private static $many_many = array(
24
        'Documents' => 'DMSDocument',
25
    );
26
27
    private static $many_many_extraFields = array(
28
        'Documents' => array(
29
            // Flag indicating if a document was added directly to a set - in which case it is set - or added
30
            // via the query-builder.
31
            'ManuallyAdded' => 'Boolean(1)',
32
            'DocumentSort' => 'Int'
33
        ),
34
    );
35
36
    private static $summary_fields = array(
37
        'Title' => 'Title',
38
        'Documents.Count' => 'No. Documents'
39
    );
40
41
    /**
42
     * Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
43
     *
44
     * You can attach an extension to this event:
45
     *
46
     * <code>
47
     * public function updateDocuments($document)
48
     * {
49
     *     // do something
50
     * }
51
     * </code>
52
     *
53
     * @return DataList|null
54
     */
55
    public function getDocuments()
56
    {
57
        $documents = $this->Documents();
58
        $this->extend('updateDocuments', $documents);
59
        return $documents;
60
    }
61
62
    /**
63
     * Put the "documents" list into the main tab instead of its own tab, and replace the default "Add Document" button
64
     * with a customised button for DMS documents
65
     *
66
     * @return FieldList
67
     */
68
    public function getCMSFields()
69
    {
70
        // PHP 5.3 only
71
        $self = $this;
72
        $this->beforeUpdateCMSFields(function (FieldList $fields) use ($self) {
73
            $fields->removeFieldsFromTab(
74
                'Root.Main',
75
                array('KeyValuePairs', 'SortBy', 'SortByDirection')
76
            );
77
            // Don't put the GridField for documents in until the set has been created
78
            if (!$self->isInDB()) {
79
                $fields->addFieldToTab(
80
                    'Root.Main',
81
                    LiteralField::create(
82
                        'GridFieldNotice',
83
                        '<p class="message warning">' . _t(
84
                            'DMSDocumentSet.GRIDFIELD_NOTICE',
85
                            'Managing documents will be available once you have created this document set.'
86
                        ) . '</p>'
87
                    ),
88
                    'Title'
89
                );
90
            } else {
91
                $fields->removeByName('DocumentSetSort');
92
                // Document listing
93
                $gridFieldConfig = GridFieldConfig::create()
94
                    ->addComponents(
95
                        new GridFieldButtonRow('before'),
96
                        new GridFieldToolbarHeader(),
97
                        new GridFieldFilterHeader(),
98
                        new GridFieldSortableHeader(),
99
                        new GridFieldDataColumns(),
100
                        new DMSGridFieldEditButton(),
101
                        // Special delete dialog to handle custom behaviour of unlinking and deleting
102
                        new GridFieldDeleteAction(true),
103
                        new GridFieldDetailForm()
104
                    );
105
106
                if (class_exists('GridFieldPaginatorWithShowAll')) {
107
                    $paginatorComponent = new GridFieldPaginatorWithShowAll(15);
108
                } else {
109
                    $paginatorComponent = new GridFieldPaginator(15);
110
                }
111
                $gridFieldConfig->addComponent($paginatorComponent);
112
113
                if (class_exists('GridFieldSortableRows')) {
114
                    $gridFieldConfig->addComponent(new GridFieldSortableRows('DocumentSort'));
115
                }
116
117
                // Don't show which page this is if we're already editing within a page context
118 View Code Duplication
                if (Controller::curr() instanceof CMSPageEditController) {
119
                    $fields->removeByName('PageID');
120
                } else {
121
                    $fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
122
                }
123
124
                // Don't show which page this is if we're already editing within a page context
125 View Code Duplication
                if (Controller::curr() instanceof CMSPageEditController) {
126
                    $fields->removeByName('PageID');
127
                } else {
128
                    $fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
129
                }
130
131
                $gridFieldConfig->getComponentByType('GridFieldDataColumns')
132
                    ->setDisplayFields($self->getDocumentDisplayFields())
133
                    ->setFieldCasting(array('LastEdited' => 'Datetime->Ago'))
134
                    ->setFieldFormatting(
135
                        array(
136
                            'FilenameWithoutID' => '<a target=\'_blank\' class=\'file-url\''
137
                                . ' href=\'$Link\'>$FilenameWithoutID</a>',
138
                            'ManuallyAdded' => function ($value) {
139
                                if ($value) {
140
                                    return _t('DMSDocumentSet.MANUAL', 'Manually');
141
                                }
142
                                return _t('DMSDocumentSet.QUERYBUILDER', 'Query Builder');
143
                            }
144
                        )
145
                    );
146
147
                // Override delete functionality with this class
148
                $gridFieldConfig->getComponentByType('GridFieldDetailForm')
149
                    ->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
150
                $gridField = GridField::create(
151
                    'Documents',
152
                    false,
153
                    $self->Documents(),
154
                    $gridFieldConfig
155
                );
156
                $gridField->setModelClass('DMSDocument');
157
                $gridField->addExtraClass('documents');
158
159
                $gridFieldConfig->addComponent(
160
                    $addNewButton = new DMSGridFieldAddNewButton('buttons-before-left'),
161
                    'GridFieldExportButton'
162
                );
163
                $addNewButton->setDocumentSetId($self->ID);
164
165
                $fields->removeByName('Documents');
166
                $fields->addFieldsToTab(
167
                    'Root.Main',
168
                    array(
169
                        $gridField,
170
                        HiddenField::create('DMSShortcodeHandlerKey', false, DMS::inst()->getShortcodeHandlerKey())
171
                    )
172
                );
173
                $self->addQueryFields($fields);
174
            }
175
        });
176
        $this->addRequirements();
177
        return parent::getCMSFields();
178
    }
179
180
    /**
181
     * Add required CSS and Javascript requirements for managing documents
182
     *
183
     * @return $this
184
     */
185
    protected function addRequirements()
186
    {
187
        // Javascript to customize the grid field for the DMS document (overriding entwine
188
        // in FRAMEWORK_DIR.'/javascript/GridField.js'
189
        Requirements::javascript(DMS_DIR . '/javascript/DMSGridField.js');
190
        Requirements::css(DMS_DIR . '/dist/css/dmsbundle.css');
191
192
        // Javascript for the link editor pop-up in TinyMCE
193
        Requirements::javascript(DMS_DIR . '/javascript/DocumentHtmlEditorFieldToolbar.js');
194
195
        return $this;
196
    }
197
198
    /**
199
     * Adds the query fields to build the document logic to the DMSDocumentSet.
200
     *
201
     * @param FieldList $fields
202
     */
203
    public function addQueryFields($fields)
204
    {
205
        /** @var DMSDocument $doc */
206
        $doc = singleton('DMSDocument');
207
        /** @var FormField $field */
208
        $dmsDocFields = $doc->scaffoldSearchFields(array('fieldClasses' => true));
209
        $membersMap = Member::get()->map('ID', 'Name')->toArray();
210
        asort($membersMap);
211
212
        foreach ($dmsDocFields as $field) {
213
            if ($field instanceof ListboxField) {
214
                $map = ($field->getName() === 'Tags__ID') ? $doc->getAllTagsMap() : $membersMap;
215
                $field->setMultiple(true)->setSource($map);
216
217
                if ($field->getName() === 'Tags__ID') {
218
                    $field->setRightTitle(
219
                        _t(
220
                            'DMSDocumentSet.TAGS_RIGHT_TITLE',
221
                            'Tags can be set in the taxonomy area, and can be assigned when editing a document.'
222
                        )
223
                    );
224
                }
225
            }
226
        }
227
        $keyValPairs = DMSJsonField::create('KeyValuePairs', $dmsDocFields->toArray());
228
229
        // Now lastly add the sort fields
230
        $sortedBy = FieldGroup::create('SortedBy', array(
231
            DropdownField::create('SortBy', '', array(
232
                'LastEdited'  => 'Last changed',
233
                'Created'     => 'Created',
234
                'Title'       => 'Document title',
235
            ), 'LastEdited'),
236
            DropdownField::create(
237
                'SortByDirection',
238
                '',
239
                array(
240
                    'DESC' => _t('DMSDocumentSet.DIRECTION_DESCENDING', 'Descending'),
241
                    'ASC' => _t('DMSDocumentSet.DIRECTION_ASCENDING', 'Ascending')
242
                ),
243
                'DESC'
244
            ),
245
        ));
246
247
        $sortedBy->setTitle(_t('DMSDocumentSet.SORTED_BY', 'Sort the document set by:'));
248
        $fields->addFieldsToTab(
249
            'Root.QueryBuilder',
250
            array(
251
                LiteralField::create(
252
                    'GridFieldNotice',
253
                    '<p class="message warning">' . _t(
254
                        'DMSDocumentSet.QUERY_BUILDER_NOTICE',
255
                        'The query builder provides the ability to add documents to a document set based on the ' .
256
                        'filters below. Please note that the set will be built using this criteria when you save the ' .
257
                        'form. This set will not be dynamically updated (see the documentation for more information).'
258
                    ) . '</p>'
259
                ),
260
                $keyValPairs,
261
                $sortedBy
262
            )
263
        );
264
    }
265
266
    public function onBeforeWrite()
267
    {
268
        parent::onBeforeWrite();
269
270
        $this->saveLinkedDocuments();
271
    }
272
273
    /**
274
     * Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
275
     */
276
    public function saveLinkedDocuments()
277
    {
278
        if (empty($this->KeyValuePairs) || !$this->isChanged('KeyValuePairs')) {
279
            return;
280
        }
281
282
        $keyValuesPair = Convert::json2array($this->KeyValuePairs);
283
284
        /** @var DMSDocument $dmsDoc */
285
        $dmsDoc = singleton('DMSDocument');
286
        $context = $dmsDoc->getDefaultSearchContext();
287
288
        $sortBy = $this->SortBy ? $this->SortBy : 'LastEdited';
289
        $sortByDirection = $this->SortByDirection ? $this->SortByDirection : 'DESC';
290
        $sortedBy = sprintf('%s %s', $sortBy, $sortByDirection);
291
292
        /** @var DataList $documents */
293
        $documents = $context->getResults($keyValuesPair, $sortedBy);
294
        $documents = $this->addEmbargoConditions($documents);
295
        $documents = $this->addQueryBuilderSearchResults($documents);
296
    }
297
298
    /**
299
     * Add embargo date conditions to a search query
300
     *
301
     * @param  DataList $documents
302
     * @return DataList
303
     */
304
    protected function addEmbargoConditions(DataList $documents)
305
    {
306
        $now = SS_Datetime::now()->Rfc2822();
307
308
        return $documents->where(
309
            "\"EmbargoedIndefinitely\" = 0 AND "
310
            . " \"EmbargoedUntilPublished\" = 0 AND "
311
            . "(\"EmbargoedUntilDate\" IS NULL OR "
312
            . "(\"EmbargoedUntilDate\" IS NOT NULL AND '{$now}' >= \"EmbargoedUntilDate\")) AND "
313
            . "\"ExpireAtDate\" IS NULL OR (\"ExpireAtDate\" IS NOT NULL AND '{$now}' < \"ExpireAtDate\")"
314
        );
315
    }
316
317
    /**
318
     * Remove all ManuallyAdded = 0 original results and add in the new documents returned by the search context
319
     *
320
     * @param  DataList $documents
321
     * @return DataList
322
     */
323
    protected function addQueryBuilderSearchResults(DataList $documents)
324
    {
325
        /** @var ManyManyList $originals Documents that belong to just this set. */
326
        $originals = $this->Documents();
327
        $originals->removeByFilter('"ManuallyAdded" = 0');
328
329
        foreach ($documents as $document) {
330
            $originals->add($document, array('ManuallyAdded' => 0));
331
        }
332
333
        return $originals;
334
    }
335
336
    /**
337
     * Customise the display fields for the documents GridField
338
     *
339
     * @return array
340
     */
341
    public function getDocumentDisplayFields()
342
    {
343
        return array_merge(
344
            (array) DMSDocument::create()->config()->get('display_fields'),
345
            array('ManuallyAdded' => _t('DMSDocumentSet.ADDEDMETHOD', 'Added'))
346
        );
347
    }
348
349
    protected function validate()
350
    {
351
        $result = parent::validate();
352
353
        if (!$this->getTitle()) {
354
            $result->error(_t('DMSDocumentSet.VALIDATION_NO_TITLE', '\'Title\' is required.'));
355
        }
356
        return $result;
357
    }
358
359 View Code Duplication
    public function canView($member = null)
360
    {
361
        $extended = $this->extendedCan(__FUNCTION__, $member);
362
        if ($extended !== null) {
363
            return $extended;
364
        }
365
        return $this->getGlobalPermission($member);
366
    }
367
368 View Code Duplication
    public function canCreate($member = null)
369
    {
370
        $extended = $this->extendedCan(__FUNCTION__, $member);
371
        if ($extended !== null) {
372
            return $extended;
373
        }
374
        return $this->getGlobalPermission($member);
375
    }
376
377 View Code Duplication
    public function canEdit($member = null)
378
    {
379
        $extended = $this->extendedCan(__FUNCTION__, $member);
380
        if ($extended !== null) {
381
            return $extended;
382
        }
383
        return $this->getGlobalPermission($member);
384
    }
385
386 View Code Duplication
    public function canDelete($member = null)
387
    {
388
        $extended = $this->extendedCan(__FUNCTION__, $member);
389
        if ($extended !== null) {
390
            return $extended;
391
        }
392
        return $this->getGlobalPermission($member);
393
    }
394
395
    /**
396
     * Checks if a then given (or logged in) member is either an ADMIN, SITETREE_EDIT_ALL or has access
397
     * to the DMSDocumentAdmin module, in which case permissions is granted.
398
     *
399
     * @param Member $member
0 ignored issues
show
Should the type for parameter $member not be null|Member?

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...
400
     * @return bool
401
     */
402
    public function getGlobalPermission(Member $member = null)
403
    {
404 View Code Duplication
        if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
405
            $member = Member::currentUser();
406
        }
407
408
        $result = ($member &&
409
            Permission::checkMember(
410
                $member,
411
                array('ADMIN', 'SITETREE_EDIT_ALL', 'CMS_ACCESS_DMSDocumentAdmin')
412
            )
413
        );
414
415
        return (bool) $result;
416
    }
417
}
418