Schneimi’s Dev Weblog


Star rating plugin for CakePHP

Posted in Ajax,CakePHP by schneimi on May 25, 2009
Tags: , , , , , ,

In the google groups I recently noticed the lack of a star rating helper/plugin for CakePHP.

As I just implemented an AJAX rating system for my current project and always wanted to learn the CakePHP plugin system, I thought this was a good opportunity to make my code into a plugin and contribute to the community.

My rating system supports multiple users and multiple models, so you can let people rate any model you want.

I tried to keep it simple and flexible, but I am sure there is still much room for improvements. So let me know what you think about it, any suggestions and comments are welcome.

Here is the plugin v2.5 for CakePHP 1.3 to download. Older versions for CakePHP 1.2 can be found here.

This article can also be found in the Bakery.

Features

  • Multi user, multi model rating
  • Guest rating
  • Just one element to place in your views
  • Seamless integration with AJAX
  • Prototype and jQuery support
  • Cross browser compatibility
  • Fallback for disabled javascript
  • Various configurations

Requirements

  • CakePHP 1.2, 1.3
  • Prototype or jQuery javascript framework
  • User id stored in session for secure rating

Demonstration
A demo can be tested at
http://ratingdemo.schneimi.hostingsociety.com/

    Installation and Use

    • Make sure you meet the requirements above. Make sure you meet the requirements above. For the download and integration of a javascript framework, please visit the Prototype or jQuery website.
      • Extract the plugin, including the subfolder ‘rating’, to your app plugins folder ‘app/plugins‘.
        • Copy the ‘rating/config/plugin_rating.php’ to your app configs folder ‘app/config’ and change the settings to your desire. It is recommended to let ‘Rating.showHelp’ set to true until everything works.
          • Apply the ‘install.sql’ to your database to create the ratings table.
            CREATE TABLE `ratings` (
              `id` int(11) unsigned NOT NULL auto_increment,
              `user_id` char(36) NOT NULL default '',
              `model_id` char(36) NOT NULL default '',  
              `model` varchar(100) NOT NULL default '',
              `rating` tinyint(2) unsigned NOT NULL default '0',
              `name` varchar(100) default '',
              `created` datetime default NULL,
              `modified` datetime default NULL,
              PRIMARY KEY (`id`),
              KEY `rating` (`model_id`,`model`,`rating`,`name`)
            );
            
          • Load the plugin javascript and css files in your layout file. Replace [your_framework] with prototype_min or jquery_min depending on the framework you use.
              <?php echo $javascript->link('/rating/js/[your_framework]'); ?>
              <?php echo $html->css('/rating/css/rating'); ?> 
              
          • For full model integration in your app, apply the following relation to your models. (replace [name_of_your_model])
              var $hasMany = array('Rating' =>
                                   array('className'   => 'Rating',
                                         'foreignKey'  => 'model_id',
                                         'conditions' => array('model' => '[name_of_your_model]'),
                                         'dependent'   => true,
                                         'exclusive'   => true
                                   )
                             );  
          • If you set ‘Rating.saveToModel’ to true, then add the defined ‘Rating.modelAverageField’ and ‘Rating.modelVotesField’ to all models you want to rate. To do that you can use the following SQL statements (replace [your_table] and [Rating.modelAverageField]).
            ALTER TABLE [your_table] ADD (`[Rating.modelAverageField]` decimal(3,1) unsigned default '0.0');
            ALTER TABLE [your_table] ADD (`[Rating.modelVotesField]` int(11) unsigned default '0');

            If the plugin shows the fields are still missing, try to clear the model cache of your app at ‘app/tmp/cache/models’.

          • You can change the styles of the rating element in the css file ‘rating/vendors/css/rating.css’.
            • Finally you can place the rating element in your views as follows. (replace [name_of_your_model] and [id_of_your_model])

              Default rating element for one model id

                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => '[name_of_your_model]',
                                                    'id' => [id_of_your_model]));
               

              More ratings for one model id
              If you want to have different ratings for one model id like sound and picture of a movie, you can use the additional name parameter.

                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => '[name_of_your_model]',
                                                    'id' => [id_of_your_model],
                                                    'name' => 'sound'));
              
                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => '[name_of_your_model]',
                                                    'id' => [id_of_your_model],
                                                    'name' => 'picture'));
              

              Individual configuration of a rating element
              Sometimes you want to use more than one style of rating elements in your app. That can be reached with the ‘config’ parameter and different config files in ‘app/config’. Just clone the original ‘plugin_rating.php’ and give it a different name, which you then pass to the element. There is also the possibility to overload the config file settings on the element.

                // Uses 'plugin_rating.php' in 'app/config'
                echo $this->element('rating', array('plugin' => 'rating', 
                                                    'model' => '[name_of_your_model]',
                                                    'id' => [id_of_your_model]));
                
                // Uses 'plugin_rating_style1.php' in 'app/config'
                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => '[name_of_your_model]',
                                                    'id' => [id_of_your_model],
                                                    'config' => 'plugin_rating_style1'));
              
                // overload default settings
                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => [name_of_model],
                                                    'id' => [id_of_model],
                                                    'config' => array('Rating.[setting_1]' => true,
                                                                     'Rating.[setting_2]' => false)));
                                                  
                // overload individual settings
                echo $this->element('rating', array('plugin' => 'rating',
                                                    'model' => [name_of_model],
                                                    'id' => [id_of_model],
                                                    'config' => array('plugin_rating_style1', array(
                                                        'Rating.[setting_1]' => true,
                                                        'Rating.[setting_2]' => false));
              
            Advertisements

            75 Responses to 'Star rating plugin for CakePHP'

            Subscribe to comments with RSS or TrackBack to 'Star rating plugin for CakePHP'.

            1. Ander said,

              Very cool!
              Thank you πŸ™‚

            2. schneimi said,

              You can now choose between jQuery and prototype for ajax in the configs.

            3. bryan said,

              hey man

              looks great… having a problem thoug

              have followed instructions step by step but where do you store the rating_app_controller + model.php?

              i get

              Fatal error: Class ‘RatingAppModel’ not found in /var/www/localhost/htdocs/app/models/rating.php on line 2

              thanks!

              • schneimi said,

                Hi bryan,

                the controller as well as the model should rest inside the plugin structure, you don’t need and have to copy any files to your app.

                If all is at it’s place, I can’t tell why you get this error. Do you use the latest cake? Maybe there is a problem with a older CakePHP version.

                Btw I just released v1.4 with some other improvements.

            4. monir said,

              Thank you for the plugin it works great

            5. schneimi said,

              v1.5
              – configurable mouseover messages
              – cakephp conform config handling
              – cakephp conform model loading
              – changed sql createdate and changedate
              – reworked js events
              – separated framework js code
              – minified js files
              – tested on IE, FF, safari, chrome, opera

              Enjoy!

            6. peter said,

              Not working for me! 😦

              • schneimi said,

                Hi Peter,

                could you be a little more specific what exactly doesn’t work? Do you at least see the rating element in your views? If not, are there shown any errors in debug mode?

                • peter said,

                  I am new with ajax, maybe thats the problem, i do see the stars but nothing happens when i place my mouse over them, neither when i click them, i do have the user model and the user id session.

                  PD: Thans a lot for quick your response. πŸ™‚

                • schneimi said,

                  Thx for the info, it looks like you didn’t load jQuery or Prototype properly in your layout, that’s one of the requirements.

                  If you don’t know how to load it, or get other problems, please write me a mail for further help.

                • peter said,

                  I do have jquery working with other javascripts, but thanks for the help i will check it more carefully.
                  PD: I didt not found a contact or mail

                • schneimi said,

                  Then it must be the plugin javascript that is not properly loaded, maybe there is a problem with the ‘/rating/js/rating_jquery’ path. Let me know if you can work it out.

                  Thx for the missing contact info, I just added a page. πŸ˜‰

                • peter said,

                  I managed to make the javascript run, I bealive it was because i had both the prototype and the jquery javascript declared…

                  But now i dont see the stars (I doo see the really good , bad, etc.. messages)… when i click the place where the star shoul be i see this error :

                  “Object not found!
                  The requested URL was not found on this server. The link on the referring page seems to be wrong or outdated. Please inform the author of that page about the error.

                  If you think this is a server error, please contact the webmaster.

                  Error 404
                  localhost
                  06/15/09 16:37:57
                  Apache/2.2.11 (Win32) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8i mod_autoindex_color PHP/5.2.8 ”

                  What am I doing wrong?
                  Thanks again for your time

                • schneimi said,

                  Ok yes, both frameworks bite each other.

                  About the images, I need to know the full link of the stars not showing. Settings concerning this are appRoot and the image locations (starFullImageLocation,…), maybe you can play around with them and work it out.

                  If not, please write me the details to michael.schneidt@arcor.de, thx.

                • Anders said,

                  I am having the same problem. I am using Jquery, but have not declared both prototype and Jq. I am using other JQ scripts on the site..

                  I can see empty stars, but nothing happens when i click on them / mouseover. :S

                  Help is appreciated πŸ™‚

                • schneimi said,

                  If jQuery works for your other scripts then the plugin javascript is most likely not loaded.

                  How does your layout look like? You need the link(‘/rating/js/rating_jquery_min’); ?> in it, the first slash in the path is necessary.

                • Anders said,

                  Yep, thats how i done it… i can look at the JS when i check the source code… :S

                  Do i have to change to Jquery manually somewhere in the plugin?

                • Anders said,

                  Update:

                  I used firebug and found out that this is ht eline causing the error:
                  $(‘#’ + element + ‘_’ + i).bind(‘mouseenter’, {i: i}, function(e) {

                  2 errors:
                  $ is not a function
                  and doc.body is undefined

                  any thoughts?

                • Anders said,

                  Sorry for so many posts. Fixed it with “var $j = jQuery.noConflict();” in the beginning of the js file.

                  Hope this helps somebody else πŸ™‚

                • schneimi said,

                  Great you found a solution, could you also figure out the script(s) causing the conflict?

            7. peter said,

              Any working examples?

              • schneimi said,

                No site online yet, but I will see if I can set up a demo somewhere.

            8. peter said,

              works great!!!
              Thanks a lot!!
              πŸ™‚
              Congrats for you job, is very flexible and easy to use

            9. peter said,

              Could it be possible to add more than one voting for the same element?… for example at the begining and at the end of a new…

              • schneimi said,

                Good idea, thx! I think about giving the elements an additional user defined name to separate them.

              • schneimi said,

                v1.6 supports this now, enjoy.

            10. peter said,

              How can I allow unlogued users to vote? can the User id be stored in a cookie instead of a session???

              • schneimi said,

                Both points are not possible because of security issues. Anonymous ratings can be easily manipulated and cookies are client side, so you could edit them and become any user you want.

            11. schneimi said,

              v1.7
              – individual configuration of single elements
              – fixed stars update on user id not found
              – helper class for the view
              – changed appRoot format

            12. peter said,

              Is there a way to disable the voting and to show only the average voting? i wish to have previews of articles showing the average voting and to allow people to vote only when they see the complete view of the article…
              Any sugestion?

              • schneimi said,

                Hi,

                this is not possible by default, but you just have to do two quick changes to reach that behavior.

                1) add a new setting in app/config/plugin.rating.php

                $config['Rating.disable'] = true;
                

                2) use it in the condition in the rating/views/view.ctp

                  // decision to enable or disable the rating
                  $enable = $session->check(Configure::read('Rating.userIdInSession')) && !Configure::read('Rating.disable')
                              && (Configure::read('Rating.allowChange') || (!Configure::read('Rating.allowChange') && $data['userRating'] == 0));
                
                • peter said,

                  Thanks πŸ™‚

            13. Francis said,

              I dont know hoy to make an user not logged in not to vote!
              If i dont write the User.id in the Session I get the error The User id was not found at “User.id” in the session

              And if I set the user.id session to an id that does not exist like 0 for example, then it takes it as valid and let it votes and saves it on the ratings with user_id 0

              Should I just left the session blank and place the show errors to false? how does the ‘Please login to rate’ message activates?

              Hope i explained myself rigth, i apologize for my english

              • schneimi said,

                Yes, you should set showErrors to false, this is just for installation to check if it works when the user is logged in. I will think about how to make this less confusing.

                The User.id 0 should not be used as a valid user, thx for that information I will fix it.

                The “Please login to rate” message appears on mouse over if showMouseOverMessages is set true and no User.id is found in session.

                • Francis said,

                  Thanks
                  Maybe if it shows as warning and not an error will be less confusing. πŸ˜‰

            14. Robin said,

              Hi schneimi,
              Thanx for this great plugin. It works fine for me.. Everything looks great except it throws a Notice

              Notice (8): Undefined index: fallback [APP\plugins\rating\controllers\ratings_controller.php, line 189]

              • schneimi said,

                Hi Robin,

                the notice is catched in the latest version 2.2, I just forgot to update the blog, you can download it now.

            15. Robin said,

              Schneimi,

              In my application, the rating is displayed vertically. Should I change any configuration to display it vertically ?

            16. Robin said,

              “In my application, the rating is displayed vertically.”
              -> This problem occurred because of the default style of Cake PHP.

              I commented ‘display: block; ‘ for label class in cake.generic.css and its working fine now.
              label {
              /*display: block; */
              }

              • schneimi said,

                Thx for showing the css problem, with two small changes on the plugin the problem can also be solved.

                rating\views\helpers\rating.php: line 58

                $output .= $this->Form->label($model.'.rating', 
                                              $htmlImage, 
                                              array('for' => $model.'Rating'.ucfirst($options['name']).$id.$i,
                                                    'class' => 'rating'));
                

                rating\vendors\css\rating.css

                div.rating label {
                  display: inline;
                }
                
            17. foroctfralion said,

              I am having a similar problem to a few people above. I am able to see the empty stars and 0.0/5 0 votes. However when I rollover the stars don’t get full and if I click on one nothing happens.

              The paths to my javascripts and my star images are all fine. I have tried with both prototype and jquery, and have tried Anders noConflict solution. Still no love. I’m not even sure how to debug this from this point.

              I would love to use this plugin so hopefully you can offer some advise as to why its not working.

              Thanks.

              • schneimi said,

                If nothing happens on mouseover and click, most likely the framework, or the plugin’s javascript file is not present for any reason. Do you use any other prototype or jquery stuff that works in the same view/page? You should look out for javascript errors, they tell you what’s missing (e.g. use the firebug addon in firefox).

                It could also help to download the working demo and figure out the differences to your installation.

            18. meotimdihia said,

              Your plugin is very good, keep it allways develop

            19. VANESSA said,

              I’m using this using “POst” as the model. Now when I view individuals Posts, I am getting this error:

              Error: The average field “rating” in the model “Post” does not exist.

              Error: The votes field “votes” in the model “Post” does not exist.

              Nowhere in your tutorial did it tell me to add ‘rating’ and ‘votes’ in the table 😦

              • schneimi said,

                You only need those fields if you have set:
                $config['Rating.saveToModel'] = true;
                This is documented in the plugin_rating.php. There are also 2 options to setup the names of the fields.
                $config['Rating.modelAverageField'] = 'rating';
                $config['Rating.modelVotesField'] = 'votes';

                hope this helps

            20. Bradley Mackenzie said,

              I have everything woking except it is not saving to my database. I even added an entry for the video I was rating into the db and that is not updating when I reload the page. I am using 2.4 with cakephp 1.3.6. The headers seem OK but the content in the XHR pane is showing the form and also the javascript printout. Any help is greatly appreciated and thanks for the plugin!

              0.0 / 5  (0 votes)

              //

              Really badBadAverageGoodReally good

            21. Bradley Mackenzie said,

              I tried to paste the response code – didn’t get there.

              It was the form, the script and the fallback form in the response (Content Pane) on XHR tab in web inspector.

              Thanks again!

            22. Bradley Mackenzie said,

              disregard my last two posts. It seems that there were a few problems I encountered. For some reason the validation in the model was doing something strange and once I removed that it worked. Also – not sure if this is relevant but the Model also had “class Rating extends Model {}” I changed Model to AppModel.

              Hope that helps someone. Not sure why it wasn’t working but that took care of it!

              Thanks again for the awesome plugin!

            23. arnab said,

              Hi Michael,

              Thanks a lot for this amazing plugin. I could set it up easily and everything worked automagically!

              I have 2 issues:

              i. When I execute some other javascript/ajax actions (for example comments which gets updated asynchronously) in the same page as the ratings… the ratings stop working. Am I missing some configuration?

              ii. Is there a way I can display individual rating according to the userid?

              Thanks a lot again,
              arnab

              • schneimi said,

                Hi arnab,

                i. I think your other ajax actions are reloading the ratings without executing their inline javascript again. The Prototype Ajax.Updater has a parameter named evalScripts (http://www.prototypejs.org/api/ajax/updater), that must be set true on your other ajax actions.
                ii. Yes this is possible, but is limited to the configurations that are available. You have to create individual config files and pass the ‘config’ as parameter to the element depending on the userid.

                Hope this helps.

                • arnab said,

                  Thanks a lot for your reply. I will definitely try out number ii to display individual ratings.

                  With regards to my first question, I figured out the specific javascript in my views that is stopping from ratings to work. I have a facebox popup action in my view. When I click on a particular link the facebox pops up and after the close action is triggered for facebox, the ratings stop working. I have no clue why this happens. Should I reinitiate the ratings by doing something or should I refresh the page (which is a costly process) after the facebox is closed?

                  I also understand that this might be an issue in the facebox code itself.

                  Appreciate your help.

                  Thanks,
                  Arnab

                • schneimi said,

                  I can only think of a javascript error caused by the facebox, but the facebox works furthermore, right?

                  Do you use Prototype and jQuery at the same time?

            24. arnab said,

              No, I use only Jquery framework…

            25. chris said,

              Hi guys,
              I’m having a problem setting up… Did as installation required …

              Missing Model
              No class found for the rating.Rating model.
              Notice: If you want to customize this error message, create app/views/errors/missing_model.ctp
              Fatal: Create the class below in file: app/models/rating.rating.php

              any one can help…?
              Or can any one help me with my site,.. I’m building one from scratch… here is a testing URL: http://www.zippopeople.com It’s a Social Network site, and I add lots of features to it…. Please send me an email chris69m AT yahoo . com
              thanks
              Chris

            26. buah said,

              Hi Schneimi,

              Thank you for your plugin. It is awesome. Good work man.

              The plugin work great in my application but i’ve an issue. When i click the star, my database does not update automatically. it is only an issue when i using chrome. it works great in IE8 but i’ve not try yet with firefox.

              do you have any idea why in chrome the it doesn’t work properly ? thank you for your help

              • schneimi said,

                Hi, it works for me in Chrome. I have no idea why it doesn’t work for you, but sounds like a javascript problem. On click the ajax call should be triggered that saves the result and updates the rating element afterwards.


            27. hey
              I got problem star image not found
              and Inernal server error when click link
              demo is same problem

              • schneimi said,

                Did you set the appRoot config correctly? I just updated to v2.5, there you don’t need this setting anymore, maybe this solves your problem.

            28. ram said,

              thank u .its rely work


            29. I am using this rating. But i see it’s working on ip address. So how can i use with user_id that’s users logged in.

              Please help me.

              • schneimi said,

                Hi Sanjay, the ip address is not used at all. There is a guest mode working with cookies, and otherwise the user_id from the session is used.

                Check out the two settings in your config/plugin.rating.php:
                $config[‘Rating.guest’] = false;
                $config[‘Rating.sessionUserId’] = ‘User.id’;


                • Thasnk Schneimi,
                  i will try to do. When i am write
                  $config[‘Rating.guest’] = false;
                  and add the
                  $config[‘Rating.sessionUserId’] = $this->Session->read(‘Auth.User.id’);

                  It’s code not working. Because guest id is already set. So how can i set my user id in guest id.

                  Please help me. Because my site for launch but the main problem is rating is not working properly.


                • Thanks For helping me.

                  But i will try to setup with session id and also check my config. But it’s always showing please login first. So how can i login.

                  Please solve my problem

                  Thanks

                • schneimi said,

                  Hi, I am sorry I cannot help. It should work as described in the article. What version CakePHP do you use? Because the plugin is not made for the latest CakePHP.

            30. Sunny Sidana said,

              how can i use user Id that’s users logged into my website. Because i want to use uses login session id.

              Please help me out……

              Thanks

            31. DK said,

              It’s really very nice …….
              it save time a lot ..

              Thanks

            32. roshan said,

              I have the following error:

              Warning (512): SQL Error: 1054: Unknown column ‘Rating.modelAverageField’ in ‘field list’ [CORE/cake/libs/model/datasources/dbo_source.php, line 684]
              Query: SELECT `Driver`.`driver_id`, `Driver`.`fname`, `Driver`.`gender`, `Driver`.`email`, `Driver`.`state`, `Driver`.`city`, `Driver`.`zipcode`, `Driver`.`address`, `Driver`.`phone_no`, `Driver`.`car_type`, `Driver`.`hourly_rate`, `Driver`.`occasion`, `Driver`.`driver_image`, `Rating`.`modelAverageField`, `Rating`.`modelVotesField`, `Driver`.`id` FROM `drivers` AS `Driver` WHERE `Driver`.`city` = ‘Altamonte Springs’ AND `Driver`.`zipcode` = ‘451456’ AND `Driver`.`car_type` = ‘Luxury’ AND `Driver`.`hourly_rate` BETWEEN 10 AND 50

              • schneimi said,

                Hi, modelAverageField and modelVotesField are the columns used when you have set $config[‘Rating.saveToModel’] = true;. I have no idea how come they appear in your query as only the value of the $config settings are called like Configure::read(‘Rating.modelAverageField’);. How does your plugin.rating.php look like at that settings? Can you figure out the line of code in the ratings_controller.php that causes that error?

                • roshan said,

                  The error is popping again even after clearing the cache as you said. I have a model ‘Driver’ and its corresponding ‘DriversController’. when I remove ‘Rating.modelAverageField’ and ‘Rating.modelVotesField’ from ‘drivers’ table, the error doesnot show. but the star displays blank, neither we can rate it .
                  Can you provide me the necessary steps beside you mentioned in this website. Well I’m using cakephp1.3. Any help would be appreciated.

                • roshan said,

                  Error: The model_id “driver_id” of “Driver” does not exist.
                  I’m getting this error where the star are displayed. Where did I missed to configure? Can you help me?


            33. It’s hard to find well-informed people about this topic, however,
              you seem like you know what you’re talking about!
              Thanks


            34. Hi, i was busy implementing this into my cakephp 2.5 installation. Since the zip files aren’t available anymore i’ve copied all the files from the backery site. It all went well, but when i use the code

              element(‘rating’, array(‘plugin’ => ‘rating’,
              ‘model’ => ‘[name_of_your_model]’,
              ‘id’ => [id_of_your_model]));
              ?>

              the page gives me the following error.

              Element Not Found: Elements\rating.ctp [CORE\Cake\View\View.php, line 425]

              Does anyone have an idea? i’m kinda lost. i’m using wamp btw.

              • schneimi said,

                Hi,
                I am sorry, this plug-in was made for CakePHP v1.2 and v1.3. As I didn’t follow CakePHP for quite a while, I cannot really help you with CakePHP v2.5.

                If you manage to get it running, please give some feedback here.

                Thx


            Leave a Reply

            Fill in your details below or click an icon to log in:

            WordPress.com Logo

            You are commenting using your WordPress.com account. Log Out / Change )

            Twitter picture

            You are commenting using your Twitter account. Log Out / Change )

            Facebook photo

            You are commenting using your Facebook account. Log Out / Change )

            Google+ photo

            You are commenting using your Google+ account. Log Out / Change )

            Connecting to %s


            %d bloggers like this: