Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • AssetAdmin
  • AssetTableField
  • FileComplexTableField
  • FileList
  • FilesystemSyncTask
  • ImageEditor
  • ThumbnailStripField
  1 <?php
  2 /**
  3  * AssetAdmin is the 'file store' section of the CMS.
  4  * It provides an interface for maniupating the File and Folder objects in the system.
  5  * 
  6  * @package cms
  7  * @subpackage assets
  8  */
  9 class AssetAdmin extends LeftAndMain {
 10 
 11     static $url_segment = 'assets';
 12     
 13     static $url_rule = '/$Action/$ID';
 14     
 15     static $menu_title = 'Files & Images';
 16 
 17     public static $tree_class = 'File';
 18     
 19     /**
 20      * @see Upload->allowedMaxFileSize
 21      * @var int
 22      */
 23     public static $allowed_max_file_size;
 24     
 25     static $allowed_actions = array(
 26         'addfolder',
 27         'deletefolder',
 28         'deletemarked',
 29         'DeleteItemsForm',
 30         'deleteUnusedThumbnails',
 31         'doUpload',
 32         'doMultiUpload',
 33         'getfile',
 34         'getsubtree',
 35         'movemarked',
 36         'removefile',
 37         'save',
 38         'savefile',
 39         'sync',
 40         'uploadiframe',
 41         'UploadForm',
 42         'handleupload',
 43         'deleteUnusedThumbnails' => 'ADMIN'
 44     );
 45     
 46     /**
 47      * @var boolean Enables upload of additional textual information
 48      * alongside each file (through multifile.js), which makes
 49      * batch changes easier.
 50      * 
 51      * CAUTION: This is an unstable API which might change.
 52      */
 53     public static $metadata_upload_enabled = false;
 54     
 55     /**
 56      * Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
 57      */
 58     public function currentPageID() {
 59         if(isset($_REQUEST['ID']) && is_numeric($_REQUEST['ID']))   {
 60             return $_REQUEST['ID'];
 61         } elseif (is_numeric($this->urlParams['ID'])) {
 62             return $this->urlParams['ID'];
 63         } elseif(is_numeric(Session::get("{$this->class}.currentPage"))) {
 64             return Session::get("{$this->class}.currentPage");
 65         } else {
 66             return "root";
 67         }
 68     }
 69 
 70     /**
 71      * Set up the controller, in particular, re-sync the File database with the assets folder./
 72      */
 73     function init() {
 74         parent::init();
 75         
 76         if(!file_exists(ASSETS_PATH)) {
 77             mkdir(ASSETS_PATH);
 78         }
 79 
 80         // needed for MemberTableField (Requirements not determined before Ajax-Call)
 81         Requirements::css(THIRDPARTY_DIR . "/greybox/greybox.css");
 82         Requirements::css(SAPPHIRE_DIR . "/css/ComplexTableField.css");
 83 
 84         Requirements::javascript(CMS_DIR . "/javascript/AssetAdmin.js");
 85         
 86         Requirements::javascript(THIRDPARTY_DIR . "/greybox/AmiJS.js");
 87         Requirements::javascript(THIRDPARTY_DIR . "/greybox/greybox.js");
 88         Requirements::css(THIRDPARTY_DIR . "/greybox/greybox.css");
 89         
 90         Requirements::css(CMS_DIR . "/css/AssetAdmin.css");
 91 
 92         Requirements::customScript(<<<JS
 93             _TREE_ICONS = {};
 94             _TREE_ICONS['Folder'] = {
 95                     fileIcon: 'sapphire/javascript/tree/images/page-closedfolder.gif',
 96                     openFolderIcon: 'sapphire/javascript/tree/images/page-openfolder.gif',
 97                     closedFolderIcon: 'sapphire/javascript/tree/images/page-closedfolder.gif'
 98             };
 99 JS
100         );
101     }
102     
103     /**
104      * Show the content of the upload iframe.  The form is specified by a template.
105      */
106     function uploadiframe() {
107         Requirements::clear();
108         
109         Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/prototype/prototype.js");
110         Requirements::javascript(SAPPHIRE_DIR . '/javascript/loader.js');
111         Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/behaviour/behaviour.js");
112         Requirements::javascript(SAPPHIRE_DIR . "/javascript/prototype_improvements.js");
113         Requirements::javascript(SAPPHIRE_DIR . "/javascript/layout_helpers.js");
114         Requirements::javascript(CMS_DIR . "/javascript/LeftAndMain.js");
115 //      Requirements::javascript(CMS_DIR . "/thirdparty/multifile/multifile.js");
116 //      Requirements::css(CMS_DIR . "/thirdparty/multifile/multifile.css");
117         Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/jquery/jquery.js");
118         Requirements::javascript(SAPPHIRE_DIR . "/javascript/jquery_improvements.js");
119         Requirements::css(CMS_DIR . "/css/typography.css");
120         Requirements::css(CMS_DIR . "/css/layout.css");
121         Requirements::css(CMS_DIR . "/css/cms_left.css");
122         Requirements::css(CMS_DIR . "/css/cms_right.css");
123         
124         if(isset($data['ID']) && $data['ID'] != 'root') $folder = DataObject::get_by_id("Folder", $data['ID']);
125         else $folder = singleton('Folder');
126         
127         return array( 'CanUpload' => $folder->canEdit());
128     }
129     
130     /**
131      * Needs to be enabled through {@link AssetAdmin::$metadata_upload_enabled}
132      * 
133      * @return String
134      */
135     function UploadMetadataHtml() {
136         if(!self::$metadata_upload_enabled) return;
137         
138         $fields = singleton('File')->uploadMetadataFields();
139 
140         // Return HTML with markers for easy replacement
141         $fieldHtml = '';
142         foreach($fields as $field) $fieldHtml = $fieldHtml . $field->FieldHolder();
143         $fieldHtml = preg_replace('/(name|for|id)="(.+?)"/', '$1="$2[__X__]"', $fieldHtml);
144 
145         // Icky hax to fix certain elements with fixed ids
146         $fieldHtml = preg_replace('/-([a-zA-Z0-9]+?)\[__X__\]/', '[__X__]-$1', $fieldHtml);
147 
148         return $fieldHtml;
149     }
150     
151     /**
152      * Return the form object shown in the uploadiframe.
153      */
154     function UploadForm() {
155         $ff = new MultiUploadField(
156             'UploadForm', 
157             'Upload', 
158             "",
159             array(
160                     'file_upload_limit' => 10, // how many files can be uploaded
161                     'file_queue_limit' => 10, // how many files can be in the queue at once
162                     'upload_url' => Director::absoluteURL('admin/assets/handleupload'),
163                     'required' => 'false'
164             )
165         );
166         
167         MultiUploadConfig::addStaticPostParams(array(
168             'FolderID' => $this->currentPageID(),
169         ));
170         MultiUploadConfig::addFileTypes(File::$allowed_extensions);
171         
172         if (property_exists('WebylonSiteConfig', 'max_file_upload_size')) {
173             MultiUploadConfig::$file_size_limit = WebylonSiteConfig::$max_file_upload_size;
174         } else {
175             MultiUploadConfig::$file_size_limit = ((int)ini_get('upload_max_filesize')) * 1024 * 1024;
176         }
177         
178         $form = new Form($this,'UploadForm', new FieldSet(
179             new HiddenField("ID", "", $this->currentPageID()),
180             new HiddenField("FolderID", "", $this->currentPageID()),
181             new HiddenField("action_doMultiUpload", "", "1"), 
182             $ff
183         ), new FieldSet(
184         ));
185         
186         $this->extend('updateUploadForm', $form);
187         
188         // Makes ajax easier
189         $form->disableSecurityToken();
190         
191         return $form;
192     }
193     
194     /**
195      * This method processes the results of the UploadForm. !!! NOT USED HERE, BUT USED IN CMSMAIN IN Visual Editor !!!
196      * It will save the uploaded files to /assets/ and create new File objects as required.
197      */
198     function doUpload($data, $form) {
199         $newFiles = array();
200         $fileIDs = array();
201         $fileNames = array();
202         $fileSizeWarnings = '';
203         $uploadErrors = '';
204         $jsErrors = '';
205         $status = '';
206         $statusMessage = '';
207         $processedFiles = array();
208 
209         foreach($data['Files'] as $param => $files) {
210             if(!is_array($files)) $files = array($files);
211             foreach($files as $key => $value) {
212                 $processedFiles[$key][$param] = $value;
213             }
214         }
215         
216         // Load POST data from arrays in to the correct dohickey.
217         $processedData = array();
218         foreach($data as $dataKey => $value) {
219             if ($dataKey == 'Files') continue;
220             if (is_array($value)) {
221                 $i = 0;
222                 foreach($value as $fileId => $dataValue) {
223                     if (!isset($processedData[$i])) $processedData[$i] = array();
224                     $processedData[$i][$dataKey] = $dataValue;
225                     $i++;
226                 }
227             }
228         }
229         $processedData = array_reverse($processedData);
230                 
231         if($data['FolderID'] && $data['FolderID'] != '') $folder = DataObject::get_by_id("Folder", $data['FolderID']);
232         else $folder = singleton('Folder');
233 
234         foreach($processedFiles as $filePostId => $tmpFile) {
235             if($tmpFile['error'] == UPLOAD_ERR_NO_TMP_DIR) {
236                 $status = 'bad';
237                 $statusMessage = _t('AssetAdmin.NOTEMP', 'There is no temporary folder for uploads. Please set upload_tmp_dir in php.ini.');
238                 break;
239             }
240         
241             if($tmpFile['tmp_name']) {
242                 // Workaround open_basedir problems
243                 if(ini_get("open_basedir")) {
244                     $newtmp = TEMP_FOLDER . '/' . $tmpFile['name'];
245                     move_uploaded_file($tmpFile['tmp_name'], $newtmp);
246                     $tmpFile['tmp_name'] = $newtmp;
247                 }
248                 
249                 // validate files (only if not logged in as admin)
250                 if(!File::$apply_restrictions_to_admin && (Permission::check('ADMIN') || Permission::check('CMS_ACCESS_AssetAdmin'))) {
251                     $valid = true;
252                 } else {
253                     
254                     // Set up the validator instance with rules
255                     $validator = new Upload_Validator();
256                     $validator->setAllowedExtensions(File::$allowed_extensions);
257                     $validator->setAllowedMaxFileSize(self::$allowed_max_file_size);
258                     
259                     // Do the upload validation with the rules
260                     $upload = new Upload();
261                     $upload->setValidator($validator);
262                     $valid = $upload->validate($tmpFile);
263                     if(!$valid) {
264                         $errors = $upload->getErrors();
265                         if($errors) foreach($errors as $error) {
266                             $jsErrors .= "alert('" . Convert::raw2js($error) . "');";
267                         }
268                     }
269                 }
270                 
271                 // move file to given folder
272                 if($valid && $folder) {
273                     $newFile = $folder->addUploadToFolder($tmpFile);
274                     
275                     if(self::$metadata_upload_enabled && isset($processedData[$filePostId])) {
276                         $fileObject = DataObject::get_by_id('File', $newFile);
277                         $metadataForm = new Form($this, 'MetadataForm', $fileObject->uploadMetadataFields(), new FieldSet());
278                         $metadataForm->loadDataFrom($processedData[$filePostId]);
279                         $metadataForm->saveInto($fileObject);
280                         $fileObject->write();
281                     }
282                     
283                     $newFiles[] = $newFile;
284                 }
285             }
286         }
287         
288         if($newFiles) {
289             $numFiles = sizeof($newFiles);
290             $statusMessage = sprintf(_t('AssetAdmin.UPLOADEDX',"Uploaded %s files"),$numFiles);
291             $status = "good";
292         } else if($status != 'bad') {
293             $statusMessage = _t('AssetAdmin.NOTHINGTOUPLOAD','There was nothing to upload');
294             $status = "";
295         }
296 
297         $fileObj = false;
298         foreach($newFiles as $newFile) {
299             $fileIDs[] = $newFile;
300             $fileObj = DataObject::get_one('File', "\"File\".\"ID\"=$newFile");
301             // notify file object after uploading
302             if (method_exists($fileObj, 'onAfterUpload')) $fileObj->onAfterUpload();
303             $fileNames[] = $fileObj->Name;
304         }
305         
306         // workaround for content editors image upload.Passing an extra hidden field
307         // in the content editors view of 'UploadMode' @see HtmlEditorField
308         // this will be refactored for 2.5
309         if(isset($data['UploadMode']) && $data['UploadMode'] == "CMSEditor" && $fileObj) {
310             // we can use $fileObj considering that the uploader in the cmseditor can only upload
311             // one file at a time. Once refactored to multiple files this is going to have to be changed
312             $width = (is_a($fileObj, 'Image')) ? $fileObj->getWidth() : '100';
313             $height = (is_a($fileObj, 'Image')) ? $fileObj->getHeight() : '100';
314             
315             $values = array(
316                 'Filename' => $fileObj->Filename,
317                 'Width' => $width,
318                 'Height' => $height
319             );
320             
321             return Convert::raw2json($values);
322         }
323         
324         $sFileIDs = implode(',', $fileIDs);
325         $sFileNames = implode(',', $fileNames);
326 
327         echo <<<HTML
328             <script type="text/javascript">
329             /* IDs: $sFileIDs */
330             /* Names: $sFileNames */
331             
332             var form = parent.document.getElementById('Form_EditForm');
333             form.getPageFromServer(form.elements.ID.value);
334             parent.statusMessage("{$statusMessage}","{$status}");
335             $jsErrors
336             parent.document.getElementById('sitetree').getTreeNodeByIdx( "{$folder->ID}" ).getElementsByTagName('a')[0].className += ' contents';
337             </script>
338 HTML;
339     }
340     
341     public function handleupload() {
342         $rs = false;
343         $message = '';
344         if(isset($_FILES['upload_file']) && !empty($_FILES['upload_file'])) {                        
345             $file = new File();
346             if(!isset($_POST['FolderID']) || !($folder = DataObject::get_by_id("Folder",$_POST['FolderID']))) {
347                 $folder = singleton('Folder');
348             }
349             try {
350                 if(!class_exists("Upload")) {
351                     throw new ValidationException(_t("FileDataObjectManager.NoUploadClass", "No Upload class!"), E_USER_WARNING);
352                 }
353                 $u = new Upload();
354                 $u->validator->setAllowedExtensions(File::$allowed_extensions);
355                 $valid = $u->validate($_FILES['upload_file']);
356                 if(!$valid) {
357                     $errors = implode("; ", $u->getErrors());
358                     throw new ValidationException($errors, E_USER_WARNING);
359                 }
360                 $newFile = $folder->addUploadToFolder($_FILES['upload_file']);
361                 $file = DataObject::get_by_id('File', $newFile);
362                 if (!$file) {
363                     $errors = _t("FileDataObjectManager.UploadError", "Upload Error");
364                     throw new ValidationException($errors, E_USER_WARNING);
365                 }
366                 
367                 if(isset($_POST['FolderID']))
368                     $file->setField("ParentID",$folder->ID);
369 
370                 // Provide an "upgrade" to File subclasses
371                 if($file->class == "File") {
372                     $ext = strtolower($file->Extension);
373                     if(in_array($ext, MP3::$allowed_file_types))
374                         $file = $file->newClassInstance("MP3");
375                     else if(in_array($ext, array('jpg','jpeg','gif','png')))
376                         $file = $file->newClassInstance("Image");
377                     else if(in_array($ext, FLV::$allowed_file_types))
378                         $file = $file->newClassInstance("FLV");
379                 }
380                 $file->OwnerID = Member::currentUserID();
381                 $file->write();
382                 $rs = true;
383                 $message = $file->ID;
384             } catch (Exception $e) {
385                 $rs = false;
386                 if (method_exists($e,'getResult') && $e->getResult()) {
387                     $message = $e->getResult()->message();              
388                 } else {
389                     $message = $e->getMessage();
390                 }
391             }
392         }
393         echo json_encode(array('rs' => $rs, 'message' => $message));
394     }
395 
396     /**
397      * This method processes the results of the UploadForm.
398      * It will save the uploaded files to /assets/ and create new File objects as required.
399      */
400     function doMultiUpload($data, $form) {      
401         if(isset($data['uploaded_files']) && !empty($data['uploaded_files'])) {
402             $statusMessage = sprintf(_t('AssetAdmin.UPLOADEDX',"Uploaded %s files"), count($data['uploaded_files']));
403             $status = "good";           
404         } else {
405             $statusMessage = _t('AssetAdmin.NOTHINGTOUPLOAD','There was nothing to upload');
406             $status = "";
407         }
408         
409         $folderID = 0;
410         if (isset($data['FolderID'])) {
411             $folderID = $data['FolderID'];
412         }
413         
414         echo <<<HTML
415             <script type="text/javascript">         
416             
417             var form = parent.document.getElementById('Form_EditForm');
418             form.getPageFromServer(form.elements.ID.value);
419             parent.statusMessage("{$statusMessage}","{$status}");
420             parent.document.getElementById('sitetree').getTreeNodeByIdx( "{$folderID}" ).getElementsByTagName('a')[0].className += ' contents';
421             </script>
422 HTML;
423     }
424     
425 
426     /**
427      * Custom currentPage() method to handle opening the 'root' folder
428      */
429     public function currentPage() {
430         $id = $this->currentPageID();
431         if($id && is_numeric($id)) {
432             return DataObject::get_by_id($this->stat('tree_class'), $id);
433         } else if($id == 'root') {
434             return singleton($this->stat('tree_class'));
435         }
436     }
437     
438     /**
439      * Return the form that displays the details of a folder, including a file list and fields for editing the folder name.
440      */
441     function getEditForm($id) {
442         if($id && $id != "root") {
443             $record = DataObject::get_by_id("File", $id);
444         } else {
445             $record = singleton("Folder");
446         }
447 
448         if($record) {
449             $fields = $record->getCMSFields();
450             $actions = new FieldSet();
451             
452             // Only show save button if not 'assets' folder
453             if($record->canEdit() && $id != 'root') {
454                 $actions = new FieldSet(
455                     new FormAction('save',_t('AssetAdmin.SAVEFOLDERNAME','Save folder name'))
456                 );
457             }
458             
459             $form = new Form($this, "EditForm", $fields, $actions);
460             if($record->ID) {
461                 $form->loadDataFrom($record);
462             } else {
463                 $form->loadDataFrom(array(
464                     "ID" => "root",
465                     "URL" => Director::absoluteBaseURL() . 'assets/',
466                 ));
467             }
468             
469             if(!$record->canEdit()) {
470                 $form->makeReadonly();
471             }
472 
473             $this->extend('updateEditForm', $form);
474 
475             return $form;
476         }
477     }
478     
479     /**
480      * Perform the "move marked" action.
481      * Called and returns in same way as 'save' function
482      */
483     public function movemarked($urlParams, $form) {
484         if($_REQUEST['DestFolderID'] && (is_numeric($_REQUEST['DestFolderID']) || ($_REQUEST['DestFolderID']) == 'root')) {
485             $destFolderID = ($_REQUEST['DestFolderID'] == 'root') ? 0 : $_REQUEST['DestFolderID'];
486             $fileList = "'" . ereg_replace(' *, *',"','",trim(addslashes($_REQUEST['FileIDs']))) . "'";
487             $numFiles = 0;
488     
489             if($fileList != "''") {
490                 $files = DataObject::get("File", "\"File\".\"ID\" IN ($fileList)");
491                 if($files) {
492                     foreach($files as $file) {
493                         if($file instanceof Image) {
494                             $file->deleteFormattedImages();
495                         }
496                         $file->ParentID = $destFolderID;
497                         $file->write();
498                         $numFiles++;
499                     }
500                 } else {
501                     user_error("No files in $fileList could be found!", E_USER_ERROR);
502                 }
503             }
504 
505             $message = sprintf(_t('AssetAdmin.MOVEDX','Moved %s files'),$numFiles);
506             
507             FormResponse::status_message($message, "good");
508             FormResponse::add("$('Form_EditForm_Files').refresh();");
509 
510             return FormResponse::respond();
511         }
512     }
513 
514     /**
515      * Perform the "delete marked" action.
516      * Called and returns in same way as 'save' function
517      */
518     public function deletemarked($urlParams, $form) {
519         $fileList = "'" . ereg_replace(' *, *',"','",trim(addslashes($_REQUEST['FileIDs']))) . "'";
520         $numFiles = 0;
521         $folderID = 0;
522         $deleteList = '';
523         $brokenPageList = '';
524 
525         if($fileList != "''") {
526             $files = DataObject::get("File", "\"File\".\"ID\" IN ($fileList)");
527             if($files) {
528                 foreach($files as $file) {
529                     if($file instanceof Image) {
530                         $file->deleteFormattedImages();
531                     }
532                     if(!$folderID) {
533                         $folderID = $file->ParentID;
534                     }
535                     $file->delete();
536                     $numFiles++;
537                 }
538                 if($brokenPages = Notifications::getItems('BrokenLink')) {
539                     $brokenPageList = "  ". _t('AssetAdmin.NOWBROKEN', 'These pages now have broken links:') . '</ul>';
540                     foreach($brokenPages as $brokenPage) {
541                         $brokenPageList .= "<li style=&quot;font-size: 65%&quot;>" . $brokenPage->Breadcrumbs(3, true) . '</li>';
542                     }
543                     $brokenPageList .= '</ul>';
544                     Notifications::notifyByEmail("BrokenLink", "Page_BrokenLinkEmail");
545                 } else {
546                     $brokenPageList = '';
547                 }
548                 
549                 $deleteList = '';
550                 if($folderID) {
551                     $remaining = DB::query("SELECT COUNT(*) FROM \"File\" WHERE \"ParentID\" = $folderID")->value();
552                     if(!$remaining) $deleteList .= "Element.removeClassName(\$('sitetree').getTreeNodeByIdx('$folderID').getElementsByTagName('a')[0],'contents');";
553                 }
554             } else {
555                 user_error("No files in $fileList could be found!", E_USER_ERROR);
556             }
557         }
558         
559         $message = sprintf(_t('AssetAdmin.DELETEDX',"Deleted %s files.%s"),$numFiles,$brokenPageList) ;
560         
561         FormResponse::add($deleteList);
562         FormResponse::status_message($message, "good");
563         FormResponse::add("$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value)");
564         
565         return FormResponse::respond(); 
566     }
567     
568     
569     /**
570      * Returns the content to be placed in Form_SubForm when editing a file.
571      * Called using ajax.
572      */
573     public function getfile() {
574         SSViewer::setOption('rewriteHashlinks', false);
575 
576         // bdc: only try to return something if user clicked on an object
577         if (is_object($this->getSubForm($this->urlParams['ID']))) {
578             return $this->getSubForm($this->urlParams['ID'])->formHtmlContent();
579         }
580         else return null;
581     }
582     
583     /**
584      * Action handler for the save button on the file subform.
585      * Saves the file
586      */
587     public function savefile($data, $form) {
588         $record = DataObject::get_by_id("File", $data['ID']);
589         $form->saveInto($record);
590         $record->write();
591         $title = Convert::raw2js($record->Title);
592         $name = Convert::raw2js($record->Name);
593         $saved = sprintf(_t('AssetAdmin.SAVEDFILE','Saved file %s'),"#$data[ID]");
594         echo <<<JS
595             statusMessage('$saved');
596             $('record-$data[ID]').getElementsByTagName('td')[1].innerHTML = "$title";
597             $('record-$data[ID]').getElementsByTagName('td')[2].innerHTML = "$name";
598 JS;
599     }
600     
601     public function sync() {
602         echo Filesystem::sync();
603     }
604     
605     /**
606      * Return the entire site tree as a nested UL.
607      * @return string HTML for site tree
608      */
609     public function SiteTreeAsUL() {
610         $obj = singleton('Folder');
611         $obj->setMarkingFilter('ClassName', ClassInfo::subclassesFor('Folder'));
612         $obj->markPartialTree(30, null, "ChildFolders");
613 
614         if($p = $this->currentPage()) $obj->markToExpose($p);
615 
616         // getChildrenAsUL is a flexible and complex way of traversing the tree
617         $siteTreeList = $obj->getChildrenAsUL(
618             '',
619             '"<li id=\"record-$child->ID\" class=\"$child->class" . $child->markingClasses() .  ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
620             '"<a href=\"" . Controller::join_links(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" class=\"" . ($child->hasChildFolders() ? " contents" : "") . "\" >" . $child->TreeTitle() . "</a>" ',
621             $this,
622             true,
623             "ChildFolders"
624         );  
625 
626         // Wrap the root if needs be
627         $rootLink = $this->Link() . 'show/root';
628         $baseUrl = Director::absoluteBaseURL() . "assets";
629         if(!isset($rootID)) {
630             $siteTree = "<ul id=\"sitetree\" class=\"tree unformatted\"><li id=\"record-root\" class=\"Root\"><a href=\"$rootLink\"><strong>{$baseUrl}</strong></a>"
631             . $siteTreeList . "</li></ul>";
632         }
633 
634         return $siteTree;
635     }
636 
637     /**
638      * Returns a subtree of items underneat the given folder.
639      */
640     public function getsubtree() {
641         $obj = DataObject::get_by_id('Folder', $_REQUEST['ID']);
642         $obj->setMarkingFilter('ClassName', ClassInfo::subclassesFor('Folder'));
643         $obj->markPartialTree();
644 
645         $results = $obj->getChildrenAsUL(
646             '',
647             '"<li id=\"record-$child->ID\" class=\"$child->class" . $child->markingClasses() .  ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
648             '"<a href=\"" . Controller::join_links(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" >" . $child->TreeTitle() . "</a>" ',
649             $this,
650             true
651         );
652 
653         return substr(trim($results), 4, -5);
654     }
655     
656 
657     //------------------------------------------------------------------------------------------//
658 
659     // Data saving handlers
660 
661     /**
662      * Add a new folder and return its details suitable for ajax.
663      */
664     public function addfolder() {
665         $parent = ($_REQUEST['ParentID'] && is_numeric($_REQUEST['ParentID'])) ? (int)$_REQUEST['ParentID'] : 0;
666         $name = (isset($_REQUEST['Name'])) ? basename($_REQUEST['Name']) : _t('AssetAdmin.NEWFOLDER',"NewFolder");
667         
668         if($parent) {
669             $parentObj = DataObject::get_by_id('File', $parent);
670             if(!$parentObj || !$parentObj->ID) $parent = 0;
671         }
672         
673         // Get the folder to be created     
674         if(isset($parentObj->ID)) $filename = $parentObj->FullPath . $name;
675         else $filename = ASSETS_PATH . '/' . $name;
676 
677         // Actually create
678         if(!file_exists(ASSETS_PATH)) {
679             mkdir(ASSETS_PATH);
680         }
681         
682         $p = new Folder();
683         $p->ParentID = $parent;
684         $p->Name = $p->Title = basename($filename);
685         
686         // Ensure uniqueness        
687         $i = 2;
688         $baseFilename = substr($p->Filename, 0, -1) . '-';
689         while(file_exists($p->FullPath)) {
690             $p->Filename = $baseFilename . $i . '/';
691             $i++;
692         }
693         
694         $p->write();
695         
696         mkdir($p->FullPath);
697         chmod($p->FullPath, Filesystem::$file_create_mask);
698         
699         if(isset($_REQUEST['returnID'])) {
700             return $p->ID;
701         } else {
702             return $this->returnItemToUser($p);
703         }
704         
705     }
706     
707     /**
708      * @return Form
709      */
710     function DeleteItemsForm() {
711         $form = new Form(
712             $this,
713             'DeleteItemsForm',
714             new FieldSet(
715                 new LiteralField('SelectedPagesNote',
716                     sprintf('<p>%s</p>', _t('AssetAdmin_left.ss.SELECTTODEL','Select the folders that you want to delete and then click the button below'))
717                 ),
718                 new HiddenField('csvIDs')
719             ),
720             new FieldSet(
721                 new FormAction('deletefolder', _t('AssetAdmin_left.ss.DELFOLDERS','Delete the selected folders'))
722             )
723         );
724         $form->addExtraClass('actionparams');
725         
726         return $form;
727     }
728     
729     /**
730      * Delete a folder
731      */
732     public function deletefolder() {
733         $ids = split(' *, *', $_REQUEST['csvIDs']);
734         
735         if(!$ids) return false;
736         $script = '';
737         
738         foreach($ids as $id) {
739             if(is_numeric($id)) {
740                 $record = DataObject::get_by_id($this->stat('tree_class'), $id);
741                 if($record) {
742                     $script .= $this->deleteTreeNodeJS($record);
743                     $record->delete();
744                     $record->destroy();
745                 }
746             }
747         }
748         
749         $size = sizeof($ids);
750         if($size > 1) {
751           $message = $size.' '._t('AssetAdmin.FOLDERSDELETED', 'folders deleted.');
752         } else {
753           $message = $size.' '._t('AssetAdmin.FOLDERDELETED', 'folder deleted.');
754         }
755         
756         $script .= "statusMessage('$message');";
757 
758         return $script;
759     }
760     
761     public function removefile(){
762         if($fileID = $this->urlParams['ID']) {
763             $file = DataObject::get_by_id('File', $fileID);
764             // Delete the temp verions of this file in assets/_resampled
765             if($file instanceof Image) {
766                 $file->deleteFormattedImages();
767             }
768             $file->delete();
769             //$file->destroy();
770 
771             if(Director::is_ajax()) {
772                 echo <<<JS
773                 $('Form_EditForm_Files').removeFile($fileID);
774                 statusMessage('removed file', 'good');
775 JS;
776             } else {
777                 Director::redirectBack();
778             }
779         } else {
780             user_error("AssetAdmin::removefile: Bad parameters: File=$fileID", E_USER_ERROR);
781         }
782     }
783     
784     public function save($urlParams, $form) {
785         // Don't save the root folder - there's no database record
786         if($_REQUEST['ID'] == 'root') {
787             FormResponse::status_message('Saved', 'good');
788             return FormResponse::respond();
789         }
790         
791         $form->dataFieldByName('Name')->Value = $form->dataFieldByName('Title')->Value();
792         
793         return parent::save($urlParams, $form);
794     }
795     
796     /**
797      * #################################
798      *        Garbage collection.
799      * #################################
800     */
801     
802     /**
803      * Removes all unused thumbnails from the file store
804      * and returns the status of the process to the user.
805      */
806     public function deleteunusedthumbnails() {
807         $count = 0;
808         $thumbnails = $this->getUnusedThumbnails();
809         
810         if($thumbnails) {
811             foreach($thumbnails as $thumbnail) {
812                 unlink(ASSETS_PATH . "/" . $thumbnail);
813                 $count++;
814             }
815         }
816         
817         $message = sprintf(_t('AssetAdmin.THUMBSDELETED', '%s unused thumbnails have been deleted'), $count);
818         FormResponse::status_message($message, 'good');
819         echo FormResponse::respond();
820     }
821     
822     /**
823      * Creates array containg all unused thumbnails.
824      * 
825      * Array is created in three steps:
826      *     1. Scan assets folder and retrieve all thumbnails
827      *     2. Scan all HTMLField in system and retrieve thumbnails from them.
828      *     3. Count difference between two sets (array_diff)
829      *
830      * @return array 
831      */
832     private function getUnusedThumbnails() {
833         $allThumbnails = array();
834         $usedThumbnails = array();
835         $dirIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(ASSETS_PATH));
836         $classes = ClassInfo::subclassesFor('SiteTree');
837         
838         if($dirIterator) {
839             foreach($dirIterator as $file) {
840                 if($file->isFile()) {
841                     if(strpos($file->getPathname(), '_resampled') !== false) {
842                         $pathInfo = pathinfo($file->getPathname());
843                         if(in_array(strtolower($pathInfo['extension']), array('jpeg', 'jpg', 'jpe', 'png', 'gif'))) {
844                             $path = str_replace('\\','/', $file->getPathname());
845                             $allThumbnails[] = substr($path, strpos($path, '/assets/') + 8);
846                         }
847                     }
848                 }
849             }
850         }
851         
852         if($classes) {
853             foreach($classes as $className) {
854                 $SNG_class = singleton($className);
855                 $objects = DataObject::get($className);
856                 
857                 if($objects !== NULL) {
858                     foreach($objects as $object) {
859                         foreach($SNG_class->db() as $fieldName => $fieldType) {
860                             if($fieldType == 'HTMLText') {
861                                 $url1 = HTTP::findByTagAndAttribute($object->$fieldName,array('img' => 'src'));
862                                 
863                                 if($url1 != NULL) {
864                                     $usedThumbnails[] = substr($url1[0], strpos($url1[0], '/assets/') + 8);
865                                 }
866                                 
867                                 if($object->latestPublished > 0) {
868                                     $object = Versioned::get_latest_version($className, $object->ID);
869                                     $url2 = HTTP::findByTagAndAttribute($object->$fieldName, array('img' => 'src'));
870                                     
871                                     if($url2 != NULL) {
872                                         $usedThumbnails[] = substr($url2[0], strpos($url2[0], '/assets/') + 8);
873                                     }
874                                 }
875                             }
876                         }
877                     }
878                 }
879             }
880         }
881         
882         return array_diff($allThumbnails, $usedThumbnails);
883     }
884     
885 }
886 ?>
887 
[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. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0