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) |
|
0 ignored issues
–
show
|
|||
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 |
||
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 |
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.