MINOR Documentation in File and Folder class (from r107265)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@112553 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2010-10-15 03:12:39 +00:00
parent ad20ddf24b
commit 2d127753ed
4 changed files with 171 additions and 30 deletions

View File

@ -73,6 +73,8 @@ class Image extends File {
/**
* An image exists if it has a filename.
* Does not do any filesystem checks.
*
* @return boolean
*/
public function exists() {
@ -82,7 +84,9 @@ class Image extends File {
}
/**
* Return an XHTML img tag for this Image.
* Return an XHTML img tag for this Image,
* or NULL if the image file doesn't exist on the filesystem.
*
* @return string
*/
function getTag() {
@ -100,6 +104,7 @@ class Image extends File {
/**
* Return an XHTML img tag for this Image.
*
* @return string
*/
function forTemplate() {

View File

@ -1,14 +1,63 @@
<?php
/**
* This class handles the representation of a File within Sapphire
* This class handles the representation of a file on the filesystem within the framework.
* Most of the methods also handle the {@link Folder} subclass.
*
* Note: The files are stored in the assets/ directory, but sapphire
* looks at the db object to gather information about a file such as URL
* It then uses this for all processing functions (like image manipulation).
*
* <b>Security</b>
*
* Caution: It is recommended to disable any script execution in the "assets/"
* directory in the webserver configuration, to reduce the risk of exploits.
* See http://doc.silverstripe.org/secure-development#filesystem
*
* <b>Properties</b>
*
* - "Name": File name (including extension) or folder name.
* Should be the same as the actual filesystem.
* - "Title": Optional title of the file (for display purposes only).
* Defaults to "Name".
* - "Filename": Path of the file or folder, relative to the webroot.
* Usually starts with the "assets/" directory, and has no trailing slash.
* Defaults to the "assets/" directory plus "Name" property if not set.
* Setting the "Filename" property will override the "Name" property.
* The value should be in sync with "ParentID".
* - "Content": Typically unused, but handy for a textual representation of
* files, e.g. for fulltext indexing of PDF documents.
* - "ParentID": Points to a {@link Folder} record. Should be in sync with
* "Filename". A ParentID=0 value points to the "assets/" folder, not the webroot.
*
* <b>Synchronization</b>
*
* Changes to a File database record can change the filesystem entry,
* but not the other way around. If the filesystem path is renamed outside
* of SilverStripe, there's no way for the database to recover this linkage.
* New physical files on the filesystem can be "discovered" via {@link Filesystem::sync()},
* the equivalent {@link File} and {@link Folder} records are automatically
* created by this method.
*
* Certain property changes within the File API that can cause a "delayed" filesystem change:
* The change is enforced in {@link onBeforeWrite()} later on.
* - setParentID()
* - setFilename()
* - setName()
* It is recommended that you use {@link write()} directly after setting any of these properties,
* otherwise getters like {@link getFullPath()} and {@link getRelativePath()}
* will result paths that are inconsistent with the filesystem.
*
* Caution: Calling {@link delete()} will also delete from the filesystem.
* Call {@link deleteDatabaseOnly()} if you want to avoid this.
*
* <b>Creating Files and Folders</b>
*
* Typically both files and folders should be created first on the filesystem,
* and then reflected in as database records. Folders can be created recursively
* from sapphire both in the database and filesystem through {@link Folder::findOrMake()}.
* Ensure that you always set a "Filename" property when writing to the database,
* leaving it out can lead to unexpected results.
*
* @package sapphire
* @subpackage filesystem
*/
@ -79,16 +128,18 @@ class File extends DataObject {
/**
* Find a File object by the given filename.
*
* @param String $filename Matched against the "Name" property.
* @return mixed null if not found, File object of found file
*/
static function find($filename) {
// Get the base file if $filename points to a resampled file
$filename = ereg_replace('_resampled/[^-]+-','',$filename);
// Split to folders and the actual filename, and traverse the structure.
$parts = explode("/", $filename);
$parentID = 0;
$item = null;
foreach($parts as $part) {
if($part == ASSETS_DIR && !$parentID) continue;
$SQL_part = Convert::raw2sql($part);
@ -112,7 +163,11 @@ class File extends DataObject {
return $this->Title;
}
// Used by AssetTableField
/**
* @todo Unnecessary shortcut for AssetTableField, coupled with cms module.
*
* @return Integer
*/
function BackLinkTrackingCount() {
return $this->BackLinkTracking()->Count();
}
@ -120,7 +175,7 @@ class File extends DataObject {
/**
* Event handler called before deleting from the database.
* You can overload this to clean up or otherwise process data before delete this
* record. Don't forget to call parent::onBeforeDelete(), though!
* record. Don't forget to call {@link parent::onBeforeDelete()}, though!
*/
protected function onBeforeDelete() {
parent::onBeforeDelete();
@ -131,6 +186,9 @@ class File extends DataObject {
}
}
/**
* Updates link tracking.
*/
protected function onAfterDelete() {
parent::onAfterDelete();
@ -204,6 +262,14 @@ class File extends DataObject {
return $this->canEdit($member);
}
/**
* Returns a category based on the file extension.
* This can be useful when grouping files by type,
* showing icons on filelinks, etc.
* Possible group values are: "audio", "mov", "zip", "image".
*
* @return String
*/
public function appCategory() {
$ext = $this->Extension;
switch($ext) {
@ -232,7 +298,11 @@ class File extends DataObject {
}
/**
* Return the URL of an icon for the file type
* Return the relative URL of an icon for the file type,
* based on the {@link appCategory()} value.
* Images are searched for in "sapphire/images/app_icons/".
*
* @return String
*/
function Icon() {
$ext = $this->Extension;
@ -269,6 +339,7 @@ class File extends DataObject {
protected function onBeforeWrite() {
parent::onBeforeWrite();
// Set default name
if(!$this->Name) $this->Name = "new-" . strtolower($this->class);
}
@ -290,19 +361,25 @@ class File extends DataObject {
}
/**
* Setter function for Name.
* Automatically sets a default title.
* Setter function for Name. Automatically sets a default title,
* and removes characters that migh be invalid on the filesystem.
* Also adds a suffix to the name if the filename already exists
* on the filesystem, and is associated to a different {@link File} database record
* in the same folder. This means "myfile.jpg" might become "myfile-1.jpg".
*
* @param String $name
*/
function setName($name) {
$oldName = $this->Name;
// It can't be blank
// It can't be blank, default to Title
if(!$name) $name = $this->Title;
// Fix illegal characters
$name = ereg_replace(' +','-',trim($name));
$name = ereg_replace('[^A-Za-z0-9.+_\-]','',$name);
$name = ereg_replace(' +','-',trim($name)); // Replace any spaces
$name = ereg_replace('[^A-Za-z0-9.+_\-]','',$name); // Replace non alphanumeric characters
// Remove all leading dots or underscores
while(!empty($name) && ($name[0] == '_' || $name[0] == '.')) {
$name = substr($name, 1);
}
@ -326,27 +403,36 @@ class File extends DataObject {
}
}
// Update title
if(!$this->getField('Title')) $this->__set('Title', str_replace(array('-','_'),' ',ereg_replace('\.[^.]+$','',$name)));
// Update actual field value
$this->setField('Name', $name);
if($oldName && $oldName != $this->Name) {
$this->resetFilename();
} else {
$this->autosetFilename();
}
return $this->getField('Name');
}
/**
* Change a filename, moving the file if appropriate.
* @param $renamePhysicalFile Set this to false if you don't want to rename the physical file. Used when calling resetFilename() on the children of a folder.
* Change the "Filename" property based on the current "Name" property, moving the file if appropriate.
* Throws an Exception if the new file already exists.
*
* Caution: This method should just be called during a {@link write()} invocation,
* otherwise the database and filesystem might become out of sync.
*
* @param Boolean $renamePhysicalFile FALSE to avoiding renaming the file on the filesystem.
* Used when calling {@link resetFilename()} on the children of a folder.
*/
protected function resetFilename($renamePhysicalFile = true) {
$oldFilename = $this->getField('Filename');
$newFilename = $this->getRelativePath();
$oldFilename = $this->getField('Filename'); // call without getter to get old value
$newFilename = $this->getRelativePath(); // calculated from $this->Name
if($this->Name && $this->Filename && file_exists(Director::getAbsFile($oldFilename)) && strpos($oldFilename, '//') === false) {
if($renamePhysicalFile) {
@ -383,7 +469,12 @@ class File extends DataObject {
}
/**
* Rewrite links to the $old file to now point to the $new file
* Rewrite links to the $old file to now point to the $new file.
*
* @uses SiteTree->rewriteFileURL()
*
* @param String $old File path relative to the webroot
* @param String $new File path relative to the webroot
*/
protected function updateLinks($old, $new) {
if(class_exists('Subsite')) Subsite::disable_subsite_filter(true);
@ -434,6 +525,12 @@ class File extends DataObject {
return "$this->Name";
}
/**
* Returns an absolute filesystem path to the file.
* Use {@link getRelativePath()} to get the same path relative to the webroot.
*
* @return String
*/
function getFullPath() {
$baseFolder = Director::baseFolder();
@ -447,7 +544,10 @@ class File extends DataObject {
}
/**
* Returns
* Returns path relative to webroot.
* If no {@link Folder} is set ("ParentID" property),
* defaults to a filename relative to the ASSETS_DIR (usually "assets/").
* Use {@link getFullPath()} to
*
* @return String
*/
@ -463,6 +563,9 @@ class File extends DataObject {
}
}
/**
* @todo Coupling with cms module, remove this method.
*/
function DeleteLink() {
return Director::absoluteBaseURL()."admin/assets/removefile/".$this->ID;
}
@ -477,13 +580,20 @@ class File extends DataObject {
function setFilename($val) {
$this->setField('Filename', $val);
// "Filename" is the "master record" (existing on the filesystem),
// meaning we have to adjust the "Name" property in the database as well.
$this->setField('Name', basename($val));
}
/*
* FIXME This overrides getExtension() in DataObject, but it does something completely different.
/**
* Returns the file extension
*
* @todo This overrides getExtension() in DataObject, but it does something completely different.
* This should be renamed to getFileExtension(), but has not been yet as it may break
* legacy code.
*
* @return String
*/
function getExtension() {
return self::get_file_extension($this->getField('Filename'));

View File

@ -1,6 +1,7 @@
<?php
/**
* A collection of static methods for manipulating the filesystem.
*
* @package sapphire
* @subpackage filesystem
*/
@ -13,7 +14,12 @@ class Filesystem extends Object {
protected static $cache_folderModTime;
/**
* Create a folder, recursively
* Create a folder on the filesystem, recursively.
* Uses {@link Filesystem::$folder_create_mask} to set filesystem permissions.
* Use {@link Folder::findOrMake()} to create a {@link Folder} database
* record automatically.
*
* @param String $folder Absolute folder path
*/
static function makeFolder($folder) {
if(!file_exists($base = dirname($folder))) self::makeFolder($base);
@ -21,8 +27,10 @@ class Filesystem extends Object {
}
/**
* Remove a directory and all subdirectories and files
* @param $contentsOnly If this is true then the contents of the folder will be removed but not the folder itself
* Remove a directory and all subdirectories and files.
*
* @param String $folder Absolute folder path
* @param Boolean $contentsOnly If this is true then the contents of the folder will be removed but not the folder itself
*/
static function removeFolder( $folder, $contentsOnly = false ) {
@ -58,10 +66,12 @@ class Filesystem extends Object {
echo "<p>Done!";
}
/*
/**
* Return the most recent modification time of anything in the folder.
*
* @param $folder The folder, relative to the site root
* @param $extensionList An option array of file extensions to limit the search to
* @return String Same as filemtime() format.
*/
static function folderModTime($folder, $extensionList = null, $recursiveCall = false) {
//$cacheID = $folder . ',' . implode(',', $extensionList);
@ -93,7 +103,10 @@ class Filesystem extends Object {
/**
* Returns true if the given filename is an absolute file reference.
* Works on Linux and Windows
* Works on Linux and Windows.
*
* @param String $filename Absolute or relative filename, with or without path.
* @return Boolean
*/
static function isAbsolute($filename) {
if($_ENV['OS'] == "Windows_NT" || $_SERVER['WINDIR']) return $filename[1] == ':' && $filename[2] == '/';
@ -107,6 +120,9 @@ class Filesystem extends Object {
* If the given Folder ID isn't found, or not specified at all, then everything will
* be synchronised from the root folder (singleton Folder).
*
* See {@link File->updateFilesystem()} to sync properties of a single database record
* back to the equivalent filesystem record.
*
* @param int $folderID Folder ID to sync along with all it's children
*/
static function sync($folderID = null) {

View File

@ -1,6 +1,14 @@
<?php
/**
* Represents a folder in the assets/ directory.
* The folder path is stored in the "Filename" property.
*
* Updating the "Name" or "Filename" properties on
* a folder object also updates all associated children
* (both {@link File} and {@link Folder} records).
*
* See {@link File} documentation for more details about the
* relationship between the database and filesystem in the sapphire file APIs.
*
* @package sapphire
* @subpackage filesystem
@ -45,10 +53,12 @@ class Folder extends File {
parent::onBeforeWrite();
}
/*
* Find the given folder or create it, recursively.
/**
* Find the given folder or create it both as {@link Folder} database records
* and on the filesystem. If necessary, creates parent folders as well.
*
* @param $folderPath string Absolute or relative path to the file
* @return Folder
*/
static function findOrMake($folderPath) {
// Create assets directory, if it is missing