XF 2.0 How to update my member statistics

SyTry

Well-known member
Hello !

I want to do an add-on to add a member statistic to the notable members page. I know very little about PHP so I use XenForo files to help me. In my Listener.php I have this :
PHP:
<?php

namespace SyTryC\MostFollowersMember;

class Listener
{
    public static function userSearcherOrders(\XF\Searcher\User $userSearcher, array &$sortOrders)
    {
        $sortOrders['sc_user_follow'] = \XF::phrase('sc_most_followers_member');
    }
}
Then I did the code_event_listener here : /admin.php?code-events/listeners/
Listen to event : user_searcher_orders
Event hint :
Execute callback : SyTryC\MostFollowersMember\Listener :: userSearcherOrders

Now in member statistics : /admin.php?member-stats/ I have this :
192139

I think it's ok because with my other codes (files) it works at the installation :
192140

My problem is that the number of followers doesn't update, I made a rebuild tool :
192141

It works too but only in the database, so I don't know where is my problem.. If someone can help me or give me some directions, thank you !

Regards, SyTry
 

nocte

Well-known member
You did not provide too much of your code, but a thing that came into my mind: try Admin -> Tools -> Rebuild caches -> Rebuild user caches

Edit: Or is the code in Listener.php all PHP code you have?
 

SyTry

Well-known member
You did not provide too much of your code
Yes you're right
but a thing that came into my mind: try Admin -> Tools -> Rebuild caches -> Rebuild user caches
I have already tried, even a private browsing with another account. I turned off my PC so tomorrow I'll show my code in Setup.php and my Entity/Repository for the rebuild-tool ! :)
 

SyTry

Well-known member
Hello, so I have this code in My\AddOn\Job :
PHP:
<?php

namespace SyTryC\MostFollowersMember\Job;

use XF\Job\AbstractRebuildJob;

class MostFollowers extends AbstractRebuildJob
{
    protected function getNextIds($start, $batch)
    {
        $db = $this->app->db();

        return $db->fetchAllColumn($db->limit(
            "
                SELECT user_id
                FROM xf_user
                WHERE user_id > ?
                ORDER BY user_id
            ", $batch
        ), $start);
    }

    protected function rebuildById($id)
    {
        $repo = $this->app->repository('SyTryC\MostFollowersMember:FollowersCount');
        $count = $repo->getMostFollowersCount($id);

        $this->app->db()->update('xf_user', ['sc_user_follow' => $count], 'user_id = ?', $id);
    }

    protected function getStatusType()
    {
        return \XF::phrase('sc_most_followers_counts');
    }
}
This code in My\AddOn\Repository :
PHP:
<?php

namespace SyTryC\MostFollowersMember\Repository;

use XF\Mvc\Entity\Finder;
use XF\Mvc\Entity\Repository;
use XF\PrintableException;

class FollowersCount extends Repository
{
    public function getMostFollowersCount($userId)
    {
        return $this->db()->fetchOne("
            SELECT COUNT(*)
            FROM xf_user_follow
            WHERE follow_user_id = ?
        ", $userId);
    }
}
In Setup.php I have this :
PHP:
    public function installStep1()
    {
        $sm = $this->schemaManager();

        $sm->alterTable('xf_user', function(Alter $table)
        {
            $table->addColumn('sc_user_follow', 'int')->setDefault(0);
            $table->addKey('sc_user_follow', 'most_followers');
        });
    }

