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