Cakephp datasource for valves steam api

The steam api is something i’ve been working with recently as i occasionally do projects for a gaming community. If you don’t know what steam is its basically a piece of software that allows you to download games, play them, chat with friends, browse the web and more. As i develop alot of websites using cakephp, i decided i should create a datasource to use the steam api. If you would prefer to use the api manually yourself there are full details on how to use it here. In order to be able to use the datasource and any of the steam api you will need to get an api key. You can do so by visiting http://steamcommunity.com/dev/apikey and logging in with your steam account. Once you have that we can get started on our cake app. First up open up your database config file /app/config/database.php and add the following code in there, make sure to enter in your steam api key you just requested.

<?php
class DATABASE_CONFIG {
    	var $steam = array(
    		'datasource' => 'steam',
    		'apikey' => 'yoursteamapikeygoeshere',
    	);
}
?>

These are the connection details just like any database connection or any other datasource we may need a way to authenticate before we can use it. In this case we have an api key to allow us access. Next up we need to add the steam datasource so create a new file called steam_source.php and save it at /app/models/datasources/steam_source.php

<?php
App::import('Core', 'HttpSocket');
class SteamSource extends DataSource {
    	function __construct($config) {
    		$this->connection = new HttpSocket("http://api.steampowered.com");
    		parent::__construct($config);
    	}
    	public function listSources() {
    		return array('steamnews','steamplayers','steamachievements');
    	}
    	public function read($model, $queryData = array())
    	{
    		$results = array();
    		switch($model->useTable)
    		{
    			case "steamnews":
    				if (!isset($queryData['conditions']['appid'])) {
    					$queryData['conditions']['appid'] = 440;
    				}
    				if (!isset($queryData['conditions']['count'])) {
    					$queryData['conditions']['count'] = 10;
    				}
    				if (!isset($queryData['conditions']['maxlength'])) {
    					$queryData['conditions']['maxlength'] = 0;
    				}
    				$url = "/ISteamNews/GetNewsForApp/v0001/";
    				$url .= "?appid={$queryData['conditions']['appid']}&count;={$queryData['conditions']['count']}&maxlength;={$queryData['conditions']['maxlength']}&format;=json";
    				$response = json_decode($this->connection->get($url), true);
    				$results[$model->useTable] = array();
    				foreach($response['appnews']['newsitems']['newsitem'] as $data)
    				{
    					$results[$model->useTable][] = $data;
    				}
    				break;
    			case "steamplayers":
    				if (!isset($queryData['conditions']['steamids'])) {
    					$queryData['conditions']['steamids'] = array("76561197960435530");
    				}
    				$steamids = implode($queryData['conditions']['steamids'], ',');
    				$url = "/ISteamUser/GetPlayerSummaries/v0001/";
    				$url .= "?key={$this->config['apikey']}&steamids;={$steamids}&format;=json";
    				$response = json_decode($this->connection->get($url), true);
    				$results[$model->useTable] = array();
    				foreach($response['response']['players']['player'] as $data)
    				{
    					$results[$model->useTable][] = $data;
    				}
    				break;
    			case "steamachievements":
    				if (!isset($queryData['conditions']['gameid'])) {
    					$queryData['conditions']['gameid'] = 440;
    				}
    				$url = "/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v0001/";
    				$url .= "?gameid={$queryData['conditions']['gameid']}&format;=json";
    				$response = json_decode($this->connection->get($url), true);
    				$results[$model->useTable] = array();
    				foreach($response['achievementpercentages']['achievements']['achievement'] as $data)
    				{
    					$results[$model->useTable][] = $data;
    				}
    				break;
    		}
    		return $results;
    	}
    	public function create($model, $fields = array(), $values = array())
    	{
    		return false;
    	}
    	public function describe($model) {
    		return $model->_schema;
    	}
}
?>

This datasource file covers requesting the data from the api and outputting it in a format we are familiar with. In order to be able to use this new datasource we need to have some models for each particular section. I use a steamnews, steamplayers and steamachievements models. As shown below. /app/models/steamnews.php

<?php
class Steamnews extends AppModel {
    	public $useDbConfig = 'steam';
    	function schema() {
            $this->_schema = array(
                'id' => array('type' => 'integer'),
    			'title' => array('type' => 'string'),
    			'url' => array('type' => 'string'),
    			'author' => array('type' => 'string'),
    			'contents' => array('type' => 'text'),
    			'feedlabel' => array('type' => 'string'),
    			'date' => array('type' => 'date'),
    			'feedname' => array('type' => 'string'),
            );
            return $this->_schema;
    	}
}
?>

/app/models/steamplayer.php

<?php
class Steamplayer extends AppModel {
    	public $useDbConfig = 'steam';
    	function schema() {
            $this->_schema = array(
                'steamid' => array('type' => 'String'),
    			'personaname' => array('type' => 'String'),
    			'profileurl' => array('type' => 'String'),
    			'avatar' => array('type' => 'String'),
                'avatarmedium' => array('type' => 'String'),
                'avatarfull' => array('type' => 'String'),
    			'personastate' => array('type' => 'integer'),
                'communityvisibilitystate' => array('type' => 'integer'),
                'profilestate' => array('type' => 'integer'),
                'lastlogoff' => array('type' => 'integer'),
                'commentpermission' => array('type' => 'integer'),
                'realname' => array('type' => 'String'),
                'primaryclanid' => array('type' => 'String'),
                'timecreated' => array('type' => 'integer'),
                'gameid' => array('type' => 'integer'),
                'gameserverip' => array('type' => 'String'),
                'gameextrainfo' => array('type' => 'String'),
                'cityid' => array('type' => 'String'),
                'loccountrycode' => array('type' => 'String'),
                'locstatecode' => array('type' => 'String'),
                'loccityid' => array('type' => 'String'),
            );
            return $this->_schema;
    	}
}
?<

