Version: current

      1 <?php
      2
      3 class FileDataObjectManager extends DataObjectManager {
      4     static $url_handlers = array(
      5             'import/$ID' => 'handleImport'
      6     );
      7
      8     public static $upgrade_audio = true;
      9     public static $upgrade_video = true;
     10     public static $upgrade_image = true;
     11
     12     public $view;
     13     public $default_view = "grid";
     14     protected $allowedFileTypes;
     15     protected $limitFileTypes;
     16     protected $uploadLimit = "20";
     17     protected $uploadMaxSize = 0;
     18     protected $allowUploadFolderSelection = false;
     19     protected $enableUploadDebugging = false;
     20     protected $customPreviewField = false;
     21     public $hasDataObject = true;
     22     public $importClass = "File";
     23
     24     protected $permissions = array(
     25             "add",
     26             "edit",
     27             "show",
     28             "delete",
     29             "upload",
     30             "import"
     31     );
     32     public $popupClass = "FileDataObjectManager_Popup";
     33     public $itemClass = "FileDataObjectManager_Item";
     34     public $template = "FileDataObjectManager";
     35     public $templatePopup = "DataObjectManager_popup";
     36
     37     public $gridLabelField;
     38     public $pluralTitle;
     39     public $browseButtonText = 'Upload files';
     40
     41     public $uploadFolder = "Uploads";
     42
     43
     44
     45     public function __construct($controller, $name = null, $sourceClass = null, $fileFieldName = null, $fieldList = null, $detailFormFields = null, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
     46         if(!class_exists("MultiUploadField"))
     47             die("<strong>"._t('DataObjectManager.ERROR','Error')."</strong>: "._t('FileDataObjectManager.SWFUPLOAD','DataObjectManager requires the SWFUpload module.'));
     48         parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin);
     49         // Intelligent constructor for fileFieldName
     50         $SNG = singleton($this->sourceClass());
     51         if($fileFieldName === null) {
     52             if($has_ones = $SNG->stat('has_one')) {
     53                 foreach($has_ones as $relation => $value) {
     54                     if($value == "File" || is_subclass_of($value,"File")) {
     55                         $fileFieldName = $relation;
     56                         $fileClassName = $value;
     57                         break;
     58                     }
     59                 }
     60             }
     61         }
     62
     63         if(isset($_REQUEST['ctf'][$this->Name()])) {
     64             $this->view = $_REQUEST['ctf'][$this->Name()]['view'];
     65             $this->search = $_REQUEST['ctf'][$this->Name()]['search'];
     66         }
     67         if($this->sourceClass() == "File" || is_subclass_of($this->sourceClass(), "File")) {
     68             $this->hasDataObject = false;
     69             $this->fileFieldName = $name;
     70             $this->fileClassName = $this->sourceClass();
     71             $this->dataObjectFieldName = null;
     72         }
     73         else {
     74             $this->dataObjectFieldName = $name;
     75             $this->fileFieldName = $fileFieldName;
     76             $this->fileClassName = $SNG->has_one($this->fileFieldName);
     77             if(!$this->fileClassName)
     78                 die("<strong>FileDataObjectManager::__construct():</strong>"._t('FileDataObjectManager.FILERELATION','Could not determine file relationship'));
     79         }
     80
     81         $this->controllerClassName = $controller->class;
     82         if($key = array_search($this->controllerClassName, $SNG->stat('has_one')))
     83             $this->controllerFieldName = $key;
     84         else
     85             $this->controllerFieldName = $this->controllerClassName;
     86         $this->controllerID = $controller->ID;
     87         // Check for allowed file types
     88         if($types = Object::get_static($this->fileClassName,'allowed_file_types'))
     89             $this->setAllowedFileTypes($types);
     90
     91         $this->setAllowedFileTypes(File::$allowed_extensions);
     92
     93         $this->setBrowseButtonText(_t('FileDataObjectManager.UPLOAD_FILES', 'Upload files'));
     94
     95         if (property_exists('WebylonSiteConfig', 'max_file_upload_size')) {
     96             $this->uploadMaxSize = WebylonSiteConfig::$max_file_upload_size;
     97         } else {
     98             $this->uploadMaxSize = ((int)ini_get('upload_max_filesize')) * 1024 * 1024;
     99         }
    100     }
    101
    102     public function getQueryString($params = array()) {
    103         $view = isset($params['view'])? $params['view'] : $this->view;
    104         return parent::getQueryString($params)."&ctf[{$this->Name()}][view]={$view}";
    105     }
    106
    107     public function setGridLabelField($fieldName) {
    108         $this->gridLabelField = $fieldName;
    109     }
    110
    111     public function GridLink() {
    112         return $this->RelativeLink(array('view' => 'grid'));
    113     }
    114
    115     public function ListLink() {
    116         return $this->RelativeLink(array('view' => 'list'));
    117     }
    118
    119     public function GridView() {
    120         return $this->ListStyle() == "grid";
    121     }
    122
    123     public function ListView() {
    124         return $this->ListStyle() == "list";
    125     }
    126
    127     public function ListStyle() {
    128         return $this->view ? $this->view : $this->default_view;
    129     }
    130
    131
    132     public function ImportDropdown() {
    133         return new HTMLDropdownField('ImportFolder','',$this->getImportFolderHierarchy(0),null, null, "-- "._t('DataObjectManager.SELECTFOLDER', 'Select a folder')." --");
    134     }
    135
    136     protected function importLinkFor($file) {
    137         return $this->BaseLink()."/import/$file->ID";
    138     }
    139
    140     protected function getImportFolderHierarchy($parentID, $level = 0) {
    141         $options = array();
    142         if($children = DataObject::get("Folder", "ParentID = $parentID")) {
    143             foreach($children as $child) {
    144                 $indent="";
    145                 for($i=0;$i<$level;$i++) $indent .= "&nbsp;&nbsp;";
    146                 $files = DataObject::get($this->importClass, "ClassName != 'Folder' AND ParentID = $child->ID");
    147                 $count = $files ? $files->Count() : "0";
    148                 $options[$this->importLinkFor($child)] = $indent.$child->Title . " <span>($count files)</span>";
    149                 $options += $this->getImportFolderHierarchy($child->ID, $level+1);
    150             }
    151         }
    152         return $options;
    153     }
    154
    155     protected function getUploadFolderHierarchy($parentID, $level = 0) {
    156         $options = array();
    157         if($children = DataObject::get("Folder", "ParentID = $parentID")) {
    158             foreach($children as $child) {
    159                 $indent="";
    160                 for($i=0;$i<$level;$i++) $indent .= "&nbsp;&nbsp;";
    161                 $options[$child->ID] = empty($child->Title) ? "<em>$indent Untitled</em>" : $indent.$child->Title;
    162                 $options += $this->getUploadFolderHierarchy($child->ID, $level+1);
    163             }
    164         }
    165         return $options;
    166     }
    167
    168
    169     public function setAllowedFileTypes($types = array()) {
    170         /*
    171         foreach($types as $type) {
    172             if(is_array($this->limitFileTypes) && !in_array(strtolower(str_replace(".","",$type)), $this->limitFileTypes))
    173             // To-do: get user_error working.
    174                 die("<strong>".$this->class . "::setAllowedFileTypes() -- Only files of type " . implode(", ", $this->limitFileTypes) . " are allowed.</strong>");
    175         }
    176         */
    177         $this->allowedFileTypes = $types;
    178     }
    179
    180     public function getAllowedFileTypes() {
    181         return $this->allowedFileTypes;
    182     }
    183
    184     public function setUploadLimit($num) {
    185         $this->uploadLimit = $num;
    186     }
    187
    188     public function getUploadLimit() {
    189         return $this->uploadLimit;
    190     }
    191
    192     public function setBrowseButtonText($text) {
    193         $this->browseButtonText = $text;
    194     }
    195
    196     public function getBrowseButtonText() {
    197         return $this->browseButtonText;
    198     }
    199
    200     public function ButtonAddTitle() {
    201         return $this->addTitle ? $this->addTitle : $this->PluralTitle();
    202     }
    203
    204     public function allowUploadFolderSelection() {
    205         $this->allowUploadFolderSelection = true;
    206     }
    207
    208     public function enableUploadDebugging() {
    209         $this->enableUploadDebugging = true;
    210     }
    211
    212     public function setDefaultView($type) {
    213         $this->default_view = $type;
    214     }
    215
    216     public function upload() {
    217         if(!$this->can('add')) return;
    218         $form = $this->UploadForm();
    219         if(is_string($form))
    220             return $this->customise(array(
    221                     'String' => true,
    222                     'NestedController' => $this->isNested,
    223                     'DetailForm' => $this->UploadForm(),
    224                     ))->renderWith($this->templatePopup);
    225         else {
    226             $form = $this->UploadForm();
    227             return $this->customise(array(
    228                     'String' => is_string($form),
    229                     'DetailForm' => $form
    230                     ))->renderWith($this->templatePopup);
    231         }
    232     }
    233
    234     public function UploadLink() {
    235         $link = Controller::join_links($this->BaseLink(),'/upload');
    236         if (Translatable::get_allowed_locales()) {
    237             $link .= '?locale=' . Translatable::get_current_locale();
    238         }
    239         return $link;
    240     }
    241
    242     protected function getUploadFields() {
    243         $uploadUrl = Director::absoluteURL('admin/FileDataObjectManager/handleupload');
    244         if (isset($_GET['locale']) && (array_search($_GET['locale'], Translatable::get_allowed_locales()) !== false)) {
    245             $uploadUrl .= '?locale=' . $_GET['locale'];
    246         }
    247         $fields = new FieldSet(
    248                 new HeaderField($title = sprintf(_t('DataObjectManager.ADDITEM', 'Add %s'),$this->PluralTitle()), $headingLevel = 2),
    249                 new HeaderField($title = _t('DataObjectManager.UPLOADFROMPC', 'Upload from my computer'), $headingLevel = 3),
    250                 new MultiUploadField(
    251                     "UploadForm",
    252                     "Upload",
    253                     "",
    254                     array(
    255                             'file_upload_limit' => $this->getUploadLimit(), // how many files can be uploaded
    256                             'file_queue_limit' => $this->getUploadLimit(), // how many files can be in the queue at once
    257                             'browse_button_text' => $this->getBrowseButtonText(),
    258                             'upload_url' => $uploadUrl,
    259                             'required' => 'true'
    260                     )
    261                 )
    262         );
    263
    264         if($this->allowUploadFolderSelection)
    265             $fields->insertBefore(new HTMLDropdownField('UploadFolder','',$this->getUploadFolderHierarchy(0),null, null, "-- Select a folder --"),"Upload");
    266         return $fields;
    267     }
    268
    269     public function UploadForm() {
    270         // Sync up the DB
    271 //      singleton('Folder')->syncChildren();
    272         $className = $this->sourceClass();
    273         $childData = new $className();
    274         $validator = $this->getValidatorFor($childData);
    275         if($this->Can('upload')) {
    276             MultiUploadConfig::addStaticPostParams(array(
    277                     'dataObjectClassName' => $this->sourceClass(),
    278                     'dataObjectFieldName' => $this->dataObjectFieldName,
    279                     'fileFieldName' => $this->fileFieldName,
    280                     'fileClassName' => $this->fileClassName,
    281                     'parentIDName' => $this->getParentIdName( $this->getParentClass(), $this->sourceClass() ),
    282                     'controllerID' => $this->controllerID,
    283                     'OverrideUploadFolder' => $this->getUploadFolder(),
    284                     'hasDataObject' => $this->hasDataObject ? 1 : 0
    285             ));
    286
    287             if($this->allowUploadFolderSelection)
    288                 MultiUploadConfig::addDynamicPostParam('UploadFolder',$this->popupClass.'_UploadForm_UploadFolder');
    289
    290             if($this->getAllowedFileTypes())
    291                 MultiUploadConfig::addFileTypes($this->getAllowedFileTypes());
    292
    293             if($this->uploadMaxSize)
    294                 MultiUploadConfig::$file_size_limit = $this->uploadMaxSize;
    295
    296             if($this->enableUploadDebugging)
    297                 MultiUploadConfig::set_var('debug','true');
    298         }
    299
    300         $fields = $this->Can('upload') ? $this->getUploadFields() : new FieldSet(
    301                 new HeaderField($title = sprintf(_t('DataObjectManager.ADD', 'Add %s'),$this->PluralTitle()), $headingLevel = 2)
    302         );
    303
    304         $form = Object::create(
    305                 $this->popupClass,
    306                 $this,
    307                 'UploadForm',
    308                 $fields,
    309                 $validator,
    310                 false,
    311                 $childData
    312         );
    313         $action = $this->Can('upload') ? new FieldSet(new FormAction('saveUploadForm', 'Upload')) : new FieldSet();
    314         $form->setActions($action);
    315         if($this->Can('import')) {
    316             $header = new HeaderField($title = _t('DataObjectManager.IMPORTFROMFOLDER', 'Import from an existing folder'), $headingLevel = 3);
    317             $holder =   new LiteralField("holder","<div class='ajax-loader'></div><div id='import-holder'></div>");
    318             if(!isset($_POST['uploaded_files']))
    319                 return $form->forTemplate() . $header->Field() . $this->ImportDropdown()->Field() . $holder->Field();
    320             else
    321                 return $form;
    322         }
    323         return $form;
    324
    325     }
    326
    327     public function saveUploadForm() {
    328         if(isset($_POST['uploaded_files']) && is_array($_POST['uploaded_files'])) {
    329             $form = $this->EditUploadedForm();
    330             return $this->customise(array(
    331                     'String' => is_string($form),
    332                     'DetailForm' => $form
    333                     ))->renderWith($this->templatePopup);
    334         }
    335     }
    336
    337     protected function getChildDataObj() {
    338         $class = $this->sourceClass();
    339         return new $class();
    340     }
    341
    342     public function setPreviewFieldFor($fields) {
    343         $this->customPreviewField = $fields;
    344     }
    345
    346     public function getPreviewFieldFor($fileObject, $size = 150) {
    347         if ($this->customPreviewField) {
    348             return $this->customPreviewField;
    349         }
    350
    351         if($fileObject instanceof Image) {
    352             $URL = $fileObject->getHeight() > $size ? $fileObject->SetHeight($size)->URL : $fileObject->URL
    353             ;
    354             return new LiteralField("icon",
    355                     "<div class='current-image'><img src='$URL' alt='' /><h3>$fileObject->Filename</h3></div>"
    356             );
    357         }
    358         else {
    359             $URL = $fileObject->Icon();
    360             return new LiteralField("icon",
    361                     "<h3><img src='$URL' alt='' /><span>$fileObject->Filename</span></h3>"
    362             );
    363         }
    364     }
    365
    366     protected function closePopup() {
    367         Requirements::clear();
    368         if($this->isNested)
    369             Requirements::customScript("parent.jQuery('#iframe_".$this->id()." a').click();");
    370         else {
    371             Requirements::customScript("
    372                     var container = parent.jQuery('#".$this->id()."');
    373                     parent.jQuery('#facebox').fadeOut(function() {
    374                         parent.jQuery('#facebox .content').removeClass().addClass('content');
    375                         parent.jQuery('#facebox_overlay').remove();
    376                         parent.jQuery('#facebox .loading').remove();
    377                         parent.refresh(container, container.attr('href'));
    378                     });");
    379         }
    380         return $this->customise(array(
    381                 'String' => true,
    382                 'DetailForm' => 'Closing...'
    383                 ))->renderWith($this->templatePopup);
    384     }
    385
    386     public function EditUploadedForm() {
    387         if(!$this->hasDataObject)
    388             return $this->closePopup();
    389
    390         $childData = $this->getChildDataObj();
    391         $validator = $this->getValidatorFor($childData);
    392         $fields = $this->getFieldsFor($childData);
    393         $fields->removeByName($this->fileFieldName);
    394         $total = 0;
    395         if(isset($_POST['totalsize'])){
    396             $total = $_POST['totalsize'];
    397         }else{
    398             if(isset($_POST['uploaded_files'])){
    399                 $total = sizeof($_POST['uploaded_files']);
    400             }
    401         }
    402         $index = isset($_POST['index']) ? $_POST['index'] + 1 : 1;
    403         $fields->push(new HiddenField('totalsize','',$total));
    404         $fields->push(new HiddenField('index','',$index));
    405         if(isset($_POST['uploaded_files']) && is_array($_POST['uploaded_files'])) {
    406             $remaining_files = $_POST['uploaded_files'];
    407             $current = $remaining_files[0];
    408             $dataObject = DataObject::get_by_id($this->sourceClass(), $current);
    409             $fileObject = $dataObject->obj($this->fileFieldName);
    410             $fields->push(new HiddenField('current','',$current));
    411             unset($remaining_files[0]);
    412             if(!$fields->loaded) {
    413                 foreach($remaining_files as $id)
    414                     $fields->push(new LiteralField("u-$id","<input type='hidden' name='uploaded_files[]' value='$id' />"));
    415                 $first = $fields->First()->Name();
    416                 $fields->insertBefore(new HeaderField("Header",_t('DataObjectManager.EDITINGFILE','Editing file')." $index "._t('DataObjectManager.OF','of')." $total",2), $first);
    417                 $fields->insertBefore($this->getPreviewFieldFor($fileObject), $first);
    418             }
    419         }
    420
    421         $form = Object::create(
    422                 $this->popupClass,
    423                 $this,
    424                 'EditUploadedForm',
    425                 $fields,
    426                 $validator,
    427                 false,
    428                 $childData
    429         );
    430         $form->setActions(new FieldSet(new FormAction("saveEditUploadedForm", $index == $total ? _t('DataObjectManager.BUTTONFINISH', 'Finish') : _t('DataObjectManager.BUTTONNEXT', 'Next'))));
    431         if(isset($dataObject) && $dataObject)
    432             $form->loadDataFrom($dataObject);
    433         $fields->loaded = true;
    434         return $form;
    435     }
    436
    437     function saveEditUploadedForm($data, $form) {
    438         $obj = DataObject::get_by_id($this->sourceClass(), $data['current']);
    439         $form->saveInto($obj);
    440         $obj->write();
    441         if(isset($data['uploaded_files']) && is_array($data['uploaded_files'])) {
    442             $form = $this->EditUploadedForm();
    443             return $this->customise(array(
    444                     'String' => is_string($form),
    445                     'DetailForm' => $form
    446                     ))->renderWith($this->templatePopup);
    447         }
    448         else {
    449             return $this->closePopup();
    450         }
    451     }
    452
    453     public function handleImport($request) {
    454         $this->importFolderID = $request->param('ID');
    455         die($this->ImportForm($this->importFolderID)->forTemplate());
    456     }
    457
    458     protected function getImportFields() {
    459         return new FieldSet(
    460                 new HiddenField('dataObjectClassName','',$this->sourceClass()),
    461                 new HiddenField('fileFieldName','', $this->fileFieldName),
    462                 new HiddenField('parentIDName','', $this->getParentIdName( $this->getParentClass(), $this->sourceClass() )),
    463                 new HiddenField('controllerID','',$this->controllerID)
    464         );
    465     }
    466
    467     protected function ImportForm($folder_id = null) {
    468         $folder_id = isset($_POST['folder_id']) ? $_POST['folder_id'] : $this->importFolderID;
    469         ;
    470         if($files = DataObject::get($this->importClass, "ClassName != 'Folder' AND ParentID = $folder_id"))
    471             $fields = $this->getImportFields();
    472         $fields->push(new HiddenField('folder_id','',$folder_id));
    473         $fields->push(new LiteralField('select','<div class="select"><span>Select</span>: <a href="javascript:void(0)" rel="all">all</a> | <a href="javascript:void(0)" rel="none">none</a></div>'));
    474         $fields->push(new LiteralField("ul","<ul>"));
    475         foreach($files as $file) {
    476             if($file instanceof Image) {
    477                 if($img = $file->CroppedImage(35,35))
    478                     $icon = $img->URL;
    479                 else
    480                     $icon = "";
    481             }
    482             elseif($file instanceof File)
    483                 $icon = $file->Icon();
    484             else
    485                 $icon = "";
    486
    487             $title = strlen($file->Title) > 30 ? substr($file->Title, 0, 30)."..." : $file->Title;
    488             $types = $this->getAllowedFileTypes();
    489             if(is_array($types) && !empty($types))
    490                 $allowed = in_array($file->Extension, $types);
    491             else
    492                 $allowed = true;
    493
    494             $class = !$allowed ? "class='disabled'" : "";
    495             $disabled = !$allowed ? "disabled='disabled'" : "";
    496
    497             $fields->push(new LiteralField("li-$file->ID",
    498                     "<li $class>
    499                         <span class='import-checkbox'><input $disabled type='checkbox' name='imported_files[]' value='$file->ID' /></span>
    500                         <span class='import-icon'><img src='$icon' alt='' /></span>
    501                         <span class='import-title'>".$title."</span>
    502                     </li>"
    503             ));
    504         }
    505         $fields->push(new LiteralField("_ul","</ul>"));
    506         return new Form(
    507                 $this,
    508                 "ImportForm",
    509                 $fields,
    510                 new FieldSet(new FormAction('saveImportForm','Import'))
    511         );
    512     }
    513
    514     public function saveImportForm($data, $form) {
    515         if(isset($data['imported_files']) && is_array($data['imported_files'])) {
    516             $_POST['uploaded_files'] = array();
    517             // If the user has set a custom upload folder, cut a new copy of the file when importing - нафиг?
    518             foreach($data['imported_files'] as $file_id) {
    519                 $file = DataObject::get_by_id("File",$file_id);
    520
    521                 // If something other than File has been specified as the linked file class,
    522                 // we need to "upgrade" the imported file to the correct class.
    523                 if($this->fileClassName != "File" && $file->ClassName != $this->fileClassName) {
    524                     $file = $file->newClassInstance($this->fileClassName);
    525                     $file->write();
    526                 }
    527                 $owner_id = $data['parentIDName'];
    528                 if($this->hasDataObject) {
    529                     $do_class = $data['dataObjectClassName'];
    530                     $idxfield = $data['fileFieldName']."ID";
    531                     $obj = new $do_class();
    532                     $obj->$idxfield = $file_id;
    533                     $obj->$owner_id = $data['controllerID'];
    534                     $obj->write();
    535                     $_POST['uploaded_files'][] = $obj->ID;
    536                 }
    537                 else {
    538                     if($file = DataObject::get_by_id($this->fileClassName, $file_id)) {
    539                         $id_field = $this->controllerFieldName."ID";
    540
    541                         if($file->hasField($owner_id)) {
    542                             $file->$owner_id = $this->controllerID;
    543                             $file->write();
    544                         }
    545                     }
    546                 }
    547             }
    548             $form = $this->EditUploadedForm();
    549             return $this->customise(array(
    550                     'String' => is_string($form),
    551                     'DetailForm' => $form
    552                     ))->renderWith($this->templatePopup);
    553
    554         }
    555     }
    556     public function setUploadFolder($override) {
    557         $this->uploadFolder = $override;
    558     }
    559     public function getUploadFolder() {
    560         return $this->uploadFolder;
    561     }
    562
    563     public function getCleanUploadFolder() {
    564         $path = str_replace(ASSETS_DIR."/","",$this->getUploadFolder());
    565         if(substr($path,-1)=="/") $path = substr($path,0, -1);
    566         return $path;
    567     }
    568
    569     function handleItem($request) {
    570         return new FileDataObjectManager_ItemRequest($this, $request->param('ID'));
    571     }
    572 }
    573
    574 class FileDataObjectManager_Controller extends Controller {
    575     public function handleupload() {
    576         $rs = false;
    577         $message = '';
    578         if(isset($_FILES['upload_file']) && !empty($_FILES['upload_file'])) {
    579             $do_class = $_POST['dataObjectClassName'];
    580             $hasDataObject = $_POST['hasDataObject'];
    581             $idxfield = $_POST['fileFieldName']."ID";
    582             $file_class = $_POST['fileClassName'];
    583             $file = new $file_class();
    584
    585             if(isset($_POST['UploadFolder'])) {
    586                 $folder = DataObject::get_by_id("Folder",$_POST['UploadFolder']);
    587                 $path = str_replace(ASSETS_DIR."/","",$folder->Filename);
    588                 if(substr($path,-1)=="/") $path = substr($path,0, -1);
    589             }
    590             else {
    591                 $path = str_replace(ASSETS_DIR."/","",$_POST['OverrideUploadFolder']);
    592                 if(substr($path,-1)=="/") $path = substr($path,0, -1);
    593             }
    594
    595             try {
    596                 if(!class_exists("Upload")) {
    597                     throw new ValidationException(_t("FileDataObjectManager.NoUploadClass", "No Upload class!"), E_USER_WARNING);
    598                 }
    599                 $u = new Upload();
    600                 $u->validator->setAllowedExtensions(File::$allowed_extensions);
    601                 $oldMaxSizes = false;
    602                 if ($hasDataObject && class_exists('ImageAutoResize') && ($obj = new $do_class()) && method_exists($obj, 'AutoresizeMaxWidth')) {
    603                     $oldMaxSizes = ImageAutoResize::get_max_size();
    604                     $maxWidth = ($obj->AutoresizeMaxWidth() > 0) ? $obj->AutoresizeMaxWidth() : $oldMaxSizes['Width'];
    605                     $maxHeight = ($obj->AutoresizeMaxHeight() > 0) ? $obj->AutoresizeMaxHeight() : $oldMaxSizes['Height'];
    606                     ImageAutoResize::set_max_size($maxWidth, $maxHeight);
    607                 }
    608                 if (!$u->loadIntoFile($_FILES['upload_file'], $file, $path)) {
    609                     if ($u->isError()) {
    610                         $errors = implode("; ", $u->getErrors());
    611                     } else {
    612                         $errors = _t("FileDataObjectManager.UploadError", "Upload Error");
    613                     }
    614                     throw new ValidationException($errors, E_USER_WARNING);
    615                 }
    616                 if(isset($_POST['UploadFolder']))
    617                     $file->setField("ParentID",$folder->ID);
    618
    619                 // Provide an "upgrade" to File subclasses
    620                 if($file->class == "File") {
    621                     $ext = strtolower($file->Extension);
    622                     if(in_array($ext, MP3::$allowed_file_types) && FileDataObjectManager::$upgrade_audio)
    623                         $file = $file->newClassInstance("MP3");
    624                     else if(in_array($ext, array('jpg','jpeg','gif','png')) && FileDataObjectManager::$upgrade_image)
    625                         $file = $file->newClassInstance("Image");
    626                     else if(in_array($ext, FLV::$allowed_file_types) && FileDataObjectManager::$upgrade_video)
    627                         $file = $file->newClassInstance("FLV");
    628                 }
    629
    630                 $file->OwnerID = Member::currentUserID();
    631                 if($hasDataObject) {
    632                     $obj = new $do_class();
    633                     $file->write();
    634                     $obj->$idxfield = $file->ID;
    635                     $ownerID = $_POST['parentIDName'];
    636                     $obj->$ownerID = $_POST['controllerID'];
    637                     if (isset($_GET['locale']) && (array_search($_GET['locale'], Translatable::get_allowed_locales()) !== false)) {
    638                         $obj->Locale = $_GET['locale'];
    639                     }
    640                     $obj->write();
    641                     $rs = true;
    642                     $message = $obj->ID;
    643                 }
    644                 else {
    645                     $ownerID = $_POST['parentIDName'];
    646                     $file->$ownerID = $_POST['controllerID'];
    647                     $file->write();
    648                     $rs = true;
    649                     $message = $file->ID;
    650                 }
    651                 if ($oldMaxSizes) {
    652                     ImageAutoResize::set_max_size($oldMaxSizes['Width'], $oldMaxSizes['Height']);
    653                 }
    654             } catch (Exception $e) {
    655                 $rs = false;
    656                 if (method_exists($e,'getResult') && $e->getResult()) {
    657                     $message = $e->getResult()->message();
    658                 } else {
    659                     $message = $e->getMessage();
    660                 }
    661             }
    662         }
    663         echo json_encode(array('rs' => $rs, 'message' => $message));
    664
    665
    666     }
    667 }
    668
    669 class FileDataObjectManager_Item extends DataObjectManager_Item {
    670     function __construct(DataObject $item, ComplexTableField $parent) {
    671         parent::__construct($item, $parent);
    672     }
    673
    674     public function IsFile() {
    675         return $this instanceof File;
    676     }
    677
    678     public function FileIcon() {
    679         if($this->parent->hasDataObject) {
    680             $field = $this->parent->fileFieldName."ID";
    681             $file = DataObject::get_by_id($this->parent->fileClassName, $this->item->$field);
    682         }
    683         else
    684             $file = $this->item;
    685
    686         if($file && $file->ID) {
    687             if($file instanceof Image)
    688                 $img = $file;
    689             else {
    690                 $ext = $file->Extension;
    691                 $imgExts = array('jpg','jpeg','gif');
    692                 if(in_array($ext, $imgExts)) {
    693                     $img = new Image_Cached($file->Filename);
    694                     $img->ID = $file->ID; //image resize functions require an id
    695                 }
    696             }
    697             return (isset($img) && (is_subclass_of($img,'Image_Cached') || $file instanceof Image)) ? $img->CroppedImage(50,50)->URL : $file->Icon();
    698
    699         }
    700         else return "{$this->item->$field}";
    701     }
    702
    703     public function FileLabel() {
    704         $idField = $this->parent->fileFieldName."ID";
    705         if($this->parent->gridLabelField) {
    706             $field = $this->parent->gridLabelField;
    707             return $this->$field;
    708         }
    709         else if(!$this->hasDataObject)
    710             $label = $this->item->Title;
    711         else if($file = DataObject::get_by_id($this->parent->fileClassName, $this->item->$idField))
    712             $label = $file->Title;
    713         else
    714             $label = "";
    715         return strlen($label) > 30 ? substr($label, 0, 30)."..." : $label;
    716     }
    717
    718 }
    719
    720
    721 class FileDataObjectManager_Popup extends DataObjectManager_Popup {
    722     function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
    723         parent::__construct($controller, $name, $fields, $validator, $readonly, $dataObject);
    724
    725         // Hack!
    726         //Requirements::block(THIRDPARTY_DIR.'/prototype.js');
    727         //if($name == "UploadForm" && !isset($_POST['uploaded_files']) && $controller->Can('upload')) MultiUploadConfig::bootstrap();
    728
    729         Requirements::javascript('dataobject_manager/javascript/filedataobjectmanager_popup.js');
    730     }
    731 }
    732
    733 class FileDataObjectManager_ItemRequest extends DataObjectManager_ItemRequest {
    734     function __construct($ctf, $itemID) {
    735         parent::__construct($ctf, $itemID);
    736     }
    737
    738     function DetailForm($childID = null) {
    739         $form = parent::DetailForm($childID);
    740         if($this->dataObj()->hasExtension('Translatable')) {
    741             $excludeFields = array(
    742                 'SortOrder',
    743             );
    744             $fields = $form->Fields();
    745             // try to get the record in "default language"
    746             $originalRecord = $this->dataObj()->getTranslation(Translatable::default_locale());
    747             // if no translation in "default language", fall back to first translation
    748
    749             $translations = $this->dataObj()->getTranslations();
    750             if(!$originalRecord) {
    751                 $originalRecord = ($translations) ? $translations->First() : null;
    752             }
    753             $isTranslationMode = $this->dataObj()->Locale != Translatable::default_locale();
    754
    755             // Show a dropdown to create a new translation.
    756             // This action is possible both when showing the "default language"
    757             // and a translation. Include the current locale (record might not be saved yet).
    758             $alreadyTranslatedLocales = $this->dataObj()->getTranslatedLocales();
    759             $alreadyTranslatedLocales[$this->dataObj()->ID] = $this->dataObj()->Locale;
    760
    761             if($originalRecord && $isTranslationMode) {
    762                 $originalLangID = Session::get($this->dataObj()->ID . '_originalLangID');
    763
    764                 $translatableFieldNames = $this->dataObj()->getTranslatableFields();
    765                 $allDataFields = $fields->dataFields();
    766
    767                 $transformation = new Translatable_Transformation($originalRecord);
    768
    769                 // iterate through sequential list of all datafields in fieldset
    770                 // (fields are object references, so we can replace them with the translatable CompositeField)
    771                 foreach($allDataFields as $dataField) {
    772                     if($dataField instanceof HiddenField) continue;
    773                     if(in_array($dataField->Name(), $excludeFields)) continue;
    774                     if(array_key_exists($dataField->Name(), $this->dataObj()->has_one())) continue; // ignore has_one relations
    775
    776                     if(in_array($dataField->Name(), $translatableFieldNames)) {
    777                         // if the field is translatable, perform transformation
    778                         $fields->replaceField($dataField->Name(), $transformation->transformFormField($dataField));
    779                     } else {
    780                         // else field shouldn't be editable in translation-mode, make readonly
    781                         $fields->replaceField($dataField->Name(), $dataField->performReadonlyTransformation());
    782                     }
    783                 }
    784             }
    785
    786             // TODO Exclude languages which are already translated into
    787             $dropdown = new LanguageDropdownField(
    788                 'NewTransLang',
    789                 _t('DataObjectManager.LANGDROPDOWNLABEL', 'Language'),
    790                 $alreadyTranslatedLocales,
    791                 $this->dataObj()->class,
    792                 'Locale-English'
    793             );
    794
    795             $action = new InlineFormAction(
    796                 'createtranslation',
    797                 _t('DataObjectManager.CREATETRANSBUTTON',
    798                 "Create translation")
    799             );
    800
    801             if($alreadyTranslatedLocales) {
    802                 $header = new HeaderField(
    803                     'ExistingTransHeader',
    804                     _t('DataObjectManager.EXISTINGTRANSTABLE', 'Existing Translations'),
    805                     4
    806                 );
    807                 $relationName = $this->ctf->Name();
    808                 $existingTransHTML = '<ul>';
    809                 foreach($translations as $translation) {
    810                     $mainLangStyle = '';
    811                     if ($translation->Locale == Translatable::default_locale()) {
    812                         $mainLangStyle = ' style="font-weight: bold;"';
    813                     }
    814                     $existingTransHTML .= sprintf('<li'.$mainLangStyle.'><a href="%s">%s</a></li>',
    815                     sprintf('admin/EditForm/field/%s/item/%d/edit', $relationName, $translation->ID), ///admin/EditForm/field/Items/item/532/edit
    816                         i18n::get_locale_name($translation->Locale)
    817                     );
    818
    819                 }
    820                 $existingTransHTML .= '</ul>';
    821                 $table = new LiteralField('existingtrans',$existingTransHTML);
    822             }
    823
    824             $action->includeDefaultJS = false;
    825             if($fields->hasTabSet()) {
    826                 $fields->findOrMakeTab(
    827                     'Root.Translations',
    828                     _t("DataObjectManager.TRANSLATIONSTAB", "Translations")
    829                 );
    830                 $fields->addFieldToTab('Root.Translations', $header);
    831                 $fields->addFieldToTab('Root.Translations', $table);
    832                 $fields->addFieldToTab('Root.Translations', $dropdown);
    833                 $fields->addFieldToTab('Root.Translations', $action);
    834             } else {
    835                 $fields->insertAfter($action, 'Image');
    836                 $fields->insertAfter($dropdown, 'Image');
    837                 $fields->insertAfter($table, 'Image');
    838                 $fields->insertAfter($header, 'Image');
    839             }
    840             // TODO This is hacky, but necessary to get proper identifiers
    841             $form->Fields()->setForm($form);
    842         }
    843
    844         return $form;
    845     }
    846
    847     function createtranslation($data, $form, $edit) {
    848         $langCode = Convert::raw2sql($data['NewTransLang']);
    849         if (isset($data['ctf']) && is_array($data['ctf'])) {
    850             if ($parentObject = DataObject::get_by_id($data['ctf']['parentClass'], (int)$data['ctf']['sourceID'])) {
    851                 $parentField = array_search($data['ctf']['parentClass'], $this->dataObj()->has_one());
    852                 if ($localParentObject = $parentObject->getTranslation($langCode)) {
    853                     Translatable::set_current_locale($langCode);
    854                     $translatedRecord = $this->dataObj()->createTranslation($langCode);
    855                     $translatedRecord->{"{$parentField}ID"} = $localParentObject->ID;
    856                     $translatedRecord->write();
    857
    858                     $newRequest = new FileDataObjectManager_ItemRequest($this->ctf, $translatedRecord->ID);
    859
    860                     return Director::redirect(Controller::join_links($newRequest->ctf->BaseLink(),'/item/'.$translatedRecord->ID.'/edit'));
    861
    862                     // TODO Return current language as GET parameter
    863                     return $newRequest->edit(null);
    864                 }
    865             }
    866         }
    867     }
    868 }
    869
    870 ?>
    871

[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. -