1

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.

Dave
  • 28,833
  • 23
  • 113
  • 183
  • You say that the readme is useless, but it seems rather straightforward to me. Can you elaborate on what's holding you back? – Justin ᚅᚔᚈᚄᚒᚔ Jul 15 '11 at 22:02
  • Seems straightforward when looking at it, but when attempting to implement, the code doesn't work. I'll get into more detail in another question if no one answers this question. – Dave Jul 15 '11 at 22:07
  • Example - it doesn't even explain what it actually takes care of and what it leaves to you to do. And it has examples that are just plain incorrect. – Dave Jul 15 '11 at 22:13
  • 3
    I agree with @Dave, the Readme is vague at best. – Matt Oct 28 '12 at 02:22

1 Answers1

1

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.

Matt
  • 1,328
  • 1
  • 16
  • 28
  • 3
    Wow, I'm pretty sure there must be a more straight-forward way. What's the use of a plugin if you have to mess around so much to get it to work? – Cos Nov 12 '12 at 21:33
  • WTF? I've written a good share of the code of the ratings plugin, what this guy does is crazy. You don't even need half of the code. He is not using the helper and component it seems, no surprise he has to write that much code. – floriank Feb 20 '14 at 01:31
  • 1
    @burzum - $this->Rating() looks like a helper call to me and $this->Carmodel->rate() looks like a component call to me. Maybe you should save the snark and use your awesome programming skills to make some documentation that is clear and actually works, which is the problem both I and the OP had. BTW my code is more complicated because I wanted it to be ajax-ified plus I modified the helper a little. Thanks for the down vote! – Matt Feb 21 '14 at 21:06