【问题标题】:Codeigniter Table Library Handle Empty / Null ValuesCodeigniter 表库处理空/空值
【发布时间】:2019-02-28 16:46:42
【问题描述】:

我正在使用 Codeigniter 3 和 table library 以按以下格式显示一些数据;

+---------------+---------------------+
| id            | 102                 |
+---------------+---------------------+
| First Name    | Ross                |
+---------------+---------------------+
| Last Name     | Bing                |
+---------------+---------------------+
| Title         | Doctor              |
+---------------+---------------------+
| Timestamp     | 2019-01-18 10:17:05 |
+---------------+---------------------+
| Member Number |                     |
+---------------+---------------------+

$tableData 的 vardump 是;

Array
(
    [0] => Array
        (
            [id] => 102
            [firstname] => Ross
            [lastname] => Bing
            [title] => Doctor
            [timestamp] => 2019-01-18 10:17:05
            [member_no] => 
        )
)

我用来生成 HTML 表格的 PHP 代码是;

$tableData = $this->My_model->getData();

$heading = array(
    'id' => 'ID',
    'firstname' => 'First Name',
    'lastname' => 'Last Name',
    'title' => 'Title',
    'timestamp' => 'Date Submitted',
    'member_no' => 'Member Number'
);

$fields = array_keys($tableData[0]);
$rows = array();

foreach($fields as $key => $field) {
    $rows[$key][0] = array(
        'data' => '<strong>' . $heading[$field] . '</strong>'
    );
    foreach($tableData as $key2 => $item) {
        $rows[$key][$key2 + 1] = $item[$field];
    }
}

foreach($rows as $row) {
    $this->table->add_row($row);
}

上面的代码工作正常,但是如果一行是空的(参见上面的member_no),我想做两件事之一(以最简单的为准);

  • 完全隐藏表格行
  • 在表格单元格中显示not available

我怎样才能做到这一点?

【问题讨论】:

  • 类似:$rows[$key][$key2 + 1] = ($item[$field!=''])?$item[$field]:'不可用'跨度>
  • 我发现这 3 个 foreach 循环是 ugly。对不起,但他们是。您可能可以做一些array_intersect_keyarray_merge 魔术来摆脱其中的一些。
  • 我需要输入和输出数据的示例,例如 $tableData 的样子和 $rows 的样子。这里的一个示例是,当您将array_merge 与字符串键一起使用时,第二个数组中的数据会替换第一个数组中的数据,但会保留第一个数组中键的顺序。您还可以array_filter 输入数据,删除任何空值,然后使用与$header 数组匹配的键预填充数组(使用not available),然后在合并它们时从过滤器中删除任何内容保留默认值...等

标签: php arrays codeigniter foreach codeigniter-3


【解决方案1】:

我会这样做:

$tableData = array (
    0 => 
    array (
        'id' => 102,
        'lastname' => 'Bing',
        'title' => 'Doctor',
        'timestamp' => '2019-01-1810:17:05',
        'member_no' => null,
        'firstname' => 'Ross', //intentionally moved to show ordering
        'foobar' => 'blah' //added for example, this will be removed by array_intersect_key
    ),
);

$heading = array(
    'id' => '<strong>ID</strong>',
    'firstname' => '<strong>First Name</strong>',
    'lastname' => '<strong>Last Name</strong>',
    'title' => '<strong>Title</strong>',
    'timestamp' => '<strong>Date Submitted</strong>',
    'member_no' => '<strong>Member Number</strong>'
);

//create a default array
//this takes the keys from $heading, and makes an array with all the values as 'not available'
// ['id' => 'not available','lastname' => 'not available', ... ]
$default = array_fill_keys(array_keys($heading), 'not available');
$rows = [];

foreach($tableData as $key => $row) {
    //remove all elements with strlen of 0 (in this case 'member_no')
    $row = array_filter($row, function($item){return strlen($item);});

    //removes 'foobar' or anything that has a key not in $heading
    $row = array_intersect_key($row, $heading);

    //combine $default and $data (empty items in $row are filled in from default)
    //such as items removed by array_filter above
    //the key order will match $default, which matches $headings
    $row = array_merge($default, $row);

    $rows[] = $row;
}

foreach($heading as $key=>$value) {
    print_r(array_merge([['data'=>$value]], array_column($rows, $key)));
}

输出

Array
(
    [0] => Array
        (
            [data] => <strong>ID</strong>
        )

    [1] => 102
    //[2] => 108
    //...
)
 ....

Sandbox

我把它们分开了,这样会更容易阅读,但你没有理由不能这样做。

