mirror of
https://github.com/silverstripe/silverstripe-frameworktest
synced 2024-10-22 11:06:02 +02:00
NEW Add fixtures for arbitrary data gridfield behat tests
This commit is contained in:
parent
8cb3a2dd24
commit
932cf6a13c
@ -15,6 +15,18 @@ SilverStripe\FrameworkTest\Model\Employee:
|
||||
extensions:
|
||||
- SilverStripe\FrameworkTest\Extension\TestDataObjectExtension
|
||||
|
||||
SilverStripe\ORM\DatabaseAdmin:
|
||||
extensions:
|
||||
- SilverStripe\FrameworkTest\GridFieldArbitraryData\DatabaseBuildExtension
|
||||
|
||||
---
|
||||
Only:
|
||||
moduleexists: 'silverstripe/testsession'
|
||||
---
|
||||
SilverStripe\TestSession\TestSessionEnvironment:
|
||||
extensions:
|
||||
- SilverStripe\FrameworkTest\GridFieldArbitraryData\DatabaseBuildExtension
|
||||
|
||||
---
|
||||
Only:
|
||||
moduleexists: 'dnadesign/silverstripe-elemental'
|
||||
|
240
code/GridFieldArbitraryData/ArbitraryDataAdmin.php
Normal file
240
code/GridFieldArbitraryData/ArbitraryDataAdmin.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\FrameworkTest\GridFieldArbitraryData;
|
||||
|
||||
use RuntimeException;
|
||||
use SilverStripe\Admin\LeftAndMain;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Forms\GridField\GridFieldDetailForm;
|
||||
use SilverStripe\Forms\GridField\GridFieldExportButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldFilterHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldPaginator;
|
||||
use SilverStripe\Forms\GridField\GridFieldPrintButton;
|
||||
use SilverStripe\Forms\GridField\GridFieldViewButton;
|
||||
use SilverStripe\Forms\HiddenField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\ORM\Search\BasicSearchContext;
|
||||
use SilverStripe\View\ArrayData;
|
||||
|
||||
class ArbitraryDataAdmin extends LeftAndMain
|
||||
{
|
||||
public const TAB_ARRAYDATA = 'arraydata';
|
||||
|
||||
public const TAB_CUSTOM_MODEL = 'custommodel';
|
||||
|
||||
private static $url_segment = 'arbitrary-data';
|
||||
|
||||
private static $menu_title = 'Arbitrary Data Gridfield';
|
||||
|
||||
private static $url_rule = '/$Tab/$Action';
|
||||
|
||||
private static $url_handlers = [
|
||||
'$Tab/$Action' => 'handleAction'
|
||||
];
|
||||
|
||||
private ?string $tab = null;
|
||||
|
||||
private static int $num_initial_items = 30;
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->tab = $this->getRequest()->param('Tab');
|
||||
|
||||
// accessing the admin directly
|
||||
if ($this->tab === null) {
|
||||
$this->tab = self::TAB_ARRAYDATA;
|
||||
}
|
||||
|
||||
if ($this->tab !== self::TAB_ARRAYDATA && $this->tab !== self::TAB_CUSTOM_MODEL) {
|
||||
throw new RuntimeException("Unexpected url segment: {$this->tab}");
|
||||
}
|
||||
}
|
||||
|
||||
public function getList()
|
||||
{
|
||||
$list = ArrayList::create();
|
||||
|
||||
switch ($this->tab) {
|
||||
case self::TAB_ARRAYDATA:
|
||||
foreach (self::getInitialRecords() as $stub) {
|
||||
$list->add(ArrayData::create($stub));
|
||||
}
|
||||
break;
|
||||
case self::TAB_CUSTOM_MODEL:
|
||||
$rawData = SQLSelect::create()->setFrom(ArbitraryDataModel::TABLE_NAME)->execute();
|
||||
foreach ($rawData as $record) {
|
||||
$list->add(ArbitraryDataModel::create($record));
|
||||
}
|
||||
$list->setDataClass(ArbitraryDataModel::class);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unexpected tab: {$this->tab}");
|
||||
}
|
||||
|
||||
$this->extend('updateList', $list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function getInitialRecords()
|
||||
{
|
||||
$numRecords = static::config()->get('num_initial_items');
|
||||
$records = [];
|
||||
for ($id = 1; $id <= $numRecords; $id++) {
|
||||
$records[] = [
|
||||
'ID' => $id,
|
||||
'Title' => "item $id",
|
||||
];
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
||||
protected function getGridFieldConfig(): GridFieldConfig
|
||||
{
|
||||
if ($this->tab === self::TAB_CUSTOM_MODEL) {
|
||||
$config = GridFieldConfig_RecordEditor::create();
|
||||
} else {
|
||||
// This is effectively the same as a GridFieldConfig_RecordViewer, but without removing the GridFieldFilterHeader.
|
||||
$config = GridFieldConfig_Base::create();
|
||||
$config->addComponent(GridFieldViewButton::create());
|
||||
$config->addComponent(GridFieldDetailForm::create());
|
||||
$fieldNames = array_keys(self::getInitialRecords()[0]);
|
||||
$config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields(array_combine($fieldNames, $fieldNames));
|
||||
$fields = array_map(fn ($name) => $name === 'ID' ? HiddenField::create($name) : TextField::create($name), $fieldNames);
|
||||
$config->getComponentByType(GridFieldDetailForm::class)->setFields(FieldList::create($fields));
|
||||
$searchContext = BasicSearchContext::create(ArrayData::class);
|
||||
$searchFields = array_map(
|
||||
fn ($name) => $name === 'ID'
|
||||
? HiddenField::create(BasicSearchContext::config()->get('general_search_field_name'))
|
||||
: TextField::create($name),
|
||||
$fieldNames
|
||||
);
|
||||
$searchContext->setFields(FieldList::create($searchFields));
|
||||
$config->getComponentByType(GridFieldFilterHeader::class)->setSearchContext($searchContext);
|
||||
}
|
||||
|
||||
$config->getComponentByType(GridFieldPaginator::class)->setItemsPerPage(10);
|
||||
|
||||
$exportButton = GridFieldExportButton::create('buttons-before-left');
|
||||
// $exportButton->setExportColumns($this->getExportFields());
|
||||
|
||||
$config->addComponents([
|
||||
$exportButton,
|
||||
GridFieldPrintButton::create('buttons-before-left')
|
||||
]);
|
||||
|
||||
$this->extend('updateGridFieldConfig', $config);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
protected function getGridField(): GridField
|
||||
{
|
||||
$field = GridField::create(
|
||||
$this->tab,
|
||||
false,
|
||||
$this->getList(),
|
||||
$this->getGridFieldConfig()
|
||||
);
|
||||
|
||||
$this->extend('updateGridField', $field);
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
public function getEditForm($id = null, $fields = null)
|
||||
{
|
||||
$form = Form::create(
|
||||
$this,
|
||||
'EditForm',
|
||||
FieldList::create($this->getGridField()),
|
||||
FieldList::create()
|
||||
)->setHTMLID('Form_EditForm');
|
||||
|
||||
$form->addExtraClass('cms-edit-form cms-panel-padded center flexbox-area-grow');
|
||||
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
|
||||
$editFormAction = Controller::join_links($this->Link($this->tab), 'EditForm');
|
||||
$form->setFormAction($editFormAction);
|
||||
$form->setAttribute('data-pjax-fragment', 'CurrentForm');
|
||||
|
||||
$this->extend('updateEditForm', $form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
protected function getManagedTabs()
|
||||
{
|
||||
$tabs = [
|
||||
self::TAB_ARRAYDATA => 'ArrayData',
|
||||
self::TAB_CUSTOM_MODEL => 'Custom Model',
|
||||
];
|
||||
$forms = new ArrayList();
|
||||
|
||||
foreach ($tabs as $tab => $title) {
|
||||
$forms->push(new ArrayData([
|
||||
'Title' => $title,
|
||||
'Tab' => $tab,
|
||||
'Link' => $this->Link($tab),
|
||||
'LinkOrCurrent' => ($tab === $this->tab) ? 'current' : 'link'
|
||||
]));
|
||||
}
|
||||
|
||||
return $forms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
public function Link($action = null)
|
||||
{
|
||||
if (!$action) {
|
||||
$action = $this->tab;
|
||||
}
|
||||
return parent::Link($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly copied from ModelAdmin with minor tweaks
|
||||
*/
|
||||
public function Breadcrumbs($unlinked = false)
|
||||
{
|
||||
$items = parent::Breadcrumbs($unlinked);
|
||||
|
||||
// Show the class name rather than ModelAdmin title as root node
|
||||
$params = $this->getRequest()->getVars();
|
||||
if (isset($params['url'])) {
|
||||
unset($params['url']);
|
||||
}
|
||||
|
||||
$items[0]->Title = $this->tab;
|
||||
$items[0]->Link = Controller::join_links(
|
||||
$this->Link($this->tab),
|
||||
'?' . http_build_query($params ?? [])
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
205
code/GridFieldArbitraryData/ArbitraryDataModel.php
Normal file
205
code/GridFieldArbitraryData/ArbitraryDataModel.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\FrameworkTest\GridFieldArbitraryData;
|
||||
|
||||
use LogicException;
|
||||
use SilverStripe\Forms\DatetimeField;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\HiddenField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\Queries\SQLDelete;
|
||||
use SilverStripe\ORM\Search\BasicSearchContext;
|
||||
use SilverStripe\View\ArrayData;
|
||||
|
||||
/**
|
||||
* A class of arbitrary data for testing GridField components.
|
||||
*
|
||||
* It stores its data in the database, but it doesn't use DataObject abstractions
|
||||
* to do so. The database in this scenario could just as easily be an API or other
|
||||
* way to fetch and send data.
|
||||
*/
|
||||
class ArbitraryDataModel extends ArrayData implements DataObjectInterface
|
||||
{
|
||||
/**
|
||||
* In order to validate that writing/deleting works for arbitrary data, we'll be storing these
|
||||
* records in the database - just not using the DataObject abstraction.
|
||||
*
|
||||
* For our purposes, the database is acting as an abitrary data storage layer. It could just as
|
||||
* easily be sending/recieving data through an API, for example.
|
||||
*
|
||||
* Note that the database will not be used for filtering/sorting/etc - it is only used to store
|
||||
* the data on save, delete the data on delete, and fetch the data when loading the admin.
|
||||
*/
|
||||
public const TABLE_NAME = 'frameworktest_ArbitraryDataModel';
|
||||
|
||||
/**
|
||||
* We need to ensure there is an ID field for new records
|
||||
*/
|
||||
public function __construct($value = [])
|
||||
{
|
||||
if (!isset($value['ID'])) {
|
||||
$value['ID'] = 0;
|
||||
}
|
||||
parent::__construct($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current data into the database - but could just as easily send it through an API
|
||||
* endpoint for storing somewhere else, or save to a file, etc.
|
||||
*/
|
||||
public function write()
|
||||
{
|
||||
$isNew = !$this->ID;
|
||||
$now = DBDatetime::now()->Rfc2822();
|
||||
$record = $this->array;
|
||||
$record['LastEdited'] = $now;
|
||||
if ($isNew) {
|
||||
$record['Created'] = $now;
|
||||
}
|
||||
|
||||
// Remove anything that isn't storable in the DB, such as Security ID
|
||||
$dbColumns = DB::field_list(self::TABLE_NAME);
|
||||
foreach ($record as $fieldName => $value) {
|
||||
if (!array_key_exists($fieldName, $dbColumns)) {
|
||||
unset($record[$fieldName]);
|
||||
}
|
||||
}
|
||||
|
||||
// This is basically a fancy SQLInsert or SQLUpdate - I just copied DataObject so I didn't have to think.
|
||||
$manipulation = [
|
||||
'command' => $isNew ? 'insert' : 'update',
|
||||
'fields' => $record,
|
||||
];
|
||||
if (!$isNew) {
|
||||
$manipulation['id'] = $this->ID;
|
||||
}
|
||||
DB::manipulate([self::TABLE_NAME => $manipulation]);
|
||||
|
||||
if ($isNew) {
|
||||
// Must save the ID in this object so GridField knows what URL to redirect to.
|
||||
$this->ID = DB::get_generated_id(self::TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if (!$this->ID) {
|
||||
throw new LogicException('DataObject::delete() called on a record without an ID');
|
||||
}
|
||||
SQLDelete::create()->setFrom(self::TABLE_NAME)->setWhere(['ID' => $this->ID])->execute();
|
||||
$this->ID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value from the form
|
||||
*/
|
||||
public function setCastedField($fieldName, $val)
|
||||
{
|
||||
$this->$fieldName = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a localisable plural name for the class.
|
||||
*
|
||||
* Used in add button, breadcrumbs, and toasts
|
||||
*/
|
||||
public function i18n_singular_name()
|
||||
{
|
||||
return _t(__CLASS__ . '.SINGULAR_NAME', 'Arbitrary Datum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a localisable plural name for the class.
|
||||
*
|
||||
* Used in filter header as the placeholder text
|
||||
*/
|
||||
public function i18n_plural_name()
|
||||
{
|
||||
return _t(__CLASS__ . '.PLURAL_NAME', 'Arbitrary Data');
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to auto-detect gridfield columns
|
||||
*/
|
||||
public function summaryFields()
|
||||
{
|
||||
$fieldNames = $this->getFieldNames();
|
||||
$summaryFields = array_combine($fieldNames, $fieldNames);
|
||||
unset($summaryFields['ID']);
|
||||
return $summaryFields;
|
||||
}
|
||||
|
||||
public function getDefaultSearchContext()
|
||||
{
|
||||
return BasicSearchContext::create(static::class);
|
||||
}
|
||||
|
||||
public function scaffoldSearchFields()
|
||||
{
|
||||
$fieldNames = $this->getFieldNames();
|
||||
$fields = [HiddenField::create(BasicSearchContext::config()->get('general_search_field_name'))];
|
||||
foreach ($fieldNames as $fieldName) {
|
||||
if ($fieldName === 'ID' || $fieldName === 'Created' || $fieldName === 'LastEdited') {
|
||||
continue;
|
||||
}
|
||||
$fields[] = TextField::create($fieldName);
|
||||
}
|
||||
return FieldList::create($fields);
|
||||
}
|
||||
|
||||
public function getCMSFields(): FieldList
|
||||
{
|
||||
$fieldNames = $this->getFieldNames();
|
||||
$fields = [];
|
||||
foreach ($fieldNames as $fieldName) {
|
||||
switch ($fieldName) {
|
||||
case 'ID':
|
||||
$fields[] = HiddenField::create($fieldName);
|
||||
break;
|
||||
case 'Created':
|
||||
case 'LastEdited':
|
||||
$fields[] = DatetimeField::create($fieldName)->performReadonlyTransformation();
|
||||
break;
|
||||
default:
|
||||
$fields[] = TextField::create($fieldName);
|
||||
}
|
||||
}
|
||||
return FieldList::create($fields);
|
||||
}
|
||||
|
||||
// Note that a FieldsValidator is used by default, but we can add additional validation if we want
|
||||
// by implementing this method:
|
||||
// public function getCMSCompositeValidator()
|
||||
// {
|
||||
// return CompositeValidator::create([
|
||||
// FieldsValidator::create(),
|
||||
// RequiredFields::create(['Title']),
|
||||
// ]);
|
||||
// }
|
||||
|
||||
public function canCreate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canEdit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDelete()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getFieldNames()
|
||||
{
|
||||
$fieldNames = array_keys(ArbitraryDataAdmin::getInitialRecords()[0]);
|
||||
$fieldNames[] = 'Created';
|
||||
$fieldNames[] = 'LastEdited';
|
||||
return $fieldNames;
|
||||
}
|
||||
}
|
144
code/GridFieldArbitraryData/DatabaseBuildExtension.php
Normal file
144
code/GridFieldArbitraryData/DatabaseBuildExtension.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\FrameworkTest\GridFieldArbitraryData;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Extension;
|
||||
use SilverStripe\ORM\DatabaseAdmin;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
|
||||
/**
|
||||
* Builds the table and adds default records for the ArbitraryDataModel.
|
||||
*/
|
||||
class DatabaseBuildExtension extends Extension
|
||||
{
|
||||
/**
|
||||
* This extension hook is on TestSessionEnvironment, which is used by behat but not by phpunit.
|
||||
* For whatever reason, behat doesn't use dev/build, so we can't rely on the below onAfterbuild
|
||||
* being run in that scenario.
|
||||
*/
|
||||
protected function onAfterStartTestSession()
|
||||
{
|
||||
$this->buildTable(true);
|
||||
$this->populateData();
|
||||
}
|
||||
|
||||
/**
|
||||
* This extension hook is on DatabaseAdmin, after dev/build has finished building the database.
|
||||
*/
|
||||
protected function onAfterBuild(bool $quiet, bool $populate, bool $testMode): void
|
||||
{
|
||||
if ($testMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$quiet) {
|
||||
if (Director::is_cli()) {
|
||||
echo "\nCREATING TABLE FOR FRAMEWORKTEST ARBITRARY DATA\n\n";
|
||||
} else {
|
||||
echo "\n<p><b>Creating table for frameworktest arbitrary data</b></p><ul>\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
$this->buildTable($quiet);
|
||||
|
||||
if (!$quiet && !Director::is_cli()) {
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
if ($populate) {
|
||||
if (!$quiet) {
|
||||
if (Director::is_cli()) {
|
||||
echo "\nCREATING DATABASE RECORDS FOR FRAMEWORKTEST ARBITRARY DATA\n\n";
|
||||
} else {
|
||||
echo "\n<p><b>Creating database records arbitrary data</b></p><ul>\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
$this->populateData();
|
||||
|
||||
if (!$quiet && !Director::is_cli()) {
|
||||
echo '</ul>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$quiet) {
|
||||
echo (Director::is_cli()) ? "\n Frameworktest database build completed!\n\n" : '<p>Frameworktest database build completed!</p>';
|
||||
}
|
||||
}
|
||||
|
||||
private function buildTable(bool $quiet): void
|
||||
{
|
||||
$tableName = ArbitraryDataModel::TABLE_NAME;
|
||||
|
||||
// Log data
|
||||
if (!$quiet) {
|
||||
$showRecordCounts = DatabaseAdmin::config()->get('show_record_counts');
|
||||
if ($showRecordCounts && DB::get_schema()->hasTable($tableName)) {
|
||||
try {
|
||||
$count = SQLSelect::create()->setFrom($tableName)->count();
|
||||
$countSuffix = " ($count records)";
|
||||
} catch (\Exception $e) {
|
||||
$countSuffix = ' (error getting record count)';
|
||||
}
|
||||
} else {
|
||||
$countSuffix = "";
|
||||
}
|
||||
|
||||
if (Director::is_cli()) {
|
||||
echo " * $tableName$countSuffix\n";
|
||||
} else {
|
||||
echo "<li>$tableName$countSuffix</li>\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Get field schema
|
||||
$fields = [
|
||||
'ID' => 'PrimaryKey',
|
||||
'LastEdited' => 'DBDatetime',
|
||||
'Created' => 'DBDatetime',
|
||||
];
|
||||
$fieldNames = array_keys(ArbitraryDataAdmin::getInitialRecords()[0]);
|
||||
foreach ($fieldNames as $fieldName) {
|
||||
if ($fieldName === 'ID') {
|
||||
continue;
|
||||
}
|
||||
$fields[$fieldName] = 'Varchar';
|
||||
}
|
||||
|
||||
// Write the table to the database
|
||||
DB::get_schema()->schemaUpdate(function () use ($tableName, $fields) {
|
||||
DB::require_table(
|
||||
$tableName,
|
||||
$fields,
|
||||
null,
|
||||
true,
|
||||
DataObject::config()->get('create_table_options')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private function populateData(): void
|
||||
{
|
||||
$tableName = ArbitraryDataModel::TABLE_NAME;
|
||||
$count = SQLSelect::create()->setFrom($tableName)->count();
|
||||
|
||||
if ($count <= 0) {
|
||||
$now = DBDatetime::now()->Rfc2822();
|
||||
$data = ArbitraryDataAdmin::getInitialRecords();
|
||||
foreach ($data as $record) {
|
||||
unset($record['ID']);
|
||||
$record['LastEdited'] = $now;
|
||||
$record['Created'] = $now;
|
||||
|
||||
$item = ArbitraryDataModel::create($record);
|
||||
$item->write();
|
||||
}
|
||||
|
||||
DB::alteration_message('Added default records for frameworktest arbitrary data', 'created');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<div class="cms-content fill-height flexbox-area-grow cms-tabset center $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content" id="ModelAdmin">
|
||||
|
||||
<div class="cms-content-header north">
|
||||
<div class="cms-content-header-info vertical-align-items flexbox-area-grow">
|
||||
<div class="breadcrumbs-wrapper">
|
||||
<span class="cms-panel-link crumb last">
|
||||
<% if $SectionTitle %>
|
||||
$SectionTitle
|
||||
<% else %>
|
||||
<%t SilverStripe\Admin\ModelAdmin.Title 'Data Models' %>
|
||||
<% end_if %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cms-content-header-tabs cms-tabset-nav-primary ss-ui-tabs-nav">
|
||||
<ul class="cms-tabset-nav-primary">
|
||||
<% loop $ManagedTabs %>
|
||||
<li class="tab-$Tab $LinkOrCurrent<% if $LinkOrCurrent == 'current' %> ui-tabs-active<% end_if %>">
|
||||
<a href="$Link" class="cms-panel-link" title="$Title.ATT">$Title</a>
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cms-content-fields center ui-widget-content cms-panel-padded fill-height flexbox-area-grow" data-layout-type="border">
|
||||
$Tools
|
||||
|
||||
<div class="cms-content-view">
|
||||
$EditForm
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
@ -0,0 +1 @@
|
||||
<% include SilverStripe/Forms/Form %>
|
@ -0,0 +1,21 @@
|
||||
<div class="importSpec" id="SpecFor{$ClassName}">
|
||||
<a href="#SpecDetailsFor{$ClassName}" class="detailsLink"><%t SilverStripe\Admin\ModelAdmin.IMPORTSPECLINK 'Show Specification for {model}' model=$ModelName %></a>
|
||||
<div class="details" id="SpecDetailsFor{$ClassName}">
|
||||
<h4><%t SilverStripe\Admin\ModelAdmin.IMPORTSPECTITLE 'Specification for {model}' model=$ModelName %></h4>
|
||||
<h5><%t SilverStripe\Admin\ModelAdmin.IMPORTSPECFIELDS 'Database columns' %></h5>
|
||||
<% loop $Fields %>
|
||||
<dl>
|
||||
<dt><em>$Name</em></dt>
|
||||
<dd>$Description</dd>
|
||||
</dl>
|
||||
<% end_loop %>
|
||||
|
||||
<h5><%t SilverStripe\Admin\ModelAdmin.IMPORTSPECRELATIONS 'Relations' %></h5>
|
||||
<% loop $Relations %>
|
||||
<dl>
|
||||
<dt><em>$Name</em></dt>
|
||||
<dd>$Description</dd>
|
||||
</dl>
|
||||
<% end_loop %>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user