mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '4.3' into 4
This commit is contained in:
commit
5d7c5ffb07
6
_config/gridfield.yml
Normal file
6
_config/gridfield.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
Name: gridfieldconfig
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
SilverStripe\Forms\GridField\FormAction\StateStore:
|
||||||
|
class: SilverStripe\Forms\GridField\FormAction\SessionStore
|
@ -472,11 +472,29 @@ functionality. See [How to Create a GridFieldComponent](../how_tos/create_a_grid
|
|||||||
|
|
||||||
## Saving the GridField State
|
## Saving the GridField State
|
||||||
|
|
||||||
`GridState` is a class that is used to contain the current state and actions on the `GridField`. It's transfered
|
`GridState` is a class that is used to contain the current state and actions on the `GridField`. It's transferred
|
||||||
between page requests by being inserted as a hidden field in the form.
|
between page requests by being inserted as a hidden field in the form.
|
||||||
|
|
||||||
The `GridState_Component` sets and gets data from the `GridState`.
|
The `GridState_Component` sets and gets data from the `GridState`.
|
||||||
|
|
||||||
|
## Saving GridField_FormAction state
|
||||||
|
|
||||||
|
By default state used for performing form actions is saved in the session and tagged with a key like `gf_abcd1234`. In
|
||||||
|
some cases session may not be an appropriate storage method. The storage method can be configured:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Name: mysitegridfieldconfig
|
||||||
|
After: gridfieldconfig
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
SilverStripe\Forms\GridField\FormAction\StateStore:
|
||||||
|
class: SilverStripe\Forms\GridField\FormAction\AttributeStore
|
||||||
|
```
|
||||||
|
|
||||||
|
The `AttributeStore` class configures action state to be stored in the DOM and sent back on the request that performs
|
||||||
|
the action. Custom storage methods can be created and used by implementing the `StateStore` interface and configuring
|
||||||
|
`Injector` in a similar fashion.
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
* [GridField](api:SilverStripe\Forms\GridField\GridField)
|
* [GridField](api:SilverStripe\Forms\GridField\GridField)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
- New React-based search UI for the CMS, Asset-Admin, GridFields and ModelAdmins.
|
- New React-based search UI for the CMS, Asset-Admin, GridFields and ModelAdmins.
|
||||||
- A new `GridFieldLazyLoader` component can be added to `GridField`. This will delay the fetching of data until the user access the container Tab of the GridField.
|
- A new `GridFieldLazyLoader` component can be added to `GridField`. This will delay the fetching of data until the user access the container Tab of the GridField.
|
||||||
- `SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController` is now the default CMS history controller and `SilverStripe\CMS\Controllers\CMSPageHistoryController` has been deprecated.
|
- `SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController` is now the default CMS history controller and `SilverStripe\CMS\Controllers\CMSPageHistoryController` has been deprecated.
|
||||||
|
- It's now possible to avoid storing GridField data in session. See [the documentation on GridField](../developer_guides/forms/field_types/gridfield/#saving-the-gridfield-state).
|
||||||
|
|
||||||
## Upgrading {#upgrading}
|
## Upgrading {#upgrading}
|
||||||
|
|
||||||
|
17
src/Forms/GridField/FormAction/AbstractRequestAwareStore.php
Normal file
17
src/Forms/GridField/FormAction/AbstractRequestAwareStore.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
namespace SilverStripe\Forms\GridField\FormAction;
|
||||||
|
|
||||||
|
use SilverStripe\Control\Controller;
|
||||||
|
use SilverStripe\Control\HTTPRequest;
|
||||||
|
|
||||||
|
abstract class AbstractRequestAwareStore implements StateStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return HTTPRequest
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
// Replicating existing functionality from GridField_FormAction
|
||||||
|
return Controller::curr()->getRequest();
|
||||||
|
}
|
||||||
|
}
|
36
src/Forms/GridField/FormAction/AttributeStore.php
Normal file
36
src/Forms/GridField/FormAction/AttributeStore.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
namespace SilverStripe\Forms\GridField\FormAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores GridField action state on an attribute on the action and then analyses request parameters to load it back
|
||||||
|
*/
|
||||||
|
class AttributeStore extends AbstractRequestAwareStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Save the given state against the given ID returning an associative array to be added as attributes on the form
|
||||||
|
* action
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param array $state
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function save($id, array $state)
|
||||||
|
{
|
||||||
|
// Just save the state in the attributes of the action
|
||||||
|
return [
|
||||||
|
'data-action-state' => json_encode($state),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load state for a given ID
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function load($id)
|
||||||
|
{
|
||||||
|
// Check the request
|
||||||
|
return (array) json_decode((string) $this->getRequest()->requestVar('ActionState'), true);
|
||||||
|
}
|
||||||
|
}
|
37
src/Forms/GridField/FormAction/SessionStore.php
Normal file
37
src/Forms/GridField/FormAction/SessionStore.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
namespace SilverStripe\Forms\GridField\FormAction;
|
||||||
|
|
||||||
|
use SilverStripe\Control\HTTPRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores GridField action state in the session in exactly the same way it has in the past
|
||||||
|
*/
|
||||||
|
class SessionStore extends AbstractRequestAwareStore implements StateStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Save the given state against the given ID returning an associative array to be added as attributes on the form
|
||||||
|
* action
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param array $state
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function save($id, array $state)
|
||||||
|
{
|
||||||
|
$this->getRequest()->getSession()->set($id, $state);
|
||||||
|
|
||||||
|
// This adapter does not require any additional attributes...
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load state for a given ID
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function load($id)
|
||||||
|
{
|
||||||
|
return (array) $this->getRequest()->getSession()->get($id);
|
||||||
|
}
|
||||||
|
}
|
23
src/Forms/GridField/FormAction/StateStore.php
Normal file
23
src/Forms/GridField/FormAction/StateStore.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
namespace SilverStripe\Forms\GridField\FormAction;
|
||||||
|
|
||||||
|
interface StateStore
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Save the given state against the given ID returning an associative array to be added as attributes on the form
|
||||||
|
* action
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @param array $state
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function save($id, array $state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load state for a given ID
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function load($id);
|
||||||
|
}
|
@ -9,8 +9,11 @@ use SilverStripe\Control\HTTPRequest;
|
|||||||
use SilverStripe\Control\HTTPResponse;
|
use SilverStripe\Control\HTTPResponse;
|
||||||
use SilverStripe\Control\HTTPResponse_Exception;
|
use SilverStripe\Control\HTTPResponse_Exception;
|
||||||
use SilverStripe\Control\RequestHandler;
|
use SilverStripe\Control\RequestHandler;
|
||||||
|
use SilverStripe\Core\Injector\Injector;
|
||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
use SilverStripe\Forms\FormField;
|
use SilverStripe\Forms\FormField;
|
||||||
|
use SilverStripe\Forms\GridField\FormAction\SessionStore;
|
||||||
|
use SilverStripe\Forms\GridField\FormAction\StateStore;
|
||||||
use SilverStripe\ORM\ArrayList;
|
use SilverStripe\ORM\ArrayList;
|
||||||
use SilverStripe\ORM\DataList;
|
use SilverStripe\ORM\DataList;
|
||||||
use SilverStripe\ORM\DataObject;
|
use SilverStripe\ORM\DataObject;
|
||||||
@ -1009,9 +1012,14 @@ class GridField extends FormField
|
|||||||
$state->setValue($fieldData['GridState']);
|
$state->setValue($fieldData['GridState']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the store for the "state" of actions (not the GridField)
|
||||||
|
/** @var StateStore $store */
|
||||||
|
$store = Injector::inst()->create(StateStore::class . '.' . $this->getName());
|
||||||
|
|
||||||
foreach ($data as $dataKey => $dataValue) {
|
foreach ($data as $dataKey => $dataValue) {
|
||||||
if (preg_match('/^action_gridFieldAlterAction\?StateID=(.*)/', $dataKey, $matches)) {
|
if (preg_match('/^action_gridFieldAlterAction\?StateID=(.*)/', $dataKey, $matches)) {
|
||||||
$stateChange = $request->getSession()->get($matches[1]);
|
$stateChange = $store->load($matches[1]);
|
||||||
|
|
||||||
$actionName = $stateChange['actionName'];
|
$actionName = $stateChange['actionName'];
|
||||||
|
|
||||||
$arguments = array();
|
$arguments = array();
|
||||||
|
@ -289,14 +289,18 @@ class GridFieldFilterHeader implements GridField_URLHandler, GridField_HTMLProvi
|
|||||||
}, array_keys($filters)), $filters);
|
}, array_keys($filters)), $filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$searchAction = GridField_FormAction::create($gridField, 'filter', false, 'filter', null);
|
||||||
|
$clearAction = GridField_FormAction::create($gridField, 'reset', false, 'reset', null);
|
||||||
$schema = [
|
$schema = [
|
||||||
'formSchemaUrl' => $schemaUrl,
|
'formSchemaUrl' => $schemaUrl,
|
||||||
'name' => $searchField,
|
'name' => $searchField,
|
||||||
'placeholder' => _t(__CLASS__ . '.Search', 'Search "{name}"', ['name' => $name]),
|
'placeholder' => _t(__CLASS__ . '.Search', 'Search "{name}"', ['name' => $name]),
|
||||||
'filters' => $filters ?: new \stdClass, // stdClass maps to empty json object '{}'
|
'filters' => $filters ?: new \stdClass, // stdClass maps to empty json object '{}'
|
||||||
'gridfield' => $gridField->getName(),
|
'gridfield' => $gridField->getName(),
|
||||||
'searchAction' => GridField_FormAction::create($gridField, 'filter', false, 'filter', null)->getAttribute('name'),
|
'searchAction' => $searchAction->getAttribute('name'),
|
||||||
'clearAction' => GridField_FormAction::create($gridField, 'reset', false, 'reset', null)->getAttribute('name')
|
'searchActionState' => $searchAction->getAttribute('data-action-state'),
|
||||||
|
'clearAction' => $clearAction->getAttribute('name'),
|
||||||
|
'clearActionState' => $clearAction->getAttribute('data-action-state'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return json_encode($schema);
|
return json_encode($schema);
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
namespace SilverStripe\Forms\GridField;
|
namespace SilverStripe\Forms\GridField;
|
||||||
|
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
|
use SilverStripe\Core\Injector\Injector;
|
||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
use SilverStripe\Forms\FormAction;
|
use SilverStripe\Forms\FormAction;
|
||||||
|
use SilverStripe\Forms\GridField\FormAction\StateStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the base class when you want to have an action that alters the state of the
|
* This class is the base class when you want to have an action that alters the state of the
|
||||||
@ -12,6 +14,11 @@ use SilverStripe\Forms\FormAction;
|
|||||||
*/
|
*/
|
||||||
class GridField_FormAction extends FormAction
|
class GridField_FormAction extends FormAction
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* A common string prefix for keys generated to store form action "state" against
|
||||||
|
*/
|
||||||
|
const STATE_KEY_PREFIX = 'gf_';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var GridField
|
* @var GridField
|
||||||
*/
|
*/
|
||||||
@ -80,29 +87,35 @@ class GridField_FormAction extends FormAction
|
|||||||
*/
|
*/
|
||||||
public function getAttributes()
|
public function getAttributes()
|
||||||
{
|
{
|
||||||
// Store state in session, and pass ID to client side.
|
// Determine the state that goes with this action
|
||||||
$state = array(
|
$state = array(
|
||||||
'grid' => $this->getNameFromParent(),
|
'grid' => $this->getNameFromParent(),
|
||||||
'actionName' => $this->actionName,
|
'actionName' => $this->actionName,
|
||||||
'args' => $this->args,
|
'args' => $this->args,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure $id doesn't contain only numeric characters
|
// Generate a key and attach it to the action name
|
||||||
$id = 'gf_' . substr(md5(serialize($state)), 0, 8);
|
$key = static::STATE_KEY_PREFIX . substr(md5(serialize($state)), 0, 8);
|
||||||
|
// Note: This field needs to be less than 65 chars, otherwise Suhosin security patch will strip it
|
||||||
|
$name = 'action_gridFieldAlterAction?StateID=' . $key;
|
||||||
|
|
||||||
$session = Controller::curr()->getRequest()->getSession();
|
// Define attributes
|
||||||
$session->set($id, $state);
|
$attributes = array(
|
||||||
$actionData['StateID'] = $id;
|
'name' => $name,
|
||||||
|
|
||||||
return array_merge(
|
|
||||||
parent::getAttributes(),
|
|
||||||
array(
|
|
||||||
// Note: This field needs to be less than 65 chars, otherwise Suhosin security patch
|
|
||||||
// will strip it from the requests
|
|
||||||
'name' => 'action_gridFieldAlterAction' . '?' . http_build_query($actionData),
|
|
||||||
'data-url' => $this->gridField->Link(),
|
'data-url' => $this->gridField->Link(),
|
||||||
'type' => "button",
|
'type' => "button",
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// Create a "store" for the "state" of this action
|
||||||
|
/** @var StateStore $store */
|
||||||
|
$store = Injector::inst()->create(StateStore::class . '.' . $this->gridField->getName());
|
||||||
|
// Store the state and update attributes as required
|
||||||
|
$attributes += $store->save($key, $state);
|
||||||
|
|
||||||
|
// Return attributes
|
||||||
|
return array_merge(
|
||||||
|
parent::getAttributes(),
|
||||||
|
$attributes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,4 +267,34 @@ class TreeMultiselectField extends TreeDropdownField
|
|||||||
$copy->setTitleField($this->getTitleField());
|
$copy->setTitleField($this->getTitleField());
|
||||||
return $copy;
|
return $copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @internal To be removed in 5.0
|
||||||
|
*/
|
||||||
|
protected function objectForKey($key)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fixes https://github.com/silverstripe/silverstripe-framework/issues/8332
|
||||||
|
*
|
||||||
|
* Due to historic reasons, the default (empty) value for this field is 'unchanged', even though
|
||||||
|
* the field is usually integer on the database side.
|
||||||
|
* MySQL handles that gracefully and returns an empty result in that case,
|
||||||
|
* whereas some other databases (e.g. PostgreSQL) do not support comparison
|
||||||
|
* of numeric types with string values, issuing a database error.
|
||||||
|
*
|
||||||
|
* This fix is not ideal, but supposed to keep backward compatibility for SS4.
|
||||||
|
*
|
||||||
|
* In 5.0 this method to be removed and NULL should be used instead of 'unchanged' (or an empty array. to be decided).
|
||||||
|
* In 5.0 this class to be refactored so that $this->value is always an array of values (or null)
|
||||||
|
*/
|
||||||
|
if ($this->getKeyField() === 'ID' && $key === 'unchanged') {
|
||||||
|
$key = null;
|
||||||
|
} elseif (is_string($key)) {
|
||||||
|
$key = preg_split('/\s*,\s*/', trim($key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::objectForKey($key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,28 +4,292 @@ namespace SilverStripe\Forms\Tests;
|
|||||||
|
|
||||||
use SilverStripe\Assets\File;
|
use SilverStripe\Assets\File;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Forms\Form;
|
||||||
|
use SilverStripe\Forms\FormTemplateHelper;
|
||||||
use SilverStripe\Forms\TreeMultiselectField;
|
use SilverStripe\Forms\TreeMultiselectField;
|
||||||
|
|
||||||
class TreeMultiselectFieldTest extends SapphireTest
|
class TreeMultiselectFieldTest extends SapphireTest
|
||||||
{
|
{
|
||||||
protected static $fixture_file = 'TreeDropdownFieldTest.yml';
|
protected static $fixture_file = 'TreeDropdownFieldTest.yml';
|
||||||
|
|
||||||
public function testReadonly()
|
protected $formId = 'TheFormID';
|
||||||
|
protected $fieldName = 'TestTree';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock object of a generic form
|
||||||
|
*
|
||||||
|
* @var Form
|
||||||
|
*/
|
||||||
|
protected $form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of the TreeMultiselectField
|
||||||
|
*
|
||||||
|
* @var TreeMultiselectField
|
||||||
|
*/
|
||||||
|
protected $field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The File objects of folders loaded from the fixture
|
||||||
|
*
|
||||||
|
* @var File[]
|
||||||
|
*/
|
||||||
|
protected $folders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array of folder ids
|
||||||
|
*
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
protected $folderIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenated folder ids for use as a value for the field
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fieldValue;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->form = $this->buildFormMock();
|
||||||
|
$this->field = $this->buildField($this->form);
|
||||||
|
$this->folders = $this->loadFolders();
|
||||||
|
|
||||||
|
$this->folderIds = array_map(
|
||||||
|
static function ($f) {
|
||||||
|
return $f->ID;
|
||||||
|
},
|
||||||
|
$this->folders
|
||||||
|
);
|
||||||
|
$this->fieldValue = implode(',', $this->folderIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new mock object of a Form
|
||||||
|
*
|
||||||
|
* @return Form
|
||||||
|
*/
|
||||||
|
protected function buildFormMock()
|
||||||
|
{
|
||||||
|
$form = $this->createMock(Form::class);
|
||||||
|
|
||||||
|
$form->method('getTemplateHelper')
|
||||||
|
->willReturn(FormTemplateHelper::singleton());
|
||||||
|
|
||||||
|
$form->method('getHTMLID')
|
||||||
|
->willReturn($this->formId);
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new instance of TreeMultiselectField
|
||||||
|
*
|
||||||
|
* @param Form $form The field form
|
||||||
|
*
|
||||||
|
* @return TreeMultiselectField
|
||||||
|
*/
|
||||||
|
protected function buildField(Form $form)
|
||||||
|
{
|
||||||
|
$field = new TreeMultiselectField($this->fieldName, 'Test tree', File::class);
|
||||||
|
$field->setForm($form);
|
||||||
|
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load several files from the fixtures and return them in an array
|
||||||
|
*
|
||||||
|
* @return File[]
|
||||||
|
*/
|
||||||
|
protected function loadFolders()
|
||||||
{
|
{
|
||||||
$field = new TreeMultiselectField('TestTree', 'Test tree', File::class);
|
|
||||||
$asdf = $this->objFromFixture(File::class, 'asdf');
|
$asdf = $this->objFromFixture(File::class, 'asdf');
|
||||||
$subfolderfile1 = $this->objFromFixture(File::class, 'subfolderfile1');
|
$subfolderfile1 = $this->objFromFixture(File::class, 'subfolderfile1');
|
||||||
$field->setValue(implode(',', [$asdf->ID, $subfolderfile1->ID]));
|
|
||||||
|
|
||||||
$readonlyField = $field->performReadonlyTransformation();
|
return [$asdf, $subfolderfile1];
|
||||||
$this->assertEquals(
|
}
|
||||||
<<<"HTML"
|
|
||||||
<span id="TestTree_ReadonlyValue" class="readonly">
|
/**
|
||||||
<Special & characters>, TestFile1InSubfolder
|
* Test the TreeMultiselectField behaviour with no selected values
|
||||||
</span><input type="hidden" name="TestTree" value="{$asdf->ID},{$subfolderfile1->ID}" class="hidden" id="TestTree" />
|
*/
|
||||||
HTML
|
public function testEmpty()
|
||||||
,
|
{
|
||||||
(string)$readonlyField->Field()
|
$field = $this->field;
|
||||||
|
|
||||||
|
$fieldId = $field->ID();
|
||||||
|
$this->assertEquals($fieldId, sprintf('%s_%s', $this->formId, $this->fieldName));
|
||||||
|
|
||||||
|
$schemaStateDefaults = $field->getSchemaStateDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $fieldId,
|
||||||
|
'name' => $this->fieldName,
|
||||||
|
'value' => 'unchanged'
|
||||||
|
],
|
||||||
|
$schemaStateDefaults,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$schemaDataDefaults = $field->getSchemaDataDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $fieldId,
|
||||||
|
'name' => $this->fieldName,
|
||||||
|
'type' => 'text',
|
||||||
|
'schemaType' => 'SingleSelect',
|
||||||
|
'component' => 'TreeDropdownField',
|
||||||
|
'holderId' => sprintf('%s_Holder', $fieldId),
|
||||||
|
'title' => 'Test tree',
|
||||||
|
'extraClass' => 'treemultiselect multiple searchable',
|
||||||
|
'data' => [
|
||||||
|
'urlTree' => 'field/TestTree/tree',
|
||||||
|
'showSearch' => true,
|
||||||
|
'emptyString' => '(Choose File)',
|
||||||
|
'hasEmptyDefault' => false,
|
||||||
|
'multiple' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
$schemaDataDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$items = $field->getItems();
|
||||||
|
$this->assertCount(0, $items, 'there must be no items selected');
|
||||||
|
|
||||||
|
$html = $field->Field();
|
||||||
|
$this->assertContains($field->ID(), $html);
|
||||||
|
$this->assertContains('unchanged', $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the field with some values set
|
||||||
|
*/
|
||||||
|
public function testChanged()
|
||||||
|
{
|
||||||
|
$field = $this->field;
|
||||||
|
|
||||||
|
$field->setValue($this->fieldValue);
|
||||||
|
|
||||||
|
$schemaStateDefaults = $field->getSchemaStateDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $field->ID(),
|
||||||
|
'name' => 'TestTree',
|
||||||
|
'value' => $this->folderIds
|
||||||
|
],
|
||||||
|
$schemaStateDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$items = $field->getItems();
|
||||||
|
$this->assertCount(2, $items, 'there must be exactly 2 items selected');
|
||||||
|
|
||||||
|
$html = $field->Field();
|
||||||
|
$this->assertContains($field->ID(), $html);
|
||||||
|
$this->assertContains($this->fieldValue, $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test empty field in readonly mode
|
||||||
|
*/
|
||||||
|
public function testEmptyReadonly()
|
||||||
|
{
|
||||||
|
$field = $this->field->performReadonlyTransformation();
|
||||||
|
|
||||||
|
$schemaStateDefaults = $field->getSchemaStateDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $field->ID(),
|
||||||
|
'name' => 'TestTree',
|
||||||
|
'value' => 'unchanged'
|
||||||
|
],
|
||||||
|
$schemaStateDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$schemaDataDefaults = $field->getSchemaDataDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $field->ID(),
|
||||||
|
'name' => $this->fieldName,
|
||||||
|
'type' => 'text',
|
||||||
|
'schemaType' => 'SingleSelect',
|
||||||
|
'component' => 'TreeDropdownField',
|
||||||
|
'holderId' => sprintf('%s_Holder', $field->ID()),
|
||||||
|
'title' => 'Test tree',
|
||||||
|
'extraClass' => 'treemultiselectfield_readonly multiple searchable',
|
||||||
|
'data' => [
|
||||||
|
'urlTree' => 'field/TestTree/tree',
|
||||||
|
'showSearch' => true,
|
||||||
|
'emptyString' => '(Choose File)',
|
||||||
|
'hasEmptyDefault' => false,
|
||||||
|
'multiple' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
$schemaDataDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$items = $field->getItems();
|
||||||
|
$this->assertCount(0, $items, 'there must be 0 selected items');
|
||||||
|
|
||||||
|
$html = $field->Field();
|
||||||
|
$this->assertContains($field->ID(), $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test changed field in readonly mode
|
||||||
|
*/
|
||||||
|
public function testChangedReadonly()
|
||||||
|
{
|
||||||
|
$field = $this->field;
|
||||||
|
$field->setValue($this->fieldValue);
|
||||||
|
$field = $field->performReadonlyTransformation();
|
||||||
|
|
||||||
|
$schemaStateDefaults = $field->getSchemaStateDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $field->ID(),
|
||||||
|
'name' => 'TestTree',
|
||||||
|
'value' => $this->folderIds
|
||||||
|
],
|
||||||
|
$schemaStateDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$schemaDataDefaults = $field->getSchemaDataDefaults();
|
||||||
|
$this->assertArraySubset(
|
||||||
|
[
|
||||||
|
'id' => $field->ID(),
|
||||||
|
'name' => $this->fieldName,
|
||||||
|
'type' => 'text',
|
||||||
|
'schemaType' => 'SingleSelect',
|
||||||
|
'component' => 'TreeDropdownField',
|
||||||
|
'holderId' => sprintf('%s_Holder', $field->ID()),
|
||||||
|
'title' => 'Test tree',
|
||||||
|
'extraClass' => 'treemultiselectfield_readonly multiple searchable',
|
||||||
|
'data' => [
|
||||||
|
'urlTree' => 'field/TestTree/tree',
|
||||||
|
'showSearch' => true,
|
||||||
|
'emptyString' => '(Choose File)',
|
||||||
|
'hasEmptyDefault' => false,
|
||||||
|
'multiple' => true
|
||||||
|
]
|
||||||
|
],
|
||||||
|
$schemaDataDefaults,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$items = $field->getItems();
|
||||||
|
$this->assertCount(2, $items, 'there must be exactly 2 selected items');
|
||||||
|
|
||||||
|
$html = $field->Field();
|
||||||
|
$this->assertContains($field->ID(), $html);
|
||||||
|
$this->assertContains($this->fieldValue, $html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user