2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
2016-06-15 06:03:16 +02:00
|
|
|
|
|
|
|
use SilverStripe\ORM\Versioning\Versioned;
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
2015-09-15 04:52:02 +02:00
|
|
|
* Represents a logical folder, which may be used to organise assets
|
|
|
|
* stored in the configured backend.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2015-09-15 04:52:02 +02:00
|
|
|
* Unlike {@see File} dataobjects, there is not necessarily a physical filesystem entite which
|
|
|
|
* represents a Folder, and it may be purely logical. However, a physical folder may exist
|
|
|
|
* if the backend creates one.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2015-09-15 04:52:02 +02:00
|
|
|
* Additionally, folders do not have URLs (relative or absolute), nor do they have paths.
|
|
|
|
*
|
|
|
|
* When a folder is moved or renamed, records within it will automatically be copied to the updated
|
|
|
|
* location.
|
|
|
|
*
|
|
|
|
* Deleting a folder will remove all child records, but not any physical files.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2010-10-15 05:12:39 +02:00
|
|
|
* See {@link File} documentation for more details about the
|
2012-03-24 04:38:57 +01:00
|
|
|
* relationship between the database and filesystem in the SilverStripe file APIs.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2012-04-12 08:02:46 +02:00
|
|
|
* @package framework
|
2008-02-25 03:10:37 +01:00
|
|
|
* @subpackage filesystem
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
class Folder extends File {
|
2009-11-21 03:32:40 +01:00
|
|
|
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $singular_name = "Folder";
|
2009-11-21 03:32:40 +01:00
|
|
|
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $plural_name = "Folders";
|
2010-10-13 03:01:12 +02:00
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
public function exists() {
|
|
|
|
return $this->isInDB();
|
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2011-12-06 01:56:24 +01:00
|
|
|
/**
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2011-12-06 01:56:24 +01:00
|
|
|
*/
|
|
|
|
public function populateDefaults() {
|
2011-03-15 10:30:31 +01:00
|
|
|
parent::populateDefaults();
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
if(!$this->Name) {
|
|
|
|
$this->Name = _t('AssetAdmin.NEWFOLDER', "NewFolder");
|
|
|
|
}
|
2011-03-15 10:30:31 +01:00
|
|
|
}
|
2012-11-16 02:19:19 +01:00
|
|
|
|
2010-10-15 05:12:39 +02:00
|
|
|
/**
|
2015-09-15 04:52:02 +02:00
|
|
|
* Find the given folder or create it as a database record
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2015-09-15 04:52:02 +02:00
|
|
|
* @param string $folderPath Directory path relative to assets root
|
2014-03-11 02:26:08 +01:00
|
|
|
* @return Folder|null
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2011-12-06 01:56:24 +01:00
|
|
|
public static function find_or_make($folderPath) {
|
2008-03-17 23:51:25 +01:00
|
|
|
// replace leading and trailing slashes
|
2015-09-15 04:52:02 +02:00
|
|
|
$folderPath = preg_replace('/^\/?(.*)\/?$/', '$1', trim($folderPath));
|
2008-03-17 23:51:25 +01:00
|
|
|
$parts = explode("/",$folderPath);
|
2010-10-13 01:02:10 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
$parentID = 0;
|
2010-10-15 05:21:41 +02:00
|
|
|
$item = null;
|
2014-02-20 02:03:40 +01:00
|
|
|
$filter = FileNameFilter::create();
|
2007-07-19 12:40:28 +02:00
|
|
|
foreach($parts as $part) {
|
2015-09-15 04:52:02 +02:00
|
|
|
if(!$part) {
|
|
|
|
continue; // happens for paths with a trailing slash
|
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2014-02-20 02:03:40 +01:00
|
|
|
// Ensure search includes folders with illegal characters removed, but
|
|
|
|
// err in favour of matching existing folders if $folderPath
|
|
|
|
// includes illegal characters itself.
|
|
|
|
$partSafe = $filter->filter($part);
|
|
|
|
$item = Folder::get()->filter(array(
|
|
|
|
'ParentID' => $parentID,
|
|
|
|
'Name' => array($partSafe, $part)
|
|
|
|
))->first();
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
if(!$item) {
|
|
|
|
$item = new Folder();
|
|
|
|
$item->ParentID = $parentID;
|
2014-02-20 02:03:40 +01:00
|
|
|
$item->Name = $partSafe;
|
2008-11-10 04:51:35 +01:00
|
|
|
$item->Title = $part;
|
2007-07-19 12:40:28 +02:00
|
|
|
$item->write();
|
2010-04-13 01:45:53 +02:00
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
$parentID = $item->ID;
|
|
|
|
}
|
2010-10-15 05:21:41 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
return $item;
|
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function onBeforeDelete() {
|
2015-09-15 04:52:02 +02:00
|
|
|
foreach($this->AllChildren() as $child) {
|
|
|
|
$child->delete();
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
parent::onBeforeDelete();
|
|
|
|
}
|
2011-03-23 01:23:43 +01:00
|
|
|
|
2016-03-15 19:12:38 +01:00
|
|
|
/**
|
2016-04-29 07:50:55 +02:00
|
|
|
* Return the relative URL of an icon for this file type
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getIcon() {
|
|
|
|
return FRAMEWORK_DIR . "/client/dist/images/app_icons/folder_32.png";
|
|
|
|
}
|
2016-03-15 19:12:38 +01:00
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
/**
|
|
|
|
* Override setting the Title of Folders to that Name and Title are always in sync.
|
2011-03-23 01:23:43 +01:00
|
|
|
* Note that this is not appropriate for files, because someone might want to create a human-readable name
|
2015-09-15 04:52:02 +02:00
|
|
|
* of a file that is different from its name on disk. But folders should always match their name on disk.
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
2015-09-15 04:52:02 +02:00
|
|
|
* @param string $title
|
|
|
|
* @return $this
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function setTitle($title) {
|
2014-05-02 04:41:10 +02:00
|
|
|
$this->setName($title);
|
2015-09-15 04:52:02 +02:00
|
|
|
return $this;
|
2014-05-02 04:41:10 +02:00
|
|
|
}
|
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
/**
|
|
|
|
* Get the folder title
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2014-05-02 04:41:10 +02:00
|
|
|
public function getTitle() {
|
|
|
|
return $this->Name;
|
2011-03-23 01:23:43 +01:00
|
|
|
}
|
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
/**
|
|
|
|
* Override setting the Title of Folders to that Name and Title are always in sync.
|
|
|
|
* Note that this is not appropriate for files, because someone might want to create a human-readable name
|
|
|
|
* of a file that is different from its name on disk. But folders should always match their name on disk.
|
|
|
|
*
|
|
|
|
* @param string $name
|
|
|
|
* @return $this
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function setName($name) {
|
2011-03-23 01:23:43 +01:00
|
|
|
parent::setName($name);
|
2014-05-02 04:41:10 +02:00
|
|
|
$this->setField('Title', $this->Name);
|
2015-09-15 04:52:02 +02:00
|
|
|
return $this;
|
2011-03-23 01:23:43 +01:00
|
|
|
}
|
2012-02-15 19:33:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A folder doesn't have a (meaningful) file size.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
2015-09-15 04:52:02 +02:00
|
|
|
* @return null
|
2012-02-15 19:33:14 +01:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getSize() {
|
2012-02-15 19:33:14 +01:00
|
|
|
return null;
|
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns all children of this folder
|
|
|
|
*
|
|
|
|
* @return DataList
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
public function myChildren() {
|
2013-06-21 00:32:08 +02:00
|
|
|
return File::get()->filter("ParentID", $this->ID);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
|
|
|
* Returns true if this folder has children
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
|
|
|
* @return bool
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
public function hasChildren() {
|
2013-06-21 00:32:08 +02:00
|
|
|
return $this->myChildren()->exists();
|
2009-07-02 00:27:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if this folder has children
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
|
|
|
* @return bool
|
2009-07-02 00:27:18 +02:00
|
|
|
*/
|
|
|
|
public function hasChildFolders() {
|
2013-06-21 00:32:08 +02:00
|
|
|
return $this->ChildFolders()->exists();
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
2011-10-28 03:37:27 +02:00
|
|
|
* Return the FieldList used to edit this folder in the CMS.
|
|
|
|
* You can modify this FieldList by subclassing folder, or by creating a {@link DataExtension}
|
2011-05-11 09:51:54 +02:00
|
|
|
* and implemeting updateCMSFields(FieldList $fields) on that extension.
|
2015-09-15 04:52:02 +02:00
|
|
|
*
|
|
|
|
* @return FieldList
|
2008-02-25 03:10:37 +01:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getCMSFields() {
|
2016-08-31 12:50:43 +02:00
|
|
|
// Don't show readonly path until we can implement parent folder selection,
|
|
|
|
// it's too confusing when readonly (makes sense for files only).
|
|
|
|
|
|
|
|
$fields = FieldList::create([
|
|
|
|
HeaderField::create('TitleHeader', $this->Title, 1),
|
|
|
|
LiteralField::create("ImageFull", $this->PreviewThumbnail()),
|
|
|
|
TextField::create("Name", $this->fieldLabel('Filename')),
|
|
|
|
HiddenField::create('ID', $this->ID)
|
|
|
|
]);
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
$this->extend('updateCMSFields', $fields);
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
|
2009-07-02 00:27:18 +02:00
|
|
|
/**
|
|
|
|
* Get the children of this folder that are also folders.
|
2013-06-21 00:32:08 +02:00
|
|
|
*
|
|
|
|
* @return DataList
|
2009-07-02 00:27:18 +02:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function ChildFolders() {
|
2014-02-20 02:03:40 +01:00
|
|
|
return Folder::get()->filter('ParentID', $this->ID);
|
2009-07-02 00:27:18 +02:00
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2015-05-19 23:19:01 +02:00
|
|
|
/**
|
|
|
|
* Get the number of children of this folder that are also folders.
|
2015-09-15 04:52:02 +02:00
|
|
|
*
|
|
|
|
* @return int
|
2015-05-19 23:19:01 +02:00
|
|
|
*/
|
|
|
|
public function numChildFolders() {
|
|
|
|
return $this->ChildFolders()->count();
|
|
|
|
}
|
2009-11-21 03:33:42 +01:00
|
|
|
/**
|
2015-09-15 04:52:02 +02:00
|
|
|
* @return string
|
2009-11-21 03:33:42 +01:00
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function CMSTreeClasses() {
|
2009-11-21 03:33:42 +01:00
|
|
|
$classes = sprintf('class-%s', $this->class);
|
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
if(!$this->canDelete()) {
|
2009-11-21 03:33:42 +01:00
|
|
|
$classes .= " nodelete";
|
2015-09-15 04:52:02 +02:00
|
|
|
}
|
2009-11-21 03:33:42 +01:00
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
if(!$this->canEdit()) {
|
2009-11-21 03:33:42 +01:00
|
|
|
$classes .= " disabled";
|
2015-09-15 04:52:02 +02:00
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2015-05-19 23:19:01 +02:00
|
|
|
$classes .= $this->markingClasses('numChildFolders');
|
2009-11-21 03:33:42 +01:00
|
|
|
|
|
|
|
return $classes;
|
|
|
|
}
|
2013-06-21 00:32:08 +02:00
|
|
|
|
2012-04-26 01:42:56 +02:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public function getTreeTitle() {
|
2015-09-15 04:52:02 +02:00
|
|
|
return sprintf(
|
2012-04-26 01:42:56 +02:00
|
|
|
"<span class=\"jstree-foldericon\"></span><span class=\"item\">%s</span>",
|
2015-09-15 04:52:02 +02:00
|
|
|
Convert::raw2att(preg_replace('~\R~u', ' ', $this->Title))
|
2012-04-26 01:42:56 +02:00
|
|
|
);
|
|
|
|
}
|
2015-09-15 04:52:02 +02:00
|
|
|
|
|
|
|
public function getFilename() {
|
2016-03-02 06:18:10 +01:00
|
|
|
return parent::generateFilename() . '/';
|
2015-09-15 04:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Folders do not have public URLs
|
|
|
|
*
|
2015-12-09 22:19:23 +01:00
|
|
|
* @param bool $grant
|
|
|
|
* @return null|string
|
2015-09-15 04:52:02 +02:00
|
|
|
*/
|
2015-12-09 22:19:23 +01:00
|
|
|
public function getURL($grant = true) {
|
2015-09-15 04:52:02 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Folders do not have public URLs
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getAbsoluteURL() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function onAfterWrite() {
|
|
|
|
parent::onAfterWrite();
|
|
|
|
|
2016-03-02 06:18:10 +01:00
|
|
|
// No publishing UX for folders, so just cascade changes live
|
|
|
|
if(Versioned::get_stage() === Versioned::DRAFT) {
|
2016-04-01 05:27:59 +02:00
|
|
|
$this->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
|
2016-03-02 06:18:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update draft version of all child records
|
2015-09-15 04:52:02 +02:00
|
|
|
$this->updateChildFilesystem();
|
|
|
|
}
|
|
|
|
|
2016-03-02 06:18:10 +01:00
|
|
|
public function onAfterDelete() {
|
|
|
|
parent::onAfterDelete();
|
|
|
|
|
|
|
|
// Cascade deletions to live
|
|
|
|
if(Versioned::get_stage() === Versioned::DRAFT) {
|
|
|
|
$this->deleteFromStage(Versioned::LIVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 04:52:02 +02:00
|
|
|
public function updateFilesystem() {
|
|
|
|
// No filesystem changes to update
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If a write is skipped due to no changes, ensure that nested records still get asked to update
|
|
|
|
*/
|
|
|
|
public function onAfterSkippedWrite() {
|
|
|
|
$this->updateChildFilesystem();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update filesystem of all children
|
|
|
|
*/
|
|
|
|
public function updateChildFilesystem() {
|
2016-03-02 06:18:10 +01:00
|
|
|
// Don't synchronise on live (rely on publishing instead)
|
|
|
|
if(Versioned::get_stage() === Versioned::LIVE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->flushCache();
|
2015-09-15 04:52:02 +02:00
|
|
|
// Writing this record should trigger a write (and potential updateFilesystem) on each child
|
2016-03-02 06:18:10 +01:00
|
|
|
foreach ($this->AllChildren() as $child) {
|
2015-09-15 04:52:02 +02:00
|
|
|
$child->write();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function StripThumbnail() {
|
|
|
|
return null;
|
|
|
|
}
|
2011-03-23 01:23:43 +01:00
|
|
|
}
|