每次在db表中插入记录时更新CakePhp视图

时间:2013-07-28 09:09:11

标签: javascript jquery cakephp websocket phpwebsocket

我正在创建一个能够通过浏览器远程查看记录和报告的应用程序。我已经使用cakePHP来使应用程序和它的工作正常,但我有一个小问题,因为应用程序不执行任何插入它只是读取数据,我想当用户打开一个视图并且已插入记录该表,它应该更新所有打开的客户端,而不是用户刷新页面以获取新记录。 是否有一个cakePHP websocket插件实际上有效吗? 我们的webhost不允许安装程序或添加apache模块,因此nodejs或类似的解决方案不适用于此。

  

我正在寻找一个纯粹的php和javascript实现   只需将您的应用程序文件上传到Web服务器即可   运行。你不必运行,安装额外的东西或对apache或东西进行任何配置......在上传文件之后

这是我的一个控制器(BooksController.php)中的一个函数,它将数据检索到视图

public function list_books()
  {
    $this->Books->recursive = 0;
    $this->paginate = array('order' => array('Serial_No' => 'DESC'));
    $this->set('All_Books', $this->paginate());
  }

这是我的一个视图(list_books.ctp),它在分页的表中显示数据。

<div class="row-fluid">

    <div class="span12">
        <?php echo $this->Session->flash() ?>   
        <h4><?php echo __('All Books') ?></h4>
        <hr>               
                    <table class="table table-bordered">
            <thead>
                <tr>    <th><?php echo __('Serial No') ?></th>
                    <th><?php echo __('Title') ?></th>
                                        <th><?php echo __('Author') ?></th>
                                        <th><?php echo __('Publisher') ?></th>
                                        <th><?php echo __('Category') ?></th>
                                        <th><?php echo __('Section') ?></th>
                                        <th><?php echo __('Available') ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach( $All_Books as $book ){ ?>
                <tr>
                    <td><?php echo $this->Html->link(__($book['Book']['Serial_No']),'/books/view/'.$book['Book']['Serial_No']) ?></td>                                         
                                        <td><?php echo $book['Book']['Title'] ?></td>
                                        <td><?php echo $book['Book']['Author'] ?></td>
                                        <td><?php echo $book['Book']['Publisher'] ?></td>
                                        <td><?php echo $book['Book']['Category'] ?></td>
                                        <td><?php echo $book['Book']['Section'] ?></td>
                                        <td><?php echo $book['Book']['Available'] ?></td>
                </tr>
                <?php } ?>
            </tbody>
        </table>
                <?php echo $this->Paginator->prev('« Previous', null, null, array('class' => 'disabled'));            
echo $this->Paginator->numbers();
echo $this->Paginator->next('Next »', null, null, array('class' => 'disabled'));
echo $this->Paginator->counter(array(
    'format' => 'Page {:page} of {:pages}, showing {:current} records out of
             {:count} total, starting on record {:start}, ending on {:end}'
));
 ?>
    </div>

</div>

我可以在视图或控制器或模型上添加什么,以使视图自动更新? 这可以用ajax实现吗?

2 个答案:

答案 0 :(得分:0)

您可以使用AJAX轮询器或(HTML5)websockets(例如使用Pusher)进行推送通知。

答案 1 :(得分:0)

你已经提到过它,AJAX。这是完成此类操作的最简单方法,只需通过AJAX在后台进行检查,并在必要时重新加载页面,或者再次使用AJAX请求更新受影响的部分。

根据数据量,您当然可以直接加载数据,而不是先检查更新。

更新我误解了这个问题,如果插入/ udpates来自您没有直接控制的外部来源,如评论中所述,我可以选择的唯一选项考虑检查是否有必要更新视图,将检查UPDATE_TIME information schema(仅适用于MyISAM),使用triggers更新可以检查的自定义信息模式,或者计算行数,但后者只会覆盖插入行。

所有方法都将获取特定视图的控制器操作中的比较值(更新时间或行数),并将该值传递给随后在AJAX调用中使用的视图。 AJAX调用调用一个控制器方法,将传递的值与当前时间/计数值进行比较,以确定是否需要更新。

请注意,这些示例未经测试!

信息架构

最简单的方法是检查UPDATE_TIME信息架构,但是如上所述,这仅适用于MyISAM表:

<强>型号:

public function getUpdateTime()
{   
    $db = $this->getDataSource();

    $result = $db->fetchAll('
        SELECT
            UNIX_TIMESTAMP(UPDATE_TIME) AS update_time
        FROM
            information_schema.tables
        WHERE
            TABLE_SCHEMA = ?
            AND
            TABLE_NAME = ?',

        array
        (
            $db->config['database'],
            $this->table
        )
    );

    if(empty($result) || !isset($result[0][0]['update_time']))
    {
        return false;
    }

    return (int)$result[0][0]['update_time'];
}

