Jump to:

3214 Posts in 848 Topics by 810 members

Template Questions

SilverStripe Forums » Template Questions » Counting hits

Moderators: martimiz, Howard, Sean, Ryan M., biapar, Willr, Ingo, swaiba, simon_w

Page: 1 2
Go to End
Author Topic: 2688 Views
  • martin_bg
    Avatar
    Community Member
    2 Posts

    Re: Counting hits Link to this post

    You can't address the DataObject inside the Controller using $this. You should try something like the following:

    class RadioStation_Controller extends RadioOverzichtNL_Controller {
    public function init() {
    parent::init();
    $data = DataObject::get_one( 'RadioStation', "URLSegment='{$this->URLSegment}'" ); // select the data object for the current page
    $data->RadioHits++;
    $data->write();
    }
    }

  • Jeroen
    Avatar
    Community Member
    6 Posts

    Re: Counting hits Link to this post

    Hi Martin thanks for your reply and help.

    I've changed URLSegment to ID instead. My final code is below which works perfectly:

    public function init()
    {
       parent::init();
       $data = DataObject::get_by_id( 'RadioStation', $this->ID);
       $data->RadioHits++;
       $data->write();
        }

    Thanks to all who helped me out on this one!

  • ajshort
    Avatar
    Community Member
    242 Posts

    Re: Counting hits Link to this post

    That's certainly odd, as you can indeed address a DataObject from within a ContentController. However, since that's not working you should access it using $this->data() rather than re-getting the object, which creates an unnecessary query and object.

  • martin_bg
    Avatar
    Community Member
    2 Posts

    Re: Counting hits Link to this post

    $this->data()

    It's never too late to learn! Thanks! I'll keep that in mind next time!

  • Pigeon
    Avatar
    Community Member
    238 Posts

    Re: Counting hits Link to this post

    I've recently been asked to do this for a client, so I just thought I'd explicitly post how it was achieved and why, perhaps, other ways are flawed.

    Firstly, working code:

    function init() {
    parent::init();
    $pageData = $this->data();
    ++$pageData->PageViews;
    $pageData->write();
    }

    Now, that seems to work and write the data to all relevant stages.

    Going and looking up a DataObject by ID or URLSegment (as ajshort points out) results in an un-required amount of work (querying the DB, making an object). This is partly why I suggested the SQL query (DB::query("UPDATE `RadioStation_Live` SET RadioHits=RadioHits+1 WHERE ID=$this->ID");) in IRC. This is the least intensive way to do it, but it only tracks one type of page and also isn't using the framework to its full effect. Yes, it also only alters data on the _Live table which can lead to inconsistencies, but in my opinion we are only tracking views of the Live site but, not the best solution.

    doPublish() is also a bad idea as it will publish draft changes without the admin's approval and will be very intensive.

    So hopefully that will help some people out.

  • k0m0r
    Avatar
    Community Member
    41 Posts

    Re: Counting hits Link to this post

    Hi guys.

    Sorry to tell you this, but you're all wrong

    Do not EVER try to write anything that is versionable inside your controller.
    If you try to do $this->write() inside init() function, you operate only on current stage. So if you increment your page views on live version, only live version is being updated in the database, but your draft version counter is still 0.
    This way every time you publish your page, PageViews field value is being rewritten from draft to live, so the counter resets to 0 every time you make changes to the page. And whatsmore - each time you call DataObject::write(), its LastEdited value changes and there's no point to update it every time user visits a page.

    I've just found a nice solution to do this. You should store your PageViews inside a separate DataObject, because DataObjects are not versionable:

    class PageStat extends DataObject {
    public static $db = array(
    'PageID' => 'Int',
    'Views' => 'Decimal(16,0)', // i am an optimist
    );
    }

    and the init() function:

    public function init() {
    parent::init();
    $do = DataObject::get_one('PageStat','PageID = '.$this->ID);
    if(!$do) {
    $do = new PageStat();
    $do->PageID = $this->ID;
    $do->Views = 0;
    $do->write();
    }
    $do->Views += 1;
    $do->write();
    }

  • k0m0r
    Avatar
    Community Member
    41 Posts

    Re: Counting hits Link to this post

    Of course, for getting this to work like, for example, Most Popular Pages, you need to use JOIN clause:

    public function MostPopularChildren() {
    return DataObject::get('Page','ParentID = '.$this->ID,'Views DESC','INNER JOIN PageStat ON PageStat.PageID = SiteTree_Live.ID');
    }

    And for example a list of the most popular articles throughout the whole site:

    DataObject::get('Page',"ClassName LIKE 'ArticlePage'",'Views DESC','INNER JOIN PageStat ON PageStat.PageID = SiteTree_Live.ID');

    2688 Views
Page: 1 2
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.