Обновление и отображение самой последней записи (в БД) после того, как AJAX обновит значение через PHP

Итак, я создаю PHP-сайт, такой как Flickr, за исключением того, что эти фотографии можно оценивать. Поэтому я настраиваю систему оценок в AJAX, чтобы, когда пользователь нажимал на звезду, чтобы оценить фотографию, звезды на фотографии отражали новый вычисленный рейтинг. (рейтинг фотографии обозначен 10 желтыми или пустыми звездами).

Звезды реагируют так, как должны, когда вы наводите на них курсор, они загораются там, где указывает ваш курсор. Когда вы нажимаете звездочку, соответствующее значение регистрируется в таблице photo_rating и обновляется в таблице фотографий. Затем вновь вычисленный рейтинг отражается через звезды.

ОБНОВЛЕНИЕ Практически все сводится к тому, что этот вызов не возвращает правильную оценку, он по-прежнему возвращает исходную оценку фотографии при загрузке страницы. А не тот новый рейтинг, который сохранился в БД через AJAX (хотя значение в БД изменено)

onmouseout="stars_current_rating(<?php echo Photograph::find_by_id($_GET['id'])->rating;?>);"

ЗДЕСЬ проблема: после нажатия звезды обновляются с правильным недавно рассчитанным рейтингом. Но когда я снова наведу курсор мыши на звезды, тогда мышка исчезнет. Звездный рейтинг возвращается к исходному рейтингу, который был у него, когда пользователь впервые загрузил страницу. Таким образом, отображаемый рейтинг — это то, что было извлечено из базы данных при загрузке страницы. Не то значение, которое сейчас находится в столбце рейтингов таблицы фотографий.

Первоначально я использовал $photo->rating, но я понял, что, поскольку я использовал AJAX, это значение больше не вычислялось. Затем я переключил onmouseout на вызов Photograph::find_by_id($_GET['id'])->rating; который должен создавать экземпляр нового объекта, проверяя базу данных по его идентификатору и получая текущий рейтинг. Но даже это, похоже, не дает мне обновленного значения.

Я использовал firebug, firePHP и выполняю профилирование, чтобы точно увидеть, какие значения передаются в эти методы, когда я нажимаю на них мышью. По какой-то причине новый рейтинг только извлекается из БД, сразу после того, как пользователь проголосовал, отображается новое значение. Но в любое время после того, как вы наведете курсор мыши на звезды, они вернутся к тому, что было при загрузке страницы. Могу ли я каким-либо образом отразить это обновленное значение в приведенном ниже коде без обновления всей страницы? Если я обновлю страницу, то она сработает, но весь смысл был в том, чтобы сделать все это через 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>

