AJAX star rating plugin
Features
- Multi user, multi model rating
- Guest rating
- Just one element in your views
- Seamless integration with AJAX
- Prototype and jQuery support
- Cross browser compatibility
- Fallback for disabled javascript
- Various configurations
Requirements
- CakePHP 1.2 or 1.3
- Prototype or jQuery framework
- User id stored in session for secure rating
Demonstration
A demo can be tested and downloaded athttp://ratingdemo.schneimi.spacequadrat.de/
Download
Latest version for CakePHP 1.2: http://www.wuala.com/mystic11/public/rating2.3.zip Latest version for CakePHP 1.3: http://www.wuala.com/mystic11/public/rating2.4.zipInstallation and Use
1) Make sure you meet the requirements above. For the download and integration of a javascript framework, please visit http://www.prototypejs.org/ for Prototype and http://jquery.com/ for jQuery.
2) Extract the plugin, including the subfolder rating, to your app plugins folder app/plugins.
3) 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.
4) 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`)
);
5) Load the plugin javascript and css files into your layout. Replace [your_framework] with prototype_min or jquery_min depending on the framework you use.
View Template:
<?php
echo $javascript->link('/rating/js/rating_[your_framework]');
echo $html->css('/rating/css/rating');
?>
6) For full model integration in your app, apply the following relation to your models. (replace [name_of_your_model])
Model Class:
<?php
var $hasMany = array('Rating' =>
array('className' => 'Rating',
'foreignKey' => 'model_id',
'conditions' => array('Rating.model' => '[name_of_your_model]'),
'dependent' => true,
'exclusive' => true
)
);
?>
7) 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], [Rating.modelAverageField], [Rating.modelVotesField]).
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.
8) You can change the styles of the rating element in the css file rating/vendors/css/rating.css.
9) 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
View Template:
<?php
echo $this->element('rating', array('plugin' => 'rating',
'model' => '[name_of_your_model]',
'id' => [id_of_your_model]));
?>
Default rating element 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.View Template:
<?php
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 default 'plugin_rating.php' and give it a different name, which you then pass to the element.View Template:
// 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'));
rating/config/plugin_rating.php
<?php
/**
* Config file for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
/**
* Disable the user rating.
*/
$config['Rating.disable'] = false;
/**
* Show errors and warnings that should help to setup the plugin.
*/
$config['Rating.showHelp'] = true;
/**
* CakePHP app root.
*
* If you access your app like http://yourdomain/mycake then /mycake/ is your app root.
*/
$config['Rating.appRoot'] = '';
/**
* Show a flash message after rating.
*
* (displays 'Rating.flashMessage')
*/
$config['Rating.flash'] = false;
/**
* Message shown on flash.
*
* (depends on 'Rating.flash')
*/
$config['Rating.flashMessage'] = __('Your rating has been saved.', true);
/**
* Enable fallback for disabled javascript.
*
* (this inserts additional html code)
*/
$config['Rating.fallback'] = true;
/**
* Show flash message on fallback save redirect.
*
* (displays 'Rating.flashMessage')
*/
$config['Rating.fallbackFlash'] = false;
/**
* User id location in the session data.
*/
$config['Rating.sessionUserId'] = 'User.id';
/**
* Enable Guest rating. (ignores 'Rating.sessionUserId')
*
* Guest access is stored in cookie to prevent multiple ratings (not secure!)
*/
$config['Rating.guest'] = false;
/**
* Guest cookie duration time. (interpreted with strtotime())
*/
$config['Rating.guestDuration'] = '1 week';
/**
* Maximum rating.
*/
$config['Rating.maxRating'] = 5;
/**
* Location of the full star image.
*/
$config['Rating.starFullImageLocation'] = 'rating/img/star-full.png';
/**
* Location of the empty star image.
*/
$config['Rating.starEmptyImageLocation'] = 'rating/img/star-empty.png';
/**
* Location of the half star image.
*/
$config['Rating.starHalfImageLocation'] = 'rating/img/star-half.png';
/**
* Save the average rating and vote count to the rated model.
*
* This may speed up loading, because the values must not be
* calculated from the ratings on every access. This is also
* helpful if you want to sort the model by rating data, e.g.
* using pagination sort.
*
* This config only works, if you use no more than one rating
* element (name parameter) for each model id and no different
* config files (config parameter) with same field names set.
*
* If set to true, you have to add the 'Rating.modelAverageField'
* and 'Rating.modelVotesField' to your rated models.
*/
$config['Rating.saveToModel'] = false;
/**
* Field name in models for the average rating.
*
* SQL: ALTER TABLE <model_table> ADD <Rating.modelAverageField> decimal(3,1) unsigned default '0.0';
*
* (depends on 'Rating.saveToModel')
*/
$config['Rating.modelAverageField'] = 'rating';
/**
* Field name in models for the rating votes.
*
* SQL: ALTER TABLE <model_table> ADD <Rating.modelVotesField> int(11) unsigned default '0';
*
* (depends on 'Rating.saveToModel')
*/
$config['Rating.modelVotesField'] = 'votes';
/**
* Allow users to change their ratings.
*/
$config['Rating.allowChange'] = true;
/**
* Allow users to delete their ratings by
* deselecting the current rating.
*
* (depends on 'Rating.allowChange')
*/
$config['Rating.allowDelete'] = true;
/**
* Display the user rating in stars instead of the average rating.
*/
$config['Rating.showUserRatingStars'] = false;
/**
* Show a mark to indicate the user rating.
*
* (change mark in /vendors/css/rating.css .rating-user)
*/
$config['Rating.showUserRatingMark'] = true;
/**
* Define the text beside the stars.
*
* %AVG% Average rating
* %MAX% Maximum rating
* %VOTES% Number of votes
* %RATING% User rating
*/
$config['Rating.statusText'] = '%AVG% / %MAX% (%VOTES%)';
/**
* Show 'Rating.mouseOverMessages' on mouseover.
*/
$config['Rating.showMouseOverMessages'] = true;
/**
* Messages that are showing on mouseover.
*
* If you want to put links into the messages like for login, you have
* to do that manually, because the CakePHP helpers don't work here yet.
*
* 'login' this message appears if the user is not signed in.
* 'rated' this message appears if the user rated already.
* 'delete' this message appears if the user mouseovers his rating and 'Rating.allowDelete' is set true.
* '1' to 'Rating.maxRating' represent the different rating values.
*
* (depends on 'Rating.showMouseOverMessages')
*/
$config['Rating.mouseOverMessages'] = array('login' => __('Please login to rate', true),
'rated' => __('Thanks for your rating', true),
'delete' => __('Click to remove your rating', true),
'1' => __('Really bad', true),
'2' => __('Bad', true),
'3' => __('Average', true),
'4' => __('Good', true),
'5' => __('Really good', true));
?>
rating/models/ratings.php
Model Class:
<?php
/**
* Model for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
class Rating extends Model {
var $name = 'Rating';
var $validate = array('user_id' => array('rule' => array('maxLength', 36),
'required' => true),
'model_id' => array('rule' => array('maxLength', 36),
'required' => true),
'model' => array('rule' => 'alphaNumeric',
'required' => true));
}
?>
rating/views/ratings/view.ctp
View Template:
<?php
/**
* View for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
?>
<?php
// decision to enable or disable the rating
$enable = ($session->check(Configure::read('Rating.sessionUserId')) // logged in user or guest
|| (Configure::read('Rating.guest') && $session->check('Rating.guest_id')))
&& !Configure::read('Rating.disable') // plugin is enabled
&& (Configure::read('Rating.allowChange') // changing is allowed or it's the first rating
|| (!Configure::read('Rating.allowChange') && $data['%RATING%'] == 0));
// the images are displayed here before js initialization to avoid flickering.
echo $rating->stars($model, $id, $data, $options, $enable);
// format the statusText and write it back
$text = $rating->format(Configure::read('Rating.statusText'), $data);
Configure::write('Rating.statusText', $text);
?>
<div id="<?php echo $model.'_rating_'.$options['name'].'_'.$id.'_text'; ?>" class="<?php echo !empty($text) ? 'rating-text' : 'rating-notext'; ?>">
<?php
echo $text;
?>
</div>
<?php
// initialize the rating element
if (!Configure::read('Rating.disable')) {
echo $javascript->codeBlock("ratingInit('".$model.'_rating_'.$options['name'].'_'.$id."', "
."'".addslashes(json_encode($data))."',"
."'".addslashes(json_encode(Configure::read('Rating')))."',"
."'".addslashes(json_encode($options))."',"
.intval($enable).");");
}
?>
<?php if (Configure::read('Rating.fallback')): ?>
<noscript>
<div class="fallback">
<?php
if ($enable) {
// show fallback form
echo $form->create('Rating',
array('type' => 'get',
'url' => array('action' => 'save')));
echo $form->radio('value',
$rating->options(),
array('legend' => false,
'id' => $model.'_rating_'.$options['name'].'_'.$id,
'value' => $data['%RATING%']));
echo $form->hidden('model', array('value' => $model));
echo $form->hidden('rating', array('value' => $id));
echo $form->hidden('name', array('value' => $options['name']));
echo $form->hidden('config', array('value' => $options['config']));
echo $form->hidden('fallback', array('value' => true));
echo $form->submit(__('Vote', true),
array('div' => false,
'title' => __('Vote', true)));
echo $form->end();
}
?>
</div>
<?php
// get mouseover messages for showing
$mouseOverMessages = Configure::read('Rating.mouseOverMessages');
?>
<?php // show login message
if (!$enable && Configure::read('Rating.showMouseOverMessages')
&& !empty($mouseOverMessages['login'])
&& !Configure::read('Rating.disable')
&& $data['%RATING%'] == 0): ?>
<div id="<?php echo $model.'_rating_'.$options['name'].'_'.$id.'_text'; ?>" class="<?php echo !empty($text) ? 'rating-text' : 'rating-notext'; ?>">
<?php
echo $mouseOverMessages['login'];
?>
</div>
<?php endif; ?>
<?php // show rated message
if (!$enable && Configure::read('Rating.showMouseOverMessages')
&& !empty($mouseOverMessages['rated'])
&& $data['%RATING%'] > 0): ?>
<div id="<?php echo $model.'_rating_'.$options['name'].'_'.$id.'_text'; ?>" class="<?php echo !empty($text) ? 'rating-text' : 'rating-notext'; ?>">
<?php
echo $mouseOverMessages['rated'];
?>
</div>
<?php endif; ?>
</noscript>
<?php endif; ?>
<?php
// show flash message
if (Configure::read('Rating.flash')) {
$session->flash('rating');
}
// debug sql dump
echo $this->element('sql_dump');
?>
rating/views/elements/rating.ctp
View Template:
<?php
/**
* Element for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
?>
<?php
// default name
if (empty($name)) {
$name = 'default';
}
// default config
if (empty($config)) {
$config = 'plugin_rating';
}
?>
<div id="<?php echo $model.'_rating_'.$name.'_'.$id; ?>" class="rating">
<?php
echo $this->requestAction('rating/ratings/view/'.$model.'/'.$id.'/'.base64_encode(json_encode(array('name' => $name, 'config' => $config))), array('return'));
?>
</div>
rating/views/helpers/rating.php
<?php
/**
* Helper for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
class RatingHelper extends AppHelper {
var $helpers = array('Html', 'Form', 'Session');
/**
* Creates the stars for a rating.
*
* @param string $model Model name
* @param integer $id Model id
* @param array $data Rating data
* @param array $options Options
* @param boolean $enable Enable element
* @return Stars as HTML images
*/
function stars($model, $id, $data, $options, $enable) {
$output = '';
$starImage = Configure::read('Rating.starEmptyImageLocation');
if (Configure::read('Rating.showUserRatingStars')) {
$stars = $data['%RATING%'];
} else {
$stars = $data['%AVG%'];
}
for ($i = 1; $i <= $data['%MAX%']; $i++) {
if ($i <= floor($stars)) {
$starImage = Configure::read('Rating.starFullImageLocation');
} else if ($i == floor($stars) + 1 && preg_match('/[0-9]\.[5-9]/', $stars)) {
$starImage = Configure::read('Rating.starHalfImageLocation');
} else {
$starImage = Configure::read('Rating.starEmptyImageLocation');
}
if (Configure::read('Rating.showUserRatingMark') && $i <= $data['%RATING%']) {
$class = 'rating-user';
} else {
$class = 'rating';
}
if (!$enable) {
$class .= '-disabled';
}
$htmlImage = $this->Html->image('/'.$starImage,
array('class' => $class,
'id' => $model.'_rating_'.$options['name'].'_'.$id.'_'.$i,
'alt' => __('Rate it with ', true).$i));
if (Configure::read('Rating.fallback')) {
$output .= $this->Form->label($model.'.rating',
$htmlImage,
array('for' => $model.'Rating'.ucfirst($options['name']).$id.$i,
'class' => 'fallback'));
} else {
$output .= $htmlImage;
}
}
return $output;
}
/**
* Formats a text in replacing data wildcards.
*
* @param string $text
* @param array $data
* @return Formatted text
*/
function format($text, $data) {
foreach ($data as $wildcard => $value) {
$text = str_replace($wildcard, $value, $text);
}
// fix lost blanks in js (excluding blanks between html tags)
$text = preg_replace('/(?!(?:[^<]+>|[^>]+<\/(.*)>))( )/', ' ', $text);
return $text;
}
/**
* Creates options for fallback radio buttons.
*
* @return Radio options
*/
function options() {
$options = array();
if (Configure::read('Rating.showMouseOverMessages')) {
$options = Configure::read('Rating.mouseOverMessages');
unset($options['login'], $options['rated'], $options['delete']);
} else {
$options = range(0, Configure::read('Rating.maxRating'));
unset($options[0]);
}
return $options;
}
}
?>
rating/controllers/ratings_controller.php
Controller Class:
<?php
/**
* Controller for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
class RatingsController extends RatingAppController {
/**
* Renders the content for the rating element.
*
* @param string $model Name of the model
* @param integer $id Id of the model
* @param string $options JSON/BASE64 encoded options
*/
function view($model = '', $id = 0, $options = '') {
$this->layout = null;
$userRating = null;
$avgRating = null;
$votes = null;
$modelInstance = ClassRegistry::init($model);
$optionsData = json_decode(base64_decode($options), true);
$name = $optionsData['name'];
$config = $optionsData['config'];
// load the config file
$this->__loadConfig($config);
// setup guest access
if (Configure::read('Rating.guest')
&& !$this->Session->check(Configure::read('Rating.sessionUserId'))) {
$this->__setupGuest();
}
// check if user id exists in session
if (Configure::read('Rating.showHelp')
&& !Configure::read('Rating.guest')
&& (!$this->Session->check(Configure::read('Rating.sessionUserId'))
|| !$this->Session->read(Configure::read('Rating.sessionUserId')) > 0)) {
echo '<p>Warning: No valid user id was found at "'.Configure::read('Rating.sessionUserId').'" in the session.</p>';
}
// check if model id exists
$modelInstance->id = $id;
if (Configure::read('Rating.showHelp') && !$modelInstance->exists(true)) {
echo '<p>Error: The model_id "'.$id.'" of "'.$model.'" does not exist.</p>';
}
// choose between user id and guest id
if (!$this->Session->read(Configure::read('Rating.sessionUserId'))
&& (Configure::read('Rating.guest') && $this->Session->read('Rating.guest_id'))) {
$userId = $this->Session->read('Rating.guest_id');
} else {
$userId = $this->Session->read(Configure::read('Rating.sessionUserId'));
}
if (!empty($userId)) {
$userRating = $this->Rating->field('rating',
array('model' => $model,
'model_id' => $id,
'user_id' => $userId,
'name' => $name));
}
if (empty($userRating)) {
$userRating = 0;
}
// retrieve rating values from model or calculate them
if (Configure::read('Rating.saveToModel')) {
if (Configure::read('Rating.showHelp')
&& !$modelInstance->hasField(Configure::read('Rating.modelAverageField'))) {
echo '<p>Error: The average field "'.Configure::read('Rating.modelAverageField').'" in the model "'.$model.'" does not exist.</p>';
}
if (Configure::read('Rating.showHelp')
&& !$modelInstance->hasField(Configure::read('Rating.modelVotesField'))) {
echo '<p>Error: The votes field "'.Configure::read('Rating.modelVotesField').'" in the model "'.$model.'" does not exist.</p>';
}
$values = $modelInstance->find(array($modelInstance->name.".".$modelInstance->primaryKey => $id),
array(Configure::read('Rating.modelAverageField'),
Configure::read('Rating.modelVotesField')),
null,
-1);
$avgRating = $values[$modelInstance->name][Configure::read('Rating.modelAverageField')];
$votes = $values[$modelInstance->name][Configure::read('Rating.modelVotesField')];
} else {
$values = $this->Rating->find(array('model' => $model,
'model_id' => $id,
'name' => $name),
array('AVG(Rating.rating)', 'COUNT(*)'));
$avgRating = round($values[0]['AVG(`Rating`.`rating`)'], 1);
$votes = $values[0]['COUNT(*)'];
}
if (empty($votes)) {
$votes = 0;
}
if ($avgRating && !strpos($avgRating, '.')) {
$avgRating = $avgRating.'.0';
} else if (!$avgRating) {
$avgRating = '0.0';
}
$this->set('id', $id);
$this->set('model', $model);
$this->set('config', $config);
$this->set('options', $optionsData);
$this->set('data', array('%VOTES%' => $votes.' '.__n('vote', 'votes', $votes, true),
'%RATING%' => $userRating,
'%AVG%' => $avgRating,
'%MAX%' => Configure::read('Rating.maxRating')));
$this->render('view');
}
/**
* Saves the user selected rating value. Depending on the plugin
* configuration, it also updates or deletes the rating.
*
* @param string $model Name of the model
* @param integer $id Id of the model
* @param integer $value User rating value
*/
function save($model = '', $id = 0, $value = 0) {
$this->layout = null;
$saved = false;
$fallback = false;
$referer = Controller::referer();
$name = $this->params['url']['name'];
$config = $this->params['url']['config'];
// load the config file
$this->__loadConfig($config);
// data from fallback form
if (isset($this->params['url']['fallback'])
&& $this->params['url']['fallback']) {
$fallback = true;
$model = $this->params['url']['model'];
$id = $this->params['url']['rating'];
$value = $this->params['url']['value'];
}
// check if model id exists
$modelInstance = ClassRegistry::init($model);
$modelInstance->id = $id;
if (!$modelInstance->exists(true)) {
if (!$fallback) {
$this->view($model, $id, base64_encode(json_encode(array('name' => $name, 'config' => $config))));
} else {
$this->redirect($referer);
}
return;
}
// choose between user and guest id
if (Configure::read('Rating.guest') && $this->Session->read('Rating.guest_id')) {
$userId = $this->Session->read('Rating.guest_id');
} else {
$userId = $this->Session->read(Configure::read('Rating.sessionUserId'));
}
// check if a rating already exists
$userRating = $this->Rating->find(array('model' => $model,
'model_id' => $id,
'user_id' => $userId,
'name' => $name));
// save, update or delete rating
if (!empty($userRating) && Configure::read('Rating.allowChange')) {
$this->Rating->id = $userRating['Rating']['id'];
if ($userRating['Rating']['rating'] == $value && Configure::read('Rating.allowDelete')) {
$this->Rating->delete($userRating['Rating']['id']);
$saved = true;
} else {
$saved = $this->Rating->saveField('rating', $value);
}
} else if (empty($userRating) && $userId) {
$this->data['Rating']['rating'] = $value;
$this->data['Rating']['model'] = $model;
$this->data['Rating']['model_id'] = $id;
$this->data['Rating']['user_id'] = $userId;
$this->data['Rating']['name'] = $name;
$this->Rating->create();
$saved = $this->Rating->save($this->data);
}
// set flash message
if ($saved && Configure::read('Rating.flash')) {
$this->Session->setFlash(Configure::read('Rating.flashMessage'),
'default',
array('class' => 'rating-flash'),
'rating');
}
// save rating values to model
if ($saved && Configure::read('Rating.saveToModel')) {
// check if fields exist in model
if (!$modelInstance->hasField(Configure::read('Rating.modelAverageField'))
&& !$modelInstance->hasField(Configure::read('Rating.modelVotesField'))) {
if (!$fallback) {
$this->view($model, $id, base64_encode(json_encode(array('name' => $name, 'config' => $config))));
} else {
$this->redirect($referer);
}
return;
}
// retrieve actual rating values
$values = $this->Rating->find(array('model' => $model,
'model_id' => $id,
'name' => $name),
array('AVG(Rating.rating)', 'COUNT(*)'));
$avgRating = round($values[0]['AVG(`Rating`.`rating`)'], 1);
$votes = $values[0]['COUNT(*)'];
if ($avgRating && !strpos($avgRating, '.')) {
$avgRating = $avgRating.'.0';
} else if (!$avgRating) {
$avgRating = '0.0';
}
if (empty($votes)) {
$votes = '0';
}
$modelInstance->id = $id;
// save rating values
if ($modelInstance->exists()) {
$modelInstance->saveField(Configure::read('Rating.modelAverageField'), $avgRating);
$modelInstance->saveField(Configure::read('Rating.modelVotesField'), $votes);
}
}
// show view again
if (!$fallback) {
$this->view($model, $id, base64_encode(json_encode(array('name' => $name, 'config' => $config))));
} else {
if ($saved && Configure::read('Rating.fallbackFlash')) {
$this->flash(Configure::read('Rating.flashMessage'), Controller::referer());
$this->Session->setFlash(null);
} else {
$this->redirect($referer);
}
}
$this->autoRender = false;
}
/**
* Loads a config file.
*
* @param $file Name of the config file
*/
function __loadConfig($file) {
// still support config values of v2.3 elements
if (count(explode('.', $file)) > 0) {
$file = str_replace('.', '_', $file);
}
// load config from app config folder
if (Configure::load($file) === false) {
// load config from plugin config folder
if (Configure::load('rating.'.$file) === false) {
echo '<p>Error: The '.$file.'.php could not be found in your app/config or app/plugins/rating/config folder. Please create it from the default rating/config/plugin_rating.php.</p>';
}
}
}
/**
* Setup the guest id in session and cookie.
*/
function __setupGuest() {
if (!$this->Session->check('Rating.guest_id')
&& !$this->Cookie->read('Rating.guest_id')) {
App::import('Core', 'String');
$uuid = String::uuid();
$this->Session->write('Rating.guest_id', $uuid);
$this->Cookie->write('Rating.guest_id', $uuid, false, Configure::read('Rating.guestDuration'));
} else if (Configure::read('Rating.guest')
&& $this->Cookie->read('Rating.guest_id')) {
$this->Session->write('Rating.guest_id', $this->Cookie->read('Rating.guest_id'));
}
}
}
?>
rating/rating_app_controller.php
Controller Class:
<?php
/**
* AppController for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
class RatingAppController extends AppController {
var $uses = array('rating.Rating');
var $helpers = array('Javascript', 'rating.Rating');
var $components = array('Cookie', 'Session');
}
?>
rating/vendors/js/rating_jquery.js
/**
* jQuery javascript for the CakePHP AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
/**
* Holds the settings for all rating elements.
*/
var ratingSettings = new Array();
/**
* Initializes the rating element.
*
* @param element Id of the rating element
* @param data JSON encoded rating data
* @param config JSON encoded plugin configurations
* @param options JSON encoded rating options
* @param enabled Enable the rating for a user
*/
function ratingInit(element, data, config, options, enabled) {
ratingSettings[element] = new Array();
ratingSettings[element]['data'] = eval('(' + data + ')');
ratingSettings[element]['options'] = eval('(' + options + ')');
ratingSettings[element]['config'] = eval('(' + config + ')');
ratingSettings[element]['enabled'] = enabled;
for (var i = 1; i <= ratingSettings[element]['data']['%MAX%']; i++) {
$('#' + element + '_' + i).bind('mouseenter', {i: i}, function(e) {
// workaround against event after reload
var target = e.relatedTarget || e.toElement;
if (target && target.id != element + '_' + e.data.i) {
if (ratingSettings[element]['enabled']) {
ratingSet(element, e.data.i);
}
if (ratingSettings[element]['config']['showMouseOverMessages']) {
ratingMessages(element, e.data.i);
}
}
});
if (ratingSettings[element]['enabled']) {
$('#' + element + '_' + i).bind('click', {i: i}, function(e) {
ratingSave(element, e.data.i);
});
}
}
$('#' + element).bind('mouseleave', function(e) {
ratingReset(element)
});
$('#' + element + '_text').bind('mouseenter', function(e) {
ratingReset(element);
if (ratingSettings[element]['config']['showMouseOverMessages']) {
ratingMessages(element);
}
});
ratingReset(element);
}
/**
* Sets the rating element to a rating value.
*
* @param element Name of element
* @param value Rating value
*/
function ratingSet(element, value) {
var starImg = ratingSettings[element]['config']['starEmptyImageLocation'];
for (i = 1; i <= ratingSettings[element]['data']['%MAX%']; i++) {
if (i <= Math.floor(value)) {
starImg = ratingSettings[element]['config']['starFullImageLocation'];
} else if (i == Math.floor(value) + 1 && value.toString().match(/[0-9]\.[5-9]/)) {
starImg = ratingSettings[element]['config']['starHalfImageLocation'];
} else {
starImg = ratingSettings[element]['config']['starEmptyImageLocation'];
}
$('#' + element + '_' + i).attr({'src': ratingSettings[element]['config']['appRoot'] + starImg});
// set user mark
if (ratingSettings[element]['config']['showUserRatingMark'] && i <= ratingSettings[element]['data']['%RATING%']) {
$('#' + element + '_' + i).attr({'class': 'rating-user'});
} else {
$('#' + element + '_' + i).attr({'class': 'rating'});
}
// disable stars
if (!ratingSettings[element]['enabled'] && !$('#' + element + '_' + i).attr('class').match(/-disabled/)) {
$('#' + element + '_' + i).attr({'class': $('#' + element + '_' + i).attr('class') + '-disabled'});
}
}
}
/**
* Resets the rating element.
*
* @param element Element id
*/
function ratingReset(element) {
if (ratingSettings[element]['config']['showUserRatingStars']) {
ratingSet(element, ratingSettings[element]['data']['%RATING%']);
} else {
ratingSet(element, ratingSettings[element]['data']['%AVG%']);
}
$('#' + element + '_text').html(ratingSettings[element]['config']['statusText']);
}
/**
* Does the AJAX call to save the rating and
* updates the rating element.
*
* @param element Name of element
* @param value Rating value
*/
function ratingSave(element, value) {
data = element.split('_');
if (ratingSettings[element]['enabled']) {
$.ajax({
url: ratingSettings[element]['config']['appRoot'] + 'rating/ratings/save/' + data[0] + '/' + data[3] + '/' + value + '?' + Math.floor(Math.random() * 999999),
async: true,
data: ratingSettings[element]['options'],
error: function() {
//alert('AJAX error');
},
beforeSend: function() {
//$('#loader').show();
},
complete: function(XMLHttpRequest) {
//$('#loader').hide();
$('#' + element).html(XMLHttpRequest.responseText);
}
});
}
}
/**
* Displays the mouseOverMessages.
*
* @param element Name of element
* @param value Rating value
*/
function ratingMessages(element, value) {
if (ratingSettings[element]['enabled'] && value > 0) {
if (value == ratingSettings[element]['data']['%RATING%']
&& ratingSettings[element]['config']['allowDelete']
&& ratingSettings[element]['config']['mouseOverMessages']['delete']) {
$('#' + element + '_text').html(ratingSettings[element]['config']['mouseOverMessages']['delete']);
} else if (ratingSettings[element]['config']['mouseOverMessages'][value]) {
$('#' + element + '_text').html(ratingSettings[element]['config']['mouseOverMessages'][value]);
}
} else if (!ratingSettings[element]['enabled']
&& !ratingSettings[element]['config']['disable']
&& ratingSettings[element]['data']['%RATING%'] == 0
&& ratingSettings[element]['config']['mouseOverMessages']['login']){
$('#' + element + '_text').html(ratingSettings[element]['config']['mouseOverMessages']['login']);
} else if (!ratingSettings[element]['enabled']
&& ratingSettings[element]['data']['%RATING%'] > 0
&& ratingSettings[element]['config']['mouseOverMessages']['rated']){
$('#' + element + '_text').html(ratingSettings[element]['config']['mouseOverMessages']['rated']);
} else {
$('#' + element + '_text').html(ratingSettings[element]['config']['statusText']);
}
}
rating/vendors/js/rating_prototype.js
/**
* Prototype javascript for the CakePHP AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
/**
* Holds the settings for all rating elements.
*/
var ratingSettings = new Array();
/**
* Initializes the rating element.
*
* @param element Id of the rating element
* @param data JSON encoded rating data
* @param options JSON encoded rating options
* @param config JSON encoded plugin configurations
* @param enabled Enable the rating for a user
*/
function ratingInit(element, data, config, options, enabled) {
ratingSettings[element] = new Array();
ratingSettings[element]['data'] = eval('(' + data + ')');
ratingSettings[element]['options'] = eval('(' + options + ')');
ratingSettings[element]['config'] = eval('(' + config + ')');
ratingSettings[element]['enabled'] = enabled;
for (var i = 1; i <= ratingSettings[element]['data']['%MAX%']; i++) {
$(element + '_' + i).observe('mouseover', function(e) {
var value = this.id.match(/[0-9]*$/);
// workaround against event after reload
var target = e.relatedTarget || e.toElement;
if (target && target.id != element + '_' + value) {
if (ratingSettings[element]['enabled']) {
ratingSet(element, value);
}
if (ratingSettings[element]['config']['showMouseOverMessages']) {
ratingMessages(element, value);
}
}
});
$(element + '_' + i).observe('click', function(e) {
var value = this.id.match(/[0-9]*$/);
ratingSave(element, value);
});
}
$(element).observe('mouseout', function(e) {
// workaround against mouseout event on child elements like links
var target = e.relatedTarget || e.toElement;
if (target && target.parentNode && target.parentNode.id != null && !target.parentNode.id.match(element)) {
ratingReset(element);
}
});
$(element + '_text').observe('mouseover', function(e) {
// workaround against mouseover event on child elements like links
var target = e.relatedTarget || e.toElement;
if (target && target.parentNode && target.parentNode.id != null && !target.parentNode.id.match(element)) {
ratingReset(element);
if (ratingSettings[element]['config']['showMouseOverMessages']) {
ratingMessages(element);
}
}
});
ratingReset(element);
}
/**
* Sets the rating element to a rating value.
*
* @param element Name of element
* @param value Rating value
*/
function ratingSet(element, value) {
var starImg = ratingSettings[element]['config']['starEmptyImageLocation'];
for (i = 1; i <= ratingSettings[element]['data']['%MAX%']; i++) {
if (i <= Math.floor(value)) {
starImg = ratingSettings[element]['config']['starFullImageLocation'];
} else if (i == Math.floor(value) + 1 && value.toString().match(/[0-9]\.[5-9]/)) {
starImg = ratingSettings[element]['config']['starHalfImageLocation'];
} else {
starImg = ratingSettings[element]['config']['starEmptyImageLocation'];
}
$(element + '_' + i).src = ratingSettings[element]['config']['appRoot'] + starImg;
// set user mark
if (ratingSettings[element]['config']['showUserRatingMark'] && i <= ratingSettings[element]['data']['%RATING%']) {
$(element + '_' + i).className = 'rating-user';
} else {
$(element + '_' + i).className = 'rating';
}
// disable stars
if (!ratingSettings[element]['enabled'] && !$(element + '_' + i).className.match(/-disabled/)) {
$(element + '_' + i).className += '-disabled';
}
}
}
/**
* Resets the rating element.
*
* @param element Element id
*/
function ratingReset(element) {
if (ratingSettings[element]['config']['showUserRatingStars']) {
ratingSet(element, ratingSettings[element]['data']['%RATING%']);
} else {
ratingSet(element, ratingSettings[element]['data']['%AVG%']);
}
$(element + '_text').update(ratingSettings[element]['config']['statusText']);
}
/**
* Does the AJAX call to save the rating and
* updates the rating element.
*
* @param element Name of element
* @param value Rating value
*/
function ratingSave(element, value) {
data = element.split('_');
if (ratingSettings[element]['enabled']) {
new Ajax.Updater(element, ratingSettings[element]['config']['appRoot'] + 'rating/ratings/save/' + data[0] + '/' + data[3] + '/' + value + '?' + Math.floor(Math.random() * 999999), {
asynchronous: true,
evalScripts: true,
method: 'get',
parameters: ratingSettings[element]['options'],
onFailure: function error() {
//alert('AJAX error');
},
onLoading: function (request) {
//Element.show('loader');
},
onComplete: function (request, json) {
//Element.hide('loader');
}
});
}
}
/**
* Displays the mouseOverMessages.
*
* @param element Name of element
* @param value Rating value
*/
function ratingMessages(element, value) {
if (ratingSettings[element]['enabled'] && value > 0) {
if (value == ratingSettings[element]['data']['%RATING%']
&& ratingSettings[element]['config']['allowDelete']
&& ratingSettings[element]['config']['mouseOverMessages']['delete']) {
$(element + '_text').update(ratingSettings[element]['config']['mouseOverMessages']['delete']);
} else if (ratingSettings[element]['config']['mouseOverMessages'][value]) {
$(element + '_text').update(ratingSettings[element]['config']['mouseOverMessages'][value]);
}
} else if (!ratingSettings[element]['enabled']
&& !ratingSettings[element]['config']['disable']
&& ratingSettings[element]['data']['%RATING%'] == 0
&& ratingSettings[element]['config']['mouseOverMessages']['login']){
$(element + '_text').update(ratingSettings[element]['config']['mouseOverMessages']['login']);
} else if (!ratingSettings[element]['enabled']
&& ratingSettings[element]['data']['%RATING%'] > 0
&& ratingSettings[element]['config']['mouseOverMessages']['rated']){
$(element + '_text').update(ratingSettings[element]['config']['mouseOverMessages']['rated']);
} else {
$(element + '_text').update(ratingSettings[element]['config']['statusText']);
}
}
rating/vendors/css/rating.css
/**
* CSS for the AJAX star rating plugin.
*
* @author Michael Schneidt <michael.schneidt@arcor.de>
* @copyright Copyright 2009, Michael Schneidt
* @license http://www.opensource.org/licenses/mit-license.php
* @link http://bakery.cakephp.org/articles/view/ajax-star-rating-plugin-1
* @version 2.4
*/
div.rating {
font-size: 8pt;
white-space: nowrap;
}
div.rating-text {
display: inline;
position: relative;
top: -4px;
padding-left: 5px;
white-space: nowrap;
}
div.rating-notext {
display: none;
}
img.rating {
cursor: pointer;
border-bottom: 2px solid transparent;
}
img.rating-disabled {
cursor: default;
border-bottom: 2px solid transparent;
}
img.rating-user {
cursor: pointer;
border-bottom: 2px solid #dddddd;
}
img.rating-user-disabled {
cursor: default;
border-bottom: 2px solid #dddddd;
}
div.fallback {
display: inline;
}
div.fallback form {
display: inline;
}
div.fallback label {
display: inline;
position: relative;
top: -4px;
}
div.rating label.fallback {
display: inline;
}
div.fallback input[type="radio"] {
}
div.fallback input[type="submit"] {
position: relative;
top: -4px;
left: 5px;
}
div.rating-flash {
display: inline;
position: relative;
top: -4px;
padding-left: 5px;
white-space: nowrap;
}
content
asdfasdf
Page: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9








My issue is the one where the stars disappear on loading. I think this is a problem with the path to the App Root set in the config file.
I have my app in a subfolder on my webroot called "cake". I can set the App Root to "/cake/" in the config file and this works fine if I go to "www.domainname.com/cake/".
However, I want to use a different specific domain name to point at the cakephp app itself. This other domain name points to www.domainname.com/cake/ as its root folder. To access it this way, from reading the config file, I would think I should leave the App Root field in the config file as ''. This however leads to the "disappearing stars" issue. I have tried many variations of what to put in the App Root field without resolving it...
I would be grateful for any assistance.
Thanks again for the great plugin.
Pete
[end quote]
I've just tried all sorts of changes, including to the filenames of the star images, but none of it makes any difference - there must be some sort of caching going on somewhere but it's got me beaten. I resolved it by manually inserting my app root into:
$('#' + element + '_' + i).attr({'src': ratingSettings[element]['config']['appRoot'] + 'myAppRoot/' + starImg});
..it'll be interesting to see what happens when any caching expires...
[quote] [quote] I have tried many variations of what to put in the App Root field without resolving it...
[end quote]
I've just tried all sorts of changes, including to the filenames of the star images, but none of it makes any difference - there must be some sort of caching going on somewhere but it's got me beaten. I resolved it by manually inserting my app root into:
$('#' + element + '_' + i).attr({'src': ratingSettings[element]['config']['appRoot'] + 'myAppRoot/' + starImg});
..it'll be interesting to see what happens when any caching expires...
[end quote]
Thanks again
However, I'm using PostgreSQL and not MySQL like most other people.
Almost everything has worked out of the box for me, just two little changes to get Postgres to work (maybe it's a Cake thing? I'm using 1.3.7), they are:
In "ratings_controller.php"
line 234 reads "$avgRating = round($values[0]['AVG(`Rating`.`rating`)'], 1);"
line 235 reads "$votes = $values[0]['COUNT(*)'];"
Change to read:
line 234 "$avgRating = round($values[0]['avg'], 1);"
line 235 "$votes = $values[0]['count'];"
and you're done
I can not seem to get it to read the user id from anywhere.
Thanks
I have an question:
Have an way to sum the ratings like on a Host Review: Price, Service, Space, Trafic.. Then sum and divide by 4 in this case to have a rating overall bar?
Thank you
// debug sql dump
if (Configure::read('Rating.showHelp')) {
echo $this->element('sql_dump');
}
Do you plan to migrate this to cake1.3?
I am on it, looks like it just needs some minor changes. :-)
Error: The .php was not found in your app/config directory. Please copy it from rating/config/plugin.rating.php
and the containing div of my page content replicates itself in the ratings box, the same type error that comment 30 was having.
So I looked in my app/config directory and its in there. When i turn off javascript, the radio buttons show and I can rate something. I also investigated the fix used in comment 29 but that did not work and I got the same result.
Still trying to get this to work.
I should change this, so long you could try to change the filename to maybe plugin_rating.php and change the default config in the rating element as well.
When I disable javascript I see the star ratings, status text, radio buttons, vote button, and mouseover messages. Also, when javascript is disabled I can vote and it works fine, adding my vote to the database. So my guess is something is happening in the rating_query.js that fouls up the display.
Any thoughts on how to fix this would be greatly appreciated.
If that warning goes away once you log in, then just turn off the help text in the plugin's config file.
$config['Rating.sessionUserId'] = 'Auth.User.id';
does not work for me
Every time a see: Warning: No valid user id was found at "Auth.User.id" in the session
help me to crack
Thanks in Advances..
Controller Class:
<?php// $values = $modelInstance->find(array($modelInstance->primaryKey => $id), //causes "field 'id' is ambiguous" warning
//
//fix:
//
$values = $modelInstance->find(array($modelInstance->name.".".$modelInstance->primaryKey => $id),
array(Configure::read('Rating.modelAverageField'),
Configure::read('Rating.modelVotesField')),
null,
-1);
?>
Router::connect('/rating/ratings/:action/*', array('controller' => 'ratings','plugin'=>'rating'));first of all i wish to thank Michael for this awesome piece of code.
Got it, had to use the element like this:
<?php
echo $this->element('rating', array('plugin' => 'rating',
'model' => 'Provider',
'id' => $provider['Provider']['id']));
?>
Just can repeat myself: Great work! Thanks a lot.
there should be an error in the redirect with custom routes (named controllers) after saving the rate.
Example:
Router::connect(
'/government',
array('controller' => 'products', 'action' => 'display', 5)
);
There return an error view by calling the XMLHttpRequest.responseText…
url: ratingSettings[element]['config']['appRoot'] + '/rating/ratings/save/' + data[0] + '/' + data[3] + '/' + value + '?' + Math.floor(Math.random() * 999999),
div.fallback label {
display: inline;
.
.
}
div.rating label {
display: inline;
}
My biggest (only) problem was that I didn't copy the plugin.rating.php config file into /app/config/plugin.rating.php
None of the Rating config values were set. All were NULL. I wasn't expecting to have to copy config files around. I thought I was diligent about reading the docs, but I must have missed something.
If for no other reason that to make me look foolish, could someone post a link to the documentation that says to copy the config file?
In addition, I think there is a 'bug' in the RatingsController where it loads the config file.
Check this out from line 45 in the RatingsController:
// load config
if (Configure::load($config) === false && Configure::read('Rating.showHelp')) {
echo 'Error: The '.$config.'.php was not found in your app/config directory. Please copy it from rating/config/plugin.rating.php';
exit;
}
Is the logic really saying if I can't load the config file AND the config value to display help is true, then display an error message?
It would seem correct to remove the AND showHelp part of the logic. Yes?
somehow you missed step 3 in the installation instructions in this article as well as in the install.nfo file. Anyway, I aggree that the plugin could load some default configurations when there is no config file found.
There should be an error message, but as you correctly found out, the condition is crap, to read the showHelp config doesn't make any sense when there are no configs loaded. ;-)
Thx for that!
very useful...
ich bastel derzeit für ein Wahlpflichtfach an der FH mit cake herum und habe dein Beispiel erst lauffähig bekommen, als ich mal die Verzeichnisse verglichen habe und festgestellt habe, dass du in app\vendors\js\ eine Datei names protoaculous1.6.packed.js drin hast. Nach dem ich diese auch in mein app/webroot/js/ geschoben habe, läuft das Beispiel einwandfrei.
Keine ahnung ob das für dich relevant ist ;)
gruß
Seven
find ich toll, dass du im Rahmen der FH die Möglichkeit hast CakePHP zu verwenden.
Das Plugin hat als Grundvoraussetzung dass entweder Prototype oder jQuery geladen ist, steht auch oben unter Requirements. Ist aber zugegeben etwas kurz und natürlich nicht klar was man machen muss, wenn man die beiden Frameworks gar nicht kennt. Werde ich mal überarbeiten, danke auf jeden Fall für das Feedback.
Gruß,
Michael
The flash messages work very well too, although as I already have flash messages in my website, I end up with some general flash messages appearing in the ratings boxes instead of in the initial place where I put my $session->flash().
Would you have any suggestions on how to separate my own flash messages (and decide of the place in the view where it gets displayed), from the ratings flash?
To solve the flash collisions you simply have to use a flash key, as shown in the following code.
rating\controllers\ratings_controller.php line 258
$this->Session->setFlash(Configure::read('Rating.flashMessage'),
'default',
array('class' => 'rating-flash'),
'rating');
rating\views\ratings\view.ctp line 95
$session->flash('rating');
Because of ajax reloading, the flash message element has to be within the plugin's view and cannot be placed elsewhere in your view. However it may help you to relocate the div.rating-flash via css in the rating\vendors\css\rating.css
Works like a charm. Thanks!
user/rating/image/star-full.png
it now points at:-
user/rating/img/star-full.png
And when I click on a one of the image place holders I get this error:-
Error: The action rating is not defined in controller UserController
I assume I've missed something simple here since everyone else seems to get it working so easily. I'm using cake 1.2.5, and rating 2.0 with JQuery.
Anyone have any ideas what the problem could be ?
Where does the "user/" come from in your case? I thought it is your appRoot, but in this case there shouldn't be the controller error.
Maybe it would help you to download the working demo and setup a similar configuration of your situation.
I wanted to let you know that I found a little bug.
If you are using a custom primary key field in your model (not "id"), and you set Rating.saveAverageToModel to true, it won't work.
To make it work I just modified line 105 in ratings_controller.php from this:
$avgRating = $modelInstance->field(Configure::read('Rating.modelAverageField'), array($model.'.id' => $id));
to this:
$avgRating = $modelInstance->field(Configure::read('Rating.modelAverageField'), array($model.'.'.$modelInstance->primaryKey => $id));
Thanks again for sharing it! It saved me a lot of work :)
Nahuel
1) Javascript need to be declared before the element instaciation: not a big deal, but i follow the Steve Souders´ performance tips, so, i prefer to declare my javascript on the end of document. Actually, it shows an error if I do this. A solution is simple - instead of call ratingInit directly, do this:
$(window).load(function() {
renderInit( // arguments, etc..
}
So, the code will be executed after document load. If you have a public svn or git repo, i would like to help you with this.
Thx,
Yuri Teixeira.
Maybe something like this:
rating_prototype.js
function ratingInit(element, data, options, config, enabled) {
Event.observe(window, 'load', function() {
...
});
}
rating_jquery.js
function ratingInit(element, data, options, config, enabled) {
$(window).load(function () {
...
});
}
Regards
I currently see no way how to handle that, if you find something working let me know.
Warning (512): DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:
Aro: Array
(
[User] => Array
(
[id] => 3
[username] => test
[group_id] => 2
[created] => 2009-07-22 17:35:44
[modified] => 2009-07-22 17:35:44
)
)
Aco: controllers/Ratings/save [CORE/cake/libs/controller/components/acl.php, line 239]
Its seems to have something to do with the DBACl http://book.cakephp.org/view/644/Initialize-the-Db-Acl-tables but cannot really figure it our. Thanks for your help!
I discovered the mistake myself. I did not have the permission to rate, so had to allow the ratings_controller.php to do this by adding:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allowedActions = array('*');
}
Warning (512): DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:
Aro: Array
(
[User] => Array
(
[id] => 3
[username] => test
[group_id] => 2
[created] => 2009-07-22 17:35:44
[modified] => 2009-07-22 17:35:44
)
)
Aco: controllers/Ratings/save [CORE/cake/libs/controller/components/acl.php, line 239]
Its seems to have something to do with the DBACl http://book.cakephp.org/view/644/Initialize-the-Db-Acl-tables but cannot really figure it our. Thanks for your help!
I keep getting model_id does not exist when I use a plugin model. I enter the model as 'Plugin.Model' eg. 'News.Article'
I've confirmed the model_id exists in d database, I've also tested the same code used in rating_controller->view()
$model = 'News.Article';
$modelInstance = ClassRegistry::init($model);
$modelInstance->id = '3ad66b8f-55ce-11de-bb54-9f1eb639fa3a';
var_dump($modelInstance->exists(true));
In my test, it returns true, but in the the rating_controller it returns false.
I'd really appreciate some help. Thanks in advance.
thx for your comment! I tried to reproduce your problem and created a dummy "news" plugin with a model "article" and also put an article with your uuid into the db "articles", but I didn't experience the problem. Your code snippet shows true on top of the ratings_controller->view().
Do you use the latest CakePHP release? Did you test it with the demo? Atm I have no other idea, but I will let you know if I come up with something.
Regards
I just tested it with the demo and I still get the same error. With models in app/models it works well.
I'm using cake 1.2.3.8166.
Here is how I called the rating plugin.
echo $this->element('rating', array('plugin' => 'rating',
'model' => 'News.Article',
'id' => $article['Article']['id'])
);
?>
Thanks for your help.
ok now I got it too and could figure it out. The problem is, that the sanitization encodes the incoming uuid, that's why the model_id is not found. Further more a rating cannot be saved in the ratings table, because the model_id is an integer field.
I will add the support in the next version, so long you can change the model_id from int to varchar and disable the encoding on Sanitize::clean (in view() and save()) as follows:
Sanitize::clean($id, array('encode' => false));
I really didn't think of uuids, so tanks for your comment.
Thanks
Comments are closed for articles over a year old