Phalcon Repository

<?php
/**
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 *
 * Encoding: UTF-8
 *
 * @package CesarEngineExample\Repository
 * @author cromero - 2015-10-30 15:03:47
 */

namespace CesarEngineExample\Repository;

use CesarEngineExample\Entity\GameConfiguration as GameConfigurationEntity;
use CesarEngineExample\Entity\Player as PlayerEntity;
use CesarEngineExample\Entity\PlayerToken as PlayerTokenEntity;

/**
 * Player Tokens repository
 *
 * @package CesarEngineExample\Repository
 * @uses \CesarEngineExample\Entity\PlayerToken
 */
class PlayerToken extends PlayerTokenEntity
{
    /**
     * Current Token
     *
     * @var \CesarEngineExample\Entity\PlayerToken
     */
    protected $playerToken;

    /**
     * Return stored player token if exists or null
     *
     * @return \CesarEngineExample\Entity\PlayerToken|null
     */
    public function getPlayerToken()
    {
        return $this->playerToken;
    }

    /**
     * Return a PlayerToken from Redis or from MySQL if not in Redis
     *
     * @param string $token
     * @return \CesarEngineExample\Entity\PlayerToken|null
     */
    public function getPlayerTokenByToken($token)
    {
        /** @var \Redis $redis */
        $redis = $this->getDI()->get('redis');

        // Get the token from Redis
        $pattern = sprintf(
            "_PHCR%1\$sPLAYER-TOKEN_TOKEN_%2\$s_PLAYER_ID_*",
            $this->getDI()->get('config')->cache->prefix,
            $token
        );

        $keys = $redis->keys($pattern);
        if (is_array($keys) && ! empty($keys)) {
            $key = reset($keys);
            $this->playerToken = unserialize($redis->get($key));
            $this->extendRedisToken();

            return $this->playerToken;
        }

        // Get the token from MySQL
        if (false === ($playerToken = PlayerTokenEntity::findFirstByToken($token))) {
            return null;
        }

        $this->playerToken = $playerToken->setExpired(true);
        return $this->playerToken;
    }

    /**
     * Get the latest token of a player, this is used in rare cases. So we don't cache it.
     *
     * @param $providerId
     * @param $playerId
     * @return \CesarEngineExample\Entity\PlayerToken | null
     */
    public function getLatestPlayerTokenByProviderIdAndPlayerId($providerId, $playerId)
    {
        $playerToken = PlayerTokenEntity::findFirst(
            array(
                "provider_id = ?1 and player_id = ?2",
                "order" => "id DESC",
                "limit" => 1,
                "bind"  => array(
                    1 => $providerId,
                    2 => $playerId
                )
            )
        );
        return ($playerToken instanceof PlayerTokenEntity) ? $playerToken : null;
    }

    /**
     * Generate a random token optionally expiring previous tokens
     *
     * @param \CesarEngineExample\Entity\Player $player
     * @param \CesarEngineExample\Entity\GameConfiguration $gameConfiguration
     * @param boolean $expirePrevious
     * @param string $hash
     * @return \CesarEngineExample\Entity\PlayerToken
     */
    public function generatePlayerToken(
        PlayerEntity $player,
        GameConfigurationEntity $gameConfiguration,
        $expirePrevious = true,
        $hash = null
    ) {
        if ($expirePrevious) {
            $this->expirePlayerTokensFromRedis($player);
        }

        $playerToken = new PlayerTokenEntity();
        $playerToken
            ->setPlayerId($player->getId())
            ->setProviderId($gameConfiguration->getGame()->getProviderId())
            ->setConfigurationId($gameConfiguration->getId())
            ->setToken($hash ?: $this->generateRandomHash());
        $playerToken->save();

        /** @var \Phalcon\Cache\BackendInterface $cache */
        $cache = $this->getDI()->get('dataCache');
        $cacheKey = sprintf(
            "PLAYER-TOKEN_TOKEN_%1\$s_PLAYER_ID_%2\$s",
            $playerToken->getToken(),
            $playerToken->getPlayerId()
        );
        $cache->save($cacheKey, $playerToken, 300);

        $this->playerToken = $playerToken;
        return $playerToken;
    }

    /**
     * Delete from redis old player tokens
     *
     * @param \CesarEngineExample\Entity\Player $player
     */
    public function expirePlayerTokensFromRedis(PlayerEntity $player)
    {
        /** @var \Redis $redis */
        $redis = $this->getDI()->get('redis');

        // Get the token from Redis
        $pattern = sprintf(
            "_PHCR%1\$sPLAYER-TOKEN_TOKEN_*_PLAYER_ID_%2\$s",
            $this->getDI()->get('config')->cache->prefix,
            $player->getId()
        );

        $redis->del($redis->keys($pattern));
    }

    /**
     * Delete from redis one player token
     *
     * @param \CesarEngineExample\Entity\PlayerToken $playerToken
     */
    public function expirePlayerTokenFromRedisByPlayerToken(PlayerTokenEntity $playerToken)
    {
        /** @var \Redis $redis */
        $redis = $this->getDI()->get('redis');

        // Get the token from Redis
        $key = sprintf(
            "_PHCR%1\$sPLAYER-TOKEN_TOKEN_%2\$s_PLAYER_ID_%3\$s",
            $this->getDI()->get('config')->cache->prefix,
            $playerToken->getToken(),
            $playerToken->getPlayerId()
        );

        $redis->del($key);
    }

    /**
     * Extend 300 seconds more the expire of the token
     */
    public function extendRedisToken()
    {
        if (empty($this->playerToken)) {
            return;
        }

        /** @var \Redis $redis */
        $redis = $this->getDI()->get('redis');

        // Get the token from Redis
        $key = sprintf(
            "_PHCR%1\$sPLAYER-TOKEN_TOKEN_%2\$s_PLAYER_ID_%3\$s",
            $this->getDI()->get('config')->cache->prefix,
            $this->playerToken->getToken(),
            $this->playerToken->getPlayerId()
        );

        $redis->expire($key, 300);
    }

    /**
     * Generates a hash for a token
     *
     * @return string
     */
    public function generateRandomHash()
    {
        return md5(uniqid(rand(), true));
    }
}