Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Let’s make some updates to our voting system to make sure a user can have only a single vote registered per book. We are going to update our book list as well to show the way the user voted by changing the arrow color.
Breaking Down the Query
Let's break down this query now that it has become more complex.
First we select all columns from the books table and get the sum total of votes for a book and saving that column as
SELECT books.*, sum(votes.value) as score, "
Then, we have a nested select statement to get our vote for the book. This is a basic select from votes where the book_id on the votes table is the same as the current book from the query, and we are getting only the vote where the user_id is our id. We then save that as myVote.
. " (SELECT value FROM votes " . " WHERE votes.book_id=books.id " . " AND votes.user_id=:userId) as myVote"
The main table used in the select.
. " FROM books "
To get the score used in the first line, we do a LEFT JOIN of the votes table where the id of the current book equals the book_id's from the votes table.
. " LEFT JOIN votes ON (books.id = votes.book_id) "
Then, I want to group everything by the book id so I only have 1 row per book
. " GROUP BY books.id "
Finally we order the books by the score DESC so the highest voted book is at the top and the lowest scored book is at the bottom.
. " ORDER BY score DESC";
For the final step in our book voting system,
I want to update the way our voting works.
Only authenticated users should be able to vote, and
any user can only vote once per book.
But that user is always able to change their vote.
Open the book.php file in the inc folder.
Around the arrows, let's check if the user is authenticated.
Next, we want to update our arrows to show the way the current user has voted.
We're going to change the color of the arrows if our user's vote corresponds
to one of the vote directions.
If ($book['myVote'] = 1,
Then we're going to set the style="color:orange".
We'll do the same thing to the down arrow, only we'll change it to -1.
To get my vote, we need to update the get all books function.
First we need the userId.
Let's set the default to 0, then, if (isAuthenticated,
Then we can set the userId equal to the userId in our jwt,
we'll decodeJwt and pass sub.
Now we need to update our query statement by adding an inner select statement.
Make sure you add a comma.
And then in parentheses, we're going to add SELECT value FROM votes.
And this will be as myVote.
Now we need to bind our variable.
Next we want to clear the votes for the current user and book combination.
So, we don't have duplicate votes for our user.
Let's go down to our vote.
Below the vote function, let's add a new function.
We'll call this clearVote.
And we'll pass the bookId.
We'll need our global $db.
And once again, we'll pull the userId from our Jwt.
For our query, we'll DELETE FROM
votes WHERE book_id = :bookId AND
user_id = :userId.
We'll prepare our query, And then bind our variables.
Execute and then we'll return the row count.
This will tell us if we actually removed a vote or not.
Finally, we need to update our vote procedure.
We're going to wrap our switch statement in the clearVote.
if (!clearVote and pass the bookId.
Then we'll make a vote.
We either clear the vote or make a vote.
Finally we need to update our vote function to use the current user to score
Instead of the user ID = 0, we'll use our decodeJwt and pass sub.
Great, we're now setting our votes table to record our user, and
we're allowing the user to vote only once.
Let's go back to the browser and view the book list page.
Great, we can now make only a single vote for each book,
either we have no vote, one vote up, Or one vote down.
You need to sign up for Treehouse in order to download course files.Sign up