Your IP : 216.73.216.172


Current Path : /var/www/html/libraries/kunena/src/Forum/Topic/User/Read/
Upload File :
Current File : /var/www/html/libraries/kunena/src/Forum/Topic/User/Read/KunenaTopicUserReadHelper.php

<?php

/**
 * Kunena Component
 *
 * @package       Kunena.Framework
 * @subpackage    Forum.Topic.User.Read
 *
 * @copyright     Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved.
 * @license       https://www.gnu.org/copyleft/gpl.html GNU/GPL
 * @link          https://www.kunena.org
 **/

namespace Kunena\Forum\Libraries\Forum\Topic\User\Read;

\defined('_JEXEC') or die();

use Exception;
use Joomla\CMS\Factory;
use Joomla\Database\Exception\ExecutionFailureException;
use Kunena\Forum\Libraries\Error\KunenaError;
use Kunena\Forum\Libraries\Forum\Topic\KunenaTopic;
use Kunena\Forum\Libraries\User\KunenaUser;
use Kunena\Forum\Libraries\User\KunenaUserHelper;

/**
 * Class \Kunena\Forum\Libraries\Forum\Topic\User\Read\ReadHelper
 *
 * @since   Kunena 6.0
 */
abstract class KunenaTopicUserReadHelper
{
    /**
     * @var     array| KunenaRead[]
     * @since   Kunena 6.0
     */
    protected static $_instances = [];

    /**
     * @var     array|KunenaRead[]
     * @since   Kunena 6.0
     */
    protected static $_topics = [];

    /**
     * Returns \Kunena\Forum\Libraries\Forum\Topic\User\Read\Read object.
     *
     * @param   mixed  $topic   User topic to load.
     * @param   mixed  $user    user
     * @param   bool   $reload  reload
     *
     * @return  KunenaRead
     *
     * @since   Kunena 6.0
     *
     * @throws  Exception
     */
    public static function get($topic = null, $user = null, $reload = false): KunenaRead
    {
        if ($topic instanceof KunenaTopic) {
            $topic = $topic->id;
        }

        $topic = \intval($topic);
        $user  = KunenaUserHelper::get($user);

        if ($topic < 1) {
            return new KunenaRead(null, $user);
        }

        if (!$user->userid) {
            return new KunenaRead($topic, 0);
        }

        if ($reload || empty(self::$_instances [$user->userid][$topic])) {
            $topics                                   = self::getTopics($topic, $user);
            self::$_instances [$user->userid][$topic] = self::$_topics [$topic][$user->userid] = array_pop($topics);
        }

        return self::$_instances [$user->userid][$topic];
    }

    /**
     * @param   bool|array  $ids   ids
     * @param   mixed       $user  user
     *
     * @return  KunenaRead[]
     *
     * @since   Kunena 6.0
     *
     * @throws  Exception
     */
    public static function getTopics($ids = false, $user = null)
    {
        $user = KunenaUserHelper::get($user);

        if ($ids === false) {
            return isset(self::$_instances[$user->userid]) ? self::$_instances[$user->userid] : [];
        }

        if (!\is_array($ids)) {
            $ids = [$ids];
        }

        // Convert topic objects into ids
        foreach ($ids as $i => $id) {
            if ($id instanceof KunenaTopic) {
                $ids[$i] = $id->id;
            }
        }

        $ids = array_unique($ids);
        self::loadTopics($ids, $user);

        $list = [];

        foreach ($ids as $id) {
            if (!empty(self::$_instances [$user->userid][$id])) {
                $list [$id] = self::$_instances [$user->userid][$id];
            }
        }

        return $list;
    }

    /**
     * @param   array       $ids   ids
     * @param   KunenaUser  $user  user
     *
     * @return  void
     *
     * @since   Kunena 6.0
     *
     * @throws  Exception
     */
    protected static function loadTopics(array $ids, KunenaUser $user): void
    {
        foreach ($ids as $i => $id) {
            $id = \intval($id);

            if (!$id || isset(self::$_instances [$user->userid][$id])) {
                unset($ids[$i]);
            }
        }

        if (empty($ids)) {
            return;
        }

        $idlist = implode(',', $ids);
        $db     = Factory::getContainer()->get('DatabaseDriver');
        $query  = $db->createQuery();
        $query->select('*')
            ->from($db->quoteName('#__kunena_user_read'))
            ->where($db->quoteName('user_id') . ' = ' . $db->quote($user->userid))
            ->andWhere($db->quoteName('topic_id') . ' IN (' . $idlist . ')');
        $db->setQuery($query);

        try {
            $results = (array) $db->loadAssocList('topic_id');
        } catch (ExecutionFailureException $e) {
            KunenaError::displayDatabaseError($e);
        }

        foreach ($ids as $id) {
            if (isset($results[$id])) {
                $instance = new KunenaRead();
                $instance->bind($results[$id]);
                $instance->exists(true);
                self::$_instances [$user->userid][$id] = self::$_topics [$id][$user->userid] = $instance;
            } else {
                self::$_instances [$user->userid][$id] = self::$_topics [$id][$user->userid] = new KunenaRead($id, $user->userid);
            }
        }

        unset($results);
    }

