Laravel Shop tutorial #1 – Building a review system

The first tutorial in “Building a shop” series is going to be a practical example of implementing a rating/review system into an application. Review systems or rating systems are very common in all kinds of e-Commerce projects, social networks, anything that requires user’s input to be some sort of concrete value on some scale.

DEMO: http://demos.maxoffsky.com/shop-reviews Source on Github : https://github.com/msurguy/laravel-shop-reviews

A very common example of a review system is when the user can submit a rating of 1-5 stars and a comment that goes with the rating like on Etsy.com:

Imagine this, you have an online shop that has products, products have reviews that consist of a rating and a comment.

This is the idea that we will replicate in this tutorial.

Here’s how this tutorial will follow the steps to reach that goal:

  1. See the Demo of the project in action to get an idea of what you will make (the link is above at the beginning of tutorial)
  2. Think about efficiency
  3. Define the routes for showing the products, showing individual product and submitting the reviews
  4. Define the database structure and the models for the products and for the reviews
  5. Create the view templates to display the shop home page and the individual product page.
  6. Create functions that will calculate and store ratings/reviews
  7. Create logic for the defined routes
  8. Refactor the code if necessary

I have looked at lots of jQuery plugins that make it a bit easier to create a nice user experience for rating a product by the number of stars/hearts, and I have found this little plugin that does the job efficiently: https://github.com/dobtco/starrr I have modified it to work with Bootstrap 3 and the modified version is included in the source code of this application.

What are the difficulties of implementing such a review system?

Well, first of all efficiency is an important factor that we will have to include in making architectural decisions. As an example, let’s think about how the product will store user’s reviews.

One way to store reviews is to store everything separately – the rating, the comment and the product each in a separate database table. We could relate the rating to the comment (one to one relationship) and then store the comment under a product as one to many relationship (a product has many reviews).

A disadvantage of this way of storing the data for reviews is that there is quite a bit of overhead (a bit too much nesting which mean lots of inefficient SQL joins). Why don’t we combine the rating and the comment into one entity and call it “Review”? Perhaps this will be a better structure for storing the comment and rating data together.

When the user submits a review, we will store both a rating (consisting of number of stars the user gives this product) and a comment (perhaps the user has something to say about the product) as a new row in table designated to store our reviews.

We also need to somehow calculate an average rating for each product based on submitted reviews and show it on product’s page and on the page that lists all products.

Online shops usually have pages that display many products at once. Take for example the homepage that shows a list of latest products. It is vital for shop’s performance that displaying products and a review count/rating will be a quick task for our application, with as few SQL queries as possible.

Taking this into an account, if we try to calculate the average rating for the product on the fly we will run into performance issues. Therefore as a step of precaution, let’s save the calculated ratings in the products table (for example as rating_cache) as well as saving all the reviews in the designated table. This way when we retrieve a product from the database, we will have all necessary information to display right away instead of executing too many unnecessary SQL queries.

Well, enough talking! Let’s see the application in action! I have made the code available on Github here and the live application is at http://demos.maxoffsky.com/shop-reviews play with it, leave some reviews for products and see how the application feels.

As we have thought about the efficiency and have checked out the demo of the application in action, let’s define the routes for the application.

Defining the routes for the shop homepage, displaying the product and submitting a review.

Our application will have 3 simple routes, a route that shows all products, a route that shows individual product and a a route that is executed upon submittal of a review.

Let’s open up the routes.php file and create a placeholder for these routes:

<?php

// Route for Homepage - displays all products from the shop
Route::get('/', function()
{
  return 'Shop homepage';
});

// Route that shows an individual product by its ID
Route::get('products/{id}', function($id)
{
  return 'Product: '.$id;
});

// Route that handles submission of review - rating/comment
Route::post('products/{id}', array('before'=>'csrf', function($id)
{	
  return 'Review submitted for product '.$id;
}));

This seems like a good start. These route placeholders will be filled out as we are progressing through the tutorial. Now let’s define what the database for this application will look like and what its data models will look like.

