Merge pull request #112 from robbieaverill/feature/document-sets

API Add document sets, remove *Page methods from DMSDocument
This commit is contained in:
sachajudd 2017-05-09 13:19:24 +12:00 committed by GitHub
commit ed6f805574
44 changed files with 1063 additions and 706 deletions

5
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,5 @@
# Contributing
Any open source product is only as good as the community behind it. You can participate by sharing code, ideas, or simply helping others. No matter what your skill level is, every contribution counts.
See our [high level overview](http://silverstripe.org/contributing-to-silverstripe) on silverstripe.org on how you can help out.

View File

@ -2,14 +2,10 @@
$config = Config::inst();
DMSSiteTreeExtension::show_documents_tab(); //show the Documents tab on all pages
DMSSiteTreeExtension::no_documents_tab(); //and don't exclude it from any pages
DMSDocumentAddController::add_allowed_extensions(); //add an array of additional allowed extensions
define('DMS_DIR', 'dms');
define('DMS_DIR', basename(__DIR__));
if (!file_exists(BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR)) {
user_error("DMS directory named incorrectly. Please install the DMS module into a folder named: ".DMS_DIR);
user_error('DMS directory named incorrectly. Please install the DMS module into a folder named: ' . DMS_DIR);
}
CMSMenu::remove_menu_item('DMSDocumentAddController');

View File

@ -5,11 +5,16 @@ After: framework/routes#coreroutes
Director:
rules:
'dmsdocument/$ID' : 'DMSDocument_Controller'
SiteTree:
extensions:
- DMSSiteTreeExtension
# Whether to show the document sets tab in the CMS for the page type this extension is applied to
documents_enabled: true
HtmlEditorField_Toolbar:
extensions:
- DocumentHtmlEditorFieldToolbar
DMSDocument_versions:
enable_versions: true

View File

@ -126,15 +126,25 @@ class DMS implements DMSInterface
// TODO: Implement getByFullTextSearch() method.
}
/**
* Returns a list of Document objects associated with a Page
* @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
*/
public function getByPage($page, $showEmbargoed = false)
public function getByPage(SiteTree $page, $showEmbargoed = false)
{
// TODO: Implement getByPage() method.
/** @var ArrayList $documents */
$documents = $page->getAllDocuments();
if (!$showEmbargoed) {
foreach ($documents as $document) {
if ($document->isEmbargoed()) {
$documents->remove($document);
}
}
}
return $documents;
}
public function getDocumentSetsByPage(SiteTree $page)
{
return $page->getDocumentSets();
}
/**

View File

@ -5,7 +5,6 @@
*/
class DMSDocumentAddController extends LeftAndMain
{
private static $url_segment = 'pages/adddocument';
private static $url_priority = 60;
private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
@ -13,7 +12,13 @@ class DMSDocumentAddController extends LeftAndMain
private static $tree_class = 'SiteTree';
private static $session_namespace = 'CMSMain';
public static $allowed_extensions = array();
/**
* Allowed file upload extensions, will be merged with `$allowed_extensions` from {@link File}
*
* @config
* @var array
*/
private static $allowed_extensions = array();
private static $allowed_actions = array(
'getEditForm',
@ -22,27 +27,10 @@ class DMSDocumentAddController extends LeftAndMain
'documentlist'
);
/**
* Add an array of additional allowed extensions
* @static
* @param $array
*/
public static function add_allowed_extensions($array = null)
{
if (empty($array)) {
return;
}
if (is_array($array)) {
self::$allowed_extensions = $array;
} else {
self::$allowed_extensions = array($array);
}
}
/**
* Custom currentPage() method to handle opening the 'root' folder
*
* @return
* @return SiteTree
*/
public function currentPage()
{
@ -61,12 +49,27 @@ class DMSDocumentAddController extends LeftAndMain
/**
* Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
*
* @return int
*/
public function currentPageID()
{
return ($result = parent::currentPageID()) === null ? 0 : $result;
}
/**
* Get the current document set, if a document set ID was provided
*
* @return DMSDocumentSet
*/
public function getCurrentDocumentSet()
{
if ($id = $this->getRequest()->getVar('dsid')) {
return DMSDocumentSet::get()->byid($id);
}
return singleton('DMSDocumentSet');
}
/**
* @return Form
* @todo what template is used here? AssetAdmin_UploadContent.ss doesn't seem to be used anymore
@ -75,9 +78,13 @@ class DMSDocumentAddController extends LeftAndMain
{
Requirements::javascript(FRAMEWORK_DIR . '/javascript/AssetUploadField.js');
Requirements::css(FRAMEWORK_DIR . '/css/AssetUploadField.css');
Requirements::css(DMS_DIR.'/css/DMSMainCMS.css');
Requirements::css(DMS_DIR . '/css/DMSMainCMS.css');
/** @var SiteTree $page */
$page = $this->currentPage();
/** @var DMSDocumentSet $documentSet */
$documentSet = $this->getCurrentDocumentSet();
$uploadField = DMSUploadField::create('AssetUploadField', '');
$uploadField->setConfig('previewMaxWidth', 40);
$uploadField->setConfig('previewMaxHeight', 30);
@ -87,31 +94,34 @@ class DMSDocumentAddController extends LeftAndMain
$uploadField->addExtraClass('ss-assetuploadfield');
$uploadField->removeExtraClass('ss-uploadfield');
$uploadField->setTemplate('AssetUploadField');
$uploadField->setRecord($page);
$uploadField->setRecord($documentSet);
$uploadField->getValidator()->setAllowedExtensions(
array_filter(array_merge(Config::inst()->get('File', 'allowed_extensions'), self::$allowed_extensions))
);
$uploadField->getValidator()->setAllowedExtensions($this->getAllowedExtensions());
$exts = $uploadField->getValidator()->getAllowedExtensions();
asort($exts);
$backlink = $this->Backlink();
$done = "
<a class=\"ss-ui-button ss-ui-action-constructive cms-panel-link ui-corner-all\" href=\"".$backlink."\">
Done!
<a class=\"ss-ui-button ss-ui-action-constructive cms-panel-link ui-corner-all\" href=\"" . $backlink . "\">
" . _t('UploadField.DONE', 'DONE') . "
</a>";
$addExistingField = new DMSDocumentAddExistingField('AddExisting', 'Add Existing');
$addExistingField->setRecord($page);
$addExistingField = new DMSDocumentAddExistingField(
'AddExisting',
_t('DMSDocumentAddExistingField.ADDEXISTING', 'Add Existing')
);
$addExistingField->setRecord($documentSet);
$form = new Form(
$this,
'getEditForm',
new FieldList(
new TabSet(
'Main',
_t('DMSDocumentAddController.MAINTAB', 'Main'),
new Tab(
'From your computer',
_t('UploadField.FROMCOMPUTER', 'From your computer'),
new HiddenField('ID', false, $page->ID),
new HiddenField('DSID', false, $documentSet->ID),
$uploadField,
new LiteralField(
'AllowedExtensions',
@ -123,7 +133,7 @@ class DMSDocumentAddController extends LeftAndMain
)
),
new Tab(
'From the CMS',
_t('UploadField.FROMCMS', 'From the CMS'),
$addExistingField
)
)
@ -136,17 +146,6 @@ class DMSDocumentAddController extends LeftAndMain
$form->Backlink = $backlink;
// Don't use AssetAdmin_EditForm, as it assumes a different panel structure
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
/*$form->Fields()->push(
new LiteralField(
'BackLink',
sprintf(
'<a href="%s" class="backlink ss-ui-button cms-panel-link" data-icon="back">%s</a>',
Controller::join_links(singleton('AssetAdmin')->Link('show'), $folder ? $folder->ID : 0),
_t('AssetAdmin.BackToFolder', 'Back to folder')
)
)
);*/
//$form->loadDataFrom($folder);
return $form;
}
@ -170,29 +169,43 @@ class DMSDocumentAddController extends LeftAndMain
}
$items->push(new ArrayData(array(
'Title' => 'Add Document',
'Title' => _t('DMSDocumentSet.ADDDOCUMENTBUTTON', 'Add Document'),
'Link' => $this->Link()
)));
return $items;
}
/**
* Returns the link to be used to return the user after uploading a document. If a document set ID (dsid) is present
* then it will be redirected back to the page that owns the document set. @todo redirect back to the document set
*
* If no document set ID is present then we assume that it has been added from the model admin, so redirect back to
* that instead.
*
* @return string
*/
public function Backlink()
{
$pageID = $this->currentPageID();
return Controller::join_links(singleton('CMSPagesController')->Link(), 'edit/show', $pageID);
if (!$this->getRequest()->getVar('dsid')) {
$modelAdmin = new DMSDocumentAdmin;
$modelAdmin->init();
return $modelAdmin->Link();
}
return Controller::join_links(singleton('CMSPagesController')->Link(), 'edit/show', $this->currentPageID());
}
public function documentautocomplete()
{
$term = (isset($_GET['term'])) ? $_GET['term'] : '';
$term_sql = Convert::raw2sql($term);
$term = (string) $this->getRequest()->getVar('term');
$termSql = Convert::raw2sql($term);
$data = DMSDocument::get()
->where(
"(\"ID\" LIKE '%".$term_sql."%' OR \"Filename\" LIKE '%".$term_sql."%' OR \"Title\" LIKE '%".$term_sql."%')"
)
->sort('ID ASC')
->limit(20);
->where(
'("ID" LIKE \'%' . $termSql . '%\' OR "Filename" LIKE \'%' . $termSql . '%\''
. ' OR "Title" LIKE \'%' . $termSql . '%\')'
)
->sort('ID ASC')
->limit(20);
$return = array();
foreach ($data as $doc) {
@ -202,22 +215,25 @@ class DMSDocumentAddController extends LeftAndMain
);
}
return json_encode($return);
return Convert::raw2json($return);
}
/**
* Link an existing document to the given document set ID
* @return string JSON
*/
public function linkdocument()
{
$return = array('error' => _t('UploadField.FIELDNOTSET', 'Could not add document to page'));
$page = $this->currentPage();
if (!empty($page)) {
$document = DataObject::get_by_id('DMSDocument', (int) $_GET['documentID']);
$document->addPage($page);
$documentSet = $this->getCurrentDocumentSet();
if (!empty($documentSet)) {
$document = DMSDocument::get()->byId($this->getRequest()->getVar('documentID'));
$documentSet->Documents()->add($document);
$buttonText = '<button class="ss-uploadfield-item-edit ss-ui-button ui-corner-all"'
. ' title="Edit this document" data-icon="pencil">'
. 'Edit<span class="toggle-details"><span class="toggle-details-icon"></span></span></button>';
. ' title="' . _t('DMSDocument.EDITDOCUMENT', 'Edit this document') . '" data-icon="pencil">'
. _t('DMSDocument.EDIT', 'Edit') . '<span class="toggle-details">'
. '<span class="toggle-details-icon"></span></span></button>';
// Collect all output data.
$return = array(
@ -232,21 +248,27 @@ class DMSDocumentAddController extends LeftAndMain
);
}
return json_encode($return);
return Convert::raw2json($return);
}
/**
* Returns HTML representing a list of documents that are associated with the given page ID, across all document
* sets.
*
* @return string HTML
*/
public function documentlist()
{
if (!isset($_GET['pageID'])) {
if (!$this->getRequest()->getVar('pageID')) {
return $this->httpError(400);
}
$page = SiteTree::get()->byId($_GET['pageID']);
$page = SiteTree::get()->byId($this->getRequest()->getVar('pageID'));
if ($page && $page->Documents()->count() > 0) {
if ($page && $page->getAllDocuments()->count() > 0) {
$list = '<ul>';
foreach ($page->Documents() as $document) {
foreach ($page->getAllDocuments() as $document) {
$list .= sprintf(
'<li><a class="add-document" data-document-id="%s">%s</a></li>',
$document->ID,
@ -264,4 +286,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')
)
);
}
}

View File

@ -63,9 +63,12 @@ class DMSDocumentAddExistingField extends CompositeField
/**
* Sets or unsets the use of the "field" class in the template. The "field" class adds Javascript behaviour
* that causes unwelcome hiding side-effects when this Field is used within the link editor pop-up
*
* @return $this
*/
public function setUseFieldClass($use = false)
{
$this->useFieldContext = $use;
return $this;
}
}

View File

@ -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;
}
}

View File

@ -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')
@ -106,7 +106,7 @@ class DMSGridFieldDeleteAction extends GridFieldDeleteAction implements
}
$delete = false;
if ($item->Pages()->Count() <= 1) {
if ($item->getRelatedPages()->count() <= 1) {
$delete = true;
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}
/**

View File

@ -5,136 +5,57 @@
*/
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'=>'<a target=\'_blank\' class=\'file-url\' href=\'$Link\'>$FilenameWithoutID</a>'
)
);
//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());
}
$documents->removeDuplicates();
return $documents;
}
public function onBeforeDelete()
@ -147,11 +68,11 @@ class DMSSiteTreeExtension extends DataExtension
// Only remove if record doesn't still exist on live stage.
if (!$existsOnOtherStage) {
$dmsDocuments = $this->owner->Documents();
$dmsDocuments = $this->owner->getAllDocuments();
foreach ($dmsDocuments as $document) {
//if the document is only associated with one page, i.e. only associated with this page
if ($document->Pages()->Count() <= 1) {
//delete the document before deleting this page
// If the document is only associated with one page, i.e. only associated with this page
if ($document->getRelatedPages()->count() <= 1) {
// Delete the document before deleting this page
$document->delete();
}
}
@ -160,8 +81,8 @@ class DMSSiteTreeExtension extends DataExtension
public function onBeforePublish()
{
$embargoedDocuments = $this->owner->Documents()->filter('EmbargoedUntilPublished', true);
if ($embargoedDocuments->Count() > 0) {
$embargoedDocuments = $this->owner->getAllDocuments()->filter('EmbargoedUntilPublished', true);
if ($embargoedDocuments->count() > 0) {
foreach ($embargoedDocuments as $doc) {
$doc->EmbargoedUntilPublished = false;
$doc->write();
@ -169,8 +90,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() . ')';
}
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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
*

View File

@ -0,0 +1,153 @@
<?php
/**
* A document set is attached to Pages, and contains many DMSDocuments
*/
class DMSDocumentSet extends DataObject
{
private static $db = array(
'Title' => '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:
*
* <code>
* public function updateDocuments($document)
* {
* // do something
* }
* </code>
*
* @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()
{
// PHP 5.3 only
$self = $this;
$this->beforeUpdateCMSFields(function (FieldList $fields) use ($self) {
// Don't put the GridField for documents in until the set has been created
if (!$self->isInDB()) {
$fields->addFieldToTab(
'Root.Main',
LiteralField::create(
'GridFieldNotice',
'<p class="message warning">' . _t(
'DMSDocumentSet.GRIDFIELD_NOTICE',
'Managing documents will be available once you have created this document set.'
) . '</p>'
),
'Title'
);
return;
}
// Document listing
$gridFieldConfig = GridFieldConfig::create()
->addComponents(
new GridFieldToolbarHeader(),
new GridFieldFilterHeader(),
new GridFieldSortableHeader(),
// new GridFieldOrderableRows('DocumentSort'),
new GridFieldDataColumns(),
new GridFieldEditButton(),
// Special delete dialog to handle custom behaviour of unlinking and deleting
new DMSGridFieldDeleteAction(),
new GridFieldDetailForm()
);
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' => '<a target=\'_blank\' class=\'file-url\' href=\'$Link\'>$FilenameWithoutID</a>'
)
);
// Override delete functionality with this class
$gridFieldConfig->getComponentByType('GridFieldDetailForm')
->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
$gridField = GridField::create(
'Documents',
false,
$self->Documents(), //->Sort('DocumentSort'),
$gridFieldConfig
);
$gridField->addExtraClass('documents');
$gridFieldConfig->addComponent(
$addNewButton = new DMSGridFieldAddNewButton,
'GridFieldExportButton'
);
$addNewButton->setDocumentSetId($self->ID);
$fields->removeByName('Documents');
$fields->addFieldToTab('Root.Main', $gridField);
});
$this->addRequirements();
return parent::getCMSFields();
}
/**
* Add required CSS and Javascript requirements for managing documents
*
* @return $this
*/
protected function addRequirements()
{
// 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');
return $this;
}
}

View File

@ -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 to 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`.

View File

@ -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
```

View File

@ -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);
```

View File

@ -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();
```

View File

@ -14,3 +14,7 @@
## CMS user help
* TBC
### Changelogs
* [2.0.0 (unreleased)](changelogs/2.0.0.md)

View File

@ -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();
```

View File

@ -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

View File

@ -4,10 +4,10 @@
$.entwine('ss', function ($) {
$('.document-add-existing').entwine({
adddocument: function (document_id) {
var page_id = $(this).closest('form').find(':input[name=ID]').val();
var documentSetId = $(this).closest('form').find('input[name="DSID"]').val();
jQuery.ajax(
'admin/pages/adddocument/linkdocument?ID=' + page_id + '&documentID=' + document_id,
'admin/pages/adddocument/linkdocument?dsid=' + documentSetId + '&documentID=' + document_id,
{
dataType: 'json',
success: function (data, textstatus) {
@ -92,7 +92,7 @@
doclist.load(
'admin/pages/adddocument/documentlist?pageID=' + $(this).val()
);
}
});
@ -128,4 +128,4 @@
});
});
}(jQuery));
}(jQuery));

View File

@ -8,7 +8,7 @@ window.tmpl.cache['ss-uploadfield-addtemplate'] = tmpl(
'<label class="ss-uploadfield-item-name">' +
'<span class="name" title="{%=file.name%}">{%=file.name%}</span> ' +
'{% if (!file.error) { %}' +
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.AddedToPage', 'Added to Page')+'">'+ss.i18n._t('UploadField.AddedToPage', 'Added to Page')+'</div>' +
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.AddedToDocumentSet', 'Added to Document Set')+'">'+ss.i18n._t('UploadField.AddedToDocumentSet', 'Added to Document Set')+'</div>' +
'{% } else { %}' +
'<div class="ss-uploadfield-item-status ui-state-error-text" title="{%=o.options.errorMessages[file.error] || file.error%}">{%=o.options.errorMessages[file.error] || file.error%}</div>' +
'{% } %}' +
@ -27,4 +27,4 @@ window.tmpl.cache['ss-uploadfield-addtemplate'] = tmpl(
'{% } %}' +
'</li>' +
'{% } %}'
);
);

View File

@ -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,15 @@ en:
Versions: Versions
DOWNLOAD: "Download {title}"
LASTCHANGED: "Last changed: {date}"
DMSDocumentSet:
ADDDOCUMENTBUTTON: Add Document
ADDDOCUMENTSBUTTON: Add Documents
GRIDFIELD_NOTICE: Managing documents will be available once you have created this document set.
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 +37,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 +48,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

View File

@ -1,64 +1,43 @@
<div id="document" class="ss-add field treedropdown searchable">
<div class="document-add-existing <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
<% if useFieldContext %>
<h3>
<% else %>
<div>
<% end_if %>
<span class="step-label">
<% if useFieldContext %>
<span class="flyout">1</span><span class="arrow"></span>
<strong class="title">Link a Document</strong>
<% else %>
<% end_if %>
</span>
<% if useFieldContext %>
</h3>
<% else %>
</div>
<% end_if %>
<div class="document-add-existing <% if $useFieldContext %>field<% else %>link-editor-context<% end_if %>">
<% if $useFieldContext %><h3><% else %><div><% end_if %>
<span class="step-label">
<% if $useFieldContext %>
<span class="flyout">1</span><span class="arrow"></span>
<strong class="title"><%t DMSDocumentAddExistingField.LINKADOCUMENT "Link a Document" %></strong>
<% end_if %>
</span>
<% if $useFieldContext %></h3><% else %></div><% end_if %>
<% if useFieldContext %>
<% else %>
<label>Link a Document</label>
<div class="middleColumn">
<% end_if %>
<input class="document-autocomplete text" type="text" placeholder="Search by ID or filename" />
<!-- <span>or Add from page</span> -->
$fieldByName(PageSelector)
<% if not $useFieldContext %>
<label><%t DMSDocumentAddExistingField.LINKADOCUMENT "Link a Document" %></label>
<div class="middleColumn">
<% end_if %>
<input class="document-autocomplete text" type="text" placeholder="<%t DMSDocumentAddExistingField.AUTOCOMPLETE "Search by ID or filename" %>" />
$fieldByName(PageSelector)
<div class="document-list"></div>
<% if not $useFieldContext %>
</div>
<% end_if %>
</div>
<div class="document-list"></div>
<% if useFieldContext %>
<% else %>
</div>
<% end_if %>
</div>
<div class="ss-assetuploadfield <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
<div class="step4">
<span class="step-label">
<% if useFieldContext %>
<span class="flyout">2</span><span class="arrow"></span>
<strong class="title">Edit Document Details</strong>
<% else %>
<label>Selected Document</label>
<% end_if %>
</span>
</div>
<!-- <div class="fileOverview"></div> -->
<% if useFieldContext %>
<% else %>
<div class="middleColumn">
<% end_if %>
<ul class="files ss-uploadfield-files ss-add-files"></ul>
<% if useFieldContext %>
<% else %>
</div>
<% end_if %>
</div>
</div>
<div class="ss-assetuploadfield <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
<div class="step4">
<span class="step-label">
<% if useFieldContext %>
<span class="flyout">2</span><span class="arrow"></span>
<strong class="title"><%t DMSDocumentAddExistingField.EDITDOCUMENTDETAILS "Edit Document Details" %></strong>
<% else %>
<label><%t DMSDocumentAddExistingField.SELECTED "Selected Document" %></label>
<% end_if %>
</span>
</div>
<% if not $useFieldContext %>
<div class="middleColumn">
<% end_if %>
<ul class="files ss-uploadfield-files ss-add-files"></ul>
<% if not $useFieldContext %>
</div>
<% end_if %>
</div>
</div>

View File

@ -12,7 +12,7 @@
<div class="clear"><!-- --></div>
</label>
<div class="ss-uploadfield-item-actions">
<% if Top.isDisabled || Top.isReadonly %>
<% if $Top.isDisabled || $Top.isReadonly %>
<% else %>
$UploadFieldFileButtons
<% end_if %>
@ -25,11 +25,11 @@
<% end_loop %>
<% end_if %>
</ul>
<% if isDisabled || isReadonly %>
<% if isSaveable %>
<% if $isDisabled || $isReadonly %>
<% if $isSaveable %>
<% else %>
<div class="ss-uploadfield-item">
<em><% _t('FileIFrameField.ATTACHONCESAVED2', 'Files can be attached once you have saved the record for the first time.') %></em>
<em><%t FileIFrameField.ATTACHONCESAVED2 "Files can be attached once you have saved the record for the first time." %></em>
</div>
<% end_if %>
<% else %>
@ -41,8 +41,8 @@
<label class="ss-uploadfield-item-name"><b>
<% _t('UploadField.ATTACHFILE', 'Attach a file') %>
</b></label>
<label class="ss-uploadfield-fromcomputer ss-ui-button ui-corner-all" title="<% _t('UploadField.FROMCOMPUTERINFO', 'Upload from your computer') %>" data-icon="drive-upload">
<% _t('UploadField.FROMCOMPUTER', 'From your computer') %>
<label class="ss-uploadfield-fromcomputer ss-ui-button ui-corner-all" title="<%t UploadField.FROMCOMPUTERINFO 'Upload from your computer' %>" data-icon="drive-upload">
<%t UploadField.FROMCOMPUTER 'From your computer' %>
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %> />
</label>
<div class="clear"><!-- --></div>

View File

@ -0,0 +1,11 @@
<% if $getDocuments %>
<div class="documentsets-set">
<% if $Title %>
<h3>$Title</h3>
<% end_if %>
<% loop $getDocuments %>
<% include Document %>
<% end_loop %>
</div>
<% end_if %>

View File

@ -0,0 +1,7 @@
<% if $getDocumentSets %>
<div class="documentsets">
<% loop $getDocumentSets %>
<% include DocumentSet %>
<% end_loop %>
</div>
<% end_if %>

View File

@ -1,8 +0,0 @@
<% if $PageDocuments %>
<div class="documents">
<h3><%t DMSDocument.PLURALNAME "Documents" %></h3>
<% loop $PageDocuments %>
<% include Document %>
<% end_loop %>
</div>
<% end_if %>

View File

@ -0,0 +1,86 @@
<?php
class DMSDocumentSetTest extends SapphireTest
{
protected static $fixture_file = 'dmstest.yml';
/**
* Ensure that getDocuments is extensible
*/
public function testGetDocumentsIsExtensible()
{
DMSDocumentSet::add_extension('StubRelatedDocumentExtension');
$set = new DMSDocumentSet;
$documents = $set->getDocuments();
$this->assertCount(1, $documents);
$this->assertSame('Extended', $documents->first()->Filename);
}
/**
* Test that the GridField for documents isn't shown until you've saved the set
*/
public function testGridFieldShowsWhenSetIsSaved()
{
$set = DMSDocumentSet::create();
// Not in database yet
$fields = $set->getCMSFields();
$this->assertNull($fields->fieldByName('Root.Main.Documents'));
$gridFieldNotice = $fields->fieldByName('Root.Main.GridFieldNotice');
$this->assertNotNull($gridFieldNotice);
$this->assertContains('Managing documents will be available', $gridFieldNotice->getContent());
// In the database
$set->Title = 'Testing';
$set->write();
$fields = $set->getCMSFields();
$this->assertNotNull($fields->fieldByName('Root.Main.Documents'));
$this->assertNull($fields->fieldByName('Root.Main.GridFieldNotice'));
}
public function testRelations()
{
$s1 = $this->objFromFixture('SiteTree', 's1');
$s2 = $this->objFromFixture('SiteTree', 's2');
$s4 = $this->objFromFixture('SiteTree', 's4');
$ds1 = $this->objFromFixture('DMSDocumentSet', 'ds1');
$ds2 = $this->objFromFixture('DMSDocumentSet', 'ds2');
$ds3 = $this->objFromFixture('DMSDocumentSet', 'ds3');
$this->assertCount(0, $s4->getDocumentSets(), 'Page 4 has no document sets associated');
$this->assertCount(2, $s1->getDocumentSets(), 'Page 1 has 2 document sets');
$this->assertEquals(array($ds1->ID, $ds2->ID), $s1->getDocumentSets()->column('ID'));
}
/**
* Test that various components exist in the GridField config. See {@link DMSDocumentSet::getCMSFields} for context.
*/
public function testDocumentGridFieldConfig()
{
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
$fields = $set->getCMSFields();
$gridField = $fields->fieldByName('Root.Main.Documents');
$this->assertTrue((bool) $gridField->hasClass('documents'));
/** @var GridFieldConfig $config */
$config = $gridField->getConfig();
$this->assertNotNull($config->getComponentByType('DMSGridFieldDeleteAction'));
$this->assertNotNull($addNew = $config->getComponentByType('DMSGridFieldAddNewButton'));
$this->assertSame($set->ID, $addNew->getDocumentSetId());
if (class_exists('GridFieldPaginatorWithShowAll')) {
$this->assertNotNull($config->getComponentByType('GridFieldPaginatorWithShowAll'));
} else {
$paginator = $config->getComponentByType('GridFieldPaginator');
$this->assertNotNull($paginator);
$this->assertSame(15, $paginator->getItemsPerPage());
}
$sortableAssertion = class_exists('GridFieldSortableRows') ? 'assertNotNull' : 'assertNull';
$this->$sortableAssertion($config->getComponentByType('GridFieldSortableRows'));
}
}

View File

@ -19,150 +19,6 @@ class DMSDocumentTest extends SapphireTest
self::$is_running_test = $this->originalIsRunningTest;
}
public function testPageRelations()
{
$s1 = $this->objFromFixture('SiteTree', 's1');
$s2 = $this->objFromFixture('SiteTree', 's2');
$s3 = $this->objFromFixture('SiteTree', 's3');
$s4 = $this->objFromFixture('SiteTree', 's4');
$s5 = $this->objFromFixture('SiteTree', 's5');
$s6 = $this->objFromFixture('SiteTree', 's6');
$d1 = $this->objFromFixture('DMSDocument', 'd1');
$pages = $d1->Pages();
$pagesArray = $pages->toArray();
$this->assertEquals($pagesArray[0]->ID, $s1->ID, 'Page 1 associated correctly');
$this->assertEquals($pagesArray[1]->ID, $s2->ID, 'Page 2 associated correctly');
$this->assertEquals($pagesArray[2]->ID, $s3->ID, 'Page 3 associated correctly');
$this->assertEquals($pagesArray[3]->ID, $s4->ID, 'Page 4 associated correctly');
$this->assertEquals($pagesArray[4]->ID, $s5->ID, 'Page 5 associated correctly');
$this->assertEquals($pagesArray[5]->ID, $s6->ID, 'Page 6 associated correctly');
}
public function testAddPageRelation()
{
$s1 = $this->objFromFixture('SiteTree', 's1');
$s2 = $this->objFromFixture('SiteTree', 's2');
$s3 = $this->objFromFixture('SiteTree', 's3');
$doc = new DMSDocument();
$doc->Filename = 'test file';
$doc->Folder = '0';
$doc->write();
$doc->addPage($s1);
$doc->addPage($s2);
$doc->addPage($s3);
$pages = $doc->Pages();
$pagesArray = $pages->toArray();
$this->assertEquals($pagesArray[0]->ID, $s1->ID, 'Page 1 associated correctly');
$this->assertEquals($pagesArray[1]->ID, $s2->ID, 'Page 2 associated correctly');
$this->assertEquals($pagesArray[2]->ID, $s3->ID, 'Page 3 associated correctly');
$doc->removePage($s1);
$pages = $doc->Pages();
$pagesArray = $pages->toArray(); // Page 1 is missing
$this->assertEquals($pagesArray[0]->ID, $s2->ID, 'Page 2 still associated correctly');
$this->assertEquals($pagesArray[1]->ID, $s3->ID, 'Page 3 still associated correctly');
$documents = $s2->Documents();
$documentsArray = $documents->toArray();
$this->assertDOSContains(
array(
array('Filename' => $doc->Filename)
),
$documentsArray,
'Document associated with page'
);
$doc->removeAllPages();
$pages = $doc->Pages();
$this->assertEquals($pages->Count(), 0, 'All pages removed');
$documents = $s2->Documents();
$documentsArray = $documents->toArray();
$this->assertNotContains($doc, $documentsArray, 'Document no longer associated with page');
}
public function testDeletingPageWithAssociatedDocuments()
{
$s1 = $this->objFromFixture('SiteTree', 's1');
$s2 = $this->objFromFixture('SiteTree', 's2');
$s2->publish('Stage', 'Live');
$s2ID = $s2->ID;
$doc = new DMSDocument();
$doc->Filename = 'delete test file';
$doc->Folder = '0';
$doc->write();
$doc->addPage($s1);
$doc->addPage($s2);
$s1->delete();
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'", false);
$this->assertEquals(
$documents->Count(),
'1',
"Deleting one of the associated page doesn't affect the single document we created"
);
$s2->delete();
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
$this->assertEquals(
$documents->Count(),
'1',
"Deleting a page from draft stage doesn't delete the associated docs,"
. "even if it's the last page they're associated with"
);
$s2 = Versioned::get_one_by_stage('SiteTree', 'Live', sprintf('"SiteTree"."ID" = %d', $s2ID));
$s2->doDeleteFromLive();
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
$this->assertEquals(
$documents->Count(),
'0',
'However, deleting the live version of the last page that a document is '
. 'associated with causes that document to be deleted as well'
);
}
public function testUnpublishPageWithAssociatedDocuments()
{
$s2 = $this->objFromFixture('SiteTree', 's2');
$s2->publish('Stage', 'Live');
$s2ID = $s2->ID;
$doc = new DMSDocument();
$doc->Filename = 'delete test file';
$doc->Folder = '0';
$doc->write();
$doc->addPage($s2);
$s2->doDeleteFromLive();
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
$this->assertEquals(
$documents->Count(),
'1',
"Deleting a page from live stage doesn't delete the associated docs,"
. "even if it's the last page they're associated with"
);
$s2 = Versioned::get_one_by_stage('SiteTree', 'Stage', sprintf('"SiteTree"."ID" = %d', $s2ID));
$s2->delete();
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
$this->assertEquals(
$documents->Count(),
'0',
'However, deleting the draft version of the last page that a document is '
. 'associated with causes that document to be deleted as well'
);
}
public function testDefaultDownloadBehabiourCMSFields()
{
$document = singleton('DMSDocument');
@ -364,4 +220,15 @@ class DMSDocumentTest extends SapphireTest
$doc3 = $this->objFromFixture('DMSDocument', 'doc-anyone');
$this->assertEquals('', $doc3->getPermissionDeniedReason());
}
/**
* Ensure that all pages that a document belongs to (via many document sets) can be retrieved in one list
*/
public function testGetRelatedPages()
{
$document = $this->objFromFixture('DMSDocument', 'd1');
$result = $document->getRelatedPages();
$this->assertCount(3, $result, 'Document 1 is related to 3 Pages');
$this->assertSame(array('s1', 's2', 's3'), $result->column('URLSegment'));
}
}

View File

@ -161,7 +161,7 @@ class DMSEmbargoTest extends SapphireTest
$doc->Folder = "0";
$dID = $doc->write();
$doc->addPage($s1);
$s1->getDocumentSets()->first()->getDocuments()->add($doc);
$s1->publish('Stage', 'Live');
$s1->doPublish();

View File

@ -24,24 +24,24 @@ class DMSGridFieldAddNewButtonTest extends SapphireTest
}
/**
* Test that when no page ID is present then it is not added to the URL for "add document"
* Test that when no document set ID is present then it is not added to the URL for "add document"
*/
public function testNoPageIdInAddUrlWhenNotProvided()
{
$fragments = $this->button->getHTMLFragments($this->gridField);
$result = array_pop($fragments)->getValue();
$this->assertNotContains('?ID', $result);
$this->assertNotContains('?dsid', $result);
}
/**
* Test that when a page ID is provided, it is added onto the "add document" link
* Test that when a document set ID is provided, it is added onto the "add document" link
*/
public function testPageIdAddedToLinkWhenProvided()
{
$this->button->setPageId(123);
$this->button->setDocumentSetId(123);
$fragments = $this->button->getHTMLFragments($this->gridField);
$result = array_pop($fragments)->getValue();
$this->assertContains('?ID=123', $result);
$this->assertContains('?dsid=123', $result);
}
}

View File

@ -1,7 +1,7 @@
<?php
class DMSTest extends FunctionalTest
{
protected $usesDatabase = true;
protected static $fixture_file = 'dmstest.yml';
/**
* Stub PDF files for testing
@ -16,6 +16,11 @@ class DMSTest extends FunctionalTest
public static $dmsFolderOld;
public static $dmsFolderSizeOld;
/**
* @var DMS
*/
protected $dms;
public function setUp()
{
parent::setUp();
@ -28,6 +33,8 @@ class DMSTest extends FunctionalTest
//clear out the test folder (in case a broken test doesn't delete it)
$this->delete(BASE_PATH . DIRECTORY_SEPARATOR . 'dms-assets-test-1234');
$this->dms = DMS::inst();
}
public function tearDown()
@ -82,10 +89,8 @@ class DMSTest extends FunctionalTest
public function testDMSStorage()
{
$dms = DMS::inst();
$file = self::$testFile;
$document = $dms->storeDocument($file);
$document = $this->dms->storeDocument($file);
$this->assertNotNull($document, "Document object created");
$this->assertTrue(
@ -100,13 +105,11 @@ class DMSTest extends FunctionalTest
public function testDMSFolderSpanning()
{
DMS::$dmsFolderSize = 5;
$dms = DMS::inst();
$file = self::$testFile;
$documents = array();
for ($i = 0; $i <= 16; $i++) {
$document = $dms->storeDocument($file);
$document = $this->dms->storeDocument($file);
$this->assertNotNull($document, "Document object created on run number: $i");
$this->assertTrue(file_exists($document->getFullPath()));
$documents[] = $document;
@ -131,10 +134,8 @@ class DMSTest extends FunctionalTest
public function testReplaceDocument()
{
$dms = DMS::inst();
// Store the first document
$document = $dms->storeDocument(self::$testFile);
$document = $this->dms->storeDocument(self::$testFile);
$document->Title = "My custom title";
$document->Description = "My custom description";
$document->write();
@ -158,4 +159,39 @@ class DMSTest extends FunctionalTest
$this->assertEquals("My custom title", $document->Title, "Custom title not modified");
$this->assertEquals("My custom description", $document->Description, "Custom description not modified");
}
/**
* Test that documents can be returned by a given page
*/
public function testGetByPageWithoutEmbargoes()
{
$pageWithEmbargoes = $this->objFromFixture('SiteTree', 's3');
$documents = $this->dms->getByPage($pageWithEmbargoes);
// Fixture: 6 documents in set, 1 is embargoed
$this->assertCount(5, $documents, 'Embargoed documents are excluded by default');
$this->assertContainsOnlyInstancesOf('DMSDocument', $documents);
}
/**
* Test that embargoed documents are excluded from getByPage
*/
public function testGetByPageWithEmbargoedDocuments()
{
$pageWithEmbargoes = $this->objFromFixture('SiteTree', 's3');
$documents = $this->dms->getByPage($pageWithEmbargoes, true);
// Fixture: 6 documents in set, 1 is embargoed
$this->assertCount(6, $documents, 'Embargoed documents can be included');
$this->assertContainsOnlyInstancesOf('DMSDocument', $documents);
}
/**
* Test that document sets can be retrieved for a given page
*/
public function testGetDocumentSetsByPage()
{
$page = $this->objFromFixture('SiteTree', 's1');
$sets = $this->dms->getDocumentSetsByPage($page);
$this->assertCount(2, $sets);
$this->assertContainsOnlyInstancesOf('DMSDocumentSet', $sets);
}
}

View File

@ -3,16 +3,38 @@
class StubRelatedDocumentExtension extends DataExtension implements TestOnly
{
/**
* Push a fixed array entry into the datalist for extensibility testing
* For method {@link DMSDocument::getRelatedDocuments}
*
* @param ArrayList $relatedDocuments
* @return ArrayList
*/
public function updateRelatedDocuments(ArrayList $relatedDocuments)
public function updateRelatedDocuments($relatedDocuments)
{
$relatedDocuments->push($this->getFakeDocument());
return $relatedDocuments;
}
/**
* For method {@link DMSDocumentSet::getDocuments}
*
* @param ArrayList $relatedDocuments
* @return ArrayList
*/
public function updateDocuments($documents)
{
$documents->push($this->getFakeDocument());
return $documents;
}
/**
* Return a dummy document for testing purposes
*
* @return DMSDocument
*/
protected function getFakeDocument()
{
$fakeDocument = new DMSDocument;
$fakeDocument->Filename = 'Extended';
$relatedDocuments->push($fakeDocument);
return $relatedDocuments;
return $fakeDocument;
}
}

View File

@ -0,0 +1,38 @@
<?php
class DMSDocumentAddControllerTest extends FunctionalTest
{
protected static $fixture_file = 'dms/tests/dmstest.yml';
public function setUp()
{
parent::setUp();
$this->logInWithPermission();
}
public function testCurrentPageReturnsSiteTree()
{
$controller = new DMSDocumentAddController;
$this->assertInstanceOf('SiteTree', $controller->currentPage());
}
public function testGetCurrentDocumentSetReturnsDocumentSet()
{
$controller = new DMSDocumentAddController;
$this->assertInstanceOf('DMSDocumentSet', $controller->getCurrentDocumentSet());
}
/**
* Test that extra allowed extensions are merged into the default upload field allowed extensions
*/
public function testGetAllowedExtensions()
{
$controller = new DMSDocumentAddController;
Config::inst()->remove('File', 'allowed_extensions');
Config::inst()->update('File', 'allowed_extensions', array('jpg', 'gif'));
$this->assertSame(array('jpg', 'gif'), $controller->getAllowedExtensions());
Config::inst()->update('DMSDocumentAddController', 'allowed_extensions', array('php', 'php5'));
$this->assertSame(array('jpg', 'gif', 'php', 'php5'), $controller->getAllowedExtensions());
}
}

View File

@ -0,0 +1,22 @@
<?php
class DMSDocumentAddExistingFieldTest extends SapphireTest
{
/**
* The constructor should create a tree dropdown field
*/
public function testFieldContainsTreeDropdownField()
{
$field = new DMSDocumentAddExistingField('Test', 'Test');
$this->assertContainsOnlyInstancesOf('TreeDropdownField', $field->getChildren());
$this->assertSame('PageSelector', $field->getChildren()->first()->getName());
}
public function testSetAndGetRecord()
{
$record = new DMSDocumentSet;
$field = new DMSDocumentAddExistingField('Test');
$field->setRecord($record);
$this->assertSame($record, $field->getRecord());
}
}

View File

@ -0,0 +1,40 @@
<?php
class DMSUploadFieldTest extends SapphireTest
{
/**
* @var DMSUploadField
*/
protected $field;
public function setUp()
{
parent::setUp();
$this->field = new DMSUploadField('StubUploadField');
}
/**
* The validator is coded to always return true. Replace this test if this behaviour changes in future.
*/
public function testValidatorAlwaysReturnsTrue()
{
$this->assertTrue($this->field->validate('foo'));
}
public function testGetItemHandler()
{
$this->assertInstanceOf('DMSUploadField_ItemHandler', $this->field->getItemHandler(123));
}
/**
* Ensure that the folder name can be get/set and that the value set is casted to a string
*/
public function testCanGetAndSetFolderName()
{
$this->field->setFolderName('qwerty');
$this->assertSame('qwerty', $this->field->getFolderName());
$this->field->setFolderName(123);
$this->assertSame('123', $this->field->getFolderName());
}
}

View File

@ -1,7 +1,11 @@
DMSDocumentSet:
ds1:
Title: Document Set 1
SiteTree:
s1:
Title: testPage1
URLSegment: s1
DocumentSets: =>DMSDocumentSet.ds1
s2:
Title: testPage2
URLSegment: s2

View File

@ -1,22 +1,25 @@
SiteTree:
s1:
Title: testPage1
Title: testPage1 has document sets
URLSegment: s1
s2:
Title: testPage2
Title: testPage2 a document set
URLSegment: s2
s3:
Title: testPage3
Title: testPage3 has document sets with embargoed docs
URLSegment: s3
s4:
Title: testPage4
Title: testPage4 has no sets
URLSegment: s4
s5:
Title: testPage5
Title: testPage5 has no sets
URLSegment: s5
s6:
Title: testPage6
Title: testPage6 has no sets
URLSegment: s6
s7:
Title: testPage7 has documents embargoed until publish
URLSegment: s7
DMSTag:
t1:
Category: tag1
@ -43,17 +46,40 @@ Group:
cable-guy:
Code: cable-guy
Title: "Cable Guy"
Member:
editor:
Name: editor
Groups: =>Group.content-author
non-editor:
Name: cable-guy
Groups: =>Group.cable-guy
DMSDocumentSet:
ds1:
Title: Document Set 1
Page: =>SiteTree.s1
ds2:
Title: Document Set 2
Page: =>SiteTree.s1
ds3:
Title: Document Set 3
Page: =>SiteTree.s2
ds4:
Title: Set containing embargoed documents
Page: =>SiteTree.s3
ds5:
Title: Set containing embargoed until publish documents
Page: =>SiteTree.s7
DMSDocument:
d1:
Filename: test-file-file-doesnt-exist-1
Folder: 5
Tags: =>DMSTag.t1, =>DMSTag.t2, =>DMSTag.t3, =>DMSTag.t4
Pages: =>SiteTree.s1, =>SiteTree.s2, =>SiteTree.s3, =>SiteTree.s4, =>SiteTree.s5, =>SiteTree.s6
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
d2:
Filename: test-file-file-doesnt-exist-2
Folder: 5
Tags: =>DMSTag.t5, =>DMSTag.t6
Pages: =>SiteTree.s5, =>SiteTree.s6
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
document_with_relations:
Filename: file-with-relations
Folder: 5
@ -64,26 +90,34 @@ DMSDocument:
CanEditType: LoggedInUsers
Folder: 5
Tags: =>DMSTag.t1, =>DMSTag.t2, =>DMSTag.t3, =>DMSTag.t4
Pages: =>SiteTree.s1, =>SiteTree.s2, =>SiteTree.s3, =>SiteTree.s4, =>SiteTree.s5, =>SiteTree.s6
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
doc-anyone:
FileName: doc-anyone
CanViewType: Anyone
Folder: 5
Tags: =>DMSTag.t1, =>DMSTag.t2, =>DMSTag.t3, =>DMSTag.t4
Pages: =>SiteTree.s1, =>SiteTree.s2, =>SiteTree.s3, =>SiteTree.s4, =>SiteTree.s5, =>SiteTree.s6
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
doc-only-these-users:
FileName: doc-only-these-users
CanViewType: OnlyTheseUsers
CanEditType: OnlyTheseUsers
Folder: 5
Tags: =>DMSTag.t1, =>DMSTag.t2, =>DMSTag.t3, =>DMSTag.t4
Pages: =>SiteTree.s1, =>SiteTree.s2, =>SiteTree.s3, =>SiteTree.s4, =>SiteTree.s5, =>SiteTree.s6
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
ViewerGroups: =>Group.content-author
EditorGroups: =>Group.content-author
Member:
editor:
Name: editor
Groups: =>Group.content-author
non-editor:
Name: cable-guy
Groups: =>Group.cable-guy
embargoed_document1:
Filename: foobar
EmbargoedIndefinitely: true
Folder: 5
Sets: =>DMSDocumentSet.ds4
embargo_until_publish1:
Filename: embargo-until-publish1
EmbargoUntilPublish: true
Folder: 5
Sets: =>DMSDocumentSet.ds5
embargo_until_publish2:
Filename: embargo-until-publish2
EmbargoUntilPublish: true
Folder: 5
Sets: =>DMSDocumentSet.ds5

View File

@ -0,0 +1,85 @@
<?php
class DMSSiteTreeExtensionTest extends SapphireTest
{
protected static $fixture_file = 'dms/tests/dmstest.yml';
protected $requiredExtensions = array(
'SiteTree' => array('DMSSiteTreeExtension')
);
/**
* Ensure that setting the configuration property "documents_enabled" to false for a page type will prevent the
* CMS fields from being modified.
*
* Also ensures that a correctly named Document Sets GridField is added to the fields in the right place.
*
* Note: the (1) is the number of sets defined for this SiteTree in the fixture
*
* @dataProvider documentSetEnabledConfigProvider
*/
public function testCanDisableDocumentSetsTab($configSetting, $assertionMethod)
{
Config::inst()->update('SiteTree', 'documents_enabled', $configSetting);
$siteTree = $this->objFromFixture('SiteTree', 's2');
$this->$assertionMethod($siteTree->getCMSFields()->fieldByName('Root.Document Sets (1).Document Sets'));
}
/**
* @return array[]
*/
public function documentSetEnabledConfigProvider()
{
return array(
array(true, 'assertNotNull'),
array(false, 'assertNull')
);
}
/**
* Tests for the Document Sets GridField.
*
* Note: the (1) is the number of sets defined for this SiteTree in the fixture
*/
public function testDocumentSetsGridFieldIsCorrectlyConfigured()
{
Config::inst()->update('SiteTree', 'documents_enabled', true);
$siteTree = $this->objFromFixture('SiteTree', 's2');
$gridField = $siteTree->getCMSFields()->fieldByName('Root.Document Sets (1).Document Sets');
$this->assertInstanceOf('GridField', $gridField);
$this->assertTrue((bool) $gridField->hasClass('documentsets'));
}
/**
* Ensure that a page title can be retrieved with the number of related documents it has (across all document sets).
*
* See fixtures for relationships that define this result.
*/
public function testGetTitleWithNumberOfDocuments()
{
$siteTree = $this->objFromFixture('SiteTree', 's1');
$this->assertSame('testPage1 has document sets (5)', $siteTree->getTitleWithNumberOfDocuments());
}
/**
* Ensure that documents marked as "embargo until publish" are unmarked as such when a page containing them is
* published
*/
public function testOnBeforePublishUnEmbargoesDocumentsSetAsEmbargoedUntilPublish()
{
$siteTree = $this->objFromFixture('SiteTree', 's7');
$siteTree->doPublish();
// Fixture defines this page as having two documents via one set
foreach (array('embargo-until-publish1', 'embargo-until-publish2') as $filename) {
$this->assertFalse(
(bool) $siteTree->getAllDocuments()
->filter('Filename', 'embargo-until-publish1')
->first()
->EmbargoedUntilPublished
);
}
$this->assertCount(0, $siteTree->getAllDocuments()->filter('EmbargoedUntilPublished', true));
}
}