    /**
     * @param   KunenaTopic  $old  old
     * @param   KunenaTopic  $new  new
     *
     * @return  boolean
     *
     * @since   Kunena 6.0
     *
     * @throws Exception
     */
    public static function move(KunenaTopic $old, KunenaTopic $new): bool
    {
        // Update database
        $db    = Factory::getContainer()->get('DatabaseDriver');
        $query = $db->createQuery();
        $query->update($db->quoteName('#__kunena_user_read'))
            ->set($db->quoteName('topic_id') . ' = ' . $db->quote($new->id))
            ->set($db->quoteName('category_id') . ' = ' . $db->quote($new->category_id))
            ->where($db->quoteName('topic_id') . ' = ' . $db->quote($old->id));
        $db->setQuery($query);

        try {
            $db->execute();
        } catch (ExecutionFailureException $e) {
            KunenaError::displayDatabaseError($e);

            return false;
        }

        // Update internal state
        if (isset(self::$_topics [$old->id])) {
            if ($new->id != $old->id) {
                self::$_topics [$new->id] = self::$_topics [$old->id];
                unset(self::$_topics [$old->id]);
            }

            foreach (self::$_topics [$new->id] as $instance) {
                $instance->topic_id    = $new->id;
                $instance->category_id = $new->category_id;
            }
        }

        return true;
    }

    /**
     * @param   KunenaTopic  $old  old
     * @param   KunenaTopic  $new  new
     *
     * @return  boolean
     *
     * @since   Kunena 6.0
     *
     * @throws Exception
     */
    public static function merge(KunenaTopic $old, KunenaTopic $new): bool
    {
        $db = Factory::getContainer()->get('DatabaseDriver');

        // Move all user topics which do not exist in new topic
        $queries[] = "UPDATE #__kunena_user_read AS ur
			INNER JOIN #__kunena_user_read AS o ON o.user_id = ur.user_id
			SET ur.topic_id={$db->quote($new->id)}, ur.category_id={$db->quote($new->category_id)}
			WHERE o.topic_id={$db->quote($old->id)} AND ur.topic_id IS NULL";

        // Merge user topics information that exists in both topics
        $queries[] = "UPDATE #__kunena_user_read AS ur
			INNER JOIN #__kunena_user_read AS o ON o.user_id = ur.user_id
			SET ur.message_id = LEAST( o.message_id, ur.message_id ),
				ur.time = LEAST( o.time, ur.time )
				WHERE ur.topic_id = {$db->quote($new->id)}
				AND o.topic_id = {$db->quote($old->id)}";

        // Delete all user topics from the shadow topic
        $queries[] = "DELETE FROM #__kunena_user_read WHERE topic_id={$db->quote($old->id)}";

        foreach ($queries as $query) {
            $db->setQuery($query);

            try {
                $db->execute();
            } catch (ExecutionFailureException $e) {
                KunenaError::displayDatabaseError($e);

                return false;
            }
        }

        // Update internal state
        self::reloadTopic($old->id);
        self::reloadTopic($new->id);

        return true;
    }

    /**
     * @param   int  $id  id
     *
     * @return  void
     *
     * @since   Kunena 6.0
     *
     * @throws Exception
     */
    protected static function reloadTopic(int $id): void
    {
        if (empty(self::$_topics [$id])) {
            return;
        }

        $idlist = implode(',', array_keys(self::$_topics [$id]));
        $db     = Factory::getContainer()->get('DatabaseDriver');
        $query  = $db->createQuery();
        $query->select('*')
            ->from($db->quoteName('#__kunena_user_read'))
            ->where($db->quoteName('user_id') . ' IN (' . $idlist . ')')
            ->andWhere($db->quoteName('topic_id') . ' = ' . $db->quote($id));
        $db->setQuery($query);

        try {
            $results = (array) $db->loadAssocList('user_id');
        } catch (ExecutionFailureException $e) {
            KunenaError::displayDatabaseError($e);
        }

        // TODO: is there a bug?
        foreach (self::$_topics [$id] as $instance) {
            if (isset($results[$instance->user_id])) {
                $instance->bind($results[$instance->user_id]);
                $instance->exists(true);
            } else {
                $instance->reset();
            }
        }

        unset($results);
    }

    /**
     * @return  boolean
     *
     * @since   Kunena 6.0
     *
     * @throws  Exception
     */
    public static function recount(): bool
    {
        $db    = Factory::getContainer()->get('DatabaseDriver');
        $query = $db->createQuery();
        $query->update($db->quoteName('#__user_read', 'ur'))
            ->innerJoin($db->quoteName('#__kunena_topics', 't') . ' ON ' . $db->quoteName('t.id') . ' = ' . $db->quoteName('ur.topic_id'))
            ->set($db->quoteName('ur.category_id') . ' = ' . $db->quoteName('t.category_id'));
        $db->setQuery($query);

        try {
            $db->execute();
        } catch (ExecutionFailureException $e) {
            KunenaError::displayDatabaseError($e);

            return false;
        }

        return true;
    }

    /**
     * @param   int  $days  days
     *
     * @return  boolean
     *
     * @since   Kunena 6.0
     *
     * @throws  Exception
     */
    public static function purge($days = 365): bool
    {
        // Purge items that are older than x days (defaulting to a year)
        $db        = Factory::getContainer()->get('DatabaseDriver');
        $timestamp = Factory::getDate()->toUnix() - 60 * 60 * 24 * $days;
        $query     = $db->createQuery();
        $query->delete($db->quoteName('#__kunena_user_read'))
            ->where($db->quoteName('time') . ' < ' . $db->quote($timestamp));
        $db->setQuery($query);

        try {
            $db->execute();
        } catch (ExecutionFailureException $e) {
            KunenaError::displayDatabaseError($e);

            return false;
        }

        return true;
    }
}