Defining the database structure and the data models:

Let’s think a bit about where the data will live for the application. I have created a simple diagram showing the different components of the product and reviews that users will leave on the product. Please look at the diagram below.

Let’s define a database structure that will store the data according to the diagram above.

The database will have the following tables:

  • Users (to store user information like name, email, password to log in)
  • Products (Will store product – related data such as name, descriptions, icon for the product, and finally rating cache and rating count)
  • Reviews (Will store reviews that users will leave for the product)

Here is the database structure visualized (click to see it bigger):

And here is the SQL for the database, including some sample data for the products:

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `published` tinyint(1) NOT NULL DEFAULT '0',
  `rating_cache` float(2,1) unsigned NOT NULL DEFAULT '3.0',
  `rating_count` int(11) unsigned NOT NULL DEFAULT '0',
  `name` varchar(255) NOT NULL,
  `pricing` float(9,2) unsigned NOT NULL DEFAULT '0.00',
  `short_description` varchar(255) NOT NULL,
  `long_description` text NOT NULL,
  `icon` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

INSERT INTO `products` (`id`, `published`, `rating_cache`, `rating_count`, `name`, `pricing`, `short_description`, `long_description`, `icon`, `created_at`, `updated_at`) VALUES
(1, 1, 3.0, 0, 'First product', 20.99, 'This is a short description asdf as This is a short description asdf as', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', '', '2013-11-06 05:11:00', '2013-11-12 05:51:07'),
(2, 1, 3.0, 0, 'Second product', 55.00, 'This is a short description', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', '', '2013-11-06 05:11:00', '2013-11-11 16:17:23'),
(3, 1, 3.0, 0, 'Third product', 65.00, 'This is a short description', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', '', '2013-11-06 05:11:00', '2013-11-06 06:08:00'),
(4, 1, 3.0, 0, 'Fourth product', 85.00, 'This is a short description', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', '', '2013-11-06 05:11:00', '2013-11-06 06:08:00'),
(5, 1, 3.0, 0, 'Fifth product', 95.00, 'This is a short description', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', '', '2013-11-06 05:11:00', '2013-11-06 06:08:00');

CREATE TABLE `reviews` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `rating` int(11) NOT NULL,
  `comment` text NOT NULL,
  `approved` tinyint(1) unsigned NOT NULL DEFAULT '1',
  `spam` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_type` int(10) unsigned NOT NULL DEFAULT '0',
  `email` varchar(128) NOT NULL,
  `password` varchar(128) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Whew! Now we can relate all this data together using Laravel’s models. Shall we?!

First, let’s create the model for Products that will relate reviews by one to many relationship, name it “Product.php” and place it into app/models folder:

<?php

class Product extends Eloquent
{
  public function reviews()
  {
	return $this->hasMany('Review');
  }
}

Then let’s relate the reviews to the products, to users and create some scopes for convenience, each review belongs to one user, and review can belong to only one product, the scopes will serve as shortcuts when we need to filter out reviews that are marked as spam(let’s say by the administrator), place the following into “app/models/Review.php“:

<?php

class Review extends Eloquent
{

  public function user()
  {
    return $this->belongsTo('User');
  }

  public function product()
  {
    return $this->belongsTo('Product');
  }

  public function scopeApproved($query)
  {
    return $query->where('approved', true);
  }

  public function scopeSpam($query)
  {
    return $query->where('spam', true);
  }

  public function scopeNotSpam($query)
  {
    return $query->where('spam', false);
  }
}

This is all we need for our relationships! We will add some additional functions into the models a bit later to do the necessary rating calculations/storing of ratings, but for now this will be enough for us to continue. Up next, creating view templates for displaying the products and the reviews.

Creating view templates to show products and reviews

I assume you know a thing or two about Laravel at this point so I won’t get too much into building templates and layouts, but couple things I wanted to mention is that for the review UI I have created a snippet on my Bootsnipp titled “Expanding review and rating box” which you can see below (using Bootstrap 3 for the user interface):

And for outputting user submitted reviews as a part of the product template I use the following foreach loop:

@foreach($reviews as $review)
  <hr>
  <div class="row">
    <div class="col-md-12">
    @for ($i=1; $i <= 5 ; $i++)
      <span class="glyphicon glyphicon-star{{ ($i <= $review->rating) ? '' : '-empty'}}"></span>
    @endfor

    {{ $review->user ? $review->user->name : 'Anonymous'}} <span class="pull-right">{{$review->timeago}}</span> 

    <p>{{{$review->comment}}}</p>
    </div>
  </div>
@endforeach

The $review->timeago is a presenter function that I will add to the app/models/Review.php:

// Attribute presenters
...
public function getTimeagoAttribute()
{
  $date = CarbonCarbon::createFromTimeStamp(strtotime($this->created_at))->diffForHumans();
  return $date;
}
...

Also, you might have noticed the triple brace used to output the $review->comment. This is Laravel’s way to not allow things like <script></script> in displaying the comments. I chose to not filter the comment data on input but rather when the comment is displayed by using Blade’s triple braces trick.

You can see the complete view templates at https://github.com/msurguy/laravel-shop-reviews.

At this point there are only few things left to finish, store the user’s reviews somehow and also connect all the routes to the functionality that we have built.

Creating helper functions to store reviews and calculate ratings

First, let’s create a helper function (let’s call it storeReviewForProduct) that will do the following :

  • take product ID, user submitted comment and rating
  • attach the comment and the rating as a child model to the product
  • call a function to recalculate all ratings for the product

This function will be a part of the app/models/Review.php model, so let’s add it there:

...

public function getTimeagoAttribute()
{
  ...
}

// this function takes in product ID, comment and the rating and attaches the review to the product by its ID, then the average rating for the product is recalculated
public function storeReviewForProduct($productID, $comment, $rating)
{
  $product = Product::find($productID);

  // this will be added when we add user's login functionality
  //$this->user_id = Auth::user()->id;

  $this->comment = $comment;
  $this->rating = $rating;
  $product->reviews()->save($this);

  // recalculate ratings for the specified product
  $product->recalculateRating();
}

For now we will not save logged in user’s id along with the comment simply because we have not built a login system.

As you might have noticed, we are calling recalculateRating function on the product instance, that function is not defined yet, so let’s create it in the app/models/Product.php model (I include comments that explain what happens when that function is executed):

<?php

class Product extends Eloquent
{
  public function reviews()
  { ... }

  // The way average rating is calculated (and stored) is by getting an average of all ratings, 
  // storing the calculated value in the rating_cache column (so that we don't have to do calculations later)
  // and incrementing the rating_count column by 1

  public function recalculateRating()
  {
    $reviews = $this->reviews()->notSpam()->approved();
    $avgRating = $reviews->avg('rating');
    $this->rating_cache = round($avgRating,1);
    $this->rating_count = $reviews->count();
    $this->save();
  }
}

Alright. The major part of the application is done! The only thing left is to connect all of our routes so that the applications becomes alive!

Connecting routes to views

In the beginning of the tutorial we have defined three route placeholders for the application, one that shows all products, one that shows an individual product and one that’s handling the review submission. Now let’s fill those routes with some logic that the application needs.

Home page route only needs to display all products from the shop:

// Route for Homepage - displays all products from the shop
Route::get('/', function()
{
  $products = Product::all();
  return View::make('index', array('products'=>$products));
});

The route to display a single product (when you click on a product from the homepage) needs to do two things, it needs to retrieve a product by id specified in the route parameter and it needs to retrieve a paginated collection of reviews that are marked as approved and not spam:

// Route that shows an individual product by its ID
Route::get('products/{id}', function($id)
{
  $product = Product::find($id);
  // Get all reviews that are not spam for the product and paginate them
  $reviews = $product->reviews()->with('user')->approved()->notSpam()->orderBy('created_at','desc')->paginate(100);

  return View::make('products.single', array('product'=>$product,'reviews'=>$reviews));
});

And lastly, when the review is submitted from the product page, we will validate that the review corresponds to validation rules(I put them in the Review model to make the route a bit cleaner), and if the validation passes, we will store the review in DB and redirect the user back to the product page with a message that the review has been posted:

// Route that handles submission of review - rating/comment
Route::post('products/{id}', array('before'=>'csrf', function($id)
{
  $input = array(
	'comment' => Input::get('comment'),
	'rating'  => Input::get('rating')
  );
  // instantiate Rating model
  $review = new Review;

  // Validate that the user's input corresponds to the rules specified in the review model
  $validator = Validator::make( $input, $review->getCreateRules());

  // If input passes validation - store the review in DB, otherwise return to product page with error message 
  if ($validator->passes()) {
	$review->storeReviewForProduct($id, $input['comment'], $input['rating']);
	return Redirect::to('products/'.$id.'#reviews-anchor')->with('review_posted',true);
  }

  return Redirect::to('products/'.$id.'#reviews-anchor')->withErrors($validator)->withInput();
}));

For a complete routes.php file please look in the application repository. I have omitted showing complete blade templates in this post as they are quite large, you can see them in the repository as well.

Refactoring ideas :
1) Move the logic from the routes to controllers (for example create shop controller and product controller and display index page from shop controller and all things related to individual product from a product controller).
2) Clean up the models by separating view presenters scopes and relationships.
3) Prevent the same user from submitting more than one review on a product (when you have a login system implemented first)

At this point the application should work as intended and you will be able to have users submit reviews to your shop/gallery/whatever website!

This concludes the first part of “Building a shop” comprehensive tutorial! Do you like the series? Do you want more of comprehensive tutorials like this? Let me know in the comments and make sure to follow me on Twitter!

Liked it? Take a second to support Maks Surguy on Patreon!
Become a patron at Patreon!

You may also like

53 comments

  • kenny November 12, 2013  

    Just order your book.

    Hope more tutorial from shop serial.

  • Thomas November 14, 2013  

    Great post, Maks. Looking forward to the rest of the series.

    I’m working on a project where a review system will be implemented. Will most likely take your considerations into account 😉

    If I may add, wouldnt using interfaces and repositories create more flexible controllers regarding your refactoring ideas? The practice of coding to an interface and (more or less) abstracting the database layer seems to me to be a good start to insure future complications/changes. This should also make testing and mocking easier/better, no?

    Thanks for the tip regarding Laravel hosting. Pagoda has been working out great so far.

    Greetings from Denmark 🙂

  • David M. November 14, 2013  

    Hi Maks,
    This was far the most thorough and most practical Laravel tutorial that I have seen to date, so THANK YOU and I hope you can continue to make time to share your Laravel knowledge in your blog by demonstrating a practical application, as you have been doing.

    I really hope I can get to the point where I can bang out a simple Laravel application within couple of days like you do with most of the Laravel sites you have deployed.

    There’s one thing that I want to pick your brain on. It makes sense track the authenticated user id for reviews and even bookmark/favorites but I also want to support “Likes” features where unregistered user can “thumbs up” on a product by “liking it” but at the same time, I want to prevent the same user doing it more than once. I know that only way this can be accomplished is by tracking the IP address but I’m more concerned about the best way of implementing this since efficiency/performance is my top concern. Rather than tracking IP address as a child (one-to-many) relationship, I was thinking maybe appending the IP addresses in a text field at the product level then check to see if that matching IP address exists in that field to prevent multiple likes. What do you think about this approach?

    Any chance you can also do enhancements to this tutorial series by implementing the “likes” features that I have mentioned? (with support for unique unregistered users)

    Cheers!
    -David

  • Maks Surguy November 15, 2013  

    This is possible to accomplish in few ways. One of the ways I am thinking of implementing is to save the IDs of products that the user liked in the session and not allow to like the same products again if the ID is already in the session. Sessions don’t require the users to be registered, it simply creates a cookie on the client side(browser) and a special object on the server side.
    One aspect that you would need to adjust is the amount of time that the session is active (not expired), Laravel apps have those configurations in the app/session.php config file.

    What do you think?

  • Maks Surguy November 15, 2013  

    Thanks! I am glad this is helpful.

    Definitely using interfaces and repositories would organize the code at refactoring stage but if I start saying which way it should be done I am sure I will get tons of people that would disagree so I try to keep out of those arguments by providing the basics (even using routes) and letting people figure out which way they want to do this on their own.

  • David M. November 16, 2013  

    That would be too easy 🙂
    I thought about that approach but people can abuse the “Likes” by not allowing the cookies on the browser setting or even deleting the cookies. The only way to have a full control of this without forcing the user to register/login is by tracking it on the server side (although they can use different IP address to cheat the “Likes” this is harder than simply deleting the cookies).

  • Maks Surguy November 17, 2013  

    I personally think you are overthinking the problem. Honestly, how many people do even know about disabling cookies, let alone deleting them? Unless of course your website’s audience is 100% developers.

    From my experience about 1-5% of general population knows what cookies are. And much less know where they are stored and even less know how to manipulate them.

  • David M. November 17, 2013  

    Thanks Maks. Yeah, I might be overthinking the problem… but imagine that you have a very popular product review sites, such as webhosting reviews or bunch of competitive products review sites. If one of my products or hosting company was on that site and if it allowed the users to vote/like without registration then I probably would try to bump up the count by eventually figuring out how to go around it (deleting the cookies).

    Anyways, thanks for your feedback. I probably will limit to the registered users for now… 🙂

  • Maks Surguy November 17, 2013  

    yeah, if you have thousands of users every day on it, and if anything depends on that count, it should be properly secured 🙂 Otherwise I suggest you focus on other parts of the site and save some time.

  • David M. November 17, 2013  

    Hi Maks,
    I was trying to follow your tutorial and realized that you provided raw sql script rather than in Laravel’s migration style. If you are doing a tutorial for Laravel, why would you use the raw sql script rather than Laravel’s migration?
    I personally do prefer raw sql for creating the db structure myself but I was curious if you had other reasons.

    Finally, while products and reviews tables are defined as InnoDB engine, the users table is defined as MyISAM engine. Was this just an oversight or intentional?

    Thanks again.

  • Pedrog November 19, 2013  

    Hello,
    I think this is a shopping cart left…

  • TSGarpian November 30, 2013  

    Good stuff, looking forward for more.

    Isn’t the avg rating thing a perfect case for mysql triggers?

  • dcrystalj December 5, 2013  

    very very nice!!
    But, “Clean up the models by separating view presenters scopes and relationships.”

    How can we do that?

  • Maks Surguy December 5, 2013  

    You can do this through the use of so called “Repository pattern” (Google that + Laravel to see lots of examples), also using Laravel’s scopes like I am using for “Review” model (like scopeSpam, scopeApproved) will be essential when you build out a bigger system.
    The view presenters would be very useful for the output of the ratings. Right now the system has a for loop to display the review stars and this could easily be factored out into a view presenter or into it’s own Blade template that is then “include”d in the template that shows the reviews.

    Hope this helps, otherwise I could maybe write out a tutorial on how to go about this.

  • oludare odunfa December 11, 2013  

    This was just too too helpful. I’ve been wanting to implement this just right now and i found it a freebies here. Wonderful tutorial. Please improve more on it so we can learn more from the masters. we appreciate your contributions so far.

  • Maks Surguy December 11, 2013  

    I’m glad this is helpful! Keep coming back to my blog!

  • Pingback: P1 | Ylyt December 17, 2013  
  • Elena Alexie March 20, 2014  

    Really great tutorial! I am a newbie to Laravel and, choosing this tutorial to build my very first Laravel PHP application, was the best choice. Thank you so much! 🙂

  • Maks Surguy March 20, 2014  

    Glad you found it useful!

  • Phebeon Vera March 27, 2014  

    Great post. I am pretty new Laravel framework but I have found the post very useful. At the moment reviews are captured as from Anonymous. What changes do I have to make to the current code so that I can capture reviewer’s details such as name etc

  • Maks Surguy March 27, 2014  

    You would have to add the user_id to the reviews table and then set it to equal to Auth::user()->id (id of the currently logged in user).

  • Phebeon Vera March 27, 2014  

    I have set $this->user_id = Auth::user()->id; in review.php and added user_id to the reviews table. When I try the leave a review I am getting an error: Trying to get property of non-object. This error is reported on the same line I added above. What am I missing?

  • Maks Surguy March 28, 2014  

    Ah, it seems you don’t have a user currently logged in? You need to create a table for users (username, email, etc) and then you need to authenticate the user (for example with a login form or manually through Auth::login()), only then the code I provided would work.

  • ganjar April 7, 2014  

    This is a very nice and complete tutorial….exellent

  • Affan August 18, 2014  

    I am Affan… I upload the template from bootsrap, and its work. But, when I upload your source code, why it doesn’t work? I alreadey create the database.

  • maxsurguy August 20, 2014  

    I’d need a bit more details on that… What do you have currently?

  • chirag bhatia October 15, 2014  

    hi, i am new to laravel where i can get this complete code

  • maxsurguy October 15, 2014  

    The complete code is available on Github.

  • tnk2006 November 6, 2014  

    Great tutorial! Thanks!

  • Finsok Yagman January 15, 2015  

    it wont work because there is missing vendor files….

  • Finsok Yagman January 18, 2015  

    Great tutorial but can i get this code in laravel 4 @maxsurguy:disqus

  • €dgar Quintero March 22, 2015  

    I’d like to see more please.

  • Vishal Shah May 10, 2015  

    I have couple of questions.. can we use this for “generic php” rather then using ” laravel” framework? Also, how can be integrate social media login for end users?

  • Andrea Lizzy Frost June 27, 2015  

    Hi folks, im new to this and downloaded the complete code, but I am struggling to understand it, is there anyone who can help, I installed all files to server but nothing happens, is there anyone with experience that could set this up for me with a fee

  • Andrea Lizzy Frost June 27, 2015  

    Hi folks, im new to this and downloaded the complete code, but I am struggling to understand it, is there anyone who can help, I installed all files to server but nothing happens

  • Javier Ceballos September 26, 2015  

    Bueno, es que aqui lo que sucede es que te dan un leve repaso de como hacer las cosas, por eso si bajan el codigo, no creo que les soluciones la vida, hay que hacer una base de datos, enlazarla al codigo del sitio mediante, javascrip o php, o algun otro y entonces empezaran a ver resultados

  • Pee Ny October 28, 2015  

    great! thank you. 🙂

  • Liudmila Kosyanova December 14, 2015  

    It very nice, but I would like to use it in the MVC .

  • Liudmila Kosyanova December 14, 2015  

    I not use hph

  • Rob June 4, 2016  

    then dont use laravel

  • rcrteam August 10, 2016  

    how do I connect with the database

  • rcrteam August 10, 2016  

    We would like to know the procedure to connect to our own mysql database, with user name and password. We have already imported to install.sql file and created the tables.

  • Dionysis Kalepanagos March 4, 2017  

    Hello Maksim! I’m not really sure if you’ re watching all the comments, but I can’t find getCreateRules() function inside Review model. Does it go by another name? Please illuminate!

  • Karthiga B April 24, 2017  

    When i cal this method $product->recalculateRating($rating); I found this error BadMethodCallException in Builder.php line 2445: how can i resolve it

  • Kenneth C. Okpe April 26, 2017  

    How do I display the result in a descending order

  • Usman Hafeez August 28, 2017  

    I want this Same in laravel 5.4. please help

Leave a comment