Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like DMSDocument often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use DMSDocument, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 29 | class DMSDocument extends DataObject implements DMSDocumentInterface  | 
            ||
| 30 | { | 
            ||
| 31 | private static $db = array(  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 32 | "Filename" => "Varchar(255)", // eg. 3469~2011-energysaving-report.pdf  | 
            ||
| 33 | "Folder" => "Varchar(255)", // eg. 0  | 
            ||
| 34 | "Title" => 'Varchar(1024)', // eg. "Energy Saving Report for Year 2011, New Zealand LandCorp"  | 
            ||
| 35 | "Description" => 'Text',  | 
            ||
| 36 | "ViewCount" => 'Int',  | 
            ||
| 37 | "EmbargoedIndefinitely" => 'Boolean(false)',  | 
            ||
| 38 | "EmbargoedUntilPublished" => 'Boolean(false)',  | 
            ||
| 39 | "EmbargoedUntilDate" => 'SS_DateTime',  | 
            ||
| 40 | "ExpireAtDate" => 'SS_DateTime',  | 
            ||
| 41 |         "DownloadBehavior" => 'Enum(array("open","download"), "download")', | 
            ||
| 42 |         "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')", | 
            ||
| 43 |         "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", | 
            ||
| 44 | );  | 
            ||
| 45 | |||
| 46 | private static $belongs_many_many = array(  | 
            ||
| 47 | 'Sets' => 'DMSDocumentSet'  | 
            ||
| 48 | );  | 
            ||
| 49 | |||
| 50 | private static $has_one = array(  | 
            ||
| 51 | 'CoverImage' => 'Image',  | 
            ||
| 52 | 'CreatedBy' => 'Member',  | 
            ||
| 53 | 'LastEditedBy' => 'Member',  | 
            ||
| 54 | );  | 
            ||
| 55 | |||
| 56 | private static $many_many = array(  | 
            ||
| 57 | 'RelatedDocuments' => 'DMSDocument',  | 
            ||
| 58 | 'ViewerGroups' => 'Group',  | 
            ||
| 59 | 'EditorGroups' => 'Group',  | 
            ||
| 60 | );  | 
            ||
| 61 | |||
| 62 | private static $display_fields = array(  | 
            ||
| 63 | 'ID' => 'ID',  | 
            ||
| 64 | 'Title' => 'Title',  | 
            ||
| 65 | 'FilenameWithoutID' => 'Filename',  | 
            ||
| 66 | 'LastEdited' => 'Last Edited'  | 
            ||
| 67 | );  | 
            ||
| 68 | |||
| 69 | private static $singular_name = 'Document';  | 
            ||
| 70 | |||
| 71 | private static $plural_name = 'Documents';  | 
            ||
| 72 | |||
| 73 | private static $summary_fields = array(  | 
            ||
| 74 | 'Filename' => 'Filename',  | 
            ||
| 75 | 'Title' => 'Title',  | 
            ||
| 76 | 'getRelatedPages.count' => 'Page Use',  | 
            ||
| 77 | 'ViewCount' => 'ViewCount',  | 
            ||
| 78 | );  | 
            ||
| 79 | |||
| 80 | /**  | 
            ||
| 81 | * @var string download|open  | 
            ||
| 82 | * @config  | 
            ||
| 83 | */  | 
            ||
| 84 | private static $default_download_behaviour = 'download';  | 
            ||
| 85 | |||
| 86 | /**  | 
            ||
| 87 | * A key value map of the "actions" tabs that will be added to the CMS fields  | 
            ||
| 88 | *  | 
            ||
| 89 | * @var array  | 
            ||
| 90 | */  | 
            ||
| 91 | protected $actionTasks = array(  | 
            ||
| 92 | 'embargo' => 'Embargo',  | 
            ||
| 93 | 'expiry' => 'Expiry',  | 
            ||
| 94 | 'replace' => 'Replace',  | 
            ||
| 95 | 'find-usage' => 'Usage',  | 
            ||
| 96 | 'find-references' => 'References',  | 
            ||
| 97 | 'find-relateddocuments' => 'Related Documents',  | 
            ||
| 98 | 'permissions' => 'Permissions'  | 
            ||
| 99 | );  | 
            ||
| 100 | |||
| 101 | public function canView($member = null)  | 
            ||
| 102 |     { | 
            ||
| 103 | View Code Duplication |         if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { | 
            |
| 104 | $member = Member::currentUser();  | 
            ||
| 105 | }  | 
            ||
| 106 | |||
| 107 | // extended access checks  | 
            ||
| 108 |         $results = $this->extend('canView', $member); | 
            ||
| 109 | |||
| 110 |         if ($results && is_array($results)) { | 
            ||
| 111 |             if (!min($results)) { | 
            ||
| 112 | return false;  | 
            ||
| 113 | }  | 
            ||
| 114 | }  | 
            ||
| 115 | |||
| 116 |         if (!$this->CanViewType || $this->CanViewType == 'Anyone') { | 
            ||
| 117 | return true;  | 
            ||
| 118 | }  | 
            ||
| 119 | if ($member && Permission::checkMember($member, array(  | 
            ||
| 120 | 'ADMIN',  | 
            ||
| 121 | 'SITETREE_EDIT_ALL',  | 
            ||
| 122 | 'SITETREE_VIEW_ALL',  | 
            ||
| 123 | ))  | 
            ||
| 124 |         ) { | 
            ||
| 125 | return true;  | 
            ||
| 126 | }  | 
            ||
| 127 | |||
| 128 |         if ($this->isHidden()) { | 
            ||
| 129 | return false;  | 
            ||
| 130 | }  | 
            ||
| 131 | |||
| 132 |         if ($this->CanViewType == 'LoggedInUsers') { | 
            ||
| 133 | return $member && $member->exists();  | 
            ||
| 134 | }  | 
            ||
| 135 | |||
| 136 |         if ($this->CanViewType == 'OnlyTheseUsers' && $this->ViewerGroups()->count()) { | 
            ||
| 137 | return ($member && $member->inGroups($this->ViewerGroups()) || $this->canEdit($member));  | 
            ||
| 138 | }  | 
            ||
| 139 | |||
| 140 | return $this->canEdit($member);  | 
            ||
| 141 | }  | 
            ||
| 142 | |||
| 143 | public function canEdit($member = null)  | 
            ||
| 144 |     { | 
            ||
| 145 | View Code Duplication |         if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { | 
            |
| 146 | $member = Member::currentUser();  | 
            ||
| 147 | }  | 
            ||
| 148 | |||
| 149 |         $results = $this->extend('canEdit', $member); | 
            ||
| 150 | |||
| 151 |         if ($results && is_array($results)) { | 
            ||
| 152 |             if (!min($results)) { | 
            ||
| 153 | return false;  | 
            ||
| 154 | }  | 
            ||
| 155 | }  | 
            ||
| 156 | |||
| 157 | // Do early admin check  | 
            ||
| 158 |         if ($member && Permission::checkMember($member, array('ADMIN','SITETREE_EDIT_ALL'))) { | 
            ||
| 159 | return true;  | 
            ||
| 160 | }  | 
            ||
| 161 | |||
| 162 |         if ($this->CanEditType === 'LoggedInUsers') { | 
            ||
| 163 | return $member && $member->exists();  | 
            ||
| 164 | }  | 
            ||
| 165 | |||
| 166 |         if ($this->CanEditType === 'OnlyTheseUsers' && $this->EditorGroups()->count()) { | 
            ||
| 167 | return $member && $member->inGroups($this->EditorGroups());  | 
            ||
| 168 | }  | 
            ||
| 169 | |||
| 170 | return false;  | 
            ||
| 171 | }  | 
            ||
| 172 | |||
| 173 | /**  | 
            ||
| 174 | * @param Member $member  | 
            ||
| 175 | *  | 
            ||
| 176 | * @return boolean  | 
            ||
| 177 | */  | 
            ||
| 178 | public function canCreate($member = null)  | 
            ||
| 179 |     { | 
            ||
| 180 | View Code Duplication |         if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { | 
            |
| 181 | $member = Member::currentUser();  | 
            ||
| 182 | }  | 
            ||
| 183 | |||
| 184 |         $results = $this->extend('canCreate', $member); | 
            ||
| 185 | |||
| 186 |         if ($results && is_array($results)) { | 
            ||
| 187 |             if (!min($results)) { | 
            ||
| 188 | return false;  | 
            ||
| 189 | }  | 
            ||
| 190 | }  | 
            ||
| 191 | |||
| 192 | // Do early admin check  | 
            ||
| 193 | if ($member &&  | 
            ||
| 194 |             Permission::checkMember($member, array('CMS_ACCESS_DMSDocumentAdmin')) | 
            ||
| 195 |         ) { | 
            ||
| 196 | return true;  | 
            ||
| 197 | }  | 
            ||
| 198 | |||
| 199 | return $this->canEdit($member);  | 
            ||
| 200 | }  | 
            ||
| 201 | |||
| 202 | /**  | 
            ||
| 203 | * @param Member $member  | 
            ||
| 204 | *  | 
            ||
| 205 | * @return boolean  | 
            ||
| 206 | */  | 
            ||
| 207 | public function canDelete($member = null)  | 
            ||
| 208 |     { | 
            ||
| 209 | View Code Duplication |         if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) { | 
            |
| 210 | $member = Member::currentUser();  | 
            ||
| 211 | }  | 
            ||
| 212 | |||
| 213 |         $results = $this->extend('canDelete', $member); | 
            ||
| 214 | |||
| 215 |         if ($results && is_array($results)) { | 
            ||
| 216 |             if (!min($results)) { | 
            ||
| 217 | return false;  | 
            ||
| 218 | }  | 
            ||
| 219 | }  | 
            ||
| 220 | |||
| 221 | return $this->canEdit($member);  | 
            ||
| 222 | }  | 
            ||