    public function postInstall(array &$stateChanges)
    {
        $this->db()->query("
            UPDATE xf_user AS user
            INNER JOIN (
                SELECT COUNT(*) AS sc_user_follow, follow_user_id
                FROM xf_user_follow
                GROUP BY follow_user_id
            ) AS follow ON (follow.follow_user_id = user.user_id)
            SET   user.sc_user_follow = follow.sc_user_follow
        ");
    }
And this in My\AddOn\XF\Entity :
PHP:
<?php

namespace SyTryC\MostFollowersMember\XF\Entity;

use XF\Mvc\Entity\Structure;

class User extends XFCP_User
{
    public static function getStructure(Structure $structure)
    {
        $structure = parent::getStructure($structure);

        $structure->columns['sc_user_follow'] = ['type' => self::UINT, 'default' => 0, 'forced' => true, 'changeLog' => false];

        return $structure;
    }
}
Regards, SyTry
 

nocte

Well-known member
You do nothing on a new follower/unfollowing, right?

Maybe you should extend XF\Service\User\Follow - the methods follow() and unfollow().

The problem I see here is, that you get no confirmation, that there was no error when you call parent::follow() or parent::unfollow(). Something like a $followedSuccess and $unfollowedSuccess property for the class would be handy, I think.

@Chris D ? 🤔

But maybe there's a better way to do this. I am not a pro dev too.. ;)

Edit: Thought about it. Maybe better to use an event listener. Event entity_post_save / event hint XF\Entity\UserFollow - in the Listener.php you have to increase the followers count accordingly. And for unfollowing use the entity_post_delete event.
 
Last edited:

SyTry

Well-known member
You do nothing on a new follower/unfollowing, right?
Yes nothing
Maybe you should extend XF\Service\User\Follow - the methods follow() and unfollow().

The problem I see here is, that you get no confirmation, that there was no error when you call parent::follow() or parent::unfollow(). Something like a $followedSuccess and $unfollowedSuccess property for the class would be handy, I think.

@Chris D ? 🤔

But maybe there's a better way to do this. I am not a pro dev too.. ;)

Edit: Thought about it. Maybe better to use an event listener. Event entity_post_save / event hint XF\Entity\UserFollow - in the Listener.php you have to increase the followers count accordingly. And for unfollowing use the entity_post_delete event.
I will take a look, thank you ! :D
 

SyTry

Well-known member
So I try to add an event listener for entity_post_save like this :
192190

Listener.php :
PHP:
    protected function _postSave()
    {
        parent::_postSave();

        $this->updateFollowerCount($this->get('follow_user_id'), 1);
    }
But I get an error when I want to save :
192193

Same for _postDelete() :unsure:
 

nocte

Well-known member
oh, you mixed up two things. Forget the non-edited part of my post, just this matters:
Edit: Thought about it. Maybe better to use an event listener. Event entity_post_save / event hint XF\Entity\UserFollow - in the Listener.php you have to increase the followers count accordingly. And for unfollowing use the entity_post_delete event.
Try:
PHP:
public static function increaseFollowersCount($entity)
{
    // $entity->user_id is the ID of the user you want to increase the follow count for.
}
 

SyTry

Well-known member
oh, you mixed up two things. Forget the non-edited part of my post, just this matters:

Try:
PHP:
public static function increaseFollowersCount($entity)
{
    // $entity->user_id is the ID of the user you want to increase the follow count for.
}
So I don't need to have _postSave() and _postDelete() but only increaseFollowersCount() ?
 

nocte

Well-known member
So I don't need to have _postSave() and _postDelete() but only increaseFollowersCount() ?
Right, you can name your method increaseFollowersCount() or choose any other name (and set this name in your event listener). You just update the sc_user_follow column for the user with user ID $entity->user_id - that's it :)
 

SyTry

Well-known member
Right, you can name your method increaseFollowersCount() or choose any other name (and set this name in your event listener). You just update the sc_user_follow column for the user with user ID $entity->user_id - that's it :)
I try this :
PHP:
    public static function increaseFollowersCount($entity)
    {
        $entity->user_id
    }
But I have the same message, I don't really understand your indications here.. :(
 

nocte

Well-known member
That's not a valid PHP code (no semicolon after $entity->user_id) AND this does nothing at all. Of course you have to write a few lines of code inside the method. Wait a minute.
 

nocte

Well-known member
try this (of course untested):

PHP:
$finder = \XF::finder('XF:User')
    ->where('user_id', $entity->user_id);

$user = $finder->fetchOne();

if ($user)
{
    $user->fastUpdate('sc_user_follow', $finder->columnSqlName('sc_user_follow') . " + 1");
}
 

SyTry

Well-known member
try this (of course untested):

PHP:
$finder = \XF::finder('XF:User')
    ->where('user_id', $entity->user_id);

$user = $finder->fetchOne();

if ($user)
{
    $user->fastUpdate('sc_user_follow', $finder->columnSqlName('sc_user_follow') . " + 1");
}
Ok now I know what you are talking about, thank you. Just tried it but didn't work, I'll try to modify the code to make it work !
 

nocte

Well-known member
Error messages are very important if you want help! Most users won't be able or willing to run your code on their installations. Why does my code not work?

Anyway, try raw sql (wich is not recommended in most cases):

PHP:
public static function increaseFollowersCount($entity)
{
    \XF::db()->query('UPDATE xf_user SET sc_user_follow = sc_user_follow + 1 WHERE user_id = ?', $entity->user_id);
}
 

SyTry

Well-known member
PHP:
public static function increaseFollowersCount($entity) { \XF::db()->query('UPDATE xf_user SET sc_user_follow = sc_user_follow + 1 WHERE user_id = ?', $entity->user_id); }
This code does not add people with followers but it add followers :
192214

On my localhost "SyTry" is following User1 & test1, but he have 0 followers
 
Top