',
$document->ID,
@@ -264,4 +285,20 @@ class DMSDocumentAddController extends LeftAndMain
_t('DMSDocumentAddController.NODOCUMENTS', 'There are no documents attached to the selected page.')
);
}
+
+ /**
+ * Get an array of allowed file upload extensions, merged with {@link File} and extra configuration from this
+ * class
+ *
+ * @return array
+ */
+ public function getAllowedExtensions()
+ {
+ return array_filter(
+ array_merge(
+ (array) Config::inst()->get('File', 'allowed_extensions'),
+ (array) $this->config()->get('allowed_extensions')
+ )
+ );
+ }
}
diff --git a/code/cms/DMSGridFieldAddNewButton.php b/code/cms/DMSGridFieldAddNewButton.php
index 132d077..cfeb475 100644
--- a/code/cms/DMSGridFieldAddNewButton.php
+++ b/code/cms/DMSGridFieldAddNewButton.php
@@ -3,11 +3,11 @@
class DMSGridFieldAddNewButton extends GridFieldAddNewButton implements GridField_HTMLProvider
{
/**
- * The page ID that the document should be attached to. Used in the GridField for Documents in a Page.
+ * The document set ID that the document should be attached to
*
* @var int
*/
- protected $pageId;
+ protected $documentSetId;
/**
* Overriding the parent method to change the template that the DMS add button will be rendered with
@@ -30,8 +30,8 @@ class DMSGridFieldAddNewButton extends GridFieldAddNewButton implements GridFiel
}
$link = singleton('DMSDocumentAddController')->Link();
- if ($this->getPageId()) {
- $link = Controller::join_links($link, '?ID=' . $this->getPageId());
+ if ($this->getDocumentSetId()) {
+ $link = Controller::join_links($link, '?dsid=' . $this->getDocumentSetId());
}
$data = new ArrayData(array(
@@ -45,24 +45,24 @@ class DMSGridFieldAddNewButton extends GridFieldAddNewButton implements GridFiel
}
/**
- * Set the page ID that this document should be attached to
+ * Set the document set ID that this document should be attached to
*
* @param int $id
* @return $this
*/
- public function setPageId($id)
+ public function setDocumentSetId($id)
{
- $this->pageId = $id;
+ $this->documentSetId = $id;
return $this;
}
/**
- * Get the page ID that this document should be attached to
+ * Get the document set ID that this document should be attached to
*
* @return int
*/
- public function getPageId()
+ public function getDocumentSetId()
{
- return $this->pageId;
+ return $this->documentSetId;
}
}
diff --git a/code/cms/DMSGridFieldDeleteAction.php b/code/cms/DMSGridFieldDeleteAction.php
index 35e6f4c..7907f35 100644
--- a/code/cms/DMSGridFieldDeleteAction.php
+++ b/code/cms/DMSGridFieldDeleteAction.php
@@ -57,7 +57,7 @@ class DMSGridFieldDeleteAction extends GridFieldDeleteAction implements
}
// Add a class to the field to if it is the last gridfield in the list
- $numberOfRelations = $record->Pages()->Count();
+ $numberOfRelations = $record->getRelatedPages()->count();
$field
// Add a new class for custom JS to handle the delete action
->addExtraClass('dms-delete')
diff --git a/code/cms/DMSGridFieldDetailForm.php b/code/cms/DMSGridFieldDetailForm.php
index 95e9ddc..9fdf8b4 100644
--- a/code/cms/DMSGridFieldDetailForm.php
+++ b/code/cms/DMSGridFieldDetailForm.php
@@ -13,7 +13,7 @@ class DMSGridFieldDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest
//add a data attribute specifying how many pages this document is referenced on
if ($record = $this->record) {
- $numberOfPageRelations = $record->Pages()->Count();
+ $numberOfPageRelations = $record->getRelatedPages()->Count();
$relations = new ShortCodeRelationFinder();
$numberOfInlineRelations = $relations->findPageCount($record->ID);
diff --git a/code/cms/DMSUploadField.php b/code/cms/DMSUploadField.php
index 4468cc5..b926baa 100644
--- a/code/cms/DMSUploadField.php
+++ b/code/cms/DMSUploadField.php
@@ -18,17 +18,12 @@ class DMSUploadField extends UploadField
"upload",
);
+ /**
+ * The temporary folder name to store files in during upload
+ * @var string
+ */
protected $folderName = 'DMSTemporaryUploads';
- public function __construct($name, $title = null, SS_List $items = null)
- {
- parent::__construct($name, $title, $items);
-
- //set default DMS replace template to false
- $this->setConfig('useDMSReplaceTemplate', 0);
- }
-
-
/**
* Override the default behaviour of the UploadField and take the uploaded file (uploaded to assets) and
* add it into the DMS storage, deleting the old/uploaded file.
@@ -48,9 +43,12 @@ class DMSUploadField extends UploadField
// Otherwise create it
$doc = $dms->storeDocument($file);
$file->delete();
- // Relate to the underlying page being edited.
- // Not applicable when editing the document itself and replacing it.
- $doc->addPage($record);
+ }
+
+ // Relate to the underlying document set being edited.
+ // Not applicable when editing the document itself and replacing it, or uploading from the ModelAdmin
+ if ($record instanceof DMSDocumentSet) {
+ $record->Documents()->add($doc);
}
return $doc;
@@ -61,17 +59,6 @@ class DMSUploadField extends UploadField
return true;
}
-
- public function isDisabled()
- {
- return (parent::isDisabled() || !$this->isSaveable());
- }
-
- public function isSaveable()
- {
- return (!empty($this->getRecord()->ID));
- }
-
/**
* Action to handle upload of a single file
*
@@ -80,6 +67,10 @@ class DMSUploadField extends UploadField
*/
public function upload(SS_HTTPRequest $request)
{
+ if ($recordId = $request->postVar('ID')) {
+ $this->setRecord(DMSDocumentSet::get()->byId($recordId));
+ }
+
if ($this->isDisabled() || $this->isReadonly()) {
return $this->httpError(403);
}
@@ -110,13 +101,13 @@ class DMSUploadField extends UploadField
if (!$return['error'] && $this->relationAutoSetting && $record && $record->exists()) {
$tooManyFiles = false;
// Some relationships allow many files to be attached.
- if ($this->getConfig('allowedMaxFileNumber') && ($record->has_many($name) || $record->many_many($name))) {
+ if ($this->getConfig('allowedMaxFileNumber') && ($record->hasMany($name) || $record->manyMany($name))) {
if (!$record->isInDB()) {
$record->write();
}
$tooManyFiles = $record->{$name}()->count() >= $this->getConfig('allowedMaxFileNumber');
// has_one only allows one file at any given time.
- } elseif ($record->has_one($name)) {
+ } elseif ($record->hasOne($name)) {
$tooManyFiles = $record->{$name}() && $record->{$name}()->exists();
}
@@ -147,7 +138,7 @@ class DMSUploadField extends UploadField
// Get the uploaded file into a new file object.
try {
- $this->upload->loadIntoFile($tmpfile, $fileObject, $this->folderName);
+ $this->upload->loadIntoFile($tmpfile, $fileObject, $this->getFolderName());
} catch (Exception $e) {
// we shouldn't get an error here, but just in case
$return['error'] = $e->getMessage();
@@ -155,7 +146,7 @@ class DMSUploadField extends UploadField
if (!$return['error']) {
if ($this->upload->isError()) {
- $return['error'] = implode(' '.PHP_EOL, $this->upload->getErrors());
+ $return['error'] = implode(' ' . PHP_EOL, $this->upload->getErrors());
} else {
$file = $this->upload->getFile();
@@ -198,10 +189,10 @@ class DMSUploadField extends UploadField
// Replace the download template with a new one only when access the upload field through a GridField.
// Needs to be enabled through setConfig('downloadTemplateName', 'ss-dmsuploadfield-downloadtemplate');
- Requirements::javascript('dms/javascript/DMSUploadField_downloadtemplate.js');
+ Requirements::javascript(DMS_DIR . '/javascript/DMSUploadField_downloadtemplate.js');
// In the add dialog, add the addtemplate into the set of file that load.
- Requirements::javascript('dms/javascript/DMSUploadField_addtemplate.js');
+ Requirements::javascript(DMS_DIR . '/javascript/DMSUploadField_addtemplate.js');
return $fields;
}
@@ -305,4 +296,26 @@ class DMSUploadField extends UploadField
user_error("Invalid value for UploadField::fileEditValidator", E_USER_ERROR);
}
+
+ /**
+ * Set the folder name to store DMS files in
+ *
+ * @param string $folderName
+ * @return $this
+ */
+ public function setFolderName($folderName)
+ {
+ $this->folderName = (string) $folderName;
+ return $this;
+ }
+
+ /**
+ * Get the folder name for storing the document
+ *
+ * @return string
+ */
+ public function getFolderName()
+ {
+ return $this->folderName;
+ }
}
diff --git a/code/cms/DMSUploadField_ItemHandler.php b/code/cms/DMSUploadField_ItemHandler.php
index b698c92..6ea3e1a 100644
--- a/code/cms/DMSUploadField_ItemHandler.php
+++ b/code/cms/DMSUploadField_ItemHandler.php
@@ -8,9 +8,14 @@ class DMSUploadField_ItemHandler extends UploadField_ItemHandler
'EditForm',
);
+ /**
+ * Gets a DMS document by its ID
+ *
+ * @return DMSDocument
+ */
public function getItem()
{
- return DataObject::get_by_id('DMSDocument', $this->itemID);
+ return DMSDocument::get()->byId($this->itemID);
}
/**
diff --git a/code/extensions/DMSSiteTreeExtension.php b/code/extensions/DMSSiteTreeExtension.php
index 1444746..6de0554 100644
--- a/code/extensions/DMSSiteTreeExtension.php
+++ b/code/extensions/DMSSiteTreeExtension.php
@@ -5,136 +5,56 @@
*/
class DMSSiteTreeExtension extends DataExtension
{
-
- private static $belongs_many_many = array(
- 'Documents' => 'DMSDocument'
+ private static $has_many = array(
+ 'DocumentSets' => 'DMSDocumentSet'
);
- private static $noDocumentsList = array();
-
- private static $showDocumentsList = array();
-
- /**
- * Do not show the documents tab on the array of pages set here
- * @static
- * @param $mixed Array of page types to not show the Documents tab on
- */
- public static function no_documents_tab($array = array())
- {
- if (empty($array)) {
- return;
- }
- if (is_array($array)) {
- self::$noDocumentsList = $array;
- } else {
- self::$noDocumentsList = array($array);
- }
- }
-
- /**
- * Only show the documents tab on the list of pages set here. Any pages set in the no_documents_tab array will
- * still not be shown. If this isn't called, or if it is called with an empty array, all pages will get
- * Document tabs.
- * @static
- * @param $array Array of page types to show the Documents tab on
- */
- public static function show_documents_tab($array = array())
- {
- if (empty($array)) {
- return;
- }
- if (is_array($array)) {
- self::$showDocumentsList = $array;
- } else {
- self::$showDocumentsList = array($array);
- }
- }
-
public function updateCMSFields(FieldList $fields)
{
- // Prevent certain pages from having a Document tab in the CMS
- if (in_array($this->owner->ClassName, self::$noDocumentsList)) {
+ // Ability to disable document sets for a Page
+ if (!$this->owner->config()->get('documents_enabled')) {
return;
}
- if (count(self::$showDocumentsList) > 0 && !in_array($this->owner->ClassName, self::$showDocumentsList)) {
- return;
- }
-
- // Javascript to customize the grid field for the DMS document (overriding entwine
- // in FRAMEWORK_DIR.'/javascript/GridField.js'
- Requirements::javascript(DMS_DIR.'/javascript/DMSGridField.js');
- Requirements::css(DMS_DIR.'/css/DMSMainCMS.css');
-
- // Javascript for the link editor pop-up in TinyMCE
- Requirements::javascript(DMS_DIR."/javascript/DocumentHtmlEditorFieldToolbar.js");
-
- // Document listing
- $gridFieldConfig = GridFieldConfig::create()->addComponents(
- new GridFieldToolbarHeader(),
- new GridFieldFilterHeader(),
- new GridFieldSortableHeader(),
- new GridFieldOrderableRows('DocumentSort'),
- new GridFieldDataColumns(),
- new GridFieldEditButton(),
- new DMSGridFieldDeleteAction(), //special delete dialog to handle custom behaviour of unlinking and deleting
- new GridFieldDetailForm()
- //GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d')
- );
-
- if (class_exists('GridFieldPaginatorWithShowAll')) {
- $paginatorComponent = new GridFieldPaginatorWithShowAll(15);
- } else {
- $paginatorComponent = new GridFieldPaginator(15);
- }
- $gridFieldConfig->addComponent($paginatorComponent);
-
- if (class_exists('GridFieldSortableRows')) {
- $sortableComponent = new GridFieldSortableRows('DocumentSort');
- //setUsePagenation method removed from newer version of SortableGridField.
- if (method_exists($sortableComponent, 'setUsePagination')) {
- $sortableComponent->setUsePagination(false)->setForceRedraw(true);
- }
- $gridFieldConfig->addComponent($sortableComponent);
- }
-
- // HACK: Create a singleton of DMSDocument to ensure extensions are applied before we try to get display fields.
- singleton('DMSDocument');
- $gridFieldConfig->getComponentByType('GridFieldDataColumns')
- ->setDisplayFields(Config::inst()->get('DMSDocument', 'display_fields'))
- ->setFieldCasting(array('LastChanged'=>"Datetime->Ago"))
- ->setFieldFormatting(
- array(
- 'FilenameWithoutID'=>'$FilenameWithoutID'
- )
- );
-
- //override delete functionality with this class
- $gridFieldConfig->getComponentByType('GridFieldDetailForm')
- ->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
$gridField = GridField::create(
- 'Documents',
+ 'Document Sets',
false,
- $this->owner->Documents()->Sort('DocumentSort'),
- $gridFieldConfig
+ $this->owner->DocumentSets(), //->Sort('DocumentSort'),
+ new GridFieldConfig_RelationEditor
);
- $gridField->addExtraClass('documents');
+ $gridField->addExtraClass('documentsets');
- $gridFieldConfig->addComponent(
- $addNewButton = new DMSGridFieldAddNewButton,
- 'GridFieldExportButton'
+ $fields->addFieldToTab(
+ 'Root.Document Sets (' . $this->owner->DocumentSets()->Count() . ')',
+ $gridField
);
- $addNewButton->setPageId($this->owner->ID);
-
- $fields->addFieldToTab('Root.Documents (' . $this->owner->Documents()->Count() . ')', $gridField);
}
/**
- * Enforce sorting for frontend
+ * Get a list of document sets for the owner page
+ *
+ * @return ArrayList
*/
- public function PageDocuments()
+ public function getDocumentSets()
{
- return $this->owner->getManyManyComponents('Documents')->sort('DocumentSort');
+ return $this->owner->DocumentSets();
+ }
+
+ /**
+ * Get a list of all documents from all document sets for the owner page
+ *
+ * @return ArrayList
+ */
+ public function getAllDocuments()
+ {
+ $documents = ArrayList::create();
+
+ foreach ($this->getDocumentSets() as $documentSet) {
+ /** @var DocumentSet $documentSet */
+ $documents->merge($documentSet->getDocuments());
+ }
+
+ return $documents;
}
public function onBeforeDelete()
@@ -160,7 +80,7 @@ class DMSSiteTreeExtension extends DataExtension
public function onBeforePublish()
{
- $embargoedDocuments = $this->owner->Documents()->filter('EmbargoedUntilPublished', true);
+ $embargoedDocuments = $this->owner->getAllDocuments()->filter('EmbargoedUntilPublished', true);
if ($embargoedDocuments->Count() > 0) {
foreach ($embargoedDocuments as $doc) {
$doc->EmbargoedUntilPublished = false;
@@ -169,8 +89,14 @@ class DMSSiteTreeExtension extends DataExtension
}
}
+ /**
+ * Returns the title of the page with the total number of documents it has associated with it across
+ * all document sets
+ *
+ * @return string
+ */
public function getTitleWithNumberOfDocuments()
{
- return $this->owner->Title . ' (' . $this->owner->Documents()->Count() . ')';
+ return $this->owner->Title . ' (' . $this->owner->getAllDocuments()->count() . ')';
}
}
diff --git a/code/interface/DMSDocumentInterface.php b/code/interface/DMSDocumentInterface.php
index 9df20f1..e46fac8 100644
--- a/code/interface/DMSDocumentInterface.php
+++ b/code/interface/DMSDocumentInterface.php
@@ -6,58 +6,6 @@
*/
interface DMSDocumentInterface
{
- /**
- * Deletes the DMSDocument, its underlying file, as well as any tags related to this DMSDocument.
- *
- * @todo Can't be applied to classes which already implement the DataObjectInterface (naming conflict)
- *
- * @abstract
- * @return null
- */
- // function delete();
-
- /**
- * Associates this DMSDocument with a Page. This method does nothing if the association already exists.
- * This could be a simple wrapper around $myDoc->Pages()->add($myPage) to add a many_many relation
- * @abstract
- * @param $pageObject Page object to associate this DMSDocument with
- * @return null
- */
- public function addPage($pageObject);
-
- /**
- * Associates this DMSDocument with a set of Pages. This method loops through a set of page ids, and then
- * associates this
- * DMSDocument with the individual Page with the each page id in the set
- * @abstract
- * @param $pageIDs array of page ids used for the page objects associate this DMSDocument with
- * @return null
- */
- public function addPages($pageIDs);
-
- /**
- * Removes the association between this DMSDocument and a Page. This method does nothing if the association does
- * not exist.
- * @abstract
- * @param $pageObject Page object to remove the association to
- * @return mixed
- */
- public function removePage($pageObject);
-
- /**
- * Returns a list of the Page objects associated with this DMSDocument
- * @abstract
- * @return DataList
- */
- public function getPages();
-
- /**
- * Removes all associated Pages from the DMSDocument
- * @abstract
- * @return null
- */
- public function removeAllPages();
-
/**
* Adds a metadata tag to the DMSDocument. The tag has a category and a value.
* Each category can have multiple values by default. So: addTag("fruit","banana") addTag("fruit", "apple") will
@@ -67,7 +15,6 @@ interface DMSDocumentInterface
* addTag("fruit","banana") addTag("fruit", "apple") would result in a single metadata tag: fruit->apple.
* Can could be implemented as a key/value store table (although it is more like category/value, because the
* same category can occur multiple times)
- * @abstract
* @param $category String of a metadata category to add (required)
* @param $value String of a metadata value to add (required)
* @param bool $multiValue Boolean that determines if the category is multi-value or single-value (optional)
@@ -78,7 +25,6 @@ interface DMSDocumentInterface
/**
* Fetches all tags associated with this DMSDocument within a given category. If a value is specified this method
* tries to fetch that specific tag.
- * @abstract
* @param $category String of the metadata category to get
* @param null $value String of the value of the tag to get
* @return array of Strings of all the tags or null if there is no match found
@@ -89,7 +35,6 @@ interface DMSDocumentInterface
* Removes a tag from the DMSDocument. If you only set a category, then all values in that category are deleted.
* If you specify both a category and a value, then only that single category/value pair is deleted.
* Nothing happens if the category or the value do not exist.
- * @abstract
* @param $category Category to remove (required)
* @param null $value Value to remove (optional)
* @return null
@@ -98,14 +43,12 @@ interface DMSDocumentInterface
/**
* Deletes all tags associated with this DMSDocument.
- * @abstract
* @return null
*/
public function removeAllTags();
/**
* Returns a link to download this DMSDocument from the DMS store
- * @abstract
* @return String
*/
public function getLink();
@@ -142,14 +85,12 @@ interface DMSDocumentInterface
* Hides the DMSDocument, so it does not show up when getByPage($myPage) is called
* (without specifying the $showEmbargoed = true parameter). This is similar to expire, except that this method
* should be used to hide DMSDocuments that have not yet gone live.
- * @abstract
* @return null
*/
public function embargoIndefinitely();
/**
* Returns if this is DMSDocument is embargoed or expired.
- * @abstract
* @return bool True or False depending on whether this DMSDocument is embargoed or expired
*/
public function isHidden();
@@ -157,7 +98,6 @@ interface DMSDocumentInterface
/**
* Returns if this is DMSDocument is embargoed.
- * @abstract
* @return bool True or False depending on whether this DMSDocument is embargoed
*/
public function isEmbargoed();
@@ -165,7 +105,6 @@ interface DMSDocumentInterface
/**
* Hides the DMSDocument, so it does not show up when getByPage($myPage) is called. Automatically un-hides the
* DMSDocument at a specific date.
- * @abstract
* @param $datetime String date time value when this DMSDocument should expire
* @return null
*/
@@ -179,21 +118,18 @@ interface DMSDocumentInterface
/**
* Clears any previously set embargos, so the DMSDocument always shows up in all queries.
- * @abstract
* @return null
*/
public function clearEmbargo();
/**
* Returns if this is DMSDocument is expired.
- * @abstract
* @return bool True or False depending on whether this DMSDocument is expired
*/
public function isExpired();
/**
* Hides the DMSDocument at a specific date, so it does not show up when getByPage($myPage) is called.
- * @abstract
* @param $datetime String date time value when this DMSDocument should expire
* @return null
*/
@@ -201,7 +137,6 @@ interface DMSDocumentInterface
/**
* Clears any previously set expiry.
- * @abstract
* @return null
*/
public function clearExpiry();
@@ -211,7 +146,6 @@ interface DMSDocumentInterface
/**
* Returns a DataList of all previous Versions of this DMSDocument (check the LastEdited date of each
* object to find the correct one)
- * @abstract
* @return DataList List of DMSDocument objects
*/
public function getVersions();
diff --git a/code/interface/DMSInterface.php b/code/interface/DMSInterface.php
index 719c8df..1909dda 100644
--- a/code/interface/DMSInterface.php
+++ b/code/interface/DMSInterface.php
@@ -57,11 +57,19 @@ interface DMSInterface
/**
- * Returns a list of Document objects associated with a Page
- * @abstract
- * @param $page SiteTree to fetch the associated Documents from
- * @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
- * @return DataList Document list associated with the Page
+ * Returns a list of Document objects associated with a Page via intermediary document sets
+ *
+ * @param SiteTree $page SiteTree to fetch the associated Documents from
+ * @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
+ * @return ArrayList Document list associated with the Page
*/
- public function getByPage($page, $showEmbargoed = false);
+ public function getByPage(SiteTree $page, $showEmbargoed = false);
+
+ /**
+ * Returns a list of Document Set objects associated with a Page
+ *
+ * @param SiteTree $page SiteTree to fetch the associated Document Sets from
+ * @return ArrayList Document list associated with the Page
+ */
+ public function getDocumentSetsByPage(SiteTree $page);
}
diff --git a/code/model/DMSDocument.php b/code/model/DMSDocument.php
index e7422f6..1995033 100644
--- a/code/model/DMSDocument.php
+++ b/code/model/DMSDocument.php
@@ -43,20 +43,17 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
"CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
);
+ private static $belongs_many_many = array(
+ 'Sets' => 'DMSDocumentSet'
+ );
+
private static $many_many = array(
- 'Pages' => 'SiteTree',
'RelatedDocuments' => 'DMSDocument',
'Tags' => 'DMSTag',
'ViewerGroups' => 'Group',
'EditorGroups' => 'Group',
);
- private static $many_many_extraFields = array(
- 'Pages' => array(
- 'DocumentSort' => 'Int'
- )
- );
-
private static $display_fields = array(
'ID' => 'ID',
'Title' => 'Title',
@@ -82,7 +79,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
'Filename' => 'Filename',
'Title' => 'Title',
'ViewCount' => 'ViewCount',
- 'getPages.count' => 'Page Use'
+ 'getRelatedPages.count' => 'Page Use'
);
/**
@@ -217,103 +214,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
return $this->canView();
}
-
-
- /**
- * Associates this document with a Page. This method does nothing if the
- * association already exists.
- *
- * This could be a simple wrapper around $myDoc->Pages()->add($myPage) to
- * add a many_many relation.
- *
- * @param SiteTree $pageObject Page object to associate this Document with
- *
- * @return DMSDocument
- */
- public function addPage($pageObject)
- {
- $this->Pages()->add($pageObject);
-
- DB::query(
- "UPDATE \"DMSDocument_Pages\" SET \"DocumentSort\"=\"DocumentSort\"+1"
- . " WHERE \"SiteTreeID\" = $pageObject->ID"
- );
-
- return $this;
- }
-
- /**
- * Associates this DMSDocument with a set of Pages. This method loops
- * through a set of page ids, and then associates this DMSDocument with the
- * individual Page with the each page id in the set.
- *
- * @param array $pageIDs
- *
- * @return DMSDocument
- */
- public function addPages($pageIDs)
- {
- foreach ($pageIDs as $id) {
- $pageObject = DataObject::get_by_id("SiteTree", $id);
-
- if ($pageObject && $pageObject->exists()) {
- $this->addPage($pageObject);
- }
- }
-
- return $this;
- }
-
- /**
- * Removes the association between this Document and a Page. This method
- * does nothing if the association does not exist.
- *
- * @param SiteTree $pageObject Page object to remove the association to
- *
- * @return DMSDocument
- */
- public function removePage($pageObject)
- {
- $this->Pages()->remove($pageObject);
-
- return $this;
- }
-
- /**
- * @see getPages()
- *
- * @return DataList
- */
- public function Pages()
- {
- $pages = $this->getManyManyComponents('Pages');
- $this->extend('updatePages', $pages);
-
- return $pages;
- }
-
- /**
- * Returns a list of the Page objects associated with this Document.
- *
- * @return DataList
- */
- public function getPages()
- {
- return $this->Pages();
- }
-
- /**
- * Removes all associated Pages from the DMSDocument
- *
- * @return DMSDocument
- */
- public function removeAllPages()
- {
- $this->Pages()->removeAll();
-
- return $this;
- }
-
/**
* Increase ViewCount by 1, without update any other record fields such as
* LastEdited.
@@ -842,8 +742,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
}
}
- $this->removeAllPages();
-
// get rid of any versions have saved for this DMSDocument, too
if (DMSDocument_versions::$enable_versions) {
$versions = $this->getVersions();
@@ -855,11 +753,9 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
}
}
- parent::delete();
+ return parent::delete();
}
-
-
/**
* Relate an existing file on the filesystem to the document.
*
@@ -1060,7 +956,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
$pagesGrid = GridField::create(
'Pages',
_t('DMSDocument.RelatedPages', 'Related Pages'),
- $this->Pages(),
+ $this->getRelatedPages(),
$gridFieldConfig
);
@@ -1321,7 +1217,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
);
//count the number of pages this document is published on
- $publishedOnCount = $this->Pages()->Count();
+ $publishedOnCount = $this->getRelatedPages()->count();
$publishedOnValue = "$publishedOnCount pages";
if ($publishedOnCount == 1) {
$publishedOnValue = "$publishedOnCount page";
@@ -1419,6 +1315,26 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
return $documents;
}
+ /**
+ * Get a list of related pages for this document by going through the associated document sets
+ *
+ * @return ArrayList
+ */
+ public function getRelatedPages()
+ {
+ $pages = ArrayList::create();
+
+ foreach ($this->Sets() as $documentSet) {
+ /** @var DocumentSet $documentSet */
+ $pages->add($documentSet->Page());
+ }
+ $pages->removeDuplicates();
+
+ $this->extend('updateRelatedPages', $pages);
+
+ return $pages;
+ }
+
/**
* Get a GridField for managing related documents
*
diff --git a/code/model/DMSDocumentSet.php b/code/model/DMSDocumentSet.php
new file mode 100644
index 0000000..84ce674
--- /dev/null
+++ b/code/model/DMSDocumentSet.php
@@ -0,0 +1,123 @@
+ 'Varchar(255)'
+ );
+
+ private static $has_one = array(
+ 'Page' => 'SiteTree'
+ );
+
+ private static $many_many = array(
+ 'Documents' => 'DMSDocument'
+ );
+
+ /**
+ * Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
+ *
+ * You can attach an extension to this event:
+ *
+ *
+ * public function updateDocuments($document)
+ * {
+ * // do something
+ * }
+ *
+ *
+ * @return DataList
+ */
+ public function getDocuments()
+ {
+ $documents = $this->Documents();
+
+ $this->extend('updateDocuments', $documents);
+
+ return $documents;
+ }
+
+ /**
+ * Put the "documents" list into the main tab instead of its own tab, and replace the default "Add Document" button
+ * with a customised button for DMS documents
+ *
+ * @return FieldList
+ */
+ public function getCMSFields()
+ {
+ $this->beforeUpdateCMSFields(function (FieldList $fields) {
+ // Javascript to customize the grid field for the DMS document (overriding entwine
+ // in FRAMEWORK_DIR.'/javascript/GridField.js'
+ Requirements::javascript(DMS_DIR . '/javascript/DMSGridField.js');
+ Requirements::css(DMS_DIR . '/css/DMSMainCMS.css');
+
+ // Javascript for the link editor pop-up in TinyMCE
+ Requirements::javascript(DMS_DIR . '/javascript/DocumentHtmlEditorFieldToolbar.js');
+
+ // Document listing
+ $gridFieldConfig = GridFieldConfig::create()
+ ->addComponents(
+ new GridFieldToolbarHeader(),
+ new GridFieldFilterHeader(),
+ new GridFieldSortableHeader(),
+ // new GridFieldOrderableRows('DocumentSort'),
+ new GridFieldDataColumns(),
+ new GridFieldEditButton(),
+ new DMSGridFieldDeleteAction(), //special delete dialog to handle custom behaviour of unlinking and deleting
+ new GridFieldDetailForm()
+ //GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d')
+ );
+
+ if (class_exists('GridFieldPaginatorWithShowAll')) {
+ $paginatorComponent = new GridFieldPaginatorWithShowAll(15);
+ } else {
+ $paginatorComponent = new GridFieldPaginator(15);
+ }
+ $gridFieldConfig->addComponent($paginatorComponent);
+
+ if (class_exists('GridFieldSortableRows')) {
+ $sortableComponent = new GridFieldSortableRows('DocumentSort');
+ //setUsePagenation method removed from newer version of SortableGridField.
+ if (method_exists($sortableComponent, 'setUsePagination')) {
+ $sortableComponent->setUsePagination(false)->setForceRedraw(true);
+ }
+ $gridFieldConfig->addComponent($sortableComponent);
+ }
+
+ // HACK: Create a singleton of DMSDocument to ensure extensions are applied before we try to get display fields.
+ singleton('DMSDocument');
+ $gridFieldConfig->getComponentByType('GridFieldDataColumns')
+ ->setDisplayFields(Config::inst()->get('DMSDocument', 'display_fields'))
+ ->setFieldCasting(array('LastChanged'=>"Datetime->Ago"))
+ ->setFieldFormatting(
+ array(
+ 'FilenameWithoutID' => '$FilenameWithoutID'
+ )
+ );
+
+ //override delete functionality with this class
+ $gridFieldConfig->getComponentByType('GridFieldDetailForm')
+ ->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
+
+ $gridField = GridField::create(
+ 'Documents',
+ false,
+ $this->Documents(),//->Sort('DocumentSort'),
+ $gridFieldConfig
+ );
+ $gridField->addExtraClass('documents');
+
+ $gridFieldConfig->addComponent(
+ $addNewButton = new DMSGridFieldAddNewButton,
+ 'GridFieldExportButton'
+ );
+ $addNewButton->setDocumentSetId($this->ID);
+
+ $fields->removeByName('Documents');
+ $fields->addFieldToTab('Root.Main', $gridField);
+ });
+ return parent::getCMSFields();
+ }
+}
diff --git a/docs/en/changelogs/2.0.0.md b/docs/en/changelogs/2.0.0.md
new file mode 100644
index 0000000..762499c
--- /dev/null
+++ b/docs/en/changelogs/2.0.0.md
@@ -0,0 +1,30 @@
+# 2.0.0 (unreleased)
+
+## Document sets
+
+Documents now belong to "sets", which are attached to Pages. A Page can have many Document Sets, and a Set has a
+many_many relationship with Documents.
+
+When upgrading from 1.x to 2.x you will need to migrate the relationships from your Pages to Documents so support
+having a Document Set intermediary (@todo Add a build task for this).
+
+## API changes
+
+* `DMSSiteTreeExtension::no_documents_tab` removed, use YAML configuration `MyPage.documents_enabled: false` instead
+* `DMSSiteTreeExtension::show_documents_tab` removed, use YAML configuration `MyPage.documents_enabled: true` instead
+* `DMSSiteTreeExtension::PageDocuments` removed, use `DMSSiteTreeExtension::getDocumentSets` instead
+* `DMSSiteTreeExtension::getDocuments` removed, use `DMSSiteTreeExtension::getAllDocuments` instead
+* `DMSDocument::addPage` removed, use document sets instead
+* `DMSDocument::addPages` removed, use document sets instead
+* `DMSDocument::removePage` removed, use document sets instead
+* `DMSDocument::removeAllPages` removed, use document sets instead
+* `DMSDocument::getPages` removed, use `DMSDocument::getRelatedPages` instead
+* `DMSDocumentInterface` has had the page manipulation methods removed, as above
+* `DMSDocumentAddController::add_allowed_extensions` removed, use YAML configuration `DMSDocumentAddController::allowed_extensions` instead
+* `DMSInterface` (and `DMS`) are stricter in the `getByPage` method, enforcing a `SiteTree` type hint
+* New method `DMSInterface::getDocumentSetsByPage` (and in `DMS`)
+
+## Template changes
+
+The default template entry point is now `DocumentSets.ss` (previously `Documents.ss`). As well as this change,
+`Documents.ss` has been renamed to `DocumentSet.ss`.
diff --git a/docs/en/configuration.md b/docs/en/configuration.md
index 01d3199..50fee04 100644
--- a/docs/en/configuration.md
+++ b/docs/en/configuration.md
@@ -1,3 +1,30 @@
# Configuration
The file location is set via the `DMS::$dmsFolder` static, and points to a location in the webroot.
+
+## Enable/disable documents/sets for a specific page type
+
+If you don't need documents/document sets for a specific page type you can disable this with YAML configuration:
+
+```yaml
+MyPageType:
+ documents_enabled: false
+```
+
+Likewise, you could override a previously set configuration value by setting this back to `true` in a configuration
+file with a higher precedence.
+
+## Allowed extensions for DMS documents
+
+By default the allowed extensions for DMS documents will come from the UploadField's allowed extesions list, and will
+have a customised list of extensions for DMS merged in. The base `allowed_extensions` is a site-wide configuration
+setting. [See here for information](https://docs.silverstripe.org/en/3/developer_guides/forms/field_types/uploadfield/#limit-the-allowed-filetypes) on changing this.
+
+To add extra allowed file extensions purely for DMS documents, you can update the YAML configuration property:
+
+```yaml
+DMSDocumentAddController:
+ allowed_extensions:
+ - php
+ - php5
+```
diff --git a/docs/en/creating-documents.md b/docs/en/creating-documents.md
index 82b7891..c749c6e 100644
--- a/docs/en/creating-documents.md
+++ b/docs/en/creating-documents.md
@@ -1,18 +1,35 @@
# Creating documents
-Create by relative path:
+The following examples will allow you to create a DMS document in the system without associating it to a document set.
+
+## Create by relative path
```php
-$dms = DMS::getDMSInstance();
+$dms = DMS::inst();
$doc = $dms->storeDocument('assets/myfile.pdf');
```
-Create from an existing `File` record:
+## Create from an existing `File` record
```php
-$dms = DMS::getDMSInstance();
+$dms = DMS::inst();
$file = File::get()->byID(99);
$doc = $dms->storeDocument($file);
```
Note: Both operations copy the existing file.
+
+## Associate to a document set
+
+If you need to associate a document to a set once it has already been created, you can use the ORM relationship from
+SiteTree to access the document sets, or you can simply access the document set directly:
+
+```php
+// Add document to the first set in my page
+$firstSetInPage = $myPage->DocumentSets()->first();
+$firstSetInPage->add($doc);
+
+// Add document to a specific document set
+$docSet = DMSDocumentSet::get()->byId(123);
+$docSet->add($doc);
+```
diff --git a/docs/en/download-documents.md b/docs/en/download-documents.md
index dcfbbf9..913c7ce 100644
--- a/docs/en/download-documents.md
+++ b/docs/en/download-documents.md
@@ -5,7 +5,7 @@
You can use `DMSDocument::getLink` to retrieve the secure route to download a DMS document:
```php
-$dms = DMS::getDMSInstance();
+$dms = DMS::inst();
$docs = $dms->getByTag('priority', 'important')->First();
$link = $doc->getLink();
```
diff --git a/docs/en/index.md b/docs/en/index.md
index eafc027..3f4e4ae 100644
--- a/docs/en/index.md
+++ b/docs/en/index.md
@@ -14,3 +14,7 @@
## CMS user help
* TBC
+
+### Changelogs
+
+* [2.0.0 (unreleased)](changelogs/2.0.0.md)
diff --git a/docs/en/manage-page-relations.md b/docs/en/manage-page-relations.md
index d91d444..f5b153f 100644
--- a/docs/en/manage-page-relations.md
+++ b/docs/en/manage-page-relations.md
@@ -1,10 +1,35 @@
# Manage page relations
-To find documents by a Page:
+Documents are associated to pages via "document sets". You can retrieve document sets for a page, then retrieve
+documents that belong to those sets. You can still retrieve all documents for a page if you want to.
+
+## Get document sets for a page
```php
-$dms = DMS::getDMSInstance();
-$page = SiteTree::get()->filter('URLSegment', 'home')->first();
-/** @var DataList $docs */
-$docs = $dms->getByPage($page);
+$dms = DMS::inst();
+$sets = $dms->getDocumentSetsByPage($myPage);
+```
+
+You can also request sets directly from the SiteTree instance:
+
+```php
+$sets = $page->getDocumentSets();
+```
+
+## Get all related documents for a page
+
+`DMS::getByPage` will exclude currently embargoed documents by default. To include embargoed documents as well
+add `true` as the second argument.
+
+```php
+$dms = DMS::inst();
+
+$documents = $dms->getByPage($myPage);
+$documentsIncludingEmbargoed = $dms->getByPage($myPage, true);
+```
+
+You can also request this directly from the SiteTree instance:
+
+```php
+$documents = $myPage->getAllDocuments();
```
diff --git a/docs/en/use-in-templates.md b/docs/en/use-in-templates.md
index b95e337..eef8139 100644
--- a/docs/en/use-in-templates.md
+++ b/docs/en/use-in-templates.md
@@ -4,7 +4,7 @@ Add a simple include to any of your `.ss` templates to display the DMSDocuments
the current page on the front-end.
```
-<% include Documents %>
+<% include DocumentSets %>
```
You can fine tune the HTML markup or display behaviour of any of the templates in `/dms/templates/Includes` to change
diff --git a/lang/en.yml b/lang/en.yml
index 23d1ffc..9e4d9f1 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -9,6 +9,8 @@ en:
TYPE: 'File type'
URL: URL
DMSDocument:
+ EDIT: Edit
+ EDITDOCUMENT: Edit this document
PLURALNAME: Documents
RelatedPages: 'Related Pages'
RelatedReferences: 'Related References'
@@ -16,9 +18,14 @@ en:
Versions: Versions
DOWNLOAD: "Download {title}"
LASTCHANGED: "Last changed: {date}"
+ DMSDocumentSet:
+ ADDDOCUMENTBUTTON: Add Document
+ ADDDOCUMENTSBUTTON: Add Documents
+ PLURALNAME: Document Sets
+ SINGULARNAME: Document Set
DMSTag:
- PLURALNAME: 'D M S Tags'
- SINGULARNAME: 'D M S Tag'
+ PLURALNAME: 'DMS Tags'
+ SINGULARNAME: 'DMS Tag'
FileIFrameField:
ATTACHONCESAVED2: 'Files can be attached once you have saved the record for the first time.'
GridAction:
@@ -29,8 +36,10 @@ en:
DeletePermissionsFailure: 'No delete permissions'
UploadField:
ATTACHFILE: 'Attach a file'
+ DONE: Done!
DROPFILE: 'drop a file'
FIELDNOTSET: 'File information not found'
+ FROMCMS: From the CMS
FROMCOMPUTER: 'From your computer'
FROMCOMPUTERINFO: 'Upload from your computer'
MAXNUMBEROFFILES: 'Max number of {count} file(s) exceeded.'
@@ -38,6 +47,14 @@ en:
MENUTITLE: 'Edit Page'
NODOCUMENTS: 'There are no documents attached to the selected page.'
RELATEDDOCUMENTS: 'Related Documents'
+ MAINTAB: Main
DMSDocument_versions:
- PLURALNAME: 'D M S Document_versionss'
- SINGULARNAME: 'D M S Document_versions'
+ PLURALNAME: 'DMS Document_versionss'
+ SINGULARNAME: 'DMS Document_versions'
+ DMSDocumentAddExistingField:
+ ADDEXISTING: Add Existing
+ AUTOCOMPLETE: Search by ID or filename
+ CHOOSESET: Choose Document Set
+ EDITDOCUMENTDETAILS: Edit Document Details
+ LINKADOCUMENT: Link a Document
+ SELECTED: Selected Document
diff --git a/templates/DMSDocumentAddExistingField.ss b/templates/DMSDocumentAddExistingField.ss
index 25c39dc..fd36fc2 100644
--- a/templates/DMSDocumentAddExistingField.ss
+++ b/templates/DMSDocumentAddExistingField.ss
@@ -1,64 +1,43 @@
-
- <% if useFieldContext %>
-
- <% else %>
-
- <% end_if %>
-
- <% if useFieldContext %>
- 1
- Link a Document
- <% else %>
- <% end_if %>
-
- <% if useFieldContext %>
-
- <% else %>
-
- <% end_if %>
+
+ <% if $useFieldContext %>
<% else %>
<% end_if %>
+
+ <% if $useFieldContext %>
+ 1
+ <%t DMSDocumentAddExistingField.LINKADOCUMENT "Link a Document" %>
+ <% end_if %>
+
+ <% if $useFieldContext %><% else %>
- <% if Top.isDisabled || Top.isReadonly %>
+ <% if $Top.isDisabled || $Top.isReadonly %>
<% else %>
$UploadFieldFileButtons
<% end_if %>
@@ -25,11 +25,11 @@
<% end_loop %>
<% end_if %>
-<% if isDisabled || isReadonly %>
- <% if isSaveable %>
+<% if $isDisabled || $isReadonly %>
+ <% if $isSaveable %>
<% else %>
- <% _t('FileIFrameField.ATTACHONCESAVED2', 'Files can be attached once you have saved the record for the first time.') %>
+ <%t FileIFrameField.ATTACHONCESAVED2 "Files can be attached once you have saved the record for the first time." %>