Simple synchronous php library for stackmob.com.
I need this for a stackmob project, and have only begun to change the basic functionality to work with stackmob instead of parse. Feel free to contribute if you are in need of the other pieces of the puzzle like "Push notifications", etc. I will update the documentation when this project is farther along.
Based on the project this is forked from: https://github.com/spacious/sparse
Modeled after the Parse Javascript SDK API.
Uses the REST API over curl.
Requires PHP 5.3+ (uses namespaces)
The ultimate purpose of this project is to make it easier to work with a more consistent API between JS/PHP.
This project is currently in early stages, so it's dirty and may have a few inconsistencies.
Features are implemented as needed, fork it and help out!
Mostly complete*, exceptions noted below.
*Supports basic Object, Query, User, Push and Cloud functions.
Not currently implemented:
- Op
- Collections
- GeoPoint (Locations)
- Roles
- Facebook Users
- Push messages
The only setup is to give the rest client class (Rest.php) your parse credentials:
This can be done anywhere or for portability just in Stackmob.php like so:
// Your credentials:
Rest::$consumerKey = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
Rest::$consumerSecret = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
Rest::$DEVELOPMENT = true; // change to false for production
If done outside a Stackmob namespaced file, you'll need the namespace:
// Your credentials:
\Stackmob\Rest::$consumerKey = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
\Stackmob\Rest::$restAPIKey = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
\Stackmob\Rest::$DEVELOPMENT = true; // change to false for production
Tests should be done as followed
> cd tests/Stackmob
> ../../vendor/bin/phpunit --stderr UserTest.php
> #view logs
> vim sm.log
The simplest way to use the library is just use Rest.php. It provides methods to get, post and put using the Stackmob REST API. (https://developer.stackmob.com/sdks/rest/api#a-rest_docs) Shortcut methods are also provided for Objects, Users, etc.
The remaining classes are meant to provide a more declaritive way to work with Objects and Queries.
We'll try to also mimic stackmob's documentation structure and note APIs which have not been implemented.
Refer to (https://github.com/jobiwankanobi/stackmobphp/tree/master/tests) for things that are working and how to use them.
With Stackmob it's usually easier to just use Object directly without subclassing it, like:
$gameScore = new Stackmob\Object('GameScore');
// or create with data (associative array of attributes)
$data = array('score'=>1337,'playerName'=>"Sean Plott",'cheatMode'=>false);
$gameScore = new Stackmob\Object('GameScore', $data);
If you use the object a lot or need custom methods you can extend as so:
class Monster extends Stackmob\Object {
public function __construct($attributes=array()){
parent::__construct('Monster',$attributes);
}
public function hasSuperHumanStrength() {
return $this->get("strength") > 18;
}
public static function spawn($strength){
// many ways to do this
$monster = new Monster();
$monster->set('strength',$strength); // or $monster->strength = $strength;
// or just simply:
//$monster = new Monster(array('strength'=>$strength));
return $monster;
}
}
Stackmob\User is also an example of an Object subclass.
$gameScore = new Stackmob\Object('GameScore');
$gameScore->set("score", 1337);
$gameScore->set("playerName", "Sean Plott");
$gameScore->set("cheatMode", false);
// Note Stackmob object getters/setters are overloaded so this is also possible:
//$gameScore->score = 1337;
//$gameScore->playerName = "Sean Plott";
//$gameScore->cheatMode = false;
$gameScore->save();
// this is a synchronous call so you can check the save was successful with:
// Note id() is the same has objectId or get('objectId'), it exists to mimic the JS API
if($gameScore->id()){
echo('GameScore saved.'."<br />");
}else{
die('Could not save GameScore.'."<br />");
}
Your object will now have the following properties:
echo('objectId: '.$gameScore->id()."<br />");
echo('createdAt: '.$gameScore->createdate."<br />");
Just like the JS API, you can set your properties on save() as well:
$gameScore = new Stackmob\Object('GameScore');
$data = array('score'=>1337,'playerName'=>"Sean Plott",'cheatMode'=>false);
$gameScore->save($data);
// Using a Query
$query = new \Stackmob\Query('GameScore');
$gameScore = $query->get('fc0Gy7fdf1');
if($gameScore){
echo('<pre>');
print_r($gameScore);
echo('</pre>');
// Your object will have the following properties:
echo('objectId: '.$gameScore->id()."<br />");
echo('createdAt: '.$gameScore->createdate."<br />");
echo('updatedAt: '.$gameScore->updateddate."<br />");
}
// Using fetch:
$gameScore = new Stackmob\Object('GameScore');
$gameScore->id('fc0Gy7fdf1');
$gameScore->fetch();
// Your object will have the following properties:
echo('objectId: '.$gameScore->id()."<br />");
echo('createdAt: '.$gameScore->createdate."<br />");
echo('updatedAt: '.$gameScore->updateddate."<br />");
$gameScore = new Stackmob\Object('GameScore');
$gameScore->set("score", 1337);
$gameScore->set("playerName", "Sean Plott");
$gameScore->set("cheatMode", false);
$gameScore->set("skills", array('pwnage','flying'));
$gameScore->save();
if($gameScore->id()){
$gameScore->set("score", 1338);
$gameScore->set("cheatMode", true);
$gameScore->save();
}
Not yet implemented
$gameScore->increment('score');
$gameScore->save();
Not yet implemented
$gameScore->addUnique("skills", "flying");
$gameScore->add("skills", "kungfu");
$gameScore->remove("skills",'pwnage');
$gameScore->save();
Not yet implemented
$gameScore->destroy();
if(!$gameScore->id()){
echo('GameScore deleted.'."<br />");
}
Delete a single field... Not yet implemented
NOTE: Changed from unset() to unsetAttr() (unset is reserved in PHP)
$gameScore->unsetAttr('playerName');
$gameScore->save();
Partially implemented - php code is different. Will update...
$post = new \Stackmob\Object('Post');
$comment = new \Stackmob\Object('Comment');
$post->title = "I'm Hungry";
$post->content = "Where should we go for lunch?";
$post->save();
$comment->comment = "Let's do Sushirrito.";
$comment->set('parent',$post);
$comment->save();
// or with id:
$post = new \Stackmob\Object('Post');
$post->id = '0HETDIVfuq';
$comment->set('parent',$post);*/
// Fetching related data
$comment = new \Stackmob\Object('Comment');
$comment->id('T0z3RIgdqD');
$comment->fetch();
$post = $comment->parent->fetch();
NOTE: Parse Relations are NOT yet implemented
Name changes due to reserved words in PHP:
- unset() to unsetAttr()
- clone() to cloneObject()
These are stubbed in but are no-ops:
- changedAttributes
- escape
- existed
- isValid
- op
- previous
- previousAttributes
- relation
- setACL
Extra public API provided to API:
Get/Set all the attributes of an Object:
NOTE: Setting all the attributes directly does not set any as 'dirty'.
$gameScore = new Stackmob\Object('GameScore');
$data = array('score'=>1337,'playerName'=>"Sean Plott",'cheatMode'=>false);
$gameScore->attributes($data);
$data = $gameScore->attributes();
Get the class name of the Object:
$gameScore->className();
Get/Set objectId:
$objectId = $gameScore->id();
$gameScore->id('fc0Gy7fdf1');
Create a 'pointer' representation of this Object:
$gameScore->pointer();
Queries are simpler in stackmob and based on object, so I don't have a separate class. Will update documentation.
$query = new \Stackmob\Query('GameScore');
$query->equalTo('playerName','Dan Stemkoski');
$gameScores = $query->find();
if($gameScores){
echo("Successfully retrieved ".count($gameScores)." scores."."<br />");
}
$query->notEqualTo('playerName','Michael Yabuti');
$query->greaterThan("playerAge", 18);
// Limit
$query->limit(10);
// First
$query = new \Stackmob\Query('GameScore');
$query->equalTo("playerEmail", "[email protected]");
$gameScore = $query->first();
if($gameScore){
echo("Successfully retrieved the object: ".$gameScore->id."<br />");
}
// skip the first 10 result
$query->skip(10);
// Sorts the results in ascending order by the score field
$query->ascending("score");
// Sorts the results in descending order by the score field
$query->descending("score");
// Restricts to wins < 50
$query->lessThan("wins", 50);
// Restricts to wins <= 50
$query->lessThanOrEqualTo("wins", 50);
// Restricts to wins > 50
$query->greaterThan("wins", 50);
// Restricts to wins >= 50
$query->greaterThanOrEqualTo("wins", 50);
// Finds scores from any of Jonathan, Dario, or Shawn
$query->containedIn("playerName", array("Jonathan Walsh", "Dario Wunsch", "Shawn Simon"));
// Finds scores from anyone who is neither Jonathan, Dario, nor Shawn
$query->notContainedIn("playerName", array("Jonathan Walsh", "Dario Wunsch", "Shawn Simon"));
// Finds objects that have the score set
$query->exists("score");
// Finds objects that don't have the score set
$query->doesNotExist("score");
- matchesKeyInQuery
- doesNotMatchKeyInQuery
- doesNotMatchQuery
NOTE: Not tested!
$query->equalTo("arrayKey", 2);
$query = new \Stackmob\Query("BarbecueSauce");
$query->matches("name", '/^[A-Z][0-9]/');
$sauces = $query->find();
// PCRE modifiers
$query = new \Stackmob\Query("BarbecueSauce");
$query->matches("description", "bbq", "im");
$sauces = $query->find();
$query = new \Stackmob\Query("BarbecueSauce");
$query->contains("name", "Extra Spicy!");
$query = new \Stackmob\Query("BarbecueSauce");
$query->startsWith("name", "Big Daddy's");
$query = new \Stackmob\Query("BarbecueSauce");
$query->endsWith("Original Recipe");
// equal to existing object:
$post = new \Stackmob\Object('Post');
$post->id = '0HETDIVfuq';
$query = new \Stackmob\Query('Comment');
$query->equalTo("parent", $post);
$comments = $query->find();
// equal to result of a query:
$innerQuery = new \Stackmob\Query('Post');
$innerQuery->exists("image");
$query = new \Stackmob\Query('Comment');
$query->matchesQuery("post", $innerQuery);
$comments = $query->find();
// include related objects:
$query = new \Stackmob\Query('Comment');
// Retrieve the most recent ones
$query->descending("createdAt");
// Only retrieve the last ten
$query->limit(10);
// Include the post data with each comment
// Changed from include()
$query->includeObject("parent");
// using dot-notation
//$query->includeObject("parent.author");
$comments = $query->find();
if($comments){
foreach($comments as $comment){
$post = $comment->parent;
}
}
$query = new \Stackmob\Query('GameScore');
$query->equalTo('playerName',"Sean Plott");
$count = $query->count();
echo("Sean has played " . $count . " games");
$lotsOfWins = new \Stackmob\Query("Player");
$lotsOfWins->greaterThan("wins",150);
$fewWins = new \Stackmob\Query("Player");
$fewWins->lessThan("wins",5);
$mainQuery = \Stackmob\Query::queryWithOrQueries(array($lotsOfWins,$fewWins));
$results = $mainQuery->find();
Name changes due to reserved words in PHP:
- include() changed to includeObject()
- or() changed to queryWithOrQueries();
These are stubbed in but are no-ops:
- collection
- doesNotMatchQuery
- matchesKeyInQuery
- near
- toJSON
- withinGeoBox
- withinKilometers
- withinMiles
- withinRadians
Sets the seldom used 'arrayKey'
$query->arrayKey($n);
Get the class name of the Query:
$query->className();
Add 'or' queries
$query->matchesOrQueries($queries);
NOTE: Collections NOT yet implemented
$user = new Stackmob\User;
$user->set("username", "my name");
$user->set("password", "my pass");
$user->set("email", "[email protected]");
// other fields can be set just like with Parse.Object
$user->set("phone", "415-392-0202");
user->signUp();
// or
$user = Stackmob\User::signUpUser("my name","my pass",array('email'=>"[email protected]"));
The JS API uses a static login method, right now we have an instance method.
$user = new Stackmob\User;
$user->set("username", "my name");
$user->set("password", "my pass");
$user->login();
// or just use the rest class
$restClient = new Stackmob\Rest();
$loggedIn = $restClient->login($username,$password);
$currentUser = Stackmob\User::current();
if ($currentUser) {
// do stuff with the user
} else {
// show the signup or login page
}
Stackmob\User::logOut();
$currentUser = Stackmob\User::current(); // this will now be null
Stackmob\User::requestPasswordReset("[email protected]");
NOTE: Roles API NOT yet implemented
NOTE: Facebook Users API NOT yet implemented
NOTE: GeoPoints API NOT yet implemented
All the options available for Push via the REST API are supported.
// Super simple example
Stackmob\Push::send(array(
'channels' => array('channel1','channel2'),
'data' => array('message'=>'blah')
));
Stackmob\Cloud::run('testMethod',array('someParam'));