mirror of
https://github.com/silverstripe/silverstripe-dms
synced 2024-10-22 14:05:56 +02:00
NEW Query Builder functionality added
This enhancement adds the ability to add documents to a document set based on a list of filters added from DMSDocument. Fixes #96
This commit is contained in:
parent
6b80f32832
commit
6b25237ec6
16
_config/querybuilder.yml
Normal file
16
_config/querybuilder.yml
Normal file
@ -0,0 +1,16 @@
|
||||
DMSDocument:
|
||||
searchable_fields:
|
||||
Title:
|
||||
title: "Document title matches ..."
|
||||
Description:
|
||||
title: "Document summary matches ..."
|
||||
CreatedByID:
|
||||
title: 'Document created by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
LastEditedByID:
|
||||
title: 'Document last changed by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
Filename:
|
||||
title: 'File name'
|
@ -120,8 +120,6 @@ class DMSDocumentAddController extends LeftAndMain
|
||||
_t('DMSDocumentAddController.MAINTAB', 'Main'),
|
||||
new Tab(
|
||||
_t('UploadField.FROMCOMPUTER', 'From your computer'),
|
||||
new HiddenField('ID', false, $page->ID),
|
||||
new HiddenField('DSID', false, $documentSet->ID),
|
||||
$uploadField,
|
||||
new LiteralField(
|
||||
'AllowedExtensions',
|
||||
@ -146,6 +144,8 @@ 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(HiddenField::create('ID', false, $documentSet->ID));
|
||||
$form->Fields()->push(HiddenField::create('DSID', false, $documentSet->ID));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class DMSUploadField extends UploadField
|
||||
// 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);
|
||||
$record->Documents()->add($doc, array('BelongsToSet' => 1));
|
||||
}
|
||||
|
||||
return $doc;
|
||||
|
118
code/forms/JsonField.php
Normal file
118
code/forms/JsonField.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class JsonField combines form inputs into a key-value pair
|
||||
*/
|
||||
class JsonField extends CompositeField
|
||||
{
|
||||
public function __construct($name, $children = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
|
||||
if ($children instanceof FieldList || is_array($children)) {
|
||||
foreach ($children as $child) {
|
||||
$this->setChildName($child);
|
||||
}
|
||||
} else {
|
||||
$children = is_array(func_get_args()) ? func_get_args() : array();
|
||||
if (!empty($children)) {
|
||||
array_shift($children);
|
||||
}
|
||||
foreach ($children as $child) {
|
||||
$this->setChildName($child);
|
||||
}
|
||||
}
|
||||
parent::__construct($children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the child object
|
||||
*
|
||||
* @param FormField $child
|
||||
*/
|
||||
private function setChildName($child)
|
||||
{
|
||||
$child->setName("{$this->getName()}[{$child->getName()}]");
|
||||
}
|
||||
|
||||
public function hasData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parent's behaviour as it's no longer required
|
||||
*
|
||||
* @param array $list
|
||||
* @param bool $saveableOnly
|
||||
*/
|
||||
public function collateDataFields(&$list, $saveableOnly = false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removed empty key-value pairs from $haystack
|
||||
*
|
||||
* @param $haystack
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function arrayFilterEmptyRecursive($haystack)
|
||||
{
|
||||
foreach ($haystack as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$haystack[$key] = $this->arrayFilterEmptyRecursive($haystack[$key]);
|
||||
}
|
||||
if (empty($haystack[$key])) {
|
||||
unset($haystack[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides parent behaviour to remove empty elements
|
||||
*
|
||||
* @return mixed|null|string
|
||||
*/
|
||||
public function dataValue()
|
||||
{
|
||||
$result = null;
|
||||
if (is_array($this->value)) {
|
||||
$this->value = $this->arrayFilterEmptyRecursive($this->value);
|
||||
$result = (!empty($this->value)) ? Convert::array2json($this->value) : $result;
|
||||
} else {
|
||||
$result = parent::dataValue();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
if (is_string($value) && !empty($value)) {
|
||||
$value = Convert::json2array($value);
|
||||
} elseif (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
|
||||
$pattern = "/^{$this->getName()}\[(.*)\]$/";
|
||||
foreach ($this->children as $c) {
|
||||
$title = $c->getName();
|
||||
preg_match($pattern, $title, $matches);
|
||||
if (!empty($matches[1]) && isset($value[$matches[1]])) {
|
||||
$c->setValue($value[$matches[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
* @property Varchar Title
|
||||
* @property Text Description
|
||||
* @property int ViewCount
|
||||
* @property DateTime LastChanged
|
||||
* @property Boolean EmbargoedIndefinitely
|
||||
* @property Boolean EmbargoedUntilPublished
|
||||
* @property DateTime EmbargoedUntilDate
|
||||
@ -22,6 +21,11 @@
|
||||
* @method ManyManyList ViewerGroups
|
||||
* @method ManyManyList EditorGroups
|
||||
*
|
||||
* @method Member CreatedBy
|
||||
* @property Int CreatedByID
|
||||
* @method Member LastEditedBy
|
||||
* @property Int LastEditedByID
|
||||
*
|
||||
*/
|
||||
class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
{
|
||||
@ -31,9 +35,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
"Title" => 'Varchar(1024)', // eg. "Energy Saving Report for Year 2011, New Zealand LandCorp"
|
||||
"Description" => 'Text',
|
||||
"ViewCount" => 'Int',
|
||||
// When this document's file was created or last replaced (small changes like updating title don't count)
|
||||
"LastChanged" => 'SS_DateTime',
|
||||
|
||||
"EmbargoedIndefinitely" => 'Boolean(false)',
|
||||
"EmbargoedUntilPublished" => 'Boolean(false)',
|
||||
"EmbargoedUntilDate" => 'SS_DateTime',
|
||||
@ -47,6 +48,12 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
'Sets' => 'DMSDocumentSet'
|
||||
);
|
||||
|
||||
private static $has_one = array(
|
||||
'CoverImage' => 'Image',
|
||||
'CreatedBy' => 'Member',
|
||||
'LastEditedBy' => 'Member',
|
||||
);
|
||||
|
||||
private static $many_many = array(
|
||||
'RelatedDocuments' => 'DMSDocument',
|
||||
'Tags' => 'DMSTag',
|
||||
@ -58,23 +65,13 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
'ID' => 'ID',
|
||||
'Title' => 'Title',
|
||||
'FilenameWithoutID' => 'Filename',
|
||||
'LastChanged' => 'LastChanged'
|
||||
'LastEdited' => 'LastEdited'
|
||||
);
|
||||
|
||||
private static $singular_name = 'Document';
|
||||
|
||||
private static $plural_name = 'Documents';
|
||||
|
||||
private static $searchable_fields = array(
|
||||
'ID' => array(
|
||||
'filter' => 'ExactMatchFilter',
|
||||
'field' => 'NumericField'
|
||||
),
|
||||
'Title',
|
||||
'Filename',
|
||||
'LastChanged'
|
||||
);
|
||||
|
||||
private static $summary_fields = array(
|
||||
'Filename' => 'Filename',
|
||||
'Title' => 'Title',
|
||||
@ -122,7 +119,12 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($member && Permission::checkMember($member, array('ADMIN', 'SITETREE_EDIT_ALL', 'SITETREE_VIEW_ALL'))) {
|
||||
if ($member && Permission::checkMember($member, array(
|
||||
'ADMIN',
|
||||
'SITETREE_EDIT_ALL',
|
||||
'SITETREE_VIEW_ALL',
|
||||
))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,13 +158,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
}
|
||||
|
||||
// Do early admin check
|
||||
if ($member && Permission::checkMember($member,
|
||||
array(
|
||||
if ($member && Permission::checkMember(
|
||||
$member,
|
||||
array(
|
||||
'ADMIN',
|
||||
'SITETREE_EDIT_ALL',
|
||||
'SITETREE_VIEW_ALL',
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@ -813,7 +816,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
$this->Title = basename($filePath, '.'.$extension);
|
||||
}
|
||||
|
||||
$this->LastChanged = SS_Datetime::now()->Rfc2822();
|
||||
$this->write();
|
||||
|
||||
return $this;
|
||||
@ -906,8 +908,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
$fieldsTop = $this->getFieldsForFile($relationList->count());
|
||||
$fields->add($fieldsTop);
|
||||
|
||||
$fields->add(new TextField('Title', 'Title'));
|
||||
$fields->add(new TextareaField('Description', 'Description'));
|
||||
$fields->add(TextField::create('Title', _t('DMSDocument.TITLE', 'Title')));
|
||||
$fields->add(TextareaField::create('Description', _t('DMSDocument.DESCRIPTION', 'Description')));
|
||||
|
||||
$coverImageField = UploadField::create('CoverImage', _t('DMSDocument.COVERIMAGE', 'Cover Image'));
|
||||
$coverImageField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif'));
|
||||
$coverImageField->setConfig('allowedMaxFileNumber', 1);
|
||||
$fields->add($coverImageField);
|
||||
|
||||
|
||||
$downloadBehaviorSource = array(
|
||||
'open' => _t('DMSDocument.OPENINBROWSER', 'Open in browser'),
|
||||
@ -984,7 +992,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
);
|
||||
$versionsGridFieldConfig->getComponentByType('GridFieldDataColumns')
|
||||
->setDisplayFields(Config::inst()->get('DMSDocument_versions', 'display_fields'))
|
||||
->setFieldCasting(array('LastChanged'=>"Datetime->Ago"))
|
||||
->setFieldFormatting(
|
||||
array(
|
||||
'FilenameWithoutID' => '<a target=\'_blank\' class=\'file-url\' href=\'$Link\'>'
|
||||
@ -1112,6 +1119,19 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
return CompositeField::create($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a title to use on the frontend, preferably the "title", otherwise the filename without it's numeric ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
if ($this->getField('Title')) {
|
||||
return $this->getField('Title');
|
||||
}
|
||||
return $this->FilenameWithoutID;
|
||||
}
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
@ -1120,7 +1140,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
//set the embargo options from the OptionSetField created in the getCMSFields method
|
||||
//do not write after clearing the embargo (write happens automatically)
|
||||
$savedDate = $this->EmbargoedUntilDate;
|
||||
$this->clearEmbargo(false); //clear all previous settings and re-apply them on save
|
||||
$this->clearEmbargo(false); // Clear all previous settings and re-apply them on save
|
||||
|
||||
if ($this->Embargo == 'Published') {
|
||||
$this->embargoUntilPublished(false);
|
||||
@ -1138,7 +1158,15 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
$this->expireAtDate($this->ExpireAtDate, false);
|
||||
} else {
|
||||
$this->clearExpiry(false);
|
||||
} //clear all previous settings
|
||||
} // Clear all previous settings
|
||||
}
|
||||
|
||||
// Set user fields
|
||||
if ($currentUserID = Member::currentUserID()) {
|
||||
if (!$this->CreatedByID) {
|
||||
$this->CreatedByID = $currentUserID;
|
||||
}
|
||||
$this->LastEditedByID = $currentUserID;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1266,11 +1294,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
_t('AssetTableField.LASTEDIT', 'Last changed') . ':',
|
||||
$this->LastEdited
|
||||
),
|
||||
new DateField_Disabled(
|
||||
"LastChanged",
|
||||
_t('AssetTableField.LASTCHANGED', 'Last replaced') . ':',
|
||||
$this->LastChanged
|
||||
),
|
||||
new ReadonlyField("PublishedOn", "Published on". ':', $publishedOnValue),
|
||||
new ReadonlyField("ReferencedOn", "Referenced on". ':', $relationListCountValue),
|
||||
new ReadonlyField("ViewCount", "View count". ':', $this->ViewCount)
|
||||
|
@ -1,19 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* A document set is attached to Pages, and contains many DMSDocuments
|
||||
*
|
||||
* @property Varchar Title
|
||||
* @property Text KeyValuePairs
|
||||
* @property Enum SortBy
|
||||
* @property Enum SortByDirection
|
||||
*/
|
||||
class DMSDocumentSet extends DataObject
|
||||
{
|
||||
|
||||
private static $db = array(
|
||||
'Title' => 'Varchar(255)'
|
||||
'Title' => 'Varchar(255)',
|
||||
'KeyValuePairs' => 'Text',
|
||||
'SortBy' => "Enum('LastEdited,Created,Title')')",
|
||||
'SortByDirection' => "Enum('DESC,ASC')')",
|
||||
);
|
||||
|
||||
private static $has_one = array(
|
||||
'Page' => 'SiteTree'
|
||||
'Page' => 'SiteTree',
|
||||
);
|
||||
|
||||
private static $many_many = array(
|
||||
'Documents' => 'DMSDocument'
|
||||
'Documents' => 'DMSDocument',
|
||||
);
|
||||
|
||||
private static $many_many_extraFields = array(
|
||||
'Documents' => array(
|
||||
'BelongsToSet' => 'Boolean(1)', // Flag indicating if a document was added directly to a set - in which case it is set - or added via the query-builder.
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
@ -28,14 +43,12 @@ class DMSDocumentSet extends DataObject
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @return DataList
|
||||
* @return DataList|null
|
||||
*/
|
||||
public function getDocuments()
|
||||
{
|
||||
$documents = $this->Documents();
|
||||
|
||||
$this->extend('updateDocuments', $documents);
|
||||
|
||||
return $documents;
|
||||
}
|
||||
|
||||
@ -49,8 +62,11 @@ class DMSDocumentSet extends DataObject
|
||||
{
|
||||
// PHP 5.3 only
|
||||
$self = $this;
|
||||
|
||||
$this->beforeUpdateCMSFields(function (FieldList $fields) use ($self) {
|
||||
$fields->removeFieldsFromTab(
|
||||
'Root.Main',
|
||||
array('KeyValuePairs', 'SortBy', 'SortByDirection')
|
||||
);
|
||||
// Don't put the GridField for documents in until the set has been created
|
||||
if (!$self->isInDB()) {
|
||||
$fields->addFieldToTab(
|
||||
@ -64,70 +80,67 @@ class DMSDocumentSet extends DataObject
|
||||
),
|
||||
'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);
|
||||
// Document listing
|
||||
$gridFieldConfig = GridFieldConfig::create()
|
||||
->addComponents(
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldFilterHeader(),
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldDataColumns(),
|
||||
new GridFieldEditButton(),
|
||||
// Special delete dialog to handle custom behaviour of unlinking and deleting
|
||||
new DMSGridFieldDeleteAction(),
|
||||
new GridFieldDetailForm()
|
||||
);
|
||||
|
||||
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);
|
||||
if (class_exists('GridFieldPaginatorWithShowAll')) {
|
||||
$paginatorComponent = new GridFieldPaginatorWithShowAll(15);
|
||||
} else {
|
||||
$paginatorComponent = new GridFieldPaginator(15);
|
||||
}
|
||||
$gridFieldConfig->addComponent($sortableComponent);
|
||||
}
|
||||
$gridFieldConfig->addComponent($paginatorComponent);
|
||||
|
||||
// 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>'
|
||||
)
|
||||
if (class_exists('GridFieldSortableRows')) {
|
||||
$sortableComponent = new GridFieldSortableRows('DocumentSort');
|
||||
// setUsePagination method removed from newer version of SortableGridField.
|
||||
if (method_exists($sortableComponent, 'setUsePagination')) {
|
||||
$sortableComponent->setUsePagination(false)->setForceRedraw(true);
|
||||
}
|
||||
$gridFieldConfig->addComponent($sortableComponent);
|
||||
}
|
||||
|
||||
$gridFieldConfig->getComponentByType('GridFieldDataColumns')
|
||||
->setDisplayFields(DMSDocument::create()->config()->get('display_fields'))
|
||||
->setFieldCasting(array('LastEdited' => '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(),
|
||||
$gridFieldConfig
|
||||
);
|
||||
$gridField->setModelClass('DMSDocument');
|
||||
$gridField->addExtraClass('documents');
|
||||
|
||||
// Override delete functionality with this class
|
||||
$gridFieldConfig->getComponentByType('GridFieldDetailForm')
|
||||
->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
|
||||
$gridFieldConfig->addComponent(
|
||||
$addNewButton = new DMSGridFieldAddNewButton,
|
||||
'GridFieldExportButton'
|
||||
);
|
||||
$addNewButton->setDocumentSetId($self->ID);
|
||||
|
||||
$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);
|
||||
$fields->removeByName('Documents');
|
||||
$fields->addFieldToTab('Root.Main', $gridField);
|
||||
$self->addQueryFields($fields);
|
||||
}
|
||||
});
|
||||
$this->addRequirements();
|
||||
return parent::getCMSFields();
|
||||
@ -150,4 +163,95 @@ class DMSDocumentSet extends DataObject
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the query fields to build the document logic to the DMSDocumentSet.
|
||||
*
|
||||
* To extend use the following from within an Extension subclass:
|
||||
*
|
||||
* <code>
|
||||
* public function updateQueryFields($result)
|
||||
* {
|
||||
* // Do something here
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param FieldList $fields
|
||||
*/
|
||||
public function addQueryFields($fields)
|
||||
{
|
||||
/** @var DMSDocument $doc */
|
||||
$doc = singleton('DMSDocument');
|
||||
/** @var FormField $field */
|
||||
$dmsDocFields = $doc->scaffoldSearchFields(array('fieldClasses' => true));
|
||||
$membersMap = Member::get()->map('ID', 'Name')->toArray();
|
||||
asort($membersMap);
|
||||
foreach ($dmsDocFields as $field) {
|
||||
// Apply field customisations where necessary
|
||||
if (in_array($field->getName(), array('CreatedByID', 'LastEditedByID', 'LastEditedByID'))) {
|
||||
/** @var ListboxField $field */
|
||||
$field->setMultiple(true)->setSource($membersMap);
|
||||
}
|
||||
}
|
||||
$keyValPairs = JsonField::create('KeyValuePairs', $dmsDocFields->toArray());
|
||||
|
||||
// Now lastly add the sort fields
|
||||
$sortedBy = FieldGroup::create('SortedBy', array(
|
||||
DropdownField::create('SortBy', '', array(
|
||||
'LastEdited' => 'Last changed',
|
||||
'Created' => 'Created',
|
||||
'Title' => 'Document title',
|
||||
), 'LastEdited'),
|
||||
DropdownField::create('SortByDirection', '', $this->dbObject('SortByDirection')->enumValues(), 'DESC'),
|
||||
));
|
||||
|
||||
$sortedBy->setTitle(_t('DMSDocumentSet.SORTED_BY', 'Sort the document set by:'));
|
||||
$fields->addFieldsToTab('Root.QueryBuilder', array($keyValPairs, $sortedBy));
|
||||
$this->extend('updateQueryFields', $fields);
|
||||
}
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
||||
$this->saveLinkedDocuments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
|
||||
*
|
||||
* @return ArrayList|null
|
||||
*/
|
||||
public function saveLinkedDocuments()
|
||||
{
|
||||
// Documents that belong to just this set.
|
||||
/** @var ManyManyList $originals */
|
||||
$originals = $this->Documents();
|
||||
if (!(empty($this->KeyValuePairs)) && $this->isChanged('KeyValuePairs')) {
|
||||
$keyValuesPair = Convert::json2array($this->KeyValuePairs);
|
||||
/** @var DMSDocument $dmsDoc */
|
||||
$dmsDoc = singleton('DMSDocument');
|
||||
$context = $dmsDoc->getDefaultSearchContext();
|
||||
|
||||
$sortBy = $this->SortBy ? $this->SortBy : 'LastEdited';
|
||||
$sortByDirection = $this->SortByDirection ? $this->SortByDirection : 'DESC';
|
||||
$sortedBy = sprintf('%s %s', $sortBy, $sortByDirection);
|
||||
/** @var DataList $documents */
|
||||
$documents = $context->getResults($keyValuesPair, $sortedBy);
|
||||
$now = SS_Datetime::now()->Rfc2822();
|
||||
$documents = $documents->where(
|
||||
"\"EmbargoedIndefinitely\" = 0 AND ".
|
||||
" \"EmbargoedUntilPublished\" = 0 AND ".
|
||||
"(\"EmbargoedUntilDate\" IS NULL OR " .
|
||||
"(\"EmbargoedUntilDate\" IS NOT NULL AND '{$now}' >= \"EmbargoedUntilDate\")) AND " .
|
||||
"\"ExpireAtDate\" IS NULL OR (\"ExpireAtDate\" IS NOT NULL AND '{$now}' < \"ExpireAtDate\")"
|
||||
);
|
||||
|
||||
// Remove all BelongsToSet as the rules have changed
|
||||
$originals->removeByFilter('"BelongsToSet" = 0');
|
||||
foreach ($documents as $document) {
|
||||
$originals->add($document, array('BelongsToSet' => 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class DMSDocument_versions extends DataObject
|
||||
private static $display_fields = array(
|
||||
'VersionCounter' => 'Version Counter',
|
||||
'FilenameWithoutID' => 'Filename',
|
||||
'LastChanged' => 'Last Changed'
|
||||
'LastEdited' => 'Last Changed'
|
||||
);
|
||||
|
||||
private static $summary_fields = array(
|
||||
@ -47,7 +47,7 @@ class DMSDocument_versions extends DataObject
|
||||
);
|
||||
|
||||
private static $default_sort = array(
|
||||
'LastChanged' => 'DESC'
|
||||
'LastEdited' => 'DESC'
|
||||
);
|
||||
|
||||
|
||||
|
@ -28,3 +28,31 @@ DMSDocumentAddController:
|
||||
- php
|
||||
- php5
|
||||
```
|
||||
|
||||
## Adding fields to the Query Builder
|
||||
Query builder fields are read from the DMSDocument::searchable_fields property set in [querybuilder.yml](../../_config/querybuilder.yml). Some default fields are provided and can be customised
|
||||
by modifying the field and/or filter properties of a field or adding a new field entirely.
|
||||
|
||||
[See here for information](https://docs.silverstripe.org/en/developer_guides/model/searchfilters/) on how to modify search filters and [see here for more information](https://docs.silverstripe.org/en/developer_guides/forms/field_types/common_subclasses/)
|
||||
on the field types available.
|
||||
|
||||
The default searchable filters available to query builder is as follows:
|
||||
|
||||
```yaml
|
||||
DMSDocument:
|
||||
searchable_fields:
|
||||
Title:
|
||||
title: "Document title matches ..."
|
||||
Description:
|
||||
title: "Document summary matches ..."
|
||||
CreatedByID:
|
||||
title: 'Document created by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
LastEditedByID:
|
||||
title: 'Document last changed by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
Filename:
|
||||
title: 'File name'
|
||||
```
|
@ -9,6 +9,8 @@ en:
|
||||
TYPE: 'File type'
|
||||
URL: URL
|
||||
DMSDocument:
|
||||
COVERIMAGE: Cover Image
|
||||
DESCRIPTION: Description
|
||||
EDIT: Edit
|
||||
EDITDOCUMENT: Edit this document
|
||||
PLURALNAME: Documents
|
||||
@ -18,6 +20,7 @@ en:
|
||||
Versions: Versions
|
||||
DOWNLOAD: "Download {title}"
|
||||
LASTCHANGED: "Last changed: {date}"
|
||||
TITLE: Title
|
||||
DMSDocumentSet:
|
||||
ADDDOCUMENTBUTTON: Add Document
|
||||
ADDDOCUMENTSBUTTON: Add Documents
|
||||
|
@ -1,9 +1,11 @@
|
||||
<% if not $isHidden %>
|
||||
<div class="document $Extension">
|
||||
<% if $Title %>
|
||||
<h4><a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$Title %>">$Title</a></h4>
|
||||
<% else %>
|
||||
<h4><a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$FilenameWithoutID %>">$FilenameWithoutID</a></h4>
|
||||
<h4><a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$getTitle %>">$getTitle</a></h4>
|
||||
|
||||
<% if $CoverImage %>
|
||||
<div class="article-thumbnail">
|
||||
$CoverImage.FitMax(100, 100)
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<p class="details"><% include DocumentDetails %></p>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<strong>$FilenameWithoutID</strong>
|
||||
| $Extension
|
||||
| $FileSizeFormatted
|
||||
| <%t DMSDocument.LASTCHANGED "Last changed: {date}" date=$LastChanged.Nice %>
|
||||
| <%t DMSDocument.LASTCHANGED "Last changed: {date}" date=$LastEdited.Nice %>
|
@ -83,4 +83,57 @@ class DMSDocumentSetTest extends SapphireTest
|
||||
$sortableAssertion = class_exists('GridFieldSortableRows') ? 'assertNotNull' : 'assertNull';
|
||||
$this->$sortableAssertion($config->getComponentByType('GridFieldSortableRows'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that query fields can be added to the gridfield
|
||||
*/
|
||||
public function testAddQueryFields()
|
||||
{
|
||||
|
||||
/** @var DMSDocumentSet $set */
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds6');
|
||||
/** @var FieldList $fields */
|
||||
$fields = new FieldList(new TabSet('Root'));
|
||||
/** @var FieldList $fields */
|
||||
$set->addQueryFields($fields);
|
||||
$keyValuePairs = $fields->dataFieldByName('KeyValuePairs');
|
||||
$this->assertNotNull(
|
||||
$keyValuePairs,
|
||||
'addQueryFields() includes KeyValuePairs composite field'
|
||||
);
|
||||
$this->assertNotNull(
|
||||
$keyValuePairs->fieldByName('KeyValuePairs[Title]'),
|
||||
'addQueryFields() includes KeyValuePairs composite field'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddQueryFieldsIsExtensible()
|
||||
{
|
||||
|
||||
DMSDocumentSet::add_extension('StubDocumentSetMockExtension');
|
||||
|
||||
$fields = new FieldList(new TabSet('Root'));
|
||||
$set = new DMSDocumentSet;
|
||||
$set->addQueryFields($fields);
|
||||
|
||||
$this->assertNotNull(
|
||||
$fields->dataFieldByName('ExtendedField'),
|
||||
'addQueryFields() is extendible as it included the field from the extension'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that extra documents are added after write
|
||||
*/
|
||||
public function testSaveLinkedDocuments()
|
||||
{
|
||||
/** @var DMSDocumentSet $set */
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'dsSaveLinkedDocuments');
|
||||
// Assert initially docs
|
||||
$this->assertEquals(1, $set->getDocuments()->count(), 'Set has 1 document');
|
||||
// Now apply the query and see if 2 extras were added with CreatedByID filter
|
||||
$set->KeyValuePairs = '{"Filename":"extradoc3"}';
|
||||
$set->saveLinkedDocuments();
|
||||
$this->assertEquals(2, $set->getDocuments()->count(), 'Set has 2 documents');
|
||||
}
|
||||
}
|
||||
|
@ -247,4 +247,16 @@ class DMSDocumentTest extends SapphireTest
|
||||
$this->assertCount(3, $result, 'Document 1 is related to 3 Pages');
|
||||
$this->assertSame(array('s1', 's2', 's3'), $result->column('URLSegment'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the title is returned if it is set, otherwise the filename without ID
|
||||
*/
|
||||
public function testGetTitleOrFilenameWithoutId()
|
||||
{
|
||||
$d1 = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$this->assertSame('test-file-file-doesnt-exist-1', $d1->getTitle());
|
||||
|
||||
$d2 = $this->objFromFixture('DMSDocument', 'd2');
|
||||
$this->assertSame('File That Doesn\'t Exist (Title)', $d2->getTitle());
|
||||
}
|
||||
}
|
||||
|
47
tests/JsonFieldTest.php
Normal file
47
tests/JsonFieldTest.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
class JsonFieldTest extends SapphireTest
|
||||
{
|
||||
public function testJsonFieldConstructorMultiWays()
|
||||
{
|
||||
$jsonField = new JsonField('MyJsonField', new FieldList(
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
));
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
|
||||
$jsonField = new JsonField('MyJsonField', array(new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')));
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
|
||||
$jsonField = new JsonField(
|
||||
'MyJsonField',
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
);
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
}
|
||||
|
||||
public function testJsonFieldDataValueCouldDealWithArray()
|
||||
{
|
||||
$jsonField = new JsonField('MyJsonField', new FieldList(
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
));
|
||||
$jsonField->setValue($value = array(
|
||||
'MyJsonField'=>array(
|
||||
'FirstName' => 'Normann',
|
||||
'Surname' => 'Lou',
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertEquals($jsonField->dataValue(), Convert::array2json($value));
|
||||
$jsonField->setValue($value = array(
|
||||
'MyJsonField'=>array(),
|
||||
));
|
||||
$this->assertNull($jsonField->dataValue());
|
||||
}
|
||||
}
|
24
tests/Stub/StubDocumentSetMockExtension.php
Normal file
24
tests/Stub/StubDocumentSetMockExtension.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class StubDocumentSetMockExtension
|
||||
*
|
||||
* @package dms
|
||||
*/
|
||||
class StubDocumentSetMockExtension extends DataExtension implements TestOnly
|
||||
{
|
||||
/**
|
||||
*
|
||||
* For method {@link DMSDocumentSet::addQueryFields}
|
||||
*
|
||||
* @param FieldList $fields
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function updateQueryFields($fields)
|
||||
{
|
||||
$fields->addFieldToTab('Root.QueryBuilder', new TextField('ExtendedField'));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class StubRelatedDocumentExtension
|
||||
*
|
||||
* @package dms
|
||||
*/
|
||||
class StubRelatedDocumentExtension extends DataExtension implements TestOnly
|
||||
{
|
||||
/**
|
||||
|
@ -20,6 +20,12 @@ SiteTree:
|
||||
s7:
|
||||
Title: testPage7 has documents embargoed until publish
|
||||
URLSegment: s7
|
||||
s8:
|
||||
Title: testPage8
|
||||
URLSegment: s8
|
||||
s9:
|
||||
Title: testPage9
|
||||
URLSegment: s9
|
||||
DMSTag:
|
||||
t1:
|
||||
Category: tag1
|
||||
@ -69,6 +75,12 @@ DMSDocumentSet:
|
||||
ds5:
|
||||
Title: Set containing embargoed until publish documents
|
||||
Page: =>SiteTree.s7
|
||||
ds6:
|
||||
Title: Test Set 6
|
||||
Page: =>SiteTree.s8
|
||||
dsSaveLinkedDocuments:
|
||||
Title: Test Set 6
|
||||
Page: =>SiteTree.s9
|
||||
DMSDocument:
|
||||
d1:
|
||||
Filename: test-file-file-doesnt-exist-1
|
||||
@ -78,6 +90,7 @@ DMSDocument:
|
||||
d2:
|
||||
Filename: test-file-file-doesnt-exist-2
|
||||
Folder: 5
|
||||
Title: File That Doesn't Exist (Title)
|
||||
Tags: =>DMSTag.t5, =>DMSTag.t6
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
document_with_relations:
|
||||
@ -121,3 +134,23 @@ DMSDocument:
|
||||
EmbargoUntilPublish: true
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds5
|
||||
extraDoc1:
|
||||
Filename: extradoc1
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds6
|
||||
BelongsToSet: 1
|
||||
CreatedByID: 2
|
||||
extraDoc2:
|
||||
Filename: extradoc2
|
||||
Folder: 5
|
||||
CreatedByID: 2
|
||||
BelongsToSet: 0
|
||||
extraDoc3:
|
||||
Filename: extradoc3
|
||||
Folder: 5
|
||||
BelongsToSet: 0
|
||||
CreatedByID: 2
|
||||
docSaveLinkedDocuments1:
|
||||
Filename: saveLinkedDocument1
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.dsSaveLinkedDocuments
|
Loading…
Reference in New Issue
Block a user