invisnik/laravel-steam-inventory

View on GitHub
src/SteamInventory.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php namespace Invisnik\LaravelSteamInventory;

use Illuminate\Support\Facades\Config;
use GuzzleHttp\Client as GuzzleClient;
use Illuminate\Cache\CacheManager;
use Illuminate\Support\Collection;

use InvalidArgumentException;

class SteamInventory
{

    /**
     * @var CacheManager $cache Caching layer
     */
    protected $cache;

    /**
     * @var Collection $collection The Collection instance
     */
    protected $collection;

    /**
     * @var integer $cacheTime Number of minutes to cache a Steam ID's inventory
     */
    protected $cacheTime;

    /**
     * @var string $cacheTag The Cache tag that will be used for all items
     */
    protected $cacheTag;

    /**
     * @var string $language
     */
    protected $language;

    /**
     * @var mixed The last inventory that was pulled
     */
    protected $currentData;

    /**
     * @var string The user steamid
     */
    protected $steamid;

    /**
     * @var GuzzleClient
     */
    private $guzzleClient;

    /**
     * SteamInventory constructor.
     * @param CacheManager $manager
     */
    public function __construct(CacheManager $manager)
    {
        $this->cache = $manager->driver();
        $this->collection = new Collection();

        $this->cacheTag = Config::get('steam-inventory.cache_tag', 'steam.inventory');
        $this->cacheTime = Config::get('steam-inventory.cache_time', 60);
        $this->language = Config::get('steam-inventory.language', 'english');

        $this->guzzleClient = new GuzzleClient;
    }

    /**
     * Load the inventory for a Steam ID
     *
     * @param integer $steamId
     * @param int $appId
     * @param int $contextId
     * @return SteamInventory
     */
    public function loadInventory($steamId, $appId = 730, $contextId = 2): SteamInventory
    {
        $this->steamid = $steamId;

        if ($this->cache->tags($this->cacheTag)->has($steamId)) {
            $this->currentData = $this->cache->tags($this->cacheTag)->get($steamId);
            // Return the cached data
            return $this;
        }

        $inventory = $this->getSteamInventory($steamId, $appId, $contextId, $this->language);

        if (is_array($inventory)) {
            $minutes = $this->cacheTime;
            $this->cache->tags($this->cacheTag)->put($steamId, $inventory, $minutes);

            $this->currentData = $inventory;
        }

        return $this;
    }

    /**
     * Fetches the inventory of the Steam ID
     *
     * @param  integer $steamId
     * @param  integer $appId
     * @param  integer $contextId
     * @param  string $lang
     * @return array
     */
    private function getSteamInventory($steamId, $appId, $contextId, $lang): array
    {
        $steamId = $this->cleanSteamId($steamId);
        $this->checkInfo($steamId, $appId, $contextId);

        $url = $this->steamApiUrl($steamId, $appId, $contextId, $lang);

        $response = $this->guzzleClient->get($url);
        $json = json_decode($response->getBody(), true);

        return $json;
    }

    /**
     * Returns a formatted Steam API Url
     *
     * @param  integer $steamId
     * @param  integer $appId
     * @param  integer $contextId
     * @param  string $lang
     * @param  bool $tradable
     * @return string
     */
    private function steamApiUrl($steamId, $appId, $contextId, $lang = 'english', $tradable = true): string
    {
        return 'http://steamcommunity.com/inventory/' . $steamId . '/' . $appId . '/' . $contextId . '?l=' . $lang . '&tradable=' . (int)$tradable;
    }

    /*
    |--------------------------------------------------------------------------
    | Returning Data
    |--------------------------------------------------------------------------
    |
    |
    */

    /**
     * Returns the current Inventory data
     *
     * @return Collection
     */
    public function getInventory(): Collection
    {
        if (!$this->currentData) {
            return false;
        }

        $data = array_get($this->currentData, 'assets');

        return $this->collection->make($data);
    }

    /**
     * Returns the current Inventory Description data
     *
     * @return Collection
     */
    public function getDescriptions(): Collection
    {
        if (!$this->currentData) {
            return false;
        }

        $data = array_get($this->currentData, 'descriptions', false);
        $data = $this->collection->make($data);

        $items = $this->parseItemDescriptions($data);

        return $items;
    }