Вот мой файл ratings.js, который содержит 3, использованные выше для onmouseactions (я понимаю, чтоsolve_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 таблицами в моей базе данных. Одним из них является photo_rating, который имеет user_id, photo_id и рейтинг. В таблице фотографий также есть столбец с текущим рейтингом (который рассчитывается как среднее значение соответствующих строк в photo_rating).

Ниже приведен файл set_rating.php, который вызывает AJAX.

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


person Alan DeLonga    schedule 05.10.2012    source источник
comment
Это определенно будет в слишком длинной, не прочитанной категории для большинства людей здесь. Можете ли вы немного изолировать проблему?   -  person NullUserException    schedule 05.10.2012
comment
Можете ли вы дать ссылку на пример этого кода в действии? Может быть немного проще отлаживать   -  person pivot    schedule 05.10.2012
comment
Да, я это понимаю, поэтому я поставил свой вопрос вверху. Я старался быть как можно более конкретным. Затем я показал весь код, относящийся к нему. Лучше иметь слишком много информации, чем ее недостаточно, особенно когда не вы написали код... верно? frompointatobeyond.com/photo_social/public/photo.php?id=48   -  person Alan DeLonga    schedule 05.10.2012
comment
Но в любое время после того, как вы наведете курсор мыши на звезды, они вернутся к тому, что было при загрузке страницы. Могу ли я каким-либо образом отразить это обновленное значение в приведенном ниже коде без обновления всей страницы? Таким образом, при загрузке страницы PHP (на стороне сервера) отвечает за отображение текущего звездного рейтинга. Что такое эквивалентный код JS, чтобы сделать то же самое сразу после сообщения XHR, чтобы установить рейтинг по клику? Его нет или он работает некорректно?   -  person ficuscr    schedule 05.10.2012
comment
@ficuscr в последней строке вызова AJAX я вызываю stars_current_rating(xmlhttp.responseText); Это единственный раз, когда у меня загораются правильные звезды после того, как пользователь выбирает свой рейтинг. После этого последующие вызовы с использованием функции onmouseout с параметрами stars_current_rating(‹?php echo Photograph::find_by_id($_GET['id'])-›rating;?›); не дает мне обновленное значение, которое было сохранено для рейтинга в таблице фотографий   -  person Alan DeLonga    schedule 05.10.2012
comment
хорошо, я вижу для данного сеанса frompointatobeyond.com/photo_social/includes/ Всегда возвращает одно и то же, независимо от того, что я нажимаю. Используете ли вы правильные инструменты, чтобы увидеть эти вещи? Фаербаг что-ли?   -  person ficuscr    schedule 05.10.2012
comment
Хорошо, похоже, что мой локальный хост и сервер находятся в двух разных состояниях, приношу свои извинения. Вы правы в том, что сервер не делает то, что я вижу через свой локальный хост. Я постараюсь обновить его, я больше сосредоточился на решении проблемы на моей локальной машине, прежде чем отправлять ее на сервер, извините.   -  person Alan DeLonga    schedule 05.10.2012
comment
Итак, теперь сервер делает то же самое, вы можете проверить это, как и я, открыв firebug, щелкнув вкладку профиля, а затем щелкнув ссылки. Когда вы закончите тестирование, снова щелкните вкладку профиля, и она отобразит каждое событие мыши и соответствующую функцию, которая была вызвана вместе с ее параметрами.   -  person Alan DeLonga    schedule 05.10.2012


Ответы (1)


Кратко изучив ваш вопрос/проблему и проверив источник вашего работающего сайта, я бы сделал следующее:

В рейтингах.js вверху добавьте:

// Global variable to hold the current rating
var star_rating = 0;

Измените stars_current_rating(r) на:

// defaults the stars to light up with the current rating
function stars_current_rating(){ // no "r"
    for(var i=1; i<=10; i++){
        var star = document.getElementById("star"+i);
        if(i<=star_rating){ // !!!
            star.src = "images/assets/rating_star.png";
        } else {
            star.src = "images/assets/rating_star_off.png";
        }
    }
    return false;
}

В set_rating(pid, rating) измените текущую строку 48 на эту:

star_rating = xmlhttp.responseText;
stars_current_rating();

В photo.php в каждом a измените onmouseout на:

onmouseout="stars_current_rating();"

Причина, по которой вы не получаете ожидаемого результата, заключается в том, что значение рейтинга жестко закодировано в вызове функции onmouseout. Наличие переменной в javascript, которая изменяется с ответом xmlhttp, имеет решающее значение.

Чтобы это работало и при загрузке страницы, создайте часть скрипта в photo.php, которая правильно устанавливает star_rating (через <?php echo Photograph::find_by_id($_GET['id'])->rating;?>)

Надеюсь это поможет!

person Alasjo    schedule 05.10.2012
comment
Хорошо, что кажется, что это будет работать лучше. Имеет гораздо больше смысла, что onmouseout не обновляет значение, что испортило бы всю эту логику. Я внес эти изменения и все работает. Еще раз спасибо, что нашли время, чтобы просмотреть его, я очень ценю помощь. - person Alan DeLonga; 06.10.2012