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 | * @property Varchar Filename |
||
7 | * @property Varchar Folder |
||
8 | * @property Varchar Title |
||
9 | * @property Text Description |
||
10 | * @property int ViewCount |
||
11 | * @property Boolean EmbargoedIndefinitely |
||
12 | * @property Boolean EmbargoedUntilPublished |
||
13 | * @property DateTime EmbargoedUntilDate |
||
14 | * @property DateTime ExpireAtDate |
||
15 | * @property Enum DownloadBehavior |
||
16 | * @property Enum CanViewType Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone') |
||
17 | * @property Enum CanEditType Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers') |
||
18 | * |
||
19 | * @method ManyManyList RelatedDocuments |
||
20 | * @method ManyManyList ViewerGroups |
||
21 | * @method ManyManyList EditorGroups |
||
22 | * |
||
23 | * @method Member CreatedBy |
||
24 | * @property Int CreatedByID |
||
25 | * @method Member LastEditedBy |
||
26 | * @property Int LastEditedByID |
||
27 | * |
||
28 | */ |
||
29 | class DMSDocument extends DataObject implements DMSDocumentInterface |
||
30 | { |
||
31 | private static $db = array( |
||
32 | "Filename" => "Varchar(255)", // eg. 3469~2011-energysaving-report.pdf |
||
33 | "Folder" => "Varchar(255)", // eg. 0 |
||
34 | "Title" => 'Varchar(1024)', // eg. "Energy Saving Report for Year 2011, New Zealand LandCorp" |
||
35 | "Description" => 'Text', |
||
36 | "ViewCount" => 'Int', |
||
37 | "EmbargoedIndefinitely" => 'Boolean(false)', |
||
38 | "EmbargoedUntilPublished" => 'Boolean(false)', |
||
39 | "EmbargoedUntilDate" => 'SS_DateTime', |
||
40 | "ExpireAtDate" => 'SS_DateTime', |
||
41 | "DownloadBehavior" => 'Enum(array("open","download"), "download")', |
||
42 | "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')", |
||
43 | "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", |
||
44 | ); |
||
45 | |||
46 | private static $belongs_many_many = array( |
||
47 | 'Sets' => 'DMSDocumentSet' |
||
48 | ); |
||
49 | |||
50 | private static $has_one = array( |
||
51 | 'CoverImage' => 'Image', |
||
52 | 'CreatedBy' => 'Member', |
||
53 | 'LastEditedBy' => 'Member', |
||
54 | ); |
||
55 | |||
56 | private static $many_many = array( |
||
57 | 'RelatedDocuments' => 'DMSDocument', |
||
58 | 'ViewerGroups' => 'Group', |
||
59 | 'EditorGroups' => 'Group', |
||
60 | ); |
||
61 | |||
62 | private static $display_fields = array( |
||
63 | 'ID' => 'ID', |
||
64 | 'Title' => 'Title', |
||
65 | 'FilenameWithoutID' => 'Filename', |
||
66 | 'LastEdited' => 'Last Edited' |
||
67 | ); |
||
68 | |||
69 | private static $singular_name = 'Document'; |
||
70 | |||
71 | private static $plural_name = 'Documents'; |
||
72 | |||
73 | private static $summary_fields = array( |
||
74 | 'Filename' => 'Filename', |
||
75 | 'Title' => 'Title', |
||
76 | 'getRelatedPages.count' => 'Page Use', |
||
77 | 'ViewCount' => 'ViewCount', |
||
78 | ); |
||
79 | |||
80 | /** |
||
81 | * @var string download|open |
||
82 | * @config |
||
83 | */ |
||
84 | private static $default_download_behaviour = 'download'; |
||
85 | |||
86 | /** |
||
87 | * A key value map of the "actions" tabs that will be added to the CMS fields |
||
88 | * |
||
89 | * @var array |
||
90 | */ |
||
91 | protected $actionTasks = array( |
||
92 | 'embargo' => 'Embargo', |
||
93 | 'expiry' => 'Expiry', |
||
94 | 'replace' => 'Replace', |
||
95 | 'find-usage' => 'Usage', |
||
96 | 'find-references' => 'References', |
||
97 | 'find-relateddocuments' => 'Related Documents', |
||
98 | 'permissions' => 'Permissions' |
||
99 | ); |
||
100 | |||
101 | public function canView($member = null) |
||
102 | { |
||
103 | View Code Duplication | if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { |
|
104 | $member = Member::currentUser(); |
||
105 | } |
||
106 | |||
107 | // extended access checks |
||
108 | $results = $this->extend('canView', $member); |
||
109 | |||
110 | if ($results && is_array($results)) { |
||
111 | if (!min($results)) { |
||
112 | return false; |
||
113 | } |
||
114 | } |
||
115 | |||
116 | if (!$this->CanViewType || $this->CanViewType == 'Anyone') { |
||
117 | return true; |
||
118 | } |
||
119 | if ($member && Permission::checkMember($member, array( |
||
120 | 'ADMIN', |
||
121 | 'SITETREE_EDIT_ALL', |
||
122 | 'SITETREE_VIEW_ALL', |
||
123 | )) |
||
124 | ) { |
||
125 | return true; |
||
126 | } |
||
127 | |||
128 | if ($this->isHidden()) { |
||
129 | return false; |
||
130 | } |
||
131 | |||
132 | if ($this->CanViewType == 'LoggedInUsers') { |
||
133 | return $member && $member->exists(); |
||
134 | } |
||
135 | |||
136 | if ($this->CanViewType == 'OnlyTheseUsers' && $this->ViewerGroups()->count()) { |
||
137 | return ($member && $member->inGroups($this->ViewerGroups()) || $this->canEdit($member)); |
||
0 ignored issues
–
show
|
|||
138 | } |
||
139 | |||
140 | return $this->canEdit($member); |
||
141 | } |
||
142 | |||
143 | public function canEdit($member = null) |
||
144 | { |
||
145 | View Code Duplication | if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { |
|
146 | $member = Member::currentUser(); |
||
147 | } |
||
148 | |||
149 | $results = $this->extend('canEdit', $member); |
||
150 | |||
151 | if ($results && is_array($results)) { |
||
152 | if (!min($results)) { |
||
153 | return false; |
||
154 | } |
||
155 | } |
||
156 | |||
157 | // Do early admin check |
||
158 | if ($member && Permission::checkMember($member, array('ADMIN','SITETREE_EDIT_ALL'))) { |
||
159 | return true; |
||
160 | } |
||
161 | |||
162 | if ($this->CanEditType === 'LoggedInUsers') { |
||
163 | return $member && $member->exists(); |
||
164 | } |
||
165 | |||
166 | if ($this->CanEditType === 'OnlyTheseUsers' && $this->EditorGroups()->count()) { |
||
167 | return $member && $member->inGroups($this->EditorGroups()); |
||
168 | } |
||
169 | |||
170 | return false; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
This check looks for 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...
|
|||
175 | * |
||
176 | * @return boolean |
||
177 | */ |
||
178 | public function canCreate($member = null) |
||
179 | { |
||
180 | View Code Duplication | if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { |
|
181 | $member = Member::currentUser(); |
||
182 | } |
||
183 | |||
184 | $results = $this->extend('canCreate', $member); |
||
185 | |||
186 | if ($results && is_array($results)) { |
||
187 | if (!min($results)) { |
||
188 | return false; |
||
189 | } |
||
190 | } |
||
191 | |||
192 | // Do early admin check |
||
193 | if ($member && |
||
194 | Permission::checkMember($member, array('CMS_ACCESS_DMSDocumentAdmin')) |
||
195 | ) { |
||
196 | return true; |
||
197 | } |
||
198 | |||
199 | return $this->canEdit($member); |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * @param Member $member |
||
204 | * |
||
205 | * @return boolean |
||
206 | */ |
||
207 | public function canDelete($member = null) |
||
208 | { |
||
209 | View Code Duplication | if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { |
|
210 | $member = Member::currentUser(); |
||
211 | } |
||
212 | |||
213 | $results = $this->extend('canDelete', $member); |
||
214 | |||
215 | if ($results && is_array($results)) { |
||
216 | if (!min($results)) { |
||
217 | return false; |
||
218 | } |
||
219 | } |
||
220 | |||
221 | return $this->canEdit($member); |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * Increase ViewCount by 1, without update any other record fields such as |
||
226 | * LastEdited. |
||
227 | * |
||
228 | * @return DMSDocument |
||
229 | */ |
||
230 | public function trackView() |
||
231 | { |
||
232 | if ($this->ID > 0) { |
||
233 | $count = $this->ViewCount + 1; |
||
234 | |||
235 | $this->ViewCount = $count; |
||
236 | |||
237 | DB::query("UPDATE \"DMSDocument\" SET \"ViewCount\"='$count' WHERE \"ID\"={$this->ID}"); |
||
238 | } |
||
239 | |||
240 | return $this; |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Returns a link to download this document from the DMS store. |
||
245 | * Alternatively a basic javascript alert will be shown should the user not have view permissions. An extension |
||
246 | * point for this was also added. |
||
247 | * |
||
248 | * To extend use the following from within an Extension subclass: |
||
249 | * |
||
250 | * <code> |
||
251 | * public function updateGetLink($result) |
||
252 | * { |
||
253 | * // Do something here |
||
254 | * } |
||
255 | * </code> |
||
256 | * |
||
257 | * @return string |
||
258 | */ |
||
259 | public function getLink() |
||
260 | { |
||
261 | $urlSegment = sprintf('%d-%s', $this->ID, URLSegmentFilter::create()->filter($this->getTitle())); |
||
262 | $result = Controller::join_links(Director::baseURL(), 'dmsdocument/' . $urlSegment); |
||
263 | if (!$this->canView()) { |
||
264 | $result = sprintf("javascript:alert('%s')", $this->getPermissionDeniedReason()); |
||
265 | } |
||
266 | |||
267 | $this->extend('updateGetLink', $result); |
||
268 | |||
269 | return $result; |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * @return string |
||
274 | */ |
||
275 | public function Link() |
||
276 | { |
||
277 | return $this->getLink(); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Hides the document, so it does not show up when getByPage($myPage) is |
||
282 | * called (without specifying the $showEmbargoed = true parameter). |
||
283 | * |
||
284 | * This is similar to expire, except that this method should be used to hide |
||
285 | * documents that have not yet gone live. |
||
286 | * |
||
287 | * @param bool $write Save change to the database |
||
288 | * |
||
289 | * @return DMSDocument |
||
290 | */ |
||
291 | public function embargoIndefinitely($write = true) |
||
292 | { |
||
293 | $this->EmbargoedIndefinitely = true; |
||
294 | |||
295 | if ($write) { |
||
296 | $this->write(); |
||
297 | } |
||
298 | |||
299 | return $this; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Hides the document until any page it is linked to is published |
||
304 | * |
||
305 | * @param bool $write Save change to database |
||
306 | * |
||
307 | * @return DMSDocument |
||
308 | */ |
||
309 | public function embargoUntilPublished($write = true) |
||
310 | { |
||
311 | $this->EmbargoedUntilPublished = true; |
||
312 | |||
313 | if ($write) { |
||
314 | $this->write(); |
||
315 | } |
||
316 | |||
317 | return $this; |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Returns if this is Document is embargoed or expired. |
||
322 | * |
||
323 | * Also, returns if the document should be displayed on the front-end, |
||
324 | * respecting the current reading mode of the site and the embargo status. |
||
325 | * |
||
326 | * I.e. if a document is embargoed until published, then it should still |
||
327 | * show up in draft mode. |
||
328 | * |
||
329 | * @return bool |
||
330 | */ |
||
331 | public function isHidden() |
||
332 | { |
||
333 | $hidden = $this->isEmbargoed() || $this->isExpired(); |
||
334 | $readingMode = Versioned::get_reading_mode(); |
||
335 | |||
336 | if ($readingMode == "Stage.Stage") { |
||
337 | if ($this->EmbargoedUntilPublished == true) { |
||
338 | $hidden = false; |
||
339 | } |
||
340 | } |
||
341 | |||
342 | return $hidden; |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Returns if this is Document is embargoed. |
||
347 | * |
||
348 | * @return bool |
||
349 | */ |
||
350 | public function isEmbargoed() |
||
351 | { |
||
352 | if (is_object($this->EmbargoedUntilDate)) { |
||
353 | $this->EmbargoedUntilDate = $this->EmbargoedUntilDate->Value; |
||
354 | } |
||
355 | |||
356 | $embargoed = false; |
||
357 | |||
358 | if ($this->EmbargoedIndefinitely) { |
||
359 | $embargoed = true; |
||
360 | } elseif ($this->EmbargoedUntilPublished) { |
||
361 | $embargoed = true; |
||
362 | } elseif (!empty($this->EmbargoedUntilDate)) { |
||
363 | if (SS_Datetime::now()->Value < $this->EmbargoedUntilDate) { |
||
364 | $embargoed = true; |
||
365 | } |
||
366 | } |
||
367 | |||
368 | return $embargoed; |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * Hides the document, so it does not show up when getByPage($myPage) is |
||
373 | * called. Automatically un-hides the Document at a specific date. |
||
374 | * |
||
375 | * @param string $datetime date time value when this Document should expire. |
||
376 | * @param bool $write |
||
377 | * |
||
378 | * @return DMSDocument |
||
379 | */ |
||
380 | View Code Duplication | public function embargoUntilDate($datetime, $write = true) |
|
381 | { |
||
382 | $this->EmbargoedUntilDate = DBField::create_field('SS_Datetime', $datetime)->Format('Y-m-d H:i:s'); |
||
383 | |||
384 | if ($write) { |
||
385 | $this->write(); |
||
386 | } |
||
387 | |||
388 | return $this; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Clears any previously set embargos, so the Document always shows up in |
||
393 | * all queries. |
||
394 | * |
||
395 | * @param bool $write |
||
396 | * |
||
397 | * @return DMSDocument |
||
398 | */ |
||
399 | public function clearEmbargo($write = true) |
||
400 | { |
||
401 | $this->EmbargoedIndefinitely = false; |
||
402 | $this->EmbargoedUntilPublished = false; |
||
403 | $this->EmbargoedUntilDate = null; |
||
404 | |||
405 | if ($write) { |
||
406 | $this->write(); |
||
407 | } |
||
408 | |||
409 | return $this; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Returns if this is Document is expired. |
||
414 | * |
||
415 | * @return bool |
||
416 | */ |
||
417 | public function isExpired() |
||
418 | { |
||
419 | if (is_object($this->ExpireAtDate)) { |
||
420 | $this->ExpireAtDate = $this->ExpireAtDate->Value; |
||
421 | } |
||
422 | |||
423 | $expired = false; |
||
424 | |||
425 | if (!empty($this->ExpireAtDate)) { |
||
426 | if (SS_Datetime::now()->Value >= $this->ExpireAtDate) { |
||
427 | $expired = true; |
||
428 | } |
||
429 | } |
||
430 | |||
431 | return $expired; |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Hides the document at a specific date, so it does not show up when |
||
436 | * getByPage($myPage) is called. |
||
437 | * |
||
438 | * @param string $datetime date time value when this Document should expire |
||
439 | * @param bool $write |
||
440 | * |
||
441 | * @return DMSDocument |
||
442 | */ |
||
443 | View Code Duplication | public function expireAtDate($datetime, $write = true) |
|
444 | { |
||
445 | $this->ExpireAtDate = DBField::create_field('SS_Datetime', $datetime)->Format('Y-m-d H:i:s'); |
||
446 | |||
447 | if ($write) { |
||
448 | $this->write(); |
||
449 | } |
||
450 | |||
451 | return $this; |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * Clears any previously set expiry. |
||
456 | * |
||
457 | * @param bool $write |
||
458 | * |
||
459 | * @return DMSDocument |
||
460 | */ |
||
461 | public function clearExpiry($write = true) |
||
462 | { |
||
463 | $this->ExpireAtDate = null; |
||
464 | |||
465 | if ($write) { |
||
466 | $this->write(); |
||
467 | } |
||
468 | |||
469 | return $this; |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * Returns a DataList of all previous Versions of this document (check the |
||
474 | * LastEdited date of each object to find the correct one). |
||
475 | * |
||
476 | * If {@link DMSDocument_versions::$enable_versions} is disabled then an |
||
477 | * Exception is thrown |
||
478 | * |
||
479 | * @throws Exception |
||
480 | * |
||
481 | * @return DataList List of Document objects |
||
482 | */ |
||
483 | public function getVersions() |
||
484 | { |
||
485 | if (!DMSDocument_versions::$enable_versions) { |
||
486 | throw new Exception("DMSDocument versions are disabled"); |
||
487 | } |
||
488 | |||
489 | return DMSDocument_versions::get_versions($this); |
||
490 | } |
||
491 | |||
492 | /** |
||
493 | * Returns the full filename of the document stored in this object. |
||
494 | * |
||
495 | * @return string |
||
496 | */ |
||
497 | public function getFullPath() |
||
498 | { |
||
499 | if ($this->Filename) { |
||
500 | return DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR |
||
501 | . $this->Folder . DIRECTORY_SEPARATOR . $this->Filename; |
||
502 | } |
||
503 | |||
504 | return null; |
||
505 | } |
||
506 | |||
507 | /** |
||
508 | * Returns the filename of this asset. |
||
509 | * |
||
510 | * @return string |
||
511 | */ |
||
512 | public function getFilename() |
||
513 | { |
||
514 | if ($this->getField('Filename')) { |
||
515 | return $this->getField('Filename'); |
||
516 | } |
||
517 | return ASSETS_DIR . '/'; |
||
518 | } |
||
519 | |||
520 | /** |
||
521 | * @return string |
||
522 | */ |
||
523 | public function getName() |
||
524 | { |
||
525 | return $this->getField('Title'); |
||
526 | } |
||
527 | |||
528 | |||
529 | /** |
||
530 | * Returns the filename of a document without the prefix, e.g. 0~filename.jpg -> filename.jpg |
||
531 | * |
||
532 | * @return string |
||
533 | */ |
||
534 | public function getFilenameWithoutID() |
||
535 | { |
||
536 | $filenameParts = explode('~', $this->Filename); |
||
537 | $filename = array_pop($filenameParts); |
||
538 | |||
539 | return $filename; |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * @return string |
||
544 | */ |
||
545 | public function getStorageFolder() |
||
546 | { |
||
547 | return DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . DMS::inst()->getStorageFolder($this->ID); |
||
548 | } |
||
549 | |||
550 | /** |
||
551 | * Deletes the DMSDocument and its underlying file. Also calls the parent DataObject's delete method in |
||
552 | * order to complete an cascade. |
||
553 | * |
||
554 | * @return void |
||
555 | */ |
||
556 | public function delete() |
||
557 | { |
||
558 | // delete the file (and previous versions of files) |
||
559 | $filesToDelete = array(); |
||
560 | $storageFolder = $this->getStorageFolder(); |
||
561 | |||
562 | if (file_exists($storageFolder)) { |
||
563 | if ($handle = opendir($storageFolder)) { |
||
564 | while (false !== ($entry = readdir($handle))) { |
||
565 | // only delete if filename starts the the relevant ID |
||
566 | if (strpos($entry, $this->ID.'~') === 0) { |
||
567 | $filesToDelete[] = $entry; |
||
568 | } |
||
569 | } |
||
570 | |||
571 | closedir($handle); |
||
572 | |||
573 | //delete all this files that have the id of this document |
||
574 | foreach ($filesToDelete as $file) { |
||
575 | $filePath = $storageFolder .DIRECTORY_SEPARATOR . $file; |
||
576 | |||
577 | if (is_file($filePath)) { |
||
578 | unlink($filePath); |
||
579 | } |
||
580 | } |
||
581 | } |
||
582 | } |
||
583 | |||
584 | // get rid of any versions have saved for this DMSDocument, too |
||
585 | if (DMSDocument_versions::$enable_versions) { |
||
586 | $versions = $this->getVersions(); |
||
587 | |||
588 | if ($versions->Count() > 0) { |
||
589 | foreach ($versions as $v) { |
||
590 | $v->delete(); |
||
591 | } |
||
592 | } |
||
593 | } |
||
594 | |||
595 | return parent::delete(); |
||
596 | } |
||
597 | |||
598 | /** |
||
599 | * Relate an existing file on the filesystem to the document. |
||
600 | * |
||
601 | * Copies the file to the new destination, as defined in {@link DMS::getStoragePath()}. |
||
602 | * |
||
603 | * @param string $filePath Path to file, relative to webroot. |
||
604 | * |
||
605 | * @return DMSDocument |
||
606 | */ |
||
607 | public function storeDocument($filePath) |
||
608 | { |
||
609 | if (empty($this->ID)) { |
||
610 | user_error("Document must be written to database before it can store documents", E_USER_ERROR); |
||
611 | } |
||
612 | |||
613 | // calculate all the path to copy the file to |
||
614 | $fromFilename = basename($filePath); |
||
615 | $toFilename = $this->ID. '~' . $fromFilename; //add the docID to the start of the Filename |
||
616 | $toFolder = DMS::inst()->getStorageFolder($this->ID); |
||
617 | $toPath = DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $toFolder . DIRECTORY_SEPARATOR . $toFilename; |
||
618 | |||
619 | DMS::inst()->createStorageFolder(DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $toFolder); |
||
620 | |||
621 | //copy the file into place |
||
622 | $fromPath = BASE_PATH . DIRECTORY_SEPARATOR . $filePath; |
||
623 | |||
624 | //version the existing file (copy it to a new "very specific" filename |
||
625 | if (DMSDocument_versions::$enable_versions) { |
||
626 | DMSDocument_versions::create_version($this); |
||
627 | } else { //otherwise delete the old document file |
||
628 | $oldPath = $this->getFullPath(); |
||
629 | if (file_exists($oldPath)) { |
||
630 | unlink($oldPath); |
||
631 | } |
||
632 | } |
||
633 | |||
634 | copy($fromPath, $toPath); //this will overwrite the existing file (if present) |
||
635 | |||
636 | //write the filename of the stored document |
||
637 | $this->Filename = $toFilename; |
||
638 | $this->Folder = strval($toFolder); |
||
639 | |||
640 | $extension = pathinfo($this->Filename, PATHINFO_EXTENSION); |
||
641 | |||
642 | if (empty($this->Title)) { |
||
643 | // don't overwrite existing document titles |
||
644 | $this->Title = basename($filePath, '.'.$extension); |
||
645 | } |
||
646 | |||
647 | $this->write(); |
||
648 | |||
649 | return $this; |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * Takes a File object or a String (path to a file) and copies it into the |
||
654 | * DMS, replacing the original document file but keeping the rest of the |
||
655 | * document unchanged. |
||
656 | * |
||
657 | * @param File|string $file path to a file to store |
||
658 | * |
||
659 | * @return DMSDocument object that we replaced the file in |
||
660 | */ |
||
661 | public function replaceDocument($file) |
||
662 | { |
||
663 | $filePath = DMS::inst()->transformFileToFilePath($file); |
||
664 | $doc = $this->storeDocument($filePath); // replace the document |
||
665 | |||
666 | return $doc; |
||
667 | } |
||
668 | |||
669 | |||
670 | /** |
||
671 | * Return the type of file for the given extension |
||
672 | * on the current file name. |
||
673 | * |
||
674 | * @param string $ext |
||
675 | * |
||
676 | * @return string |
||
677 | */ |
||
678 | public static function get_file_type($ext) |
||
679 | { |
||
680 | $types = array( |
||
681 | 'gif' => 'GIF image - good for diagrams', |
||
682 | 'jpg' => 'JPEG image - good for photos', |
||
683 | 'jpeg' => 'JPEG image - good for photos', |
||
684 | 'png' => 'PNG image - good general-purpose format', |
||
685 | 'ico' => 'Icon image', |
||
686 | 'tiff' => 'Tagged image format', |
||
687 | 'doc' => 'Word document', |
||
688 | 'xls' => 'Excel spreadsheet', |
||
689 | 'zip' => 'ZIP compressed file', |
||
690 | 'gz' => 'GZIP compressed file', |
||
691 | 'dmg' => 'Apple disk image', |
||
692 | 'pdf' => 'Adobe Acrobat PDF file', |
||
693 | 'mp3' => 'MP3 audio file', |
||
694 | 'wav' => 'WAV audo file', |
||
695 | 'avi' => 'AVI video file', |
||
696 | 'mpg' => 'MPEG video file', |
||
697 | 'mpeg' => 'MPEG video file', |
||
698 | 'js' => 'Javascript file', |
||
699 | 'css' => 'CSS file', |
||
700 | 'html' => 'HTML file', |
||
701 | 'htm' => 'HTML file' |
||
702 | ); |
||
703 | |||
704 | return isset($types[$ext]) ? $types[$ext] : $ext; |
||
705 | } |
||
706 | |||
707 | |||
708 | /** |
||
709 | * Returns the Description field with HTML <br> tags added when there is a |
||
710 | * line break. |
||
711 | * |
||
712 | * @return string |
||
713 | */ |
||
714 | public function getDescriptionWithLineBreak() |
||
715 | { |
||
716 | return nl2br($this->getField('Description')); |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * @return FieldList |
||
721 | */ |
||
722 | public function getCMSFields() |
||
723 | { |
||
724 | //include JS to handling showing and hiding of bottom "action" tabs |
||
725 | Requirements::javascript(DMS_DIR . '/javascript/DMSDocumentCMSFields.js'); |
||
726 | Requirements::css(DMS_DIR . '/dist/css/cmsbundle.css'); |
||
727 | |||
728 | $fields = new FieldList(); //don't use the automatic scaffolding, it is slow and unnecessary here |
||
729 | |||
730 | $extraTasks = ''; //additional text to inject into the list of tasks at the bottom of a DMSDocument CMSfield |
||
731 | |||
732 | //get list of shortcode page relations |
||
733 | $relationFinder = new ShortCodeRelationFinder(); |
||
734 | $relationList = $relationFinder->getList($this->ID); |
||
735 | |||
736 | $fieldsTop = $this->getFieldsForFile($relationList->count()); |
||
737 | $fields->add($fieldsTop); |
||
738 | |||
739 | $fields->add(TextField::create('Title', _t('DMSDocument.TITLE', 'Title'))); |
||
740 | $fields->add(TextareaField::create('Description', _t('DMSDocument.DESCRIPTION', 'Description'))); |
||
741 | |||
742 | $coverImageField = UploadField::create('CoverImage', _t('DMSDocument.COVERIMAGE', 'Cover Image')); |
||
743 | $coverImageField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif')); |
||
744 | $coverImageField->setConfig('allowedMaxFileNumber', 1); |
||
745 | $fields->add($coverImageField); |
||
746 | |||
747 | |||
748 | $downloadBehaviorSource = array( |
||
749 | 'open' => _t('DMSDocument.OPENINBROWSER', 'Open in browser'), |
||
750 | 'download' => _t('DMSDocument.FORCEDOWNLOAD', 'Force download'), |
||
751 | ); |
||
752 | $defaultDownloadBehaviour = Config::inst()->get('DMSDocument', 'default_download_behaviour'); |
||
753 | if (!isset($downloadBehaviorSource[$defaultDownloadBehaviour])) { |
||
754 | user_error('Default download behaviour "' . $defaultDownloadBehaviour . '" not supported.', E_USER_WARNING); |
||
755 | } else { |
||
756 | $downloadBehaviorSource[$defaultDownloadBehaviour] .= ' (' . _t('DMSDocument.DEFAULT', 'default') . ')'; |
||
757 | } |
||
758 | |||
759 | $fields->add( |
||
760 | OptionsetField::create( |
||
761 | 'DownloadBehavior', |
||
762 | _t('DMSDocument.DOWNLOADBEHAVIOUR', 'Download behavior'), |
||
763 | $downloadBehaviorSource, |
||
764 | $defaultDownloadBehaviour |
||
765 | ) |
||
766 | ->setDescription( |
||
767 | 'How the visitor will view this file. <strong>Open in browser</strong> ' |
||
768 | . 'allows files to be opened in a new tab.' |
||
769 | ) |
||
770 | ); |
||
771 | |||
772 | //create upload field to replace document |
||
773 | $uploadField = new DMSUploadField('ReplaceFile', 'Replace file'); |
||
774 | $uploadField->setConfig('allowedMaxFileNumber', 1); |
||
775 | $uploadField->setConfig('downloadTemplateName', 'ss-dmsuploadfield-downloadtemplate'); |
||
776 | $uploadField->setRecord($this); |
||
777 | |||
778 | $gridFieldConfig = GridFieldConfig::create()->addComponents( |
||
779 | new GridFieldToolbarHeader(), |
||
780 | new GridFieldSortableHeader(), |
||
781 | new GridFieldDataColumns(), |
||
782 | new GridFieldPaginator(30), |
||
783 | //new GridFieldEditButton(), |
||
784 | new GridFieldDetailForm() |
||
785 | ); |
||
786 | |||
787 | $gridFieldConfig->getComponentByType('GridFieldDataColumns') |
||
788 | ->setDisplayFields(array( |
||
789 | 'Title' => 'Title', |
||
790 | 'ClassName' => 'Page Type', |
||
791 | 'ID' => 'Page ID' |
||
792 | )) |
||
793 | ->setFieldFormatting(array( |
||
794 | 'Title' => sprintf( |
||
795 | '<a class=\"cms-panel-link\" href=\"%s/$ID\">$Title</a>', |
||
796 | singleton('CMSPageEditController')->Link('show') |
||
797 | ) |
||
798 | )); |
||
799 | |||
800 | $pagesGrid = GridField::create( |
||
801 | 'Pages', |
||
802 | _t('DMSDocument.RelatedPages', 'Related Pages'), |
||
803 | $this->getRelatedPages(), |
||
804 | $gridFieldConfig |
||
805 | ); |
||
806 | |||
807 | $referencesGrid = GridField::create( |
||
808 | 'References', |
||
809 | _t('DMSDocument.RelatedReferences', 'Related References'), |
||
810 | $relationList, |
||
811 | $gridFieldConfig |
||
812 | ); |
||
813 | |||
814 | if (DMSDocument_versions::$enable_versions) { |
||
815 | $versionsGridFieldConfig = GridFieldConfig::create()->addComponents( |
||
816 | new GridFieldToolbarHeader(), |
||
817 | new GridFieldSortableHeader(), |
||
818 | new GridFieldDataColumns(), |
||
819 | new GridFieldPaginator(30) |
||
820 | ); |
||
821 | $versionsGridFieldConfig->getComponentByType('GridFieldDataColumns') |
||
822 | ->setDisplayFields(Config::inst()->get('DMSDocument_versions', 'display_fields')) |
||
823 | ->setFieldFormatting( |
||
824 | array( |
||
825 | 'FilenameWithoutID' => '<a target="_blank" class="file-url" href="$Link">' |
||
826 | . '$FilenameWithoutID</a>' |
||
827 | ) |
||
828 | ); |
||
829 | |||
830 | $versionsGrid = GridField::create( |
||
831 | 'Versions', |
||
832 | _t('DMSDocument.Versions', 'Versions'), |
||
833 | $this->getVersions(), |
||
834 | $versionsGridFieldConfig |
||
835 | ); |
||
836 | $this->addActionPanelTask('find-versions', 'Versions'); |
||
837 | } |
||
838 | |||
839 | $embargoValue = 'None'; |
||
840 | if ($this->EmbargoedIndefinitely) { |
||
841 | $embargoValue = 'Indefinitely'; |
||
842 | } elseif ($this->EmbargoedUntilPublished) { |
||
843 | $embargoValue = 'Published'; |
||
844 | } elseif (!empty($this->EmbargoedUntilDate)) { |
||
845 | $embargoValue = 'Date'; |
||
846 | } |
||
847 | $embargo = new OptionsetField( |
||
848 | 'Embargo', |
||
849 | _t('DMSDocument.EMBARGO', 'Embargo'), |
||
850 | array( |
||
851 | 'None' => _t('DMSDocument.EMBARGO_NONE', 'None'), |
||
852 | 'Published' => _t('DMSDocument.EMBARGO_PUBLISHED', 'Hide document until page is published'), |
||
853 | 'Indefinitely' => _t('DMSDocument.EMBARGO_INDEFINITELY', 'Hide document indefinitely'), |
||
854 | 'Date' => _t('DMSDocument.EMBARGO_DATE', 'Hide until set date') |
||
855 | ), |
||
856 | $embargoValue |
||
857 | ); |
||
858 | $embargoDatetime = DatetimeField::create('EmbargoedUntilDate', ''); |
||
859 | $embargoDatetime->getDateField() |
||
860 | ->setConfig('showcalendar', true) |
||
861 | ->setConfig('dateformat', 'dd-MM-yyyy') |
||
862 | ->setConfig('datavalueformat', 'dd-MM-yyyy'); |
||
863 | |||
864 | $expiryValue = 'None'; |
||
865 | if (!empty($this->ExpireAtDate)) { |
||
866 | $expiryValue = 'Date'; |
||
867 | } |
||
868 | $expiry = new OptionsetField( |
||
869 | 'Expiry', |
||
870 | 'Expiry', |
||
871 | array( |
||
872 | 'None' => 'None', |
||
873 | 'Date' => 'Set document to expire on' |
||
874 | ), |
||
875 | $expiryValue |
||
876 | ); |
||
877 | $expiryDatetime = DatetimeField::create('ExpireAtDate', ''); |
||
878 | $expiryDatetime->getDateField() |
||
879 | ->setConfig('showcalendar', true) |
||
880 | ->setConfig('dateformat', 'dd-MM-yyyy') |
||
881 | ->setConfig('datavalueformat', 'dd-MM-yyyy'); |
||
882 | |||
883 | // This adds all the actions details into a group. |
||
884 | // Embargo, History, etc to go in here |
||
885 | // These are toggled on and off via the Actions Buttons above |
||
886 | // exit('hit'); |
||
887 | $actionsPanel = FieldGroup::create( |
||
888 | FieldGroup::create($embargo, $embargoDatetime)->addExtraClass('embargo'), |
||
889 | FieldGroup::create($expiry, $expiryDatetime)->addExtraClass('expiry'), |
||
890 | FieldGroup::create($uploadField)->addExtraClass('replace'), |
||
891 | FieldGroup::create($pagesGrid)->addExtraClass('find-usage'), |
||
892 | FieldGroup::create($referencesGrid)->addExtraClass('find-references'), |
||
893 | FieldGroup::create($this->getPermissionsActionPanel())->addExtraClass('permissions') |
||
894 | ); |
||
895 | |||
896 | if ($this->canEdit()) { |
||
897 | $actionsPanel->push(FieldGroup::create($versionsGrid)->addExtraClass('find-versions')); |
||
898 | $actionsPanel->push( |
||
899 | FieldGroup::create($this->getRelatedDocumentsGridField())->addExtraClass('find-relateddocuments') |
||
900 | ); |
||
901 | } else { |
||
902 | $this->removeActionPanelTask('find-relateddocuments')->removeActionPanelTask('find-versions'); |
||
903 | } |
||
904 | $fields->add(LiteralField::create('BottomTaskSelection', $this->getActionTaskHtml())); |
||
905 | $actionsPanel->setName('ActionsPanel'); |
||
906 | $actionsPanel->addExtraClass('dmsdocument-actionspanel'); |
||
907 | $fields->push($actionsPanel); |
||
908 | |||
909 | $this->extend('updateCMSFields', $fields); |
||
910 | |||
911 | return $fields; |
||
912 | } |
||
913 | |||
914 | /** |
||
915 | * Adds permissions selection fields to a composite field and returns so it can be used in the "actions panel" |
||
916 | * |
||
917 | * @return CompositeField |
||
918 | */ |
||
919 | public function getPermissionsActionPanel() |
||
920 | { |
||
921 | $fields = FieldList::create(); |
||
922 | $showFields = array( |
||
923 | 'CanViewType' => '', |
||
924 | 'ViewerGroups' => 'hide', |
||
925 | 'CanEditType' => '', |
||
926 | 'EditorGroups' => 'hide', |
||
927 | ); |
||
928 | /** @var SiteTree $siteTree */ |
||
929 | $siteTree = singleton('SiteTree'); |
||
930 | $settingsFields = $siteTree->getSettingsFields(); |
||
931 | |||
932 | foreach ($showFields as $name => $extraCss) { |
||
933 | $compositeName = "Root.Settings.$name"; |
||
934 | /** @var FormField $field */ |
||
935 | if ($field = $settingsFields->fieldByName($compositeName)) { |
||
936 | $field->addExtraClass($extraCss); |
||
937 | $title = str_replace('page', 'document', $field->Title()); |
||
938 | $field->setTitle($title); |
||
939 | |||
940 | // Remove Inherited source option from DropdownField |
||
941 | if ($field instanceof DropdownField) { |
||
942 | $options = $field->getSource(); |
||
943 | unset($options['Inherit']); |
||
944 | $field->setSource($options); |
||
945 | } |
||
946 | $fields->push($field); |
||
947 | } |
||
948 | } |
||
949 | |||
950 | $this->extend('updatePermissionsFields', $fields); |
||
951 | |||
952 | return CompositeField::create($fields); |
||
953 | } |
||
954 | |||
955 | /** |
||
956 | * Return a title to use on the frontend, preferably the "title", otherwise the filename without it's numeric ID |
||
957 | * |
||
958 | * @return string |
||
959 | */ |
||
960 | public function getTitle() |
||
961 | { |
||
962 | if ($this->getField('Title')) { |
||
963 | return $this->getField('Title'); |
||
964 | } |
||
965 | return $this->FilenameWithoutID; |
||
966 | } |
||
967 | |||
968 | public function onBeforeWrite() |
||
969 | { |
||
970 | parent::onBeforeWrite(); |
||
971 | |||
972 | if (isset($this->Embargo)) { |
||
973 | //set the embargo options from the OptionSetField created in the getCMSFields method |
||
974 | //do not write after clearing the embargo (write happens automatically) |
||
975 | $savedDate = $this->EmbargoedUntilDate; |
||
976 | $this->clearEmbargo(false); // Clear all previous settings and re-apply them on save |
||
977 | |||
978 | if ($this->Embargo == 'Published') { |
||
979 | $this->embargoUntilPublished(false); |
||
980 | } |
||
981 | if ($this->Embargo == 'Indefinitely') { |
||
982 | $this->embargoIndefinitely(false); |
||
983 | } |
||
984 | if ($this->Embargo == 'Date') { |
||
985 | $this->embargoUntilDate($savedDate, false); |
||
986 | } |
||
987 | } |
||
988 | |||
989 | if (isset($this->Expiry)) { |
||
990 | if ($this->Expiry == 'Date') { |
||
991 | $this->expireAtDate($this->ExpireAtDate, false); |
||
992 | } else { |
||
993 | $this->clearExpiry(false); |
||
994 | } // Clear all previous settings |
||
995 | } |
||
996 | |||
997 | // Set user fields |
||
998 | if ($currentUserID = Member::currentUserID()) { |
||
999 | if (!$this->CreatedByID) { |
||
1000 | $this->CreatedByID = $currentUserID; |
||
1001 | } |
||
1002 | $this->LastEditedByID = $currentUserID; |
||
1003 | } |
||
1004 | } |
||
1005 | |||
1006 | /** |
||
1007 | * Return the relative URL of an icon for the file type, based on the |
||
1008 | * {@link appCategory()} value. |
||
1009 | * |
||
1010 | * Images are searched for in "dms/images/app_icons/". |
||
1011 | * |
||
1012 | * @return string |
||
1013 | */ |
||
1014 | public function Icon($ext) |
||
1015 | { |
||
1016 | if (!Director::fileExists(DMS_DIR."/images/app_icons/{$ext}_32.png")) { |
||
1017 | $ext = File::get_app_category($ext); |
||
1018 | } |
||
1019 | |||
1020 | if (!Director::fileExists(DMS_DIR."/images/app_icons/{$ext}_32.png")) { |
||
1021 | $ext = "generic"; |
||
1022 | } |
||
1023 | |||
1024 | return DMS_DIR."/images/app_icons/{$ext}_32.png"; |
||
1025 | } |
||
1026 | |||
1027 | /** |
||
1028 | * Return the extension of the file associated with the document |
||
1029 | * |
||
1030 | * @return string |
||
1031 | */ |
||
1032 | public function getExtension() |
||
1033 | { |
||
1034 | return strtolower(pathinfo($this->Filename, PATHINFO_EXTENSION)); |
||
1035 | } |
||
1036 | |||
1037 | /** |
||
1038 | * @return string |
||
1039 | */ |
||
1040 | public function getSize() |
||
1041 | { |
||
1042 | $size = $this->getAbsoluteSize(); |
||
1043 | return ($size) ? File::format_size($size) : false; |
||
1044 | } |
||
1045 | |||
1046 | /** |
||
1047 | * Return the size of the file associated with the document. |
||
1048 | * |
||
1049 | * @return string |
||
1050 | */ |
||
1051 | public function getAbsoluteSize() |
||
1052 | { |
||
1053 | return file_exists($this->getFullPath()) ? filesize($this->getFullPath()) : null; |
||
1054 | } |
||
1055 | |||
1056 | /** |
||
1057 | * An alias to DMSDocument::getSize() |
||
1058 | * |
||
1059 | * @return string |
||
1060 | */ |
||
1061 | public function getFileSizeFormatted() |
||
1062 | { |
||
1063 | return $this->getSize(); |
||
1064 | } |
||
1065 | |||
1066 | |||
1067 | /** |
||
1068 | * @return FieldList |
||
1069 | */ |
||
1070 | protected function getFieldsForFile($relationListCount) |
||
1071 | { |
||
1072 | $extension = $this->getExtension(); |
||
1073 | |||
1074 | $previewField = new LiteralField( |
||
1075 | "ImageFull", |
||
1076 | "<img id='thumbnailImage' class='thumbnail-preview' src='{$this->Icon($extension)}?r=" |
||
1077 | . rand(1, 100000) . "' alt='{$this->Title}' />\n" |
||
1078 | ); |
||
1079 | |||
1080 | //count the number of pages this document is published on |
||
1081 | $publishedOnCount = $this->getRelatedPages()->count(); |
||
1082 | $publishedOnValue = "$publishedOnCount pages"; |
||
1083 | if ($publishedOnCount == 1) { |
||
1084 | $publishedOnValue = "$publishedOnCount page"; |
||
1085 | } |
||
1086 | |||
1087 | $relationListCountValue = "$relationListCount pages"; |
||
1088 | if ($relationListCount == 1) { |
||
1089 | $relationListCountValue = "$relationListCount page"; |
||
1090 | } |
||
1091 | |||
1092 | $fields = new FieldGroup( |
||
1093 | $filePreview = CompositeField::create( |
||
1094 | CompositeField::create( |
||
1095 | $previewField |
||
1096 | )->setName("FilePreviewImage")->addExtraClass('cms-file-info-preview'), |
||
1097 | CompositeField::create( |
||
1098 | CompositeField::create( |
||
1099 | new ReadonlyField("ID", "ID number". ':', $this->ID), |
||
1100 | new ReadonlyField( |
||
1101 | "FileType", |
||
1102 | _t('AssetTableField.TYPE', 'File type') . ':', |
||
1103 | self::get_file_type($extension) |
||
1104 | ), |
||
1105 | new ReadonlyField( |
||
1106 | "Size", |
||
1107 | _t('AssetTableField.SIZE', 'File size') . ':', |
||
1108 | $this->getFileSizeFormatted() |
||
1109 | ), |
||
1110 | $urlField = new ReadonlyField( |
||
1111 | 'ClickableURL', |
||
1112 | _t('AssetTableField.URL', 'URL'), |
||
1113 | sprintf( |
||
1114 | '<a href="%s" target="_blank" class="file-url">%s</a>', |
||
1115 | $this->getLink(), |
||
1116 | $this->getLink() |
||
1117 | ) |
||
1118 | ), |
||
1119 | new ReadonlyField("FilenameWithoutIDField", "Filename". ':', $this->getFilenameWithoutID()), |
||
1120 | new DateField_Disabled( |
||
1121 | "Created", |
||
1122 | _t('AssetTableField.CREATED', 'First uploaded') . ':', |
||
1123 | $this->Created |
||
1124 | ), |
||
1125 | new DateField_Disabled( |
||
1126 | "LastEdited", |
||
1127 | _t('AssetTableField.LASTEDIT', 'Last changed') . ':', |
||
1128 | $this->LastEdited |
||
1129 | ), |
||
1130 | new ReadonlyField("PublishedOn", "Published on". ':', $publishedOnValue), |
||
1131 | new ReadonlyField("ReferencedOn", "Referenced on". ':', $relationListCountValue), |
||
1132 | new ReadonlyField("ViewCount", "View count". ':', $this->ViewCount) |
||
1133 | )->setName('FilePreviewDataFields') |
||
1134 | )->setName("FilePreviewData")->addExtraClass('cms-file-info-data') |
||
1135 | )->setName("FilePreview")->addExtraClass('cms-file-info') |
||
1136 | ); |
||
1137 | |||
1138 | $fields->addExtraClass('dmsdocument-documentdetails'); |
||
1139 | $urlField->dontEscape = true; |
||
1140 | |||
1141 | $this->extend('updateFieldsForFile', $fields); |
||
1142 | |||
1143 | return $fields; |
||
1144 | } |
||
1145 | |||
1146 | /** |
||
1147 | * Takes a file and adds it to the DMSDocument storage, replacing the |
||
1148 | * current file. |
||
1149 | * |
||
1150 | * @param File $file |
||
1151 | * |
||
1152 | * @return $this |
||
1153 | */ |
||
1154 | public function ingestFile($file) |
||
1155 | { |
||
1156 | $this->replaceDocument($file); |
||
1157 | $file->delete(); |
||
1158 | |||
1159 | return $this; |
||
1160 | } |
||
1161 | |||
1162 | /** |
||
1163 | * Get a data list of documents related to this document |
||
1164 | * |
||
1165 | * @return DataList |
||
1166 | */ |
||
1167 | public function getRelatedDocuments() |
||
1168 | { |
||
1169 | $documents = $this->RelatedDocuments(); |
||
1170 | |||
1171 | $this->extend('updateRelatedDocuments', $documents); |
||
1172 | |||
1173 | return $documents; |
||
1174 | } |
||
1175 | |||
1176 | /** |
||
1177 | * Get a list of related pages for this document by going through the associated document sets |
||
1178 | * |
||
1179 | * @return ArrayList |
||
1180 | */ |
||
1181 | public function getRelatedPages() |
||
1182 | { |
||
1183 | $pages = ArrayList::create(); |
||
1184 | |||
1185 | foreach ($this->Sets() as $documentSet) { |
||
1186 | /** @var DocumentSet $documentSet */ |
||
1187 | $pages->add($documentSet->Page()); |
||
1188 | } |
||
1189 | $pages->removeDuplicates(); |
||
1190 | |||
1191 | $this->extend('updateRelatedPages', $pages); |
||
1192 | |||
1193 | return $pages; |
||
1194 | } |
||
1195 | |||
1196 | /** |
||
1197 | * Get a GridField for managing related documents |
||
1198 | * |
||
1199 | * @return GridField |
||
1200 | */ |
||
1201 | protected function getRelatedDocumentsGridField() |
||
1202 | { |
||
1203 | $gridField = GridField::create( |
||
1204 | 'RelatedDocuments', |
||
1205 | _t('DMSDocument.RELATEDDOCUMENTS', 'Related Documents'), |
||
1206 | $this->RelatedDocuments(), |
||
1207 | new GridFieldConfig_RelationEditor |
||
1208 | ); |
||
1209 | |||
1210 | $gridFieldConfig = $gridField->getConfig(); |
||
1211 | $gridFieldConfig->removeComponentsByType('GridFieldEditButton'); |
||
1212 | $gridFieldConfig->addComponent(new DMSGridFieldEditButton(), 'GridFieldDeleteAction'); |
||
1213 | |||
1214 | $gridField->getConfig()->removeComponentsByType('GridFieldAddNewButton'); |
||
1215 | // Move the autocompleter to the left |
||
1216 | $gridField->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter'); |
||
1217 | $gridField->getConfig()->addComponent( |
||
1218 | $addExisting = new GridFieldAddExistingAutocompleter('buttons-before-left') |
||
1219 | ); |
||
1220 | |||
1221 | // Ensure that current document doesn't get returned in the autocompleter |
||
1222 | $addExisting->setSearchList($this->getRelatedDocumentsForAutocompleter()); |
||
1223 | |||
1224 | // Restrict search fields to specific fields only |
||
1225 | $addExisting->setSearchFields(array('Title:PartialMatch', 'Filename:PartialMatch')); |
||
1226 | $addExisting->setResultsFormat('$Filename'); |
||
1227 | |||
1228 | $this->extend('updateRelatedDocumentsGridField', $gridField); |
||
1229 | return $gridField; |
||
1230 | } |
||
1231 | |||
1232 | /** |
||
1233 | * Get the list of documents to show in "related documents". This can be modified via the extension point, for |
||
1234 | * example if you wanted to exclude embargoed documents or something similar. |
||
1235 | * |
||
1236 | * @return DataList |
||
1237 | */ |
||
1238 | protected function getRelatedDocumentsForAutocompleter() |
||
1239 | { |
||
1240 | $documents = DMSDocument::get()->exclude('ID', $this->ID); |
||
1241 | $this->extend('updateRelatedDocumentsForAutocompleter', $documents); |
||
1242 | return $documents; |
||
1243 | } |
||
1244 | |||
1245 | /** |
||
1246 | * Checks at least one group is selected if CanViewType || CanEditType == 'OnlyTheseUsers' |
||
1247 | * |
||
1248 | * @return ValidationResult |
||
1249 | */ |
||
1250 | protected function validate() |
||
1251 | { |
||
1252 | $valid = parent::validate(); |
||
1253 | |||
1254 | if ($this->CanViewType == 'OnlyTheseUsers' && !$this->ViewerGroups()->count()) { |
||
1255 | $valid->error( |
||
1256 | _t( |
||
1257 | 'DMSDocument.VALIDATIONERROR_NOVIEWERSELECTED', |
||
1258 | "Selecting 'Only these people' from a viewers list needs at least one group selected." |
||
1259 | ) |
||
1260 | ); |
||
1261 | } |
||
1262 | |||
1263 | if ($this->CanEditType == 'OnlyTheseUsers' && !$this->EditorGroups()->count()) { |
||
1264 | $valid->error( |
||
1265 | _t( |
||
1266 | 'DMSDocument.VALIDATIONERROR_NOEDITORSELECTED', |
||
1267 | "Selecting 'Only these people' from a editors list needs at least one group selected." |
||
1268 | ) |
||
1269 | ); |
||
1270 | } |
||
1271 | |||
1272 | return $valid; |
||
1273 | } |
||
1274 | |||
1275 | /** |
||
1276 | * Returns a reason as to why this document cannot be viewed. |
||
1277 | * |
||
1278 | * @return string |
||
1279 | */ |
||
1280 | public function getPermissionDeniedReason() |
||
1281 | { |
||
1282 | $result = ''; |
||
1283 | |||
1284 | if ($this->CanViewType == 'LoggedInUsers') { |
||
1285 | $result = _t('DMSDocument.PERMISSIONDENIEDREASON_LOGINREQUIRED', 'Please log in to view this document'); |
||
1286 | } |
||
1287 | |||
1288 | if ($this->CanViewType == 'OnlyTheseUsers') { |
||
1289 | $result = _t( |
||
1290 | 'DMSDocument.PERMISSIONDENIEDREASON_NOTAUTHORISED', |
||
1291 | 'You are not authorised to view this document' |
||
1292 | ); |
||
1293 | } |
||
1294 | |||
1295 | return $result; |
||
1296 | } |
||
1297 | |||
1298 | /** |
||
1299 | * Add an "action panel" task |
||
1300 | * |
||
1301 | * @param string $panelKey |
||
1302 | * @param string $title |
||
1303 | * @return $this |
||
1304 | */ |
||
1305 | public function addActionPanelTask($panelKey, $title) |
||
1306 | { |
||
1307 | $this->actionTasks[$panelKey] = $title; |
||
1308 | return $this; |
||
1309 | } |
||
1310 | |||
1311 | /** |
||
1312 | * Returns a HTML representation of the action tasks for the CMS |
||
1313 | * |
||
1314 | * @return string |
||
1315 | */ |
||
1316 | public function getActionTaskHtml() |
||
1317 | { |
||
1318 | $html = '<div class="field dmsdocment-actions">' |
||
1319 | . '<label class="left">' . _t('DMSDocument.ACTIONS_LABEL', 'Actions') . '</label>' |
||
1320 | . '<ul>'; |
||
1321 | |||
1322 | foreach ($this->actionTasks as $panelKey => $title) { |
||
1323 | $html .= '<li class="ss-ui-button dmsdocument-action" data-panel="' . $panelKey . '">' |
||
1324 | . _t('DMSDocument.ACTION_' . strtoupper($panelKey), $title) |
||
1325 | . '</li>'; |
||
1326 | } |
||
1327 | |||
1328 | $html .= '</ul></div>'; |
||
1329 | |||
1330 | return $html; |
||
1331 | } |
||
1332 | |||
1333 | /** |
||
1334 | * Removes an "action panel" tasks |
||
1335 | * |
||
1336 | * @param string $panelKey |
||
1337 | * @return $this |
||
1338 | */ |
||
1339 | public function removeActionPanelTask($panelKey) |
||
1340 | { |
||
1341 | if (array_key_exists($panelKey, $this->actionTasks)) { |
||
1342 | unset($this->actionTasks[$panelKey]); |
||
1343 | } |
||
1344 | return $this; |
||
1345 | } |
||
1346 | } |
||
1347 |
If you implement
__call
and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.This is often the case, when
__call
is implemented by a parent class and only the child class knows which methods exist: