Jump to content

A simple way to do per-user progress/preference saving?


Chad
 Share

Recommended Posts

Hello, Processwire forums.

I am trying to build a login and progress-tracking system for a series of 3 shockwave/flash training games that will be embedded in a page. There are 3 games, and we just need to know which ones the user has completed.

What would be the best way to store this information in processwire and how would we modify it? We were thinking that we could use http post from within the games at certain points to mark progress at certain points in the game, but as a first milestone, I'm trying to get this working with basic html forms first but am running into problems.

My initial thought was to make a special class of users called "gamePlayers" and to have 3 checkbox fields in the user pages that represent which of the 3 games have been played to completion. I was able to create a template page that reads this game-state information from a checkbox field using "$user->game1completed", but I'm not really sure how to use Processwire's API to modify and overwrite this information.

I have used Renobird's login scripts from elsewhere in the forums to successfully login and logout users and to read whether the users have the checkbox toggled.

I have tried a few approaches so far that have not yet yeilded good results. I tried making php script (to control the check-box toggling) in the same directory and ran into 403 permission problems. When I created a new template using that form-handling php script, I couldn't get the information to save. When I put a php script into the root of the site, I can run the php script on the post request, but I can't access or modify Processwire data.

Could someone please give me some advice for how to proceed? More specifically, am I going about this in a crazy way? Is there a way I could do this all in one page?

Thanks!

Link to comment
Share on other sites

Just to clarify further, I'm a PHP novice and was in need of help with not only knowing which Processwire commands to input to toggle these states, but how to create the form in such a way that it will actually *trigger* those commands.

Link to comment
Share on other sites

I'm not sure if that's what you looking for and if you already know it. Since users are like pages you can just populate or assign a value to a field and then save it.

Checkboxes have state 0 or 1 vor checked. Assuming the checkbox field is the "game1completed".

$user->game1completed = 1;
$user->save();

This should work

That's ok the way you do it, though not very scaleable and flexible. This approach may work if you only have 3 games and there wont be any more ever.

There's other ways of doing it without checkbox.

1. Using a page that stands for a game. So you could create a template with only the default title field and call it "game-completed". Now you create pages for each game using that template somewhere. If you now create a page field "games_completed" that allows multiple pages for that particular template and assign it to the user template. Then you use that field to save and add a reference to the game the user completed.

// get game page using it's name or id or path
$game = $pages->get( "template=game-completed, name=game1" );

// assign the game page to the page field on user object
$user->games_completed = $game;
$user->save();

To check the pages

// to see if or what games the user completed
foreach ( $user->games_completed as $game ) {
 echo "Game:" . $game->title;
}

// or to output users that have completed a particular game
$game = $pages->get( "/games/game1/" );
$users_completed = $users->find("games_completed=$game");

foreach ( $users_completed as $u ) {
 echo "User:" . $u->name;
}

2. You could also use a textfield to store the game informations as JSON encoded string. And read the string and decode it when needed. But this way it would not be possible to use nice selectors and not so flexible.

3. One that would allow for saving games, along with some informations like score and time, would be to create pages for each game completed as children of the user page. Create a template "game-saved" that has the fields needed for the meta information. Then create new page when saving the game using this template and the user as parent. To be able to add child pages to the user pages, you first need to allow children for the system "user" template (use filter on template list to see it and edit it) under family tab.

// create new page
$game = new Page();
$game->template = $templates->get( "game-saved" );
$game->title = "Game1";

// parent is the user page (user = special page)
$game->parent = $user;

// assign some values
$game->score = $somevar;
$game->time_completed = $timevar;

// save it.
$game->save();

Checking for games could be like this

$game1 = "game1";

// get all users that have completed "game1"
foreach( $users as $u ) {
 // check if user has a child page using the name "game1"
 if( count( $u->children->find( "name=$game1" ) ) ) {
echo "User: " . $u->name;
 }
}

To output game informations

// or cycle the completed games and output
if( $user->numChildren ) ) {
 foreach( $user->children as $game ) {
echo "Game: $game->title<br/>";
echo "Score: $game->score<br/>";
echo "Score: $game->time_completed<br/>";
 }
} else {
 echo "no games completed";
}

