0

我正在制作一个应用程序,可以通过浏览器远程查看记录和报告。我已经使用 cakePHP 使应用程序及其工作正常,但我有一个小问题,因为应用程序不做任何插入它只是读取数据,我想要当用户打开视图并插入记录时表,它应该更新所有打开的客户端,而不是用户刷新页面来获取新记录。是否有实际工作的 cakePHP websocket 插件?我们的虚拟主机不允许安装程序或添加 apache 模块,因此 nodejs 或类似的解决方案在这里不适用。

我正在寻找一个纯粹的 php 和 javascript 实现,您只需将应用程序文件上传到网络服务器并运行一切。您不必在 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来实现吗?

4

2 回答 2

0

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

于 2013-07-28T11:48:18.940 回答
0

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

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

更新我误解了这个问题,如果插入/更新是由您无法直接控制的外部来源进行的,如评论中所述,我能想到的检查是否有必要更新视图的唯一选项是检查UPDATE_TIME 信息模式(仅适用于 MyISAM),使用触发器更新可以检查的自定义信息模式,或计算行数,但后者仅涵盖插入。

所有方法都会在特定视图的控制器操作中获取比较值(更新时间或行数),并将该值传递给视图,然后在 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>

使用触发器

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

信息表

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>
于 2013-07-28T11:48:32.860 回答