mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '4' into 5.0
This commit is contained in:
commit
15e4cbeb7a
@ -8,8 +8,15 @@ Requires PHPUnit ^9
|
|||||||
<testsuite name="Default">
|
<testsuite name="Default">
|
||||||
<directory>tests/php</directory>
|
<directory>tests/php</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="framework">
|
<!-- Framework ORM tests are split up to run in parallel -->
|
||||||
|
<testsuite name="framework-core">
|
||||||
<directory>tests/php</directory>
|
<directory>tests/php</directory>
|
||||||
|
<exclude>
|
||||||
|
<directory>tests/php/ORM</directory>
|
||||||
|
</exclude>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="framework-orm">
|
||||||
|
<directory>tests/php/ORM</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="cms">
|
<testsuite name="cms">
|
||||||
<directory>vendor/silverstripe/cms/tests</directory>
|
<directory>vendor/silverstripe/cms/tests</directory>
|
||||||
|
26
src/Forms/FieldsValidator.php
Normal file
26
src/Forms/FieldsValidator.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the internal state of all fields in the form.
|
||||||
|
*/
|
||||||
|
class FieldsValidator extends Validator
|
||||||
|
{
|
||||||
|
public function php($data): bool
|
||||||
|
{
|
||||||
|
$valid = true;
|
||||||
|
$fields = $this->form->Fields();
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$valid = ($field->validate($this) && $valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBeCached(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -214,7 +214,7 @@ class GridFieldFilterHeader extends AbstractGridFieldComponent implements GridFi
|
|||||||
sort($searchableFields);
|
sort($searchableFields);
|
||||||
sort($summaryFields);
|
sort($summaryFields);
|
||||||
// searchable_fields has been explictily defined i.e. searchableFields() is not falling back to summary_fields
|
// searchable_fields has been explictily defined i.e. searchableFields() is not falling back to summary_fields
|
||||||
if ($searchableFields !== $summaryFields) {
|
if (!empty($searchableFields) && ($searchableFields !== $summaryFields)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// we have fallen back to summary_fields, check they are filterable
|
// we have fallen back to summary_fields, check they are filterable
|
||||||
|
@ -190,4 +190,14 @@ class HTMLEditorField extends TextareaField
|
|||||||
$stateDefaults['data'] = $config->getConfigSchemaData();
|
$stateDefaults['data'] = $config->getConfigSchemaData();
|
||||||
return $stateDefaults;
|
return $stateDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return value with all values encoded in html entities
|
||||||
|
*
|
||||||
|
* @return string Raw HTML
|
||||||
|
*/
|
||||||
|
public function ValueEntities()
|
||||||
|
{
|
||||||
|
return htmlentities($this->Value() ?? '', ENT_COMPAT, 'UTF-8', false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use SilverStripe\Forms\FieldList;
|
|||||||
use SilverStripe\Forms\FormField;
|
use SilverStripe\Forms\FormField;
|
||||||
use SilverStripe\Forms\FormScaffolder;
|
use SilverStripe\Forms\FormScaffolder;
|
||||||
use SilverStripe\Forms\CompositeValidator;
|
use SilverStripe\Forms\CompositeValidator;
|
||||||
|
use SilverStripe\Forms\FieldsValidator;
|
||||||
use SilverStripe\Forms\HiddenField;
|
use SilverStripe\Forms\HiddenField;
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
use SilverStripe\i18n\i18nEntityProvider;
|
use SilverStripe\i18n\i18nEntityProvider;
|
||||||
@ -2543,7 +2544,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
public function getCMSCompositeValidator(): CompositeValidator
|
public function getCMSCompositeValidator(): CompositeValidator
|
||||||
{
|
{
|
||||||
$compositeValidator = CompositeValidator::create();
|
$compositeValidator = CompositeValidator::create([FieldsValidator::create()]);
|
||||||
|
|
||||||
// Support for the old method during the deprecation period
|
// Support for the old method during the deprecation period
|
||||||
if ($this->hasMethod('getCMSValidator')) {
|
if ($this->hasMethod('getCMSValidator')) {
|
||||||
@ -3689,6 +3690,52 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
$this->extend('onAfterBuild');
|
$this->extend('onAfterBuild');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDatabaseBackedField(string $fieldPath): ?string
|
||||||
|
{
|
||||||
|
$component = $this;
|
||||||
|
$fieldParts = [];
|
||||||
|
$parts = explode('.', $fieldPath ?? '');
|
||||||
|
|
||||||
|
foreach ($parts as $nextPart) {
|
||||||
|
if (!$component) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$fieldParts[] = $nextPart;
|
||||||
|
|
||||||
|
if ($component instanceof Relation || $component instanceof DataList) {
|
||||||
|
if ($component->hasMethod($nextPart)) {
|
||||||
|
// If the next part is a method, we don't have a database-backed field.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// The next part could either be a field, or another relation
|
||||||
|
$singleton = DataObject::singleton($component->dataClass());
|
||||||
|
if ($singleton->dbObject($nextPart) instanceof DBField) {
|
||||||
|
// If the next part is a DBField, we've found the database-backed field.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$component = $component->relation($nextPart);
|
||||||
|
array_shift($parts);
|
||||||
|
} elseif ($component instanceof DataObject && ($component->dbObject($nextPart) instanceof DBField)) {
|
||||||
|
// If the next part is a DBField, we've found the database-backed field.
|
||||||
|
break;
|
||||||
|
} elseif ($component instanceof DataObject && $component->getRelationType($nextPart) !== null) {
|
||||||
|
// If it's a last part or only one elemnt of a relation, we don't have a database-backed field.
|
||||||
|
if (count($parts) === 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$component = $component->$nextPart();
|
||||||
|
array_shift($parts);
|
||||||
|
} elseif (ClassInfo::hasMethod($component, $nextPart)) {
|
||||||
|
// If the next part is a method, we don't have a database-backed field.
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('.', $fieldParts) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default searchable fields for this object, as defined in the
|
* Get the default searchable fields for this object, as defined in the
|
||||||
* $searchable_fields list. If searchable fields are not defined on the
|
* $searchable_fields list. If searchable fields are not defined on the
|
||||||
@ -3707,21 +3754,10 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
$summaryFields = array_keys($this->summaryFields() ?? []);
|
$summaryFields = array_keys($this->summaryFields() ?? []);
|
||||||
$fields = [];
|
$fields = [];
|
||||||
|
|
||||||
// remove the custom getters as the search should not include them
|
|
||||||
$schema = static::getSchema();
|
|
||||||
if ($summaryFields) {
|
if ($summaryFields) {
|
||||||
foreach ($summaryFields as $key => $name) {
|
foreach ($summaryFields as $name) {
|
||||||
$spec = $name;
|
if ($field = $this->getDatabaseBackedField($name)) {
|
||||||
|
$fields[] = $field;
|
||||||
// Extract field name in case this is a method called on a field (e.g. "Date.Nice")
|
|
||||||
if (($fieldPos = strpos($name ?? '', '.')) !== false) {
|
|
||||||
$name = substr($name ?? '', 0, $fieldPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($schema->fieldSpec($this, $name)) {
|
|
||||||
$fields[] = $name;
|
|
||||||
} elseif ($this->relObject($spec)) {
|
|
||||||
$fields[] = $spec;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Security\MemberAuthenticator;
|
|||||||
|
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
use SilverStripe\Control\Cookie;
|
use SilverStripe\Control\Cookie;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
use SilverStripe\Control\HTTPRequest;
|
use SilverStripe\Control\HTTPRequest;
|
||||||
use SilverStripe\Control\Session;
|
use SilverStripe\Control\Session;
|
||||||
@ -62,7 +63,7 @@ class SessionAuthenticationHandler implements AuthenticationHandler
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/** @var Member $member */
|
/** @var Member $member */
|
||||||
$member = Member::get()->byID($id);
|
$member = DataObject::get_by_id(Member::class, $id);
|
||||||
return $member;
|
return $member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use Behat\Behat\Context\Context;
|
|||||||
use Behat\Behat\Hook\Scope\AfterStepScope;
|
use Behat\Behat\Hook\Scope\AfterStepScope;
|
||||||
use Behat\Mink\Element\Element;
|
use Behat\Mink\Element\Element;
|
||||||
use Behat\Mink\Element\NodeElement;
|
use Behat\Mink\Element\NodeElement;
|
||||||
|
use Behat\Mink\Exception\ElementNotFoundException;
|
||||||
use Behat\Mink\Selector\Xpath\Escaper;
|
use Behat\Mink\Selector\Xpath\Escaper;
|
||||||
use Behat\Mink\Session;
|
use Behat\Mink\Session;
|
||||||
use PHPUnit\Framework\Assert;
|
use PHPUnit\Framework\Assert;
|
||||||
@ -92,26 +93,37 @@ class CmsUiContext implements Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Then /^I should see a "(.+)" (\w+) toast$/
|
* @Then /^I should (not |)see a "(.+)" (\w+) toast$/
|
||||||
*/
|
*/
|
||||||
public function iShouldSeeAToast($notice, $type)
|
public function iShouldSeeAToast($not, $notice, $type)
|
||||||
{
|
{
|
||||||
$this->getMainContext()->assertElementContains('.toast--' . $type, $notice);
|
if ($not) {
|
||||||
|
try {
|
||||||
|
// If there is a toast of that type, ensure it doesn't contain the notice.
|
||||||
|
$this->getMainContext()->assertElementNotContains('.toast--' . $type, $notice);
|
||||||
|
} catch (ElementNotFoundException $e) {
|
||||||
|
// no-op - if the element doesn't exist at all, then that passes the test.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->getMainContext()->assertElementContains('.toast--' . $type, $notice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Then /^I should see a "(.+)" (\w+) toast with these actions: (.+)$/
|
* @Then /^I should (not |)see a "(.+)" (\w+) toast with these actions: (.+)$/
|
||||||
*/
|
*/
|
||||||
public function iShouldSeeAToastWithAction($notice, $type, $actions)
|
public function iShouldSeeAToastWithAction($not, $notice, $type, $actions)
|
||||||
{
|
{
|
||||||
$this->iShouldSeeAToast($notice, $type);
|
$this->iShouldSeeAToast($not, $notice, $type);
|
||||||
|
|
||||||
$actions = explode(',', $actions ?? '');
|
if (!$not) {
|
||||||
foreach ($actions as $order => $action) {
|
$actions = explode(',', $actions ?? '');
|
||||||
$this->getMainContext()->assertElementContains(
|
foreach ($actions as $order => $action) {
|
||||||
sprintf('.toast--%s .toast__action:nth-child(%s)', $type, $order+1),
|
$this->getMainContext()->assertElementContains(
|
||||||
trim($action ?? '')
|
sprintf('.toast--%s .toast__action:nth-child(%s)', $type, $order+1),
|
||||||
);
|
trim($action ?? '')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
tests/php/Forms/FieldsValidatorTest.php
Normal file
79
tests/php/Forms/FieldsValidatorTest.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Forms\EmailField;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
|
use SilverStripe\Forms\FieldsValidator;
|
||||||
|
use SilverStripe\Forms\Form;
|
||||||
|
|
||||||
|
class FieldsValidatorTest extends SapphireTest
|
||||||
|
{
|
||||||
|
protected $usesDatabase = false;
|
||||||
|
|
||||||
|
public function provideValidation()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'missing values arent invalid' => [
|
||||||
|
'values' => [],
|
||||||
|
'isValid' => true,
|
||||||
|
],
|
||||||
|
'empty values arent invalid' => [
|
||||||
|
'values' => [
|
||||||
|
'EmailField1' => '',
|
||||||
|
'EmailField2' => null,
|
||||||
|
],
|
||||||
|
'isValid' => true,
|
||||||
|
],
|
||||||
|
'any invalid is invalid' => [
|
||||||
|
'values' => [
|
||||||
|
'EmailField1' => 'email@example.com',
|
||||||
|
'EmailField2' => 'not email',
|
||||||
|
],
|
||||||
|
'isValid' => false,
|
||||||
|
],
|
||||||
|
'all invalid is invalid' => [
|
||||||
|
'values' => [
|
||||||
|
'EmailField1' => 'not email',
|
||||||
|
'EmailField2' => 'not email',
|
||||||
|
],
|
||||||
|
'isValid' => false,
|
||||||
|
],
|
||||||
|
'all valid is valid' => [
|
||||||
|
'values' => [
|
||||||
|
'EmailField1' => 'email@example.com',
|
||||||
|
'EmailField2' => 'email@example.com',
|
||||||
|
],
|
||||||
|
'isValid' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideValidation
|
||||||
|
*/
|
||||||
|
public function testValidation(array $values, bool $isValid)
|
||||||
|
{
|
||||||
|
$fieldList = new FieldList([
|
||||||
|
$field1 = new EmailField('EmailField1'),
|
||||||
|
$field2 = new EmailField('EmailField2'),
|
||||||
|
]);
|
||||||
|
if (array_key_exists('EmailField1', $values)) {
|
||||||
|
$field1->setValue($values['EmailField1']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('EmailField2', $values)) {
|
||||||
|
$field2->setValue($values['EmailField2']);
|
||||||
|
}
|
||||||
|
$form = new Form(null, 'testForm', $fieldList, new FieldList([/* no actions */]), new FieldsValidator());
|
||||||
|
|
||||||
|
$result = $form->validationResult();
|
||||||
|
$this->assertSame($isValid, $result->isValid());
|
||||||
|
$messages = $result->getMessages();
|
||||||
|
if ($isValid) {
|
||||||
|
$this->assertEmpty($messages);
|
||||||
|
} else {
|
||||||
|
$this->assertNotEmpty($messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -208,4 +208,25 @@ EOS
|
|||||||
$readonlyContent->getValue()
|
$readonlyContent->getValue()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValueEntities()
|
||||||
|
{
|
||||||
|
$inputText = "The company & partners";
|
||||||
|
$field = new HTMLEditorField("Content");
|
||||||
|
$field->setValue($inputText);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
"The company & partners",
|
||||||
|
$field->obj('ValueEntities')->forTemplate()
|
||||||
|
);
|
||||||
|
|
||||||
|
$inputText = "The company && partners";
|
||||||
|
$field = new HTMLEditorField("Content");
|
||||||
|
$field->setValue($inputText);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
"The company && partners",
|
||||||
|
$field->obj('ValueEntities')->forTemplate()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ use SilverStripe\ORM\Tests\DataObjectTest\TreeNode;
|
|||||||
use SilverStripe\ORM\ValidationException;
|
use SilverStripe\ORM\ValidationException;
|
||||||
use SilverStripe\Security\Member;
|
use SilverStripe\Security\Member;
|
||||||
use SilverStripe\View\ViewableData;
|
use SilverStripe\View\ViewableData;
|
||||||
|
use ReflectionMethod;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
class DataObjectTest extends SapphireTest
|
class DataObjectTest extends SapphireTest
|
||||||
@ -2678,4 +2679,48 @@ class DataObjectTest extends SapphireTest
|
|||||||
// Getter overrides it with all upper case
|
// Getter overrides it with all upper case
|
||||||
$this->assertSame('SOME VALUE', $obj->MyTestField);
|
$this->assertSame('SOME VALUE', $obj->MyTestField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideTestGetDatabaseBackedField()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Captain.IsRetired', 'Captain.IsRetired'],
|
||||||
|
['Captain.ShirtNumber', 'Captain.ShirtNumber'],
|
||||||
|
['Captain.FavouriteTeam', null],
|
||||||
|
['Captain.FavouriteTeam.Fans', null],
|
||||||
|
['Captain.FavouriteTeam.Fans.Count', null],
|
||||||
|
['Captain.FavouriteTeam.Title', 'Captain.FavouriteTeam.Title'],
|
||||||
|
['Captain.FavouriteTeam.Title.Plain', 'Captain.FavouriteTeam.Title'],
|
||||||
|
['Captain.FavouriteTeam.ReturnsNull', null],
|
||||||
|
['Captain.FavouriteTeam.MethodDoesNotExist', null],
|
||||||
|
['Captain.ReturnsNull', null],
|
||||||
|
['Founder.FavouriteTeam.Captain.ShirtNumber', 'Founder.FavouriteTeam.Captain.ShirtNumber'],
|
||||||
|
['Founder.FavouriteTeam.Captain.Fans', null],
|
||||||
|
['Founder.FavouriteTeam.Captain.Fans.Name.Plain', 'Founder.FavouriteTeam.Captain.Fans.Name'],
|
||||||
|
['Founder.FavouriteTeam.Captain.ReturnsNull', null],
|
||||||
|
['HasOneRelationship.FavouriteTeam.MyTitle', null],
|
||||||
|
['SubTeams.Comments.Name.Plain', 'SubTeams.Comments.Name'],
|
||||||
|
['Title', 'Title'],
|
||||||
|
['Title.Plain', 'Title'],
|
||||||
|
['DatabaseField', 'DatabaseField'],
|
||||||
|
['DatabaseField.MethodDoesNotExist', 'DatabaseField'],
|
||||||
|
['ReturnsNull', null],
|
||||||
|
['DynamicField', null],
|
||||||
|
['SubTeams.ParentTeam.Fans', null],
|
||||||
|
['SubTeams.ParentTeam.Founder.FoundingTeams', null],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideTestGetDatabaseBackedField
|
||||||
|
*/
|
||||||
|
public function testGetDatabaseBackedField(string $fieldPath, $expected)
|
||||||
|
{
|
||||||
|
$dataObjectClass = new DataObject();
|
||||||
|
$method = new ReflectionMethod($dataObjectClass, 'getDatabaseBackedField');
|
||||||
|
$method->setAccessible(true);
|
||||||
|
$class = new Team([]);
|
||||||
|
|
||||||
|
$databaseBackedField = $method->invokeArgs($class, [$fieldPath]);
|
||||||
|
$this->assertSame($expected, $databaseBackedField);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,4 +37,9 @@ class Player extends Member implements TestOnly
|
|||||||
'IsRetired',
|
'IsRetired',
|
||||||
'ShirtNumber'
|
'ShirtNumber'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function ReturnsNull()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,13 +58,22 @@ class SearchContextTest extends SapphireTest
|
|||||||
$obj = new SearchContextTest\NoSearchableFields();
|
$obj = new SearchContextTest\NoSearchableFields();
|
||||||
$summaryFields = $obj->summaryFields();
|
$summaryFields = $obj->summaryFields();
|
||||||
$expected = [];
|
$expected = [];
|
||||||
foreach ($summaryFields as $field => $label) {
|
|
||||||
|
$expectedSearchableFields = [
|
||||||
|
'Name',
|
||||||
|
'Customer.FirstName',
|
||||||
|
'HairColor',
|
||||||
|
'EyeColor',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($expectedSearchableFields as $field) {
|
||||||
$expected[$field] = [
|
$expected[$field] = [
|
||||||
'title' => $obj->fieldLabel($field),
|
'title' => $obj->fieldLabel($field),
|
||||||
'filter' => 'PartialMatchFilter',
|
'filter' => 'PartialMatchFilter',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$this->assertEquals($expected, $obj->searchableFields());
|
$this->assertEquals($expected, $obj->searchableFields());
|
||||||
|
$this->assertNotEquals($summaryFields, $obj->searchableFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSummaryIncludesDefaultFieldsIfNotDefined()
|
public function testSummaryIncludesDefaultFieldsIfNotDefined()
|
||||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Tests\Search\SearchContextTest;
|
|||||||
|
|
||||||
use SilverStripe\Dev\TestOnly;
|
use SilverStripe\Dev\TestOnly;
|
||||||
use SilverStripe\ORM\DataObject;
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Assets\Image;
|
||||||
|
|
||||||
class NoSearchableFields extends DataObject implements TestOnly
|
class NoSearchableFields extends DataObject implements TestOnly
|
||||||
{
|
{
|
||||||
@ -18,12 +19,34 @@ class NoSearchableFields extends DataObject implements TestOnly
|
|||||||
|
|
||||||
private static $has_one = [
|
private static $has_one = [
|
||||||
'Customer' => Customer::class,
|
'Customer' => Customer::class,
|
||||||
|
'Image' => Image::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $summary_fields = [
|
private static $summary_fields = [
|
||||||
'Name' => 'Custom Label',
|
'Name' => 'Custom Label',
|
||||||
|
'Customer' => 'Customer',
|
||||||
'Customer.FirstName' => 'Customer',
|
'Customer.FirstName' => 'Customer',
|
||||||
|
'Image.CMSThumbnail' => 'Image',
|
||||||
|
'Image.BackLinks' => 'Backlinks',
|
||||||
|
'Image.BackLinks.Count' => 'Backlinks',
|
||||||
'HairColor',
|
'HairColor',
|
||||||
'EyeColor',
|
'EyeColor',
|
||||||
|
'ReturnsNull',
|
||||||
|
'DynamicField'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function MyName()
|
||||||
|
{
|
||||||
|
return 'Class ' . $this->Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDynamicField()
|
||||||
|
{
|
||||||
|
return 'dynamicfield';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ReturnsNull()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,10 +287,11 @@ class GroupTest extends FunctionalTest
|
|||||||
|
|
||||||
$newGroup = new Group();
|
$newGroup = new Group();
|
||||||
|
|
||||||
$validators = $newGroup->getCMSCompositeValidator()->getValidators();
|
$validators = $newGroup->getCMSCompositeValidator()->getValidatorsByType(RequiredFields::class);
|
||||||
$this->assertCount(1, $validators);
|
$this->assertCount(1, $validators);
|
||||||
$this->assertInstanceOf(RequiredFields::class, $validators[0]);
|
$validator = array_shift($validators);
|
||||||
$this->assertTrue(in_array('Title', $validators[0]->getRequired() ?? []));
|
$this->assertInstanceOf(RequiredFields::class, $validator);
|
||||||
|
$this->assertTrue(in_array('Title', $validator->getRequired() ?? []));
|
||||||
|
|
||||||
$newGroup->Title = $group1->Title;
|
$newGroup->Title = $group1->Title;
|
||||||
$result = $newGroup->validate();
|
$result = $newGroup->validate();
|
||||||
|
Loading…
Reference in New Issue
Block a user