//...
$default = array_fill_keys(array_keys($heading), 'not available');

foreach($tableData as $key => $row) $rows[] = array_merge($default, array_intersect_key(array_filter($row, function($item){return strlen($item);}), $heading));

foreach($heading as $key=>$value) print_r(array_merge([['data'=>$value]],array_column($rows, $key)));

Sandbox

我不得不猜测最终结果是什么,所以我运行了你的原始代码,它给了我这个:

Array
(
    [0] => Array
        (
            [data] => <strong>ID</strong>
        )

    [1] => 102
    //[2] => 108
    //...
)
....

在我的代码中,您可以将 print_r 替换为此调用 $this-&gt;table-&gt;add_row([..array data..]);。其中array dataprint_r 调用中的内容。您可以将其设为变量,但如果仅在此处使用它又有什么意义。这消除了一些循环(见下文)和其他一些优点:

  • 保留$headings 的键顺序,元素出现在$headings 数组中的位置,无论它们在$tableData 中的位置。这也允许轻松重新排序数据,例如:您甚至可以将其映射到动态数组,我在 CSV 文件中执行此操作,它允许用户更改标题和列的顺序。他们甚至可以重命名标题,因为 key =&gt; value 配对的工作方式 my_key =&gt; their_key...
  • $tableData 中缺少的数据默认为从$default 中提取的not available,理论上您可以手动将其映射到不同的东西。例如:您可以在使用array_fill_keys 创建时间戳后立即执行$default['timestamp'] = date('Y-m-d H:i:s');,将时间戳默认为当前时间。
  • $tableData 中未在 $headings 中定义的额外数据已删除。这有利于向前兼容。
  • 而且它更容易理解(一旦你知道它是如何工作的),因为“瞬态”变量更少,对键等的摆弄也更少......

基本上我所做的是在您的原始代码中控制$headings 数组。您可以通过循环键 (fields) 来实现这一点,但这会使后来的事情变得复杂,例如 $rows[$key][$key2 + 1]。如果数据在以后发生更改,例如向数据库添加新字段,它会让您面临未定义的数组索引问题。 输出的顺序取决于$tableData 中的数据,如果它依赖于$headings,则不太直观(也不太有用)。

以下是原始代码中这些问题的示例:

//for example if your data changes to this and run your original code
 $tableData = array (
 0 => 
    array (
        'id' => 102,
        'lastname' => 'Bing',
        'title' => 'Doctor',
        'timestamp' => '2019-01-1810:17:05',
        'member_no' => null,
        'firstname' => 'Ross', //intentionally moved to show ordering
        'foo' => 'bar' //added this undefined in $headings
    ),
);

您会收到此通知,还会发现最后 2 个元素是:

 <br />
 <b>Notice</b>:  Undefined index: foo in <b>[...][...]</b> on line <b>30</b><br />
 //... all other elements ...

 //in orignal: displayed in the order of $tableData
 //in my code: order is based on $headings, so this would be moved to the correct location
Array(
    [0] => Array (
         [data] => <strong>First Name</strong>
    )        
    [1] => Ross
)

//in orignal: $headings['foo'] is not defined so we have no label here
//in my code: this element is removed and doesn't get rendered
Array(
     [0] => Array(
           [data] => <strong></strong>
      )

     [1] => bar
)

Sandbox (Orignal Code)

虽然这些事情可能永远不会引起问题,但它突出了我的观点,即基于$headings 而不是$tableData 的输出。事情往往会发生变化,这样如果您从该数据中添加/删除一个字段,您就不必担心它会破坏此页面等...

array_fill_keysarray_intersect_keyarray_merge 的组合可用于将一个数组的标题(如上所示)映射到另一个数组。你可以使用array_combine($headings, $row) 物理交换它们,你会得到这样的东西:

[
     [
         '<strong>ID</strong>' => 102,
         '<strong>First Name</strong>' => 'Ross',
          //...
     ],
     [...]
]

它适用于 CSV 文件(这是我想出来的)以及您需要重新映射密钥的任何其他内容。

不管怎样,希望对你有帮助!

【讨论】:

  • 嘿@ArtisticPhoenix - 这是关于 SO 的最佳答案之一,它绝对对我有帮助!非常感谢您的详细解释,现在一切都变得更有意义了!
  • 如果您不完全了解我在本文中使用的功能以及它们如何协同工作,那就有点复杂了。但它真的很好用,我对用户提交的 CSV 文件做了很多工作(我们针对数据库运行它们,并返回报告)。所以我们必须想办法自定义标题(名称、顺序)等......因此我想出了上面所做的基本方法......谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 2017-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多