7

我正在尝试为 SilverStripe 站点做一些非常不同的事情:在几个子页面上是数据表,这些表每个都有自己的列标题集,有些表的列比其他表多。我想避免在富文本编辑器中构建表格,因为这样容易出错,而且随着时间的推移维护起来很麻烦。

我想做的是创建一个允许第 n 个列和第 n 个相应行的 DataObject。通过这种方式,我可以在模板内调用一个循环(或可能两个),其中已经有 HTML 表结构。内容管理员可以完全控制任何给定子页面的表格中的列,并且他们不必担心维护 HTML 表格设置。

如果没有 a) 使 UI 体验对于内容管理器来说过于复杂,并且 b) 无法正确地将列与行链接起来,我有几个想法不会产生我想要的结果。

我曾想过为表头创建一个数据对象,为表行创建一个,但后来我不知道如何以一种有意义的方式组合它们,特别是因为可能有任意数量的列。

有人对解决这个问题有什么建议吗?

更新:好的,我有一些可能工作的 TableRowItem 数据对象,并且接近工作。但是,现在的问题是:当我基本上动态创建字段值时,如何将它们保存到数据库中?就像现在一样,保存到数据库的唯一字段是 PDF 文件上传字段,其他所有内容在点击“创建”时都会被删除。

<?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;
    }
}

但这些是棘手的部分:弄清楚如何将一个 DataObject 的值映射到另一个 DataObject 的标签,然后根据已创建的列数自动生成第 n 行。

<?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
    }
}

下面是 TableColumnSet 和 TableRowValue 类。我想,会有一组列标题与第 n 个行相关联,所以我想这$has_many两个类之间会有关系,因为一个 TableColumnSet 可以有很多 TableRowValues,但只有一个 TableColumnSet 用于所有表行值。我希望使用下拉菜单将 TableRowValues 与 TableColumnSet 值相关联,并创建所有列标题,但这听起来是个坏主意。必须手动将行中的每个字段与列标题关联起来似乎很乏味,而且内容管理器可能很困难。

<?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;
    }
}

我觉得这里可能有点意思,至少在列标题和行之间的关系方面?不过,我不确定。

4

1 回答 1

-1

我可能不在这儿,因为我没有使用 SilverStripe 的经验。但是......我的 PHP / HTML 表格解决方案可能适用于这里:

<?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);

?>

循环中所有步骤的数组结构都是为了保持默认的服务器内存清洁以删除旧数据。如果您$var .= "string";将所有内容作为字符串连接 (),则所有引用都将存储在内存中,并在显示大型表时使服务器陷入困境。我希望这会有所帮助

于 2017-05-23T21:26:44.640 回答