    /**
     * Returns the current Inventory data with descriptions
     * @param int $contextid
     * @return Collection
     */
    public function getInventoryWithDescriptions($contextid = 2): Collection
    {
        if (!array_get($this->currentData, 'success')) {
            return false;
        }

        $inventory = array_get($this->currentData, 'assets');
        $descriptions = array_get($this->currentData, 'descriptions');
        $data = array_map(function ($item) use ($descriptions, $contextid) {
            foreach ($descriptions as $desc) {
                if ($desc['classid'] == $item['classid'] && $desc['instanceid'] == $item['instanceid']) {
                    foreach ($desc as $key => $value) {
                        if (isset($desc[$key])) {
                            $item[$key] = $desc[$key];
                        }
                    }
                }
            }
            $tags = $this->parseItemTags(array_get($item, 'tags', []));
            $item['tags'] = $tags;
            $item['contextid'] = $contextid;
            return $item;
        }, $inventory);

        $items = $this->collection->make($data);

        return $items;

    }

    /**
     * Clears the user inventory cache
     * @param $steamid
     */
    public function clearCache($steamid): void
    {
        $this->cache->tags('steam.inventory')->forget($steamid);
    }

    /**
     * @param Collection $data
     * @return Collection
     */
    public function parseItemDescriptions(Collection $data): Collection
    {
        $items = $this->collection->make();

        if ($data->count() == 0) {
            return $items;
        }

        foreach ($data as $dataItem) {
            $name = trim(last(explode('|', array_get($dataItem, 'name'))));
            $desc = $this->parseItemDescription(array_get($dataItem, 'descriptions', []));
            $tags = $this->parseItemTags(array_get($dataItem, 'tags', []));
            $cat = array_get($tags, 'Category', '');

            $array = [
                'appid' => array_get($dataItem, 'appid'),
                'classid' => array_get($dataItem, 'classid'),
                'instanceid' => array_get($dataItem, 'instanceid'),
                'name' => $name,
                'market_name' => array_get($dataItem, 'market_name'),
                'weapon' => array_get($tags, 'Weapon'),
                'type' => array_get($tags, 'Type'),
                'quality' => array_get($tags, 'Quality'),
                'exterior' => array_get($tags, 'Exterior'),
                'collection' => array_get($tags, 'Collection'),
                'stattrack' => (stripos($cat, 'StatTrak') !== false) ? true : false,
                'icon_url' => array_get($dataItem, 'icon_url'),
                'icon_url_large' => array_get($dataItem, 'icon_url_large'),
                'description' => $desc,
                'name_color' => '#' . array_get($dataItem, 'name_color'),
            ];

            $items->push(json_decode(json_encode($array)));

            unset($desc, $tags, $cat, $array);
        }

        return $items;
    }

    /**
     * Parse an item's description about the item
     *
     * @param  StdClass $description
     * @return string
     */
    protected function parseItemDescription($description): string
    {
        $description = json_decode(json_encode($description), true);

        return trim(array_get($description, '2.value'));
    }

    /**
     * Parses an item's tags into a usable array
     *
     * @param  array $tags
     * @return array
     */
    protected function parseItemTags(array $tags): array
    {
        if (!count($tags)) {
            return [];
        }

        $parsed = [];

        foreach ($tags as $tag) {
            $categoryName = array_get($tag, 'category');
            $tagName = array_get($tag, 'localized_tag_name');

            $parsed[$categoryName] = $tagName;
        }

        return $parsed;
    }



    /*
    |--------------------------------------------------------------------------
    | Steam ID Cleanup & Check
    |--------------------------------------------------------------------------
    |
    |
    */

    /**
     * Checks if all the variables are numbers
     *
     * @param  integer $steamId
     * @param  integer $appId
     * @param  integer $contextId
     * @return bool
     */
    protected function checkInfo($steamId, $appId, $contextId): bool
    {
        if (!is_numeric($steamId) || !is_numeric($appId) || !is_numeric($contextId)) {
            throw new InvalidArgumentException('One or more variables are invalid: `steamId`, `appId`, `contextId`. They must be numeric!');

            return false;
        }

        return true;
    }

    /**
     * Prepares the Steam ID for usage against most copy/paste problems
     *
     * @param  string $steamId
     * @return string
     */
    protected function cleanSteamId($steamId): string
    {
        $steamId = trim($steamId);

        if (is_numeric($steamId)) {
            return $steamId;
        }

        return $this->steamIdTo64($steamId);
    }

    /**
     * Convert a Steam ID to 64 bit, if it isn't already
     *
     * @param  string $steamId
     * @return string
     */
    protected function steamIdTo64($steamId): string
    {
        if (strlen($steamId) === 17) {
            return $steamId;
        }

        $steamId = explode(':', $steamId);
        $steamId = bcadd((bcadd('76561197960265728', $steamId[1])), (bcmul($steamId[2], '2')));
        $steamId = str_replace('.0000000000', '', $steamId);

        return $steamId;
    }

}