そこで、Flickr のような PHP サイトをセットアップしていますが、これらの写真は評価できます。そのため、ユーザーが星をクリックして写真を評価すると、写真の星が計算された新しい評価を反映するように、AJAX で評価システムを設定しています。(写真の評価は、黄色または空白の 10 個の星で表されます)。
星は、マウスオーバーすると、カーソルが指している場所に点灯するように反応します。星をクリックすると、対応する値が photo_rating テーブルに記録され、photo テーブルで更新されます。次に、新しく計算された評価が星に反映されます。
更新 ほとんどすべてが、この呼び出しが正しい評価を返さないことに要約されます。ページが読み込まれたときに、写真の元の評価が返されます。また、AJAX を介して DB に保存された新しい評価ではありません (DB の値は変更されていますが)。
onmouseout="stars_current_rating(<?php echo Photograph::find_by_id($_GET['id'])->rating;?>);"
ここに問題があります。クリックすると、新しく計算された正しい評価で星が更新されます。しかし、星の上にマウスを戻すと、マウスが外れます。星の評価は、ユーザーが最初にページを読み込んだときの元の評価に戻ります。したがって、反映されている評価は、ページが読み込まれたときにデータベースから取得されたものです。写真テーブルの評価列に現在存在する値ではありません。
もともと $photo->rating を使用していましたが、AJAX を使用したため、その値が再度計算されていないことがわかりました。そこで、onmouseout を切り替えて Photograph::find_by_id($_GET['id'])->rating; を呼び出しました。IDからデータベースをチェックし、現在の評価を取得することにより、新しいオブジェクトをインスタンス化する必要があります。しかし、これでも更新された値が得られないようです。
私はfirebug、firePHPを使用しており、プロファイリングを行って、これらのメソッドをクリックしてマウスオーバーしたときにこれらのメソッドに渡される値を正確に確認しています。何らかの理由で、ユーザーが投票した直後に、新しい評価が DB からのみ取得され、新しい値が表示されます。ただし、星の上にマウスを置いた後はいつでも、ページを読み込んだときの状態に戻ります. ページ全体を更新せずに、更新された値を以下のコードに反映させる方法はありますか? ページを更新すると機能しますが、ポイントはすべてAJAXを介して行うことでしたので、ページ全体をリロードする必要はありません...
これは、呼び出しがページに設定される方法です。
<div id="rating" class="rating">
<?php
for($i=1; $i<11; $i++){
?>
<a id="rating_star<?php echo $i ?>" href="#" onmouseover="decide_rating(<?php echo $i ?>);"
onmouseout="stars_current_rating(<?php echo Photograph::find_by_id($_GET['id'])->rating;?>);"
onmousedown="set_rating(<?php echo $photo->id.", ".$i ?>);">
<img id="star<?php echo $i ?>" class="rating_star" src=
<?php
// keeps stars always set at rating for photo when not being rated
if($photo->rating >= $i){
echo "images/assets/rating_star.png";
} else {
echo "images/assets/rating_star_off.png";
}
?>
/>
</a>
<?php } ?>
</div>
上記の onmouseactions で使用した 3 つを含む rating.js ファイルを次に示します (decision_rating と stars_current_rating は同じコードであることは理解していますが、ロジックが異なる別のページ用に設定したときは異なっていましたが、更新はうまくいかなかったので、この単純な例に戻りました)
// Makes stars light up, up to where you have your cursor pointing
// pass in current rating of star hovered over
function decide_rating( r ){
for(var i=1; i<=10; i++){
var star = document.getElementById("star"+i);
if(i<=r){
star.src = "images/assets/rating_star.png";
} else {
star.src = "images/assets/rating_star_off.png";
}
}
return false;
}
// defaults the stars to light up with the current rating
function stars_current_rating(r){
for(var i=1; i<=10; i++){
var star = document.getElementById("star"+i);
if(i<=r){
star.src = "images/assets/rating_star.png";
} else {
star.src = "images/assets/rating_star_off.png";
}
}
return false;
}
function set_rating(pid, rating){
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
// no message to be displayed
//document.getElementById("message").innerHTML=xmlhttp.responseText;
// for this to work ratings.js must be before this file when linked to
// set_ratings is echoing the $photo->rating for the calling pid
// as the xmlhttp.responseText
stars_current_rating(xmlhttp.responseText);
}
}
xmlhttp.open("GET","../includes/set_rating.php?pid="+pid+"&rating="+rating,true);
xmlhttp.send();
}
データベースに2つのテーブルを設定しました。1 つは、user_id、photo_id、および rating を持つ photo_rating です。photo テーブルには、現在の評価の列もあります (これは、photo_rating の対応する行の平均として計算されます)。
以下は、AJAX が呼び出している set_rating.php ファイルです。
<?php
// This file is called by the ratings.js function set_rating
// echo output is used by to update the current rating of the
// photo after it has been saved in the database
require_once('initialize.php');
// create new photo rating and set up attributes
if(isset($session->user_id)){
$pr = new PhotoRating( $_GET['pid'], $session->user_id, $_GET['rating']);
} else {
$pr = new PhotoRating( $_GET['pid'], NULL, $_GET['rating']);
}
// save the rating in photo_ratings table
// and the rating in the photograph table
$pr->save_rating_update_photo();
echo Photograph::find_by_id($_GET['pid'])->rating;
?>
これらは、PhotoRating 内で呼び出されている関数です。
// saves the current photo_rating into the database
// Then calls update photo rating up update the
// rating in the photo database table
function save_rating_update_photo(){
if($this->save()){
// Success
$message = "entry saved in photo_rating";
//$session->message("{$photo->filename} was uploaded");
} else {
// Failure
$message = join("<br />", $this->errors);
}
$this->update_photo_rating();
}
function update_photo_rating(){
$photo = Photograph::find_by_id($this->p_id);
$newRating = ($this->rating + self::sum_all_ratings($this->p_id))/($this->count_all()+1);
$photo->rating = $newRating%10;
if($photo->save()){
// Success
} else {
// Failure
$message = join("<br />", $photo->errors);
}
}
昨日遅くにこれをテストし始めて以来、私は机に頭をぶつけていました。ページをリロードするだけでよいことは理解していますが、これはすべて AJAX を介して行う効率を無効にしているように感じます。