| 223 | |||
| 224 | /**  | 
            ||
| 225 | * Increase ViewCount by 1, without update any other record fields such as  | 
            ||
| 226 | * LastEdited.  | 
            ||
| 227 | *  | 
            ||
| 228 | * @return DMSDocument  | 
            ||
| 229 | */  | 
            ||
| 230 | public function trackView()  | 
            ||
| 231 |     { | 
            ||
| 232 |         if ($this->ID > 0) { | 
            ||
| 233 | $count = $this->ViewCount + 1;  | 
            ||
| 234 | |||
| 235 | $this->ViewCount = $count;  | 
            ||
| 236 | |||
| 237 |             DB::query("UPDATE \"DMSDocument\" SET \"ViewCount\"='$count' WHERE \"ID\"={$this->ID}"); | 
            ||
| 238 | |||
| 239 |             $this->extend('trackView'); | 
            ||
| 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()  | 
            ||
| 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 | |||
| 824 |             $versionsGridFieldConfig->getComponentByType('GridFieldDataColumns') | 
            ||
| 825 |                 ->setDisplayFields(Config::inst()->get('DMSDocument_versions', 'display_fields')) | 
            ||
| 826 | ->setFieldFormatting(  | 
            ||
| 827 | array(  | 
            ||
| 828 | 'FilenameWithoutID' => '<a target=\"_blank\" class=\"file-url\" href=\"$Link\">$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 | $embargoValue = 'None';  | 
            ||
| 842 |         if ($this->EmbargoedIndefinitely) { | 
            ||
| 843 | $embargoValue = 'Indefinitely';  | 
            ||
| 844 |         } elseif ($this->EmbargoedUntilPublished) { | 
            ||
| 845 | $embargoValue = 'Published';  | 
            ||
| 846 |         } elseif (!empty($this->EmbargoedUntilDate)) { | 
            ||
| 847 | $embargoValue = 'Date';  | 
            ||
| 848 | }  | 
            ||
| 849 | $embargo = new OptionsetField(  | 
            ||
| 850 | 'Embargo',  | 
            ||
| 851 |             _t('DMSDocument.EMBARGO', 'Embargo'), | 
            ||
| 852 | array(  | 
            ||
| 853 |                 'None' => _t('DMSDocument.EMBARGO_NONE', 'None'), | 
            ||
| 854 |                 'Published' => _t('DMSDocument.EMBARGO_PUBLISHED', 'Hide document until page is published'), | 
            ||
| 855 |                 'Indefinitely' => _t('DMSDocument.EMBARGO_INDEFINITELY', 'Hide document indefinitely'), | 
            ||
| 856 |                 'Date' => _t('DMSDocument.EMBARGO_DATE', 'Hide until set date') | 
            ||
| 857 | ),  | 
            ||
| 858 | $embargoValue  | 
            ||
| 859 | );  | 
            ||
| 860 |         $embargoDatetime = DatetimeField::create('EmbargoedUntilDate', ''); | 
            ||
| 861 | $embargoDatetime->getDateField()  | 
            ||
| 862 |             ->setConfig('showcalendar', true) | 
            ||
| 863 |             ->setConfig('dateformat', 'dd-MM-yyyy') | 
            ||
| 864 |             ->setConfig('datavalueformat', 'dd-MM-yyyy'); | 
            ||
| 865 | |||
| 866 | $expiryValue = 'None';  | 
            ||
| 867 |         if (!empty($this->ExpireAtDate)) { | 
            ||
| 868 | $expiryValue = 'Date';  | 
            ||
| 869 | }  | 
            ||
| 870 | $expiry = new OptionsetField(  | 
            ||
| 871 | 'Expiry',  | 
            ||
| 872 | 'Expiry',  | 
            ||
| 873 | array(  | 
            ||
| 874 | 'None' => 'None',  | 
            ||
| 875 | 'Date' => 'Set document to expire on'  | 
            ||
| 876 | ),  | 
            ||
| 877 | $expiryValue  | 
            ||
| 878 | );  | 
            ||
| 879 |         $expiryDatetime = DatetimeField::create('ExpireAtDate', ''); | 
            ||
| 880 | $expiryDatetime->getDateField()  | 
            ||
| 881 |             ->setConfig('showcalendar', true) | 
            ||
| 882 |             ->setConfig('dateformat', 'dd-MM-yyyy') | 
            ||
| 883 |             ->setConfig('datavalueformat', 'dd-MM-yyyy'); | 
            ||
| 884 | |||
| 885 | // This adds all the actions details into a group.  | 
            ||
| 886 | // Embargo, History, etc to go in here  | 
            ||
| 887 | // These are toggled on and off via the Actions Buttons above  | 
            ||
| 888 |         // exit('hit'); | 
            ||
| 889 | $actionsPanel = FieldGroup::create(  | 
            ||
| 890 |             FieldGroup::create($embargo, $embargoDatetime)->addExtraClass('embargo'), | 
            ||
| 891 |             FieldGroup::create($expiry, $expiryDatetime)->addExtraClass('expiry'), | 
            ||
| 892 |             FieldGroup::create($uploadField)->addExtraClass('replace'), | 
            ||
| 893 |             FieldGroup::create($pagesGrid)->addExtraClass('find-usage'), | 
            ||
| 894 |             FieldGroup::create($referencesGrid)->addExtraClass('find-references'), | 
            ||
| 895 |             FieldGroup::create($this->getPermissionsActionPanel())->addExtraClass('permissions') | 
            ||
| 896 | );  | 
            ||
| 897 | |||
| 898 |         if ($this->canEdit()) { | 
            ||
| 899 |             $actionsPanel->push(FieldGroup::create($versionsGrid)->addExtraClass('find-versions')); | 
            ||
| 900 | $actionsPanel->push(  | 
            ||
| 901 |                 FieldGroup::create($this->getRelatedDocumentsGridField())->addExtraClass('find-relateddocuments') | 
            ||
| 902 | );  | 
            ||
| 903 |         } else { | 
            ||
| 904 |             $this->removeActionPanelTask('find-relateddocuments')->removeActionPanelTask('find-versions'); | 
            ||
| 905 | }  | 
            ||
| 906 |         $fields->add(LiteralField::create('BottomTaskSelection', $this->getActionTaskHtml())); | 
            ||
| 907 |         $actionsPanel->setName('ActionsPanel'); | 
            ||
| 908 |         $actionsPanel->addExtraClass('dmsdocument-actionspanel'); | 
            ||
| 909 | $fields->push($actionsPanel);  | 
            ||
| 910 | |||
| 911 |         $this->extend('updateCMSFields', $fields); | 
            ||
| 912 | |||
| 913 | return $fields;  | 
            ||
| 914 | }  | 
            ||
| 915 | |||
| 916 | /**  | 
            ||
| 917 | * Adds permissions selection fields to a composite field and returns so it can be used in the "actions panel"  | 
            ||
| 918 | *  | 
            ||
| 919 | * @return CompositeField  | 
            ||
| 920 | */  | 
            ||
| 921 | public function getPermissionsActionPanel()  | 
            ||
| 956 | |||
| 957 | /**  | 
            ||
| 958 | * Return a title to use on the frontend, preferably the "title", otherwise the filename without it's numeric ID  | 
            ||
| 959 | *  | 
            ||
| 960 | * @return string  | 
            ||
| 961 | */  | 
            ||
| 962 | public function getTitle()  | 
            ||
| 969 | |||
| 970 | public function onBeforeWrite()  | 
            ||
| 971 |     { | 
            ||
| 972 | parent::onBeforeWrite();  | 
            ||
| 973 | |||
| 974 |         if (isset($this->Embargo)) { | 
            ||
| 975 | //set the embargo options from the OptionSetField created in the getCMSFields method  | 
            ||
| 976 | //do not write after clearing the embargo (write happens automatically)  | 
            ||
| 977 | $savedDate = $this->EmbargoedUntilDate;  | 
            ||
| 978 | $this->clearEmbargo(false); // Clear all previous settings and re-apply them on save  | 
            ||
| 979 | |||
| 980 |             if ($this->Embargo == 'Published') { | 
            ||
| 981 | $this->embargoUntilPublished(false);  | 
            ||
| 982 | }  | 
            ||
| 983 |             if ($this->Embargo == 'Indefinitely') { | 
            ||
| 984 | $this->embargoIndefinitely(false);  | 
            ||
| 985 | }  | 
            ||
| 986 |             if ($this->Embargo == 'Date') { | 
            ||
| 987 | $this->embargoUntilDate($savedDate, false);  | 
            ||
| 988 | }  | 
            ||
| 989 | }  | 
            ||
| 990 | |||
| 991 |         if (isset($this->Expiry)) { | 
            ||
| 992 |             if ($this->Expiry == 'Date') { | 
            ||
| 993 | $this->expireAtDate($this->ExpireAtDate, false);  | 
            ||
| 994 |             } else { | 
            ||
| 995 | $this->clearExpiry(false);  | 
            ||
| 996 | } // Clear all previous settings  | 
            ||
| 997 | }  | 
            ||
| 998 | |||
| 999 | // Set user fields  | 
            ||
| 1000 |         if ($currentUserID = Member::currentUserID()) { | 
            ||
| 1001 |             if (!$this->CreatedByID) { | 
            ||
| 1002 | $this->CreatedByID = $currentUserID;  | 
            ||
| 1003 | }  | 
            ||
| 1004 | $this->LastEditedByID = $currentUserID;  | 
            ||
| 1005 | }  | 
            ||
| 1006 | |||
| 1007 | // make sure default DownloadBehavior is respected when initially writing document  | 
            ||
| 1008 | // in case the default in the enum is different than what's set in an outside config  | 
            ||
| 1009 |         $defaultDownloadBehaviour = Config::inst()->get('DMSDocument', 'default_download_behaviour'); | 
            ||
| 1010 |         if ($this->DownloadBehavior == null && !empty($defaultDownloadBehaviour)) { | 
            ||
| 1011 |             $possibleBehaviors = $this->dbObject('DownloadBehavior') | 
            ||
| 1012 | ->enumValues();  | 
            ||
| 1013 | |||
| 1014 |             if (array_key_exists($defaultDownloadBehaviour, $possibleBehaviors)) { | 
            ||
| 1015 | $behavior = $possibleBehaviors[$defaultDownloadBehaviour];  | 
            ||
| 1016 |                 if ($behavior) { | 
            ||
| 1017 | $this->DownloadBehavior = $behavior;  | 
            ||
| 1018 | }  | 
            ||
| 1019 | }  | 
            ||
| 1020 | }  | 
            ||
| 1021 | }  | 
            ||
| 1022 | |||
| 1023 | /**  | 
            ||
| 1024 | * Return the relative URL of an icon for the file type, based on the  | 
            ||
| 1025 |      * {@link appCategory()} value. | 
            ||
| 1026 | *  | 
            ||
| 1027 | * Images are searched for in "dms/images/app_icons/".  | 
            ||
| 1028 | *  | 
            ||
| 1029 | * @return string  | 
            ||
| 1030 | */  | 
            ||
| 1031 | public function Icon($ext)  | 
            ||
| 1032 |     { | 
            ||
| 1033 |         if (!Director::fileExists(DMS_DIR."/images/app_icons/{$ext}_32.png")) { | 
            ||
| 1034 | $ext = File::get_app_category($ext);  | 
            ||
| 1035 | }  | 
            ||
| 1036 | |||
| 1037 |         if (!Director::fileExists(DMS_DIR."/images/app_icons/{$ext}_32.png")) { | 
            ||
| 1038 | $ext = "generic";  | 
            ||
| 1039 | }  | 
            ||
| 1040 | |||
| 1041 |         return DMS_DIR."/images/app_icons/{$ext}_32.png"; | 
            ||
| 1042 | }  | 
            ||
| 1043 | |||
| 1044 | /**  | 
            ||
| 1045 | * Return the extension of the file associated with the document  | 
            ||
| 1046 | *  | 
            ||
| 1047 | * @return string  | 
            ||
| 1048 | */  | 
            ||
| 1049 | public function getExtension()  | 
            ||
| 1050 |     { | 
            ||
| 1051 | return strtolower(pathinfo($this->Filename, PATHINFO_EXTENSION));  | 
            ||
| 1052 | }  | 
            ||
| 1053 | |||
| 1054 | /**  | 
            ||
| 1055 | * @return string  | 
            ||
| 1056 | */  | 
            ||
| 1057 | public function getSize()  | 
            ||
| 1058 |     { | 
            ||
| 1059 | $size = $this->getAbsoluteSize();  | 
            ||
| 1060 | return ($size) ? File::format_size($size) : false;  | 
            ||
| 1061 | }  | 
            ||
| 1062 | |||
| 1063 | /**  | 
            ||
| 1064 | * Return the size of the file associated with the document.  | 
            ||
| 1065 | *  | 
            ||
| 1066 | * @return string  | 
            ||
| 1067 | */  | 
            ||
| 1068 | public function getAbsoluteSize()  | 
            ||
| 1069 |     { | 
            ||
| 1070 | return file_exists($this->getFullPath()) ? filesize($this->getFullPath()) : null;  | 
            ||
| 1071 | }  | 
            ||
| 1072 | |||
| 1073 | /**  | 
            ||
| 1074 | * An alias to DMSDocument::getSize()  | 
            ||
| 1075 | *  | 
            ||
| 1076 | * @return string  | 
            ||
| 1077 | */  | 
            ||
| 1078 | public function getFileSizeFormatted()  | 
            ||
| 1079 |     { | 
            ||
| 1080 | return $this->getSize();  | 
            ||
| 1081 | }  | 
            ||
| 1082 | |||
| 1083 | |||
| 1084 | /**  | 
            ||
| 1085 | * @return FieldList  | 
            ||
| 1086 | */  | 
            ||
| 1087 | protected function getFieldsForFile($relationListCount)  | 
            ||
| 1088 |     { | 
            ||
| 1089 | $extension = $this->getExtension();  | 
            ||
| 1090 | |||
| 1091 | $previewField = new LiteralField(  | 
            ||
| 1092 | "ImageFull",  | 
            ||
| 1093 |             "<img id='thumbnailImage' class='thumbnail-preview' src='{$this->Icon($extension)}?r=" | 
            ||
| 1094 |             . rand(1, 100000) . "' alt='{$this->Title}' />\n" | 
            ||
| 1095 | );  | 
            ||
| 1096 | |||
| 1097 | //count the number of pages this document is published on  | 
            ||
| 1098 | $publishedOnCount = $this->getRelatedPages()->count();  | 
            ||
| 1099 | $publishedOnValue = "$publishedOnCount pages";  | 
            ||
| 1100 |         if ($publishedOnCount == 1) { | 
            ||
| 1101 | $publishedOnValue = "$publishedOnCount page";  | 
            ||
| 1102 | }  | 
            ||
| 1103 | |||
| 1104 | $relationListCountValue = "$relationListCount pages";  | 
            ||
| 1105 |         if ($relationListCount == 1) { | 
            ||
| 1106 | $relationListCountValue = "$relationListCount page";  | 
            ||
| 1107 | }  | 
            ||
| 1108 | |||
| 1109 | $fields = new FieldGroup(  | 
            ||
| 1110 | $filePreview = CompositeField::create(  | 
            ||
| 1111 | CompositeField::create(  | 
            ||
| 1112 | $previewField  | 
            ||
| 1113 |                 )->setName("FilePreviewImage")->addExtraClass('cms-file-info-preview'), | 
            ||
| 1114 | CompositeField::create(  | 
            ||
| 1115 | CompositeField::create(  | 
            ||
| 1116 |                         new ReadonlyField("ID", "ID number". ':', $this->ID), | 
            ||
| 1117 | new ReadonlyField(  | 
            ||
| 1118 | "FileType",  | 
            ||
| 1119 |                             _t('AssetTableField.TYPE', 'File type') . ':', | 
            ||
| 1120 | self::get_file_type($extension)  | 
            ||
| 1121 | ),  | 
            ||
| 1122 | new ReadonlyField(  | 
            ||
| 1123 | "Size",  | 
            ||
| 1124 |                             _t('AssetTableField.SIZE', 'File size') . ':', | 
            ||
| 1125 | $this->getFileSizeFormatted()  | 
            ||
| 1126 | ),  | 
            ||
| 1127 | $urlField = new ReadonlyField(  | 
            ||
| 1128 | 'ClickableURL',  | 
            ||
| 1129 |                             _t('AssetTableField.URL', 'URL'), | 
            ||
| 1130 | sprintf(  | 
            ||
| 1131 | '<a href="%s" target="_blank" class="file-url">%s</a>',  | 
            ||
| 1132 | $this->getLink(),  | 
            ||
| 1133 | $this->getLink()  | 
            ||
| 1134 | )  | 
            ||
| 1135 | ),  | 
            ||
| 1136 |                         new ReadonlyField("FilenameWithoutIDField", "Filename". ':', $this->getFilenameWithoutID()), | 
            ||
| 1137 | new DateField_Disabled(  | 
            ||
| 1138 | "Created",  | 
            ||
| 1139 |                             _t('AssetTableField.CREATED', 'First uploaded') . ':', | 
            ||
| 1140 | $this->Created  | 
            ||
| 1141 | ),  | 
            ||
| 1142 | new DateField_Disabled(  | 
            ||
| 1143 | "LastEdited",  | 
            ||
| 1144 |                             _t('AssetTableField.LASTEDIT', 'Last changed') . ':', | 
            ||
| 1145 | $this->LastEdited  | 
            ||
| 1146 | ),  | 
            ||
| 1147 |                         new ReadonlyField("PublishedOn", "Published on". ':', $publishedOnValue), | 
            ||
| 1148 |                         new ReadonlyField("ReferencedOn", "Referenced on". ':', $relationListCountValue), | 
            ||
| 1149 |                         new ReadonlyField("ViewCount", "View count". ':', $this->ViewCount) | 
            ||
| 1150 |                     )->setName('FilePreviewDataFields') | 
            ||
| 1151 |                 )->setName("FilePreviewData")->addExtraClass('cms-file-info-data') | 
            ||
| 1152 |             )->setName("FilePreview")->addExtraClass('cms-file-info') | 
            ||
| 1153 | );  | 
            ||
| 1154 | |||
| 1155 |         $fields->addExtraClass('dmsdocument-documentdetails'); | 
            ||
| 1156 | $urlField->dontEscape = true;  | 
            ||
| 1157 | |||
| 1158 |         $this->extend('updateFieldsForFile', $fields); | 
            ||
| 1159 | |||
| 1160 | return $fields;  | 
            ||
| 1161 | }  | 
            ||
| 1162 | |||
| 1163 | /**  | 
            ||
| 1164 | * Takes a file and adds it to the DMSDocument storage, replacing the  | 
            ||
| 1165 | * current file.  | 
            ||
| 1166 | *  | 
            ||
| 1167 | * @param File $file  | 
            ||
| 1168 | *  | 
            ||
| 1169 | * @return $this  | 
            ||
| 1170 | */  | 
            ||
| 1171 | public function ingestFile($file)  | 
            ||
| 1172 |     { | 
            ||
| 1173 | $this->replaceDocument($file);  | 
            ||
| 1174 | $file->delete();  | 
            ||
| 1175 | |||
| 1176 | return $this;  | 
            ||
| 1177 | }  | 
            ||
| 1178 | |||
| 1179 | /**  | 
            ||
| 1180 | * Get a data list of documents related to this document  | 
            ||
| 1181 | *  | 
            ||
| 1182 | * @return DataList  | 
            ||
| 1183 | */  | 
            ||
| 1184 | public function getRelatedDocuments()  | 
            ||
| 1192 | |||
| 1193 | /**  | 
            ||
| 1194 | * Get a list of related pages for this document by going through the associated document sets  | 
            ||
| 1195 | *  | 
            ||
| 1196 | * @return ArrayList  | 
            ||
| 1197 | */  | 
            ||
| 1198 | public function getRelatedPages()  | 
            ||
| 1212 | |||
| 1213 | /**  | 
            ||
| 1214 | * Get a GridField for managing related documents  | 
            ||
| 1215 | *  | 
            ||
| 1216 | * @return GridField  | 
            ||
| 1217 | */  | 
            ||
| 1218 | protected function getRelatedDocumentsGridField()  | 
            ||
| 1248 | |||
| 1249 | /**  | 
            ||
| 1250 | * Get the list of documents to show in "related documents". This can be modified via the extension point, for  | 
            ||
| 1251 | * example if you wanted to exclude embargoed documents or something similar.  | 
            ||
| 1252 | *  | 
            ||
| 1253 | * @return DataList  | 
            ||
| 1254 | */  | 
            ||
| 1255 | protected function getRelatedDocumentsForAutocompleter()  | 
            ||
| 1261 | |||
| 1262 | /**  | 
            ||
| 1263 | * Checks at least one group is selected if CanViewType || CanEditType == 'OnlyTheseUsers'  | 
            ||
| 1264 | *  | 
            ||
| 1265 | * @return ValidationResult  | 
            ||
| 1266 | */  | 
            ||
| 1267 | protected function validate()  | 
            ||
| 1291 | |||
| 1292 | /**  | 
            ||
| 1293 | * Returns a reason as to why this document cannot be viewed.  | 
            ||
| 1294 | *  | 
            ||
| 1295 | * @return string  | 
            ||
| 1296 | */  | 
            ||
| 1297 | public function getPermissionDeniedReason()  | 
            ||
| 1314 | |||
| 1315 | /**  | 
            ||
| 1316 | * Add an "action panel" task  | 
            ||
| 1317 | *  | 
            ||
| 1318 | * @param string $panelKey  | 
            ||
| 1319 | * @param string $title  | 
            ||
| 1320 | * @return $this  | 
            ||
| 1321 | */  | 
            ||
| 1322 | public function addActionPanelTask($panelKey, $title)  | 
            ||
| 1327 | |||
| 1328 | /**  | 
            ||
| 1329 | * Returns a HTML representation of the action tasks for the CMS  | 
            ||
| 1330 | *  | 
            ||
| 1331 | * @return string  | 
            ||
| 1332 | */  | 
            ||
| 1333 | public function getActionTaskHtml()  | 
            ||
| 1352 | |||
| 1353 | /**  | 
            ||
| 1354 | * Removes an "action panel" tasks  | 
            ||
| 1355 | *  | 
            ||
| 1356 | * @param string $panelKey  | 
            ||
| 1357 | * @return $this  | 
            ||
| 1358 | */  | 
            ||
| 1359 | public function removeActionPanelTask($panelKey)  | 
            ||
| 1366 | }  | 
            ||
| 1367 |