douxun4860 2013-06-19 11:10
浏览 36

如何从Lithium中的记录集的所有实体中删除特定字段?

I am using MySQL as the database connection adapter for all my models. I have a downloads model and controller with an index function that renders either an HTML table or a CSV file depending on the type passed from the request. I also have a CSV media type to handle an array of data, which is working as expected (outputs array keys as headers then array values for each row of data).

I wish to do the same find query but then remove ID fields from the record set if a CSV file is going to be rendered. You'll notice that the download ID is being fetched even though it is not in the fields array, so simply changing the fields array based on the request type will not work.

I have tried the following in the index action of my downloads controller:

<?php
namespace app\controllers;
use app\models\Downloads;

class DownloadsController extends \lithium\action\Controller {

    public function index() {

        // Dynamic conditions
        $conditions = array(...);

        $downloads = Downloads::find('all', array(
            'fields' => array('user_id', 'Surveys.name'),
            'conditions' => $conditions,
            'with' => 'Surveys',
            'order' => array('created' => 'desc')
        ));

        if ($this->request->params['type'] == 'csv') {
            $downloads->each(function ($download) {

                // THIS DOES NOT WORK
                unset($download->id, $download->user_id);

                // I HAVE TRIED THIS HERE AND THE ID FIELDS STILL EXIST
                // var_dump($download->data());
                // exit;

                return $download;
            });
            return $this->render(array('csv' => $downloads->to('array')));
        }

        return compact('downloads');
    }

}
?>

I thought there was an __unset() magic method on the entity object that would be called when you call the standard PHP unset() function on an entity's field.

It would be great if there was a $recordSet->removeField('field') function, but I can not find one.

Any help would be greatly appreciated.

  • 写回答

2条回答 默认 最新

  • doufangyan6862 2013-06-19 22:28
    关注

    Perhaps you should do $downloads = $downloads->to('array');, iterate the array with a for loop, remove those fields from each row, then return that array. If you have to do this same thing for a lot of actions, you could setup a custom Media handler that could alter the data without needing logic for it in your controller.

    Take a look at this example in the Lithium Media class unit test.

    You can also avoid having much logic for it in your controller at all through the use of a custom handler. This example also auto-generates a header row from the keys in your data.

    In config/bootstrap/media.php:

    Media::type('csv', 'application/csv', array(
        'encode' => function($data, $handler, $response) {
            $request = $handler['request'];
            $privateKeys = null;
            if ($request->privateKeys) {
                $privateKeys = array_fill_keys($request->privateKeys, true);
            }
            // assuming your csv data is the first key in
            // the template data and the first row keys names
            // can be used as headers
            $data = current($data);
            $row = (array) current($data);
            if ($privateKeys) {
                $row = array_diff_key($row, $privateKeys);
            }
            $headers = array_keys($row);
            ob_start();
            $out = fopen('php://output', 'w');
            fputcsv($out, $headers);
            foreach ($data as $record) {
                if (!is_array($record)) {
                    $record = (array) $record;
                }
                if ($privateKeys) {
                    $record = array_diff_key($record, $privateKeys);
                }
                fputcsv($out, $record);
            }
            fclose($out);
            return ob_get_clean();
        }
    ));
    

    Your controller:

    <?php
    namespace app\controllers;
    use app\models\Downloads;
    
    class DownloadsController extends \lithium\action\Controller {
    
        public function index() {
    
            $this->request->privateKeys = array('id', 'user_id');
    
            // Dynamic conditions
            $conditions = array(...);
    
            $downloads = Downloads::find('all', array(
                'fields' => array('user_id', 'Surveys.name'),
                'conditions' => $conditions,
                'with' => 'Surveys',
                'order' => array('created' => 'desc')
            ));
    
            return compact('downloads');
        }
    
    }
    ?>
    
    评论

报告相同问题?

悬赏问题

  • ¥15 msix packaging tool打包问题
  • ¥28 微信小程序开发页面布局没问题,真机调试的时候页面布局就乱了
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线