The field is yours. ;)

  • Like 3
Link to comment
Share on other sites

... but how to create the form in such a way that it will actually *trigger* those commands.

That depends how you want or need to do it. Depends on how you proceed after the game is completed in flash. You could call a javascript from the flash game and do some simple ajax to call a php script. I remember you can simply use the trick:

getURL("javascript:saveGame('game1', 2332, 109233)");

Easy enough if you know how, but there's many resources out there. More advanced would be to use some connector or comunicate back and forth with callbacks. But just some pseudo code:

// on the page where the flash game is using jquery
function saveGame( game, userid, score ) {
$.ajax({
	 url: '/ajax/saveGame.php',
	 type: 'post',
	 data: { 'game': game, 'score': score, 'userid' : userid },
	 dataType: "json",
	 onsuccess: function(data) {
		  if( data.status == 1 ) alert( "GameSaved!" );
	 }
});
}

Then some simple php under /ajax/saveGame.php

// bootstrap PW index
include( "../index.php" );

// get some fuel; create PW variables as if in a template file
$sanitizer = wire( "sanitizer" );
$input = wire( "input" );
$pages = wire( "pages" );
$users = wire( "users" );

$game = $sanitizer->name( $input->post->game );
$score = (int) $input->post->score;
$user_id = (int) $input->post->userid;

// get the user object
$user = $users->get($user_id);

// do some magic;

// if successful

echo json_encode( array( 'status' => 1 ) );

Or you could simply use a getURL to redirect to a certain page after game is completed. You could add a get var to the url, read that out in php and use it to save some informations.

/some/url/?game=game1&score=42

Then in the php template script use

$game = $sanitizer->name($input->get->game);
$score = (int) $input->get->score;

Or if you use a php file that is not connected to PW use the bootstrap, as in the previous script, to get access to PW through using "wire()".

Edit: Oh and hello Chad, welcome to the forums! :D

  • Like 3
Link to comment
Share on other sites

Soma, I will try a few of these strategies out tomorrow morning. Seeing your examples gave me a much better idea of how to make user-facing web applications with Processwire. Thanks!

Link to comment
Share on other sites

@Soma, @Chad

maybe a bit offtopic, but there is no need to call javascript via getURL, actionscript can do it too.

Something like that should work for you:

function saveGame(game:String, userid:String, score:int):void {   
   var url:String = "/ajax/saveGame.php";
   var request:URLRequest = new URLRequest(url);
   var requestVars:URLVariables = new URLVariables();
    requestVars.game = game;
    requestVars.userid = userid;
    requestVars.score = score;
    request.data = requestVars;
    request.method = URLRequestMethod.POST;

   var urlLoader:URLLoader = new URLLoader();
    urlLoader = new URLLoader();
    urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
    urlLoader.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
    urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler, false, 0, true);
    urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false, 0, true);
    urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false, 0, true);
   for (var prop:String in requestVars) {
    //trace("Sent: " + prop + " is: " + requestVars[prop]);
   }
   try {
    urlLoader.load(request);
   } catch (e:Error) {
    trace(e);
   }
}
function loaderCompleteHandler(e:Event):void {
   var responseVars = URLVariables( e.target.data );
   trace( "responseVars: " + responseVars );
}
function httpStatusHandler( e:HTTPStatusEvent ):void {
   //trace("httpStatusHandler:" + e);
}
function securityErrorHandler( e:SecurityErrorEvent ):void {
   trace("securityErrorHandler:" + e);
}
function ioErrorHandler( e:IOErrorEvent ):void {
   trace("ioErrorHandler:" + e);
}
Link to comment
Share on other sites

Thanks interrobang. There's even more possibilities, but depends what AS version is used :)

I did not make any assumptions to what would be appropriate in his situation as I don't know what flash AS version he uses. getURL will work with any actionscript version and was the simplest example to bring the concept in.

  • Like 1
Link to comment
Share on other sites

Thanks interrobang, that will be very useful and I will pass your code snippet along to the actionscript developers.

Soma's example is very useful too and has given me ideas for how I could build an ajax-driven webapp with ProcessWire and jQuery.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...