0

ブラウザを介して記録やレポートをリモートで表示できるアプリケーションを作成しています。私は CakePHP を使用してアプリケーションを作成し、正常に動作させましたが、アプリケーションはデータを読み取るだけで挿入を行わないため、ユーザーがビューを開いてレコードが挿入されたときに必要な小さな問題が 1 つあります。ユーザーがページを更新して新しいレコードを取得するのではなく、開いているすべてのクライアントを更新する必要があります。実際に動作する CakePHP Websocket プラグインはありますか? 私たちのウェブホストは、プログラムのインストールやApacheモジュールの追加を許可していないため、nodejsまたは同様のソリューションはここでは適用できません.

アプリケーションファイルをウェブサーバーにアップロードするだけですべてが実行される、純粋にphpとjavascriptの実装を探しています。ファイルをアップロードした後、実行したり、エクストラをインストールしたり、apache などで構成を行ったりする必要はありません。

これは、ビューにデータを取得するコントローラーの1つ(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) の 1 つです。

<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>

トリガーの使用

別のオプションは、トリガーを使用することです。たとえば、テーブル名を使用してテーブルと時間値を接続する追加のテーブルと、挿入用と更新用の 2 つのトリガーが必要です。これらのトリガーは、カスタム情報テーブルを更新できます。

情報テーブル

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は前の例と同じです。


行のカウント

最後のオプションは行数を比較することです。これはもちろん挿入に対してのみ機能します。この例では、モデルは変更されません。

コントローラ:

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 に答える