【问题标题】:Update CakePhp View each time a record is inserted in the db table每次在 db 表中插入记录时更新 CakePhp View
【发布时间】:2013-07-28 09:09:11
【问题描述】:

我正在制作一个可以通过浏览器远程查看记录和报告的应用程序。我已经使用 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来实现吗?

【问题讨论】:

    标签: javascript jquery cakephp websocket phpwebsocket


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      更新我误解了这个问题,如果插入/更新是由您无法直接控制的外部来源制作的,如 cmets 中所述,我能想到的唯一选择检查是否需要更新视图,将检查 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'];
      }
      

      ControllerView 与前面的示例相同。


      计算行数

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

      控制器:

      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>
      

      【讨论】:

      • 我没有从 cakephp(网络应用程序)进行任何更新或插入,所以这仍然有效吗? "缓存::write('model_last_update_books', time());"
      • 对不起,我误解了你的问题。不,在这种情况下,这将不起作用,因为 afterSave 回调仅在模型保存时触发。您对进行实际插入/更新的应用程序有任何影响吗?即,您是否可以让它插入/更新其他数据,或者如果它在同一台服务器上运行,则将数据写入文件系统?如果没有,插入/更新是否可能包括创建/修改日期?
      • 我无权访问该系统及其桌面应用程序、不同用户的电脑和我们应用程序服务器上的服务器,但它不会保存所有表格的修改日期和时间,我们需要的大部分数据是在没有修改日期和时间的表格中
      • 我明白了……您使用的是哪个 DBMS(版本和存储引擎)?这是一个固定的要求,还是您想支持不同的 DBMS?
      • 我们正在使用 Mysql 以及 innodb 和 myisam 表。我们无法更改,因为桌面系统无法支持另一个 dbms。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-13
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      相关资源
      最近更新 更多