Create a DataObject to Create Table Rows and Columns in SilverStripe

I'm trying to do something completely different for the SilverStripe website: several subpages have data tables, and each of these tables has its own set of column headers, and some tables have more columns than others. I want to avoid creating tables in the Rich Text Editor, as this is subject to a lot of errors, and this is difficult to handle over time.

I would like to create a DataObject that allows the nth number of columns and the nth number of matching rows. That way, I can invoke a loop (or maybe two) inside the template, where the HTML table structure already exists. Content managers have full control over which columns are in the tables for any sub-page, and they don’t have to worry about supporting customization of the HTML table.

I had several ideas that do not give the results that I want, without a) creating too complicated an interface for content managers and b) the impossibility of correctly binding columns to rows.

I thought about creating a DataObject for table headers, and another for table rows, but then I am puzzled by how to combine them in such a way that it makes sense, especially since there can be any number of columns.

Anyone have any suggestions on this?

UPDATE: Okay, something is happening for me for a TableRowItem data object that can work, and is close to work. However, the problem is this: how to save field values ​​in the database when I create them mostly on the fly? As now, the only field that is stored in the database is the field for loading PDF files, everything else is erased when you click "create".

<?php class TruckBodyPdfTableRowItem extends DataObject { private static $db = array( ); // One-to-one relationship with gallery page private static $has_one = array( 'TablePage'=> 'Page', 'TableColumnSet' => 'TableColumnSet', 'PDF' => 'File', ); // tidy up the CMS by not showing these fields public function getCMSFields() { $fields = parent::getCMSFields(); $fields->removeFieldFromTab("Root.Main","TablePageID"); $fields->removeFieldFromTab("Root.Main","TableColumnSetID"); $fields->removeFieldFromTab("Root.Main","SortOrder"); $fields->addFieldsToTab("Root.Main", $this->getMyColumnOptions()); return $fields; } public function getMyColumnOptions() { $columnArray = []; $Columns = DataObject::get('TableColumnSet'); foreach($Columns as $Column){ $columnArray[] = TextField::create($Column->TableColumnHeader); } return $columnArray; } // Tell the datagrid what fields to show in the table private static $summary_fields = array( ); public function canEdit() { return true; } public function canDelete() { return true; } public function canCreate(){ return true; } public function canPublish(){ return true; } public function canView(){ return true; } } 

But this is the hard part: determining how to map values ​​from one DataObject to labels for another, and then automatically generate the nth number of rows based on how many columns have been created.

 <?php class TablePage extends Page { private static $db = array( 'H1' => 'varchar(250)', ); private static $has_many = array( 'TableRowItems' => 'TableRowItem', 'TableColumnSets' => 'TableColumnSet' ); private static $has_one = array( ); public function getCMSFields() { $fields = parent::getCMSFields(); $fields->addFieldToTab("Root.Main", new TextField("H1"), "Content"); $gridFieldConfig = GridFieldConfig_RecordEditor::create(); $gridFieldConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(array( // field from drawer class => label in UI 'TableColumnHeader' => 'Table Column Header' )); $gridfield = new GridField( "TableColumnSets", "Table Column Sets", $this->TableColumnSets(), $gridFieldConfig ); $fields->addFieldToTab('Root.Specs Table', $gridfield); $gridFieldConfig2 = GridFieldConfig_RecordEditor::create(); $gridFieldConfig2->getComponentByType('GridFieldDataColumns')->setDisplayFields(array( // field from drawer class => label in UI 'TableRowValue' => 'Table Row Value' )); $gridfield2 = new GridField( "TableRowItems", "Table Row Items", $this->TableRowItems(), $gridFieldConfig2 ); $fields->addFieldToTab('Root.Specs Table', $gridfield2); return $fields; } } class TablePage_Controller extends Page_Controller { private static $allowed_actions = array( ); public function init() { parent::init(); // You can include any CSS or JS required by your project here. // See: http://doc.silverstripe.org/framework/en/reference/requirements } } 

Here are the TableColumnSet and TableRowValue classes. I assumed that there would be one set of column headers associated with the nth number of rows, so I decided that there would be a $has_many relationship between the two classes, since a TableColumnSet can have many table resources, but there will be only one TableColumnSet for all TableRowValues. I was hoping to associate TableRowValues ​​with TableColumnSet values ​​using a drop-down list with all the column headers created, but that just sounds like a bad idea. To manually associate each field in a row with column headings, it seems like tedious and potentially complex content managers.

 <?php class TableColumnSet extends DataObject { private static $db = array( 'SortOrder' => 'Int', 'TableColumnHeader'=>'varchar(250)' ); // One-to-one relationship with gallery page private static $has_one = array( 'TablePage'=> 'Page' ); private static $has_many = array( 'TableRowItems' => 'TableRowItem' ); // tidy up the CMS by not showing these fields public function getCMSFields() { $fields = parent::getCMSFields(); $fields->removeFieldFromTab("Root.Main","TablePageID"); $fields->removeFieldFromTab("Root.Main","SortOrder"); return $fields; } // Tell the datagrid what fields to show in the table private static $summary_fields = array( 'TableColumnHeader' => 'Table Column Header', ); public function canEdit() { return true; } public function canDelete() { return true; } public function canCreate(){ return true; } public function canPublish(){ return true; } public function canView(){ return true; } } 

I feel there might be something here, at least in relation to the relationship between column headings and rows? I am not sure, however.

+8
data-objects silverstripe
source share
1 answer

I can be here because I have no experience with SilverStripe. But ... my desktop PHP / HTML solution can be applied here:

 <?php // parse your table data into this structure $tableData = array( "rowOne" => array( "columnName" => "columnValue1", "colName" => "colValue1" // ..... ), "rowTwo" => array( "columnName" => "columnValue2", "colName" => "colValue2" // ..... ) ); // now loop through the array with a printHeader parameter $tableHTML = array( "<table>" ); $tableHead = array( "<thead>" ); $tableBody = array( "<tbody>" ); $printHeader = true; foreach ($tableData as $row) { foreach ($row as $column => $value) { $tableRow = "<tr>"; if ($printHeader) { $tableHead[] = "<th>".$column."</th>"; } $tableRow .= "<td>".$value."</td>"; } $tableBody[] = $tableRow."</tr>"; // after the first row, set printHeader to false and close the <thead> $printHeader = false; $tableHead[] = "</thead>"; } // implode table header to string with linebreaks $tableHead = implode(PHP_EOL, $tableHead); // close table <tbody> & implode to string with linebreaks $tableBody[] = "</tbody>"; $tableBody = implode(PHP_EOL, $tableBody); // add all table elements together $tableHTML[] = $tableHead; $tableHTML[] = $tableBody; $tableHTML[] = "</table>"; // implode table array to string $tableHTML = implode(PHP_EOL, $tableHTML); // print or write anywhere echo($tableHTML); ?> 

The array structure for all steps of the cycle is to keep the default server memory cleanup to delete old data. If you concat ( $var .= "string"; ) everything is like a string, all links will remain in memory and start the server when displaying large tables. Hope this helps.

-one
source share

All Articles