phpcakephppluginscakephp-1.3cakedc

CakeDC Ratings Plugin - any tutorial/instructions anywhere?


Is there a good tutorial / instructions for the CakeDC ratings plugin anywhere? I'm 4 hours in and still no end in site - the read-me is useless.


Solution

  • Here is some code that I used to get the ratings plugin working. It is all Ajax, so I added one hack to the RatingHelper to avoid showing a "Rate!" button, just add submit=>false to the options.

        if ($options['createForm']) {
            if (!empty($options['target']) && !empty($options['createForm']['url']) && !empty($options['createForm']['ajaxOptions'])) {
                $ajaxOptions = array_merge(array('url' => $options['createForm']['url']), $options['createForm']['ajaxOptions']);
                $result .= $this->Js->submit(__d('ratings', 'Rate!'), $ajaxOptions) . "\n";
                $flush = true;
            } elseif ( !isset($options['submit']) || !empty($options['submit']) ) {
                if(empty($options['submit'])) {
                    $result .= $this->Form->submit(__d('ratings', 'Rate!')) . "\n";
                } else {
                    $result .= $this->Form->submit($options['submit']) . "\n";                  
                }
            }
            $result .= $this->Form->end() . "\n";
            if ($flush) {
                $this->Js->writeBuffer();
            }
        }
    

    I have an index view that is showing a bunch of car models and I show an overall rating and the current users rating:

                <?php foreach ($carmodels as $carmodel): ?>
                <tr>
                    <td><?php echo h($carmodel['Carmodel']['id']); ?>&nbsp;</td>
                    <td><?php echo h($carmodel['Carmodel']['name']); ?>&nbsp;</td>              
                    <td>
                        <?php echo $this->Html->link($carmodel['Make']['name'], array('controller' => 'makes', 'action' => 'view', $carmodel['Make']['id'])); ?>
                    </td>
                    <td>
                        <?php $overall_div = 'overall-rating' . $carmodel['Carmodel']['id']; ?>
                        <div id="<?php echo $overall_div; ?>">
                            <?php
                            echo $this->element('rating', array('rating' => $carmodel['Carmodel']['rating']));
                            ?>
                        </div>
                    </td>   
                    <td>
    
                        <?php
                        $msg_div = 'rating-msg' . $carmodel['Carmodel']['id'];
                        $rating = 0;
                        if (!empty($carmodel['Rating'])) {
                            $rating = $carmodel['Rating'][0]['value'];
                        }
                        echo $this->Rating->display(array(
                            'item' => $carmodel['Carmodel']['id'],
                            'type' => 'radio',
                            'stars' => 5,
                            'value' => $rating,
                            'submit' => false,
                            'createForm' => array(
                                'id' => 'CarmodelsRatingsDemoForm' . $carmodel['Carmodel']['id'],
                                'url' => array('action' => 'ratings_update', $carmodel['Carmodel']['id']),
                                'class' => 'rating',
                                'update-overall' => '#' . $overall_div,
                                'update-msg' => '#' . $msg_div,
                                )));
                        ?>  
                        <div id="<?php echo $msg_div; ?>" class="label label-info hidden">
                            <button class="close" data-dismiss="alert" type="button">×</button>
                            <div class="msg-default"><?php echo __('One moment...'); ?></div>
                            <div class="msg-result"></div>
                        </div>
                    </td>
    

    Then I have some Jquery goodness to create the stars and then react on the click

        $(document).ready(function(){
        $('form.rating').stars({
            cancelShow:true,
            callback: function(ui, type, new_value) {
                var values = ui.$form.serializeArray();
                values.push({
                    'name': 'rating',
                    'value': new_value
                });
                values = jQuery.param(values);
                var msg = ui.$form.attr('update-msg');
                $(msg).removeClass('hidden');
                $(msg).show();
                $(msg).find('div.msg-default').show();
                $(msg).find('div.msg-result').hide();
                $.ajax({
                    'type': 'POST',
                    'dataType': 'json',
                    'url': ui.$form.attr('action'),
                    'data': values
                }).done(function(data) { 
                    var overall_rating = ui.$form.attr('update-overall');
                    if(overall_rating && data['overall_rating']){
                        $(overall_rating).html(data['overall_rating']);
                    }
                    if(msg){
                        $(msg).find('div.msg-default').hide();
                        if(data['msg']) {
                            $(msg).find('div.msg-result').show();
                            $(msg).find('div.msg-result').html(data['msg']);
                            window.setTimeout(function() {
                                $(msg).addClass('hidden');
                            }, 2000);
                        } else {
                            $(msg).addClass('hidden');
                        }
                    }
                    if(data['user_rating'] && data['user_rating']>0) {
                        ui.select(parseInt(data['user_rating']));
                    }
                });
            }
        });
    })
    

    Plus I need a little snippet of css to hide the radio button labels that Cake adds.

        form.rating > div.input {
        display: none;      
    }
    

    Then in the controller, I check if the user has rated the item before and save if not. I return a json array that contains a rendered element of the overall rating, the users rating (new or existing) and a string message to show in a div that disappears after 2 seconds.

        public function ratings_update($id = null) {
        $this->Carmodel->id = $id;
        if (!$this->Carmodel->exists()) {
            throw new NotFoundException(__('Invalid carmodel'));
        }
        $ratings = $this->Carmodel->isRatedBy($id, 1);
        if (!$ratings) {
            $this->Carmodel->rate($id, 1, $this->request->data['rating'], array('values' => array_combine(range(1, 5), range(1, 5))));
            $json['msg'] = __('Thank you');
        } else {
            if ($this->request->data['rating'] == 0) {
                $this->Carmodel->removeRating($id, 1);
                $json['msg'] = __('Rating removed');
            } else {
                $json['msg'] = __('Already rated');
            }
        }
        $this->set('rating', $this->Carmodel->field('rating'));
        $ratings = $this->Carmodel->isRatedBy($id, 1);
        $my_rating = 0;
        if (!empty($ratings)) {
            $my_rating = $ratings['Rating']['value'];
        }
        $this->autoRender = false;
        App::uses('View', 'View');
        $View = new View($this);
    
        $response = $View->render('/Elements/rating', 'ajax');
        $json['overall_rating'] = $response;
        $json['user_rating'] = $my_rating;
        return json_encode($json);
    }
    

    Here is the code for the element that shows stars for the overall rating, it probably should be part of the helper.

    if (empty($rating)) {
        echo __('Be the first to rate!');
    } else {
        echo str_repeat('<div class="ui-stars-star ui-stars-star-on"><a title=""></a></div>', $rating);
    }
    

    So while that isn't a super-detailed instruction, you should be able to figure out what the code is doing and replicate it. It took me the better part of a day to get it working.