/app/models/steamachievements.php

>?php
class Steamachievements extends AppModel {
    	public $useDbConfig = 'steam';
    	function schema() {
            $this->_schema = array(
                'name' => array('type' => 'String'),
    			'percent' => array('type' => 'Integer'),
            );
            return $this->_schema;
    	}
}
?<

Once we have everything setup in our app we can access the data like we would with any other model. Here are some examples i created in a quick test controller i made.

<?php
class TestsController extends AppController {
    	var $name = 'Tests';
    	var $uses = array('Steamnews','Steamplayer','Steamachievements');
    	function index()
    	{
    		# Find all steam news articles (default is to show 10 news with full content length and for game tf2)
    		pr($this->Steamnews->find('all'));
    		# Find all the News items For a game by supplying gameid the number of news items and content length to return.
    		pr($this->Steamnews->find('all',array('conditions'=>array('appid'=>440,'count'=>3,'maxlength'=>300))));
    		# Find all the PlayerSummaries (because api requires steamid default is robin walker)
    		pr($this->Steamplayer->find('all'));
    		# Find all the PlayerSummaries by supplying steam ids
    		pr($this->Steamplayer->find('all',array('conditions'=>array('steamids'=>array("76561197994235337","76561198034180652")))));
    		# Find all the Global Achievement Percentages For a game
    		pr($this->Steamachievements->find('all'));
    		$this->autoRender = false;
    		exit();
    	}
}
?>

Heres an example of the kind of output you will get back using the steamnews

Array
(
        [steamnews] => Array
            (
                [0] => Array
                    (
                        [gid] => 1.1778970971792E+18
                        [title] => Team Fortress 2 raises $300k for Japan
                        [url] => http://store.steampowered.com/news/externalpost/eurogamer/1177897097179204650
                        [is_external_url] => 1
                        [author] =>
                        [contents] => Last week Valve started offering Team Fortress 2 players three different pieces of limited edition in-game headwear, with all proceeds going to the post-tsunami relief effort in Japan. According to a message on the official Team Fortress 2 site, the promotion has now raised a whopping $300,000. "Wow...
                        [feedlabel] => Eurogamer
                        [date] => 1301515440
                        [feedname] => eurogamer
                    )
                [1] => Array
                    (
                        [gid] => 1.1778970971697E+18
                        [title] => Hat-tipping: Team Fortress 2 “Hats For Japan” sale raises $300,000
                        [url] => http://store.steampowered.com/news/externalpost/pcgamer/1177897097169747774
                        [is_external_url] => 1
                        [author] =>
                        [contents] => Good work, you hat-craving, conditionally-generous gentlemen and women. Valve's charity drive that began last Thursday has already produced more than $300,000 in aid to Japan by way of the American Red Cross. The items--three hats and a few of noise-maker consumables--are available until April 6.
                        [feedlabel] => PC Gamer
                        [date] => 1301447491
                        [feedname] => pcgamer
                    )
                [2] => Array
                    (
                        [gid] => 1.177897097168E+18
                        [title] => Hats For Help
                        [url] => http://store.steampowered.com/news/externalpost/tf2_blog/1177897097168037565
                        [is_external_url] => 1
                        [author] =>
                        [contents] => Wow. Seriously, people, WOW. We knew you had it in you, but we're still amazed you've raised over $300,000 so far. Take a BOW, TF2 community -- because that is an incredible, frankly astounding, amount of money from a dedicated number of gamers, to one heck of a lot of people in some real need right...
                        [feedlabel] => TF2 Blog
                        [date] => 1301434740
                        [feedname] => tf2_blog
                    )
            )
)

You can download all the files used in this example here. UPDATE This project is now available on git hub https://github.com/davidejones/steam-cakephp

Downloads

Comments

  • avatar-ketam
    # ketam
    Is this ready to run? I mean CakePHP+Steam CakePHP alone will make it work?
  • avatar-davidejones
    # davidejones

    Its just a datasource, so all it does is make access to the data the same as regular cakephp models so you can do simple queries using the model->find

    Yes it will work with cakephp and steam api alone however this was made some time ago so some adjustments may need to be made to work with the latest cakephp and if the api has changed.

    If i get some time i will try and create an updated version.

  • avatar-cameron
    # cameron
    This was a great article not only for the Steam API but for working with data sources as well. Thank You!
  • avatar-bryan-aubry
    # Bryan Aubry

    Mine’s not working, this is what it says on Cake’s home.

    Your version of PHP is 5.2.8 or higher.

    Your tmp directory is writable.

    The FileEngine is being used for core caching. To change the config edit APP/Config/core.php

    Your database configuration file is present.

    Notice (8): Undefined index: message [APP/View/Pages/home.ctp, line 107] Cake is NOT able to connect to the database.

    The datasource configuration “default” was not found in database.php

    • avatar-davidejones
      # davidejones
      You have to have some knowledge of cakephp to get this working. Its possible this might not work on newer versions of cakephp either or may need some tweaking. It sounds like it can’t find the database either you connection details are incorrect or you aren’t using a db and should probably put something like public $useTable = false; in your model file.
  • avatar-eendz0r
    # eendz0r
    best to connect to steam is trough openId here you can get the 64bit steamId and then you can user this to get the desired API info (since you need the 64bit steamid)

Comments are currently closed