Version: current

      1 <?php
      2
      3 /**
      4  * Decorate a data object so that it has an associated folder on the file system that
      5  * lives and dies with this object.
      6  * You can access this associated folder from the object via myObj->AssociatedFolder()
      7  * Extend a DataObject class by calling
      8  * DataObject::add_extension('MyDataObject', 'AssociatedFolderDecorator');
      9  *
     10  */
     11 class AssociatedFolderDecorator extends SiteTreeDecorator {
     12
     13     function extraStatics() {
     14         return array(
     15             'has_one' => array(
     16                 'AssociatedFolder' => 'Folder'
     17             )
     18         );
     19     }
     20
     21     /**
     22      * Флаг - создавать ли автоматически прикрепленную папку. По умолчанию true.
     23      * Можно использовать при импорте - когда не нужно создавать папки сразу.
     24      *
     25      * @var boolean
     26      */
     27     static $createFolders = true;
     28
     29     /**
     30      * Способ формирования имен hash папок
     31      * Возможные значения:
     32      * * ceil_100 - делением id страницы на 100 (по 100 страниц в одной hash папке) - удобно если id меньше 25 000, допустимо до 100 0000
     33      * * rem_256 - остаток от деления id страницы на 256 (256 hash папок, равномерное распределение) - удобно при кол-ве страниц более 10 000
     34      * * rem_1000 - остаток от деления на 1000 (1000 hash папок, равномерное распределение) - удобно при кол-ве страниц более 200 000
     35      * NB: если есть регулярный импорт товаров с созданием AssociatedFolder рекомендуется менять hash_mode на rem_256 или rem_1000
     36      */
     37     static $hash_mode = 'ceil_100';
     38
     39     /**
     40      * The folder name to use if the decorated object's parent has no associated folder of its own.
     41      *
     42      * @var string
     43      */
     44     protected static $defaultRootFolderName = "page-files";
     45
     46     /**
     47      * Set the folder name to use if the decorated object's parent has no associated folder of its own.
     48      *
     49      * @param string $folderName
     50      */
     51     static function setDefaultRootFolderName($folderName) {
     52         AssociatedFolderDecorator::$defaultRootFolderName = $folderName;
     53     }
     54
     55     /**
     56      * Get the folder name to use if the decorated object's parent has no associated folder of its own.
     57      *
     58      * @return string
     59      */
     60     static function getDefaultRootFolderName() {
     61         return AssociatedFolderDecorator::$defaultRootFolderName;
     62     }
     63
     64     /**
     65      * Do stuff before the decorated object is written.
     66      * In this case create the associated folder if it does not already exist.
     67      *
     68      */
     69     function onAfterWrite() {
     70         parent::onAfterWrite();
     71
     72         $folder = null;
     73
     74         // Check whether the folder id is 0 or the Folder object does not exist
     75         if ($this->owner->AssociatedFolderID != 0) {
     76             $folder = DataObject::get_by_id('Folder', $this->owner->AssociatedFolderID);
     77         }
     78
     79         if (!$folder || !$folder->ID) {
     80             // A valid folder does not exist
     81             if (self::$createFolders) {
     82                 $this->createAssociatedFolder();
     83             }
     84         } else {
     85             if (!file_exists($folder->getFullPath())) {
     86                 // The folder object may exist but the folder on the file system does not.
     87                 mkdir($folder->getFullPath(), Filesystem::$folder_create_mask, true);
     88             }
     89             if ($folder->Title != $this->getAssociatedFolderTitle()) {
     90                 $folder->Title = $this->getAssociatedFolderTitle();
     91                 $folder->write();
     92             }
     93         }
     94     }
     95
     96     function onBeforeDuplicate($page) {
     97         $page->AssociatedFolderID = 0;
     98     }
     99
    100     function getHash() {
    101         if (self::$hash_mode == 'rem_256') {
    102             return sprintf('d%04d', $this->owner->ID % 256);
    103         }
    104         if (self::$hash_mode == 'rem_1000') {
    105             return sprintf('d%04d', $this->owner->ID % 1000);
    106         }
    107         // default  - self::$hash_mode == 'ceil_100'
    108         return sprintf('%04d', ceil($this->owner->ID / 100));
    109     }
    110
    111     function getAssociatedFolderName() {
    112         return $this->getAssociatedFolderParentName() . '/' . $this->owner->ID;
    113     }
    114
    115     function getAssociatedFolderTitle() {
    116         return $this->owner->ID . ' - ' . $this->owner->Title;
    117     }
    118
    119     function getAssociatedFolderParentName() {
    120         return $this->getDefaultRootFolderName() . '/' . $this->getHash() ;
    121     }
    122
    123     function getAssociatedFolderParentTitle() {
    124         if (self::$hash_mode != 'ceil_100') return $this->getHash();
    125         $hash = intval($this->getHash());
    126         return sprintf('%02d01-%02d00', $hash-1, $hash);
    127     }
    128
    129     /**
    130      * Create the associated folder
    131      *
    132      * @return Folder
    133      */
    134     function createAssociatedFolder() {
    135         if (!self::$createFolders) {
    136             return false;
    137         }
    138         //если страница не сохранена, то не нужно создавать AssociatedFolder
    139         if (!$this->owner->ID || (!$this->owner->ExistsOnLive && $this->owner->IsDeletedFromStage)) {
    140             return false;
    141         }
    142
    143         $hashFolder = Folder::findOrMake($this->getAssociatedFolderParentName());
    144         $hashTitle = $this->getAssociatedFolderParentTitle();
    145         if ($hashFolder->Title != $hashTitle) {
    146             $hashFolder->Title = $hashTitle;
    147             $hashFolder->write();
    148         }
    149
    150         $associatedFolder = Folder::findOrMake($this->getAssociatedFolderName());
    151         $associatedFolder->Title = $this->getAssociatedFolderTitle();
    152         $associatedFolder->write();
    153
    154         $this->owner->AssociatedFolderID = $associatedFolder->ID;
    155         $this->owner->writeWithoutVersion();
    156         return $associatedFolder;
    157     }
    158
    159     /**
    160      * Return the associated folder
    161      *
    162      * @return Folder
    163      */
    164     function getAssociatedFolder() {
    165         if ($this->owner->AssociatedFolderID && $this->owner->AssociatedFolder()->ID) {
    166             $folder = $this->owner->AssociatedFolder();
    167         } else {
    168             $folder = $this->owner->createAssociatedFolder();
    169         }
    170         return $folder;
    171     }
    172
    173     function onAfterDelete() {
    174         parent::onAfterDelete();
    175         // Total delete from site
    176         if ($this->owner->IsDeletedFromStage && !$this->owner->ExistsOnLive) {
    177             if ($folder = $this->owner->AssociatedFolder()) {
    178                 $folder->delete();
    179             }
    180         }
    181     }
    182
    183 }
    184

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -