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