<强>控制器:

public function list_books()
{
    $this->set('lastUpdate', $this->Books->getUpdateTime());

    $this->Books->recursive = 0;
    $this->paginate = array('order' => array('Serial_No' => 'DESC'));
    $this->set('All_Books', $this->paginate());
}

public function checkForUpdate($time)
{
    $updateNecessary = $this->Books->getUpdateTime() > (int)$time;
    return new CakeResponse(array('body' => json_encode($updateNecessary)));
}

查看:

<script>
jQuery(function($)
{
    var lastUpdate = <?php echo $lastUpdate; ?>;

    function checkForUpdate()
    {
        $.get('/books/checkForUpdate', {time: lastUpdate}, function(updateNecessary)
        {
            if(updateNecessary === true)
            {
                alert('update necessary');
                // now reload the page or use an additional AJAX request for updating the content
            }
            else
            {
                queueUpdateCheck();
            }
        },
        'json');
    }

    function queueUpdateCheck()
    {
        setTimeout(checkForUpdate, 5000);
    }

    queueUpdateCheck();
});
</script>

使用触发器

另一种选择是使用triggers。您需要一个额外的表来连接表和时间值,例如使用表名和两个触发器,一个用于插入,一个用于更新。然后,这些触发器可以更新自定义信息表。

信息表

CREATE TABLE IF NOT EXISTS `table_stats` (
  `table_name` varchar(255) NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`table_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

INSERT INTO `table_stats` (`table_name`, `update_time`)
VALUES ('books', NOW());

<强>触发器

CREATE TRIGGER `update_time_after_insert` AFTER INSERT ON `books`
    FOR EACH ROW 
        UPDATE `table_stats` SET `update_time` = NOW() WHERE `table_name` = 'books';

CREATE TRIGGER `update_time_after_update` AFTER UPDATE ON `books`
    FOR EACH ROW 
        UPDATE `table_stats` SET `update_time` = NOW() WHERE `table_name` = 'books';

<强>型号:

public function getUpdateTime()
{   
    $db = $this->getDataSource();

    $result = $db->fetchAll('
        SELECT
            UNIX_TIMESTAMP(update_time) AS update_time
        FROM
            `table_stats`
        WHERE
            `table_name` = ?',

        array
        (
            $this->table
        )
    );

    if(empty($result) || !isset($result[0][0]['update_time']))
    {
        return false;
    }

    return (int)$result[0][0]['update_time'];
}

控制器查看与上一个示例相同。


计算行

现在最后一个选项是比较行数,这当然只适用于插入。在此示例中,模型将保持不变。

<强>控制器:

public function list_books()
{
    $this->set('rowCount', $this->Books->find('count'));

    $this->Books->recursive = 0;
    $this->paginate = array('order' => array('Serial_No' => 'DESC'));
    $this->set('All_Books', $this->paginate());
}

public function checkForUpdate($rowCount)
{
    $updateNecessary = $this->Books->find('count') != (int)$rowCount;
    return new CakeResponse(array('body' => json_encode($updateNecessary)));
}

查看:

<script>
jQuery(function($)
{
    var rowCount = <?php echo $rowCount; ?>;

    function checkForUpdate()
    {
        $.get('/books/checkForUpdate', {rowCount: rowCount}, function(updateNecessary)
        {
            if(updateNecessary === true)
            {
                alert('update necessary');
                // now reload the page or use an additional AJAX request for updating the content
            }
            else
            {
                queueUpdateCheck();
            }
        },
        'json');
    }

    function queueUpdateCheck()
    {
        setTimeout(checkForUpdate, 5000);
    }

    queueUpdateCheck();
});
</script>

与更新检查一起检索数据

当然,您也可以提交可能的数据以及更新检查,以避免其他请求。例如:

<强>模型

public function checkForUpdate($time)
{
    $data = '';

    $updateAvailable = $this->Books->getUpdateTime() > (int)$time;
    if($updateAvailable)
    {
        $this->set('books', $this->Books->find('all'));

        // render /Elements/books.ctp in ajax.ctp layout and grab the rendered content
        $this->viewPath = 'Elements';
        $view = $this->render('books', 'ajax');
        $data = $view->body();
    }

    $body = compact('updateAvailable', 'data');

    return new CakeResponse(array('body' => json_encode($body)));
}

查看

<script>
jQuery(function($)
{
    var lastUpdate = <?php echo $lastUpdate; ?>;

    function checkForUpdate()
    {
        $.get('/books/checkForUpdate', {time: lastUpdate}, function(response)
        {
            if(response.updateAvailable === true)
            {
                // the data is already available, so directly update the content
                $('#content').html(response.data);
            }

            queueUpdateCheck();
        },
        'json');
    }

    function queueUpdateCheck()
    {
        setTimeout(checkForUpdate, 5000);
    }

    queueUpdateCheck();
});
</script>