Skip to content
Browse files

Added initial release with methods for get(), getAll() and getAllLang…

…uages(). Includes tests and README documentation.
  • Loading branch information...
1 parent ef11978 commit c5b4fbfc4d7851d7e66d493285b52ec01210dec3 @benjaminpearson committed
View
103 README
@@ -0,0 +1,103 @@
+Snipplr API PHP Library
+
+A small library that allows interaction with Snipplr's API. Designed to be used in PHP projects or as a CakePHP vendor. When using this library its highly recommended that you cache your results, visit CakePHP Cache page: http://book.cakephp.org/view/767/Cache-write
+
+QUIRKS
+----------------------------------------------------------------------------------------
+1. In getAll method: Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+2. In getAll method: Limit of 0 or 1 appears to return all snippets (ie, not limited)
+
+
+USAGE
+----------------------------------------------------------------------------------------
+
+CakePHP:
+App::import('Vendor', 'SnipplrCore', array('file' => 'snipplr-api-php'.DS.'snipplr.core.php'));
+$SnipplrCore = new SnipplrCore();
+$snippet = $SnipplrCore->get('18153');
+$snippets = $SnipplrCore->getAll();
+$languages = $SnipplrCore->getAllLanguages();
+
+PHP:
+require_once "snipplr-api-php".DIRECTORY_SEPARATOR."snipplr.core.php";
+$SnipplrCore = new SnipplrCore();
+$snippet = $SnipplrCore->get('18153');
+$snippets = $SnipplrCore->getAll();
+$languages = $SnipplrCore->getAllLanguages();
+
+
+OUTPUT
+----------------------------------------------------------------------------------------
+
+Method Call: get('18153');
+Example Output:
+ Array
+ (
+ [id] => 18153
+ [user_id] => 11806
+ [username] => benjaminpearson
+ [title] => CakePHP highlight active menu item for page
+ [language] => Other
+ [comment] =>
+ [created] => 2009-08-11 00:35:14
+ [updated] => 2009-11-14 15:56:18
+ [source] => <ul>
+ <li class="<?php if($this->viewVars['page'] == 'home') { echo 'active'; } ?>"><?php echo $html->link('Home', '/') ?></li>
+ </ul>
+ [tags] => Array
+ (
+ [0] => textmate
+ [1] => cakephp
+ )
+ [snipplr_url] => http://snipplr.com/view/18153/cakephp-highlight-active-menu-item-for-page
+ )
+
+
+Method Call: getAll();
+Example Output:
+ Array
+ (
+ [0] => Array
+ (
+ [id] => 22696
+ [title] => Sinatra Ajax Layout
+ [updated] => Array
+ (
+ [datetime] => 20091107T07:47:12
+ [timezone] => -05:00 EST
+ )
+ [private] => 0
+ [favourite] => 0
+ )
+
+ [1] => Array
+ (
+ [id] => 22385
+ [title] => jQuery Log Function
+ [updated] => Array
+ (
+ [datetime] => 20091103T08:12:37
+ [timezone] => -05:00 EST
+ )
+ [private] => 0
+ [favourite] => 0
+ )
+ ..etc
+ )
+
+Method Call: getAllLanguages();
+Example Output:
+ Array
+ (
+ [0] => Array
+ (
+ [slug] => actionscript
+ [name] => ActionScript
+ )
+ [1] => Array
+ (
+ [slug] => actionscript-3
+ [name] => ActionScript 3
+ )
+ ...etc
+ )
View
77 helpers/snipplr.response.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * A Response Helper that manipulates the response XML into formatted arrays for ease of use.
+ * The responses received from Snipplr follow a set structure. Each method attempts to format
+ * this structure for use in your application. If a response doesn't match the structure
+ * defined, an error is assumed. If Snipplr changes the output of their responses in future updates,
+ * this file will also need to be updated.
+ */
+
+class SnipplrResponse
+{
+ function processSnippetGetResponse($response) {
+ $formatted = array();
+
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['struct']['member'])) {
+ $item = $response['params']['param']['value']['struct']['member'];
+ $formatted = array(
+ 'id' => $item[0]['value']['string'],
+ 'user_id' => $item[1]['value']['string'],
+ 'username' => $item[2]['value']['string'],
+ 'title' => $item[3]['value']['string'],
+ 'language' => $item[4]['value']['string'],
+ 'comment' => $item[5]['value']['string'],
+ 'created' => $item[6]['value']['string'],
+ 'updated' => $item[7]['value']['string'],
+ 'source' => $item[8]['value']['string'],
+ 'tags' => explode(" ", trim($item[9]['value']['string'])),
+ 'snipplr_url' => $item[10]['value']['string']
+ );
+ }
+
+ return $formatted;
+ }
+
+ function processSnippetListResponse($response) {
+ $formatted = array();
+
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['array']['data']['value'])) {
+ foreach($response['params']['param']['value']['array']['data']['value'] as $item) {
+ $item = $item['struct']['member'];
+
+ $datetime = new DateTime($item[2]['value']['struct']['member'][0]['value']['dateTime.iso8601']);
+
+ $formatted[] = array(
+ 'id' => $item[0]['value']['string'],
+ 'title' => $item[1]['value']['string'],
+ 'updated' => array(
+ 'datetime' => $datetime->format('Y-m-d h:m:s'),
+ 'timezone' => $item[2]['value']['struct']['member'][1]['value']['string'],
+ ),
+ 'private' => $item[3]['value']['boolean'],
+ 'favourite' => $item[4]['value']['boolean'],
+ );
+ }
+ }
+
+ return $formatted;
+ }
+
+ function processLanguagesListResponse($response) {
+ $formatted = array();
+ // if response is in correct array structure then process it, else return empty array
+ if(isset($response['params']['param']['value']['struct']['member'])) {
+ foreach($response['params']['param']['value']['struct']['member'] as $item) {
+ $formatted[] = array(
+ 'slug' => $item['name'],
+ 'name' => $item['value']['string']
+ );
+ }
+ }
+
+ return $formatted;
+ }
+}
+?>
View
91 helpers/snipplr.rest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * A REST Helper that prepares and sends data to API URLs.
+ * Snipplr only uses POST requests which require XML structured data to be sent to them.
+ *
+ */
+
+require_once('snipplr.xml.php');
+require_once('snipplr.response.php');
+
+class SnipplrRest
+{
+ var $api_key;
+ var $url = 'http://snipplr.com/xml-rpc.php';
+ var $SnipplrXML;
+ var $SnipplrResponse;
+
+ function SnipplrRest($api_key) {
+ $this->api_key = $api_key;
+ $this->SnipplrXML = new SnipplrXML();
+ $this->SnipplrResponse = new SnipplrResponse();
+ }
+
+ // Snipplr API only uses post calls. This manages the steps involved.
+ function post($method, $params = array()) {
+ try {
+ $xml = $this->_constructXML($method, $params);
+ $response = $this->_httpPost($this->url, $xml);
+ return $this->_processResponse($method, $response);
+ } catch (Exception $e) {
+ return null;
+ }
+ }
+
+ // Contructs an XML object in the format required by Snipplr
+ function _constructXML($method, $params = array()) {
+ // list of methods that require an api key
+ $api_key_required_methods = array('snippet.list');
+
+ // set the methodName for xml query
+ $xml_data['methodName'] = $method;
+
+ // if method requires api key then add it
+ if(in_array($method, $api_key_required_methods)) {
+ $xml_data['params']['param'][] = array(
+ 'key' => "api_key",
+ 'value' => $this->api_key
+ );
+ }
+
+ // add all other specified params
+ foreach($params as $key => $value) {
+ $xml_data['params']['param'][] = array(
+ 'key' => $key,
+ 'value' => $value
+ );
+ }
+
+ return $this->SnipplrXML->toXML($xml_data, 'methodCall');
+ }
+
+ // Makes a generic http post request
+ function _httpPost($url, $data) {
+ $c = curl_init();
+ curl_setopt($c, CURLOPT_URL, $url);
+ curl_setopt($c, CURLOPT_POST, 1);
+ curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($c, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
+ $output = curl_exec($c);
+ curl_close($c);
+ return $output;
+ }
+
+ // Processes the xml
+ function _processResponse($method, $response) {
+ $raw = $this->SnipplrXML->toArray($response);
+
+ switch($method) {
+ case 'snippet.get':
+ return $this->SnipplrResponse->processSnippetGetResponse($raw);
+ case 'snippet.list':
+ return $this->SnipplrResponse->processSnippetListResponse($raw);
+ case 'languages.list':
+ return $this->SnipplrResponse->processLanguagesListResponse($raw);
+ default:
+ return null;
+ }
+ }
+}
+?>
View
117 helpers/snipplr.xml.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * An XML Helper that allows conversion between arrays and XML objects.
+ * This version isn't specific for Snipplr and can be transported to other applications by changing
+ * the classname and appropriate static class name calls in the code. "SnipplrXML" is used as a pseudo namespace.
+ *
+ * Originating Source: http://snipplr.com/view/3491/convert-php-array-to-xml-or-simple-xml-object-if-you-wish/
+ */
+class SnipplrXML
+{
+ /**
+ * The main function for converting to an XML document.
+ * Pass in a multi dimensional array and this recursively loops through and builds up an XML document.
+ *
+ * @param array $data
+ * @param string $rootNodeName - what you want the root node to be - defaults to data.
+ * @param SimpleXMLElement $xml - should only be used recursively
+ * @return string XML
+ */
+ public static function toXML($data, $rootNodeName = 'ResultSet', &$xml = null) {
+ // turn off compatibility mode as simple xml throws a wobbly if you don't.
+ if(ini_get('zend.ze1_compatibility_mode') == 1) {
+ ini_set('zend.ze1_compatibility_mode', 0);
+ }
+
+ if(is_null($xml)) {
+ $xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$rootNodeName/>");
+ }
+
+ // loop through the data passed in.
+ foreach($data as $key => $value) {
+ // no numeric keys in our xml please!
+ $numeric = 0;
+ if(is_numeric($key)) {
+ $numeric = 1;
+ $key = $rootNodeName;
+ }
+
+ // delete any char not allowed in XML element names
+ $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
+
+ // if there is another array found recrusively call this function
+ if(is_array($value)) {
+ $node = SnipplrXML::isAssoc($value) || $numeric ? $xml->addChild($key) : $xml;
+
+ // recrusive call.
+ if($numeric) {
+ $key = 'anon';
+ }
+ SnipplrXML::toXml($value, $key, $node);
+ } else {
+ // add single node.
+ $value = htmlentities($value);
+ $xml->addChild($key, $value);
+ }
+ }
+
+ // pass back as XML
+ return $xml->asXML();
+ }
+
+
+ /**
+ * Convert an XML document to a multi dimensional array
+ * Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
+ *
+ * @param string $xml - XML document - can optionally be a SimpleXMLElement object
+ * @return array ARRAY
+ */
+ public static function toArray( $xml ) {
+ if(is_string($xml)) {
+ $xml = new SimpleXMLElement( $xml );
+ }
+
+ $children = $xml->children();
+
+ if(!$children) {
+ return (string) $xml;
+ }
+
+ $arr = array();
+ $adjusted = array(); // used to determine if a node has been converted to an array of nodes
+ foreach($children as $key => $node) {
+ $node = SnipplrXML::toArray($node);
+
+ // support for 'anon' non-associative arrays
+ if($key == 'anon') {
+ $key = count($arr);
+ }
+
+ // if the node is already set, put it into an array
+ if(isset($arr[$key])) {
+ if(isset($adjusted[$key]) && $adjusted[$key] == false) {
+ $first_value = $arr[$key];
+ $arr[$key] = array();
+ $arr[$key][] = $first_value;
+ $adjusted[$key] = true;
+ }
+
+ if(!is_array($arr[$key]) || (isset($arr[$key][0]) && $arr[$key][0] == null)) {
+ $arr[$key] = array( $arr[$key] );
+ }
+ $arr[$key][] = $node;
+ } else {
+ $arr[$key] = $node;
+ $adjusted[$key] = false;
+ }
+ }
+ return $arr;
+ }
+
+ // determine if a variable is an associative array
+ public static function isAssoc( $array ) {
+ return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
+ }
+}
+?>
View
11 snipplr.config.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Configuration for Snipplr
+ * SnipplrCore can be instantiated with a passed api_key or it will default to the one below.
+ * Initially this used Configure::write() method but that coupled it with CakePHP. Using defined
+ * constants should allow for it to work outside the CakePHP framework.
+ */
+
+define('SNIPPLR_API_KEY', 'yourapikeyhere');
+
+?>
View
88 snipplr.core.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * This is the mothership file. Create an instance of this and you'll have access to the API methods defined below.
+ * Add new API methods as they become available. Each method contains documentation about the params and return values.
+ */
+
+require_once('helpers'.DIRECTORY_SEPARATOR.'snipplr.rest.php');
+require_once('snipplr.config.php');
+
+class SnipplrCore
+{
+ var $SnipplrRest;
+
+ function SnipplrCore($api_key = SNIPPLR_API_KEY) {
+ $this->SnipplrRest = new SnipplrRest($api_key);
+ }
+
+ /*
+ Gets a single snippet with more detail than a "getAll" call.
+
+ Returns
+ - id
+ - user_id
+ - username
+ - title
+ - language
+ - comment
+ - created
+ - updated
+ - source
+ - tags (space delimited list of the snippet’s tags)
+ - snipplr_url
+
+ Params
+ snippet_id (required) The ID of the snippet to fetch. An error message will be returned if the ID is invalid.
+ */
+ function get($snippet_id) {
+ $snippet = $this->SnipplrRest->post('snippet.get', compact('snippet_id'));
+ return $snippet;
+ }
+
+ /*
+ Gets all snippets owned by the user or marked as favorites of the user. Note: It doesn't search all
+ of the snippets on Snipplr.
+
+ Returns and array of snippets with following fields
+ - id
+ - title
+ - updated['datetime']
+ - updated['timezone']
+ - private (boolean)
+ - favorite (boolean)
+
+ Params:
+ options['tags'] (optional) NOTE: Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ A space delimited list of tags (keywords) to filter the results by.
+ Returns snippets which contain at least one of the keywords in the snippet’s
+ title or that match one of the snippet’s tags.
+ options['sort'] (optional) Can be one of these three values: “title”, “date”, “random”.
+ options['limit'] (optional) The number of snippets to return. A limit of 0 or 1 appears to return unlimited snippets.
+
+ */
+ function getAll($options = array()) {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $tags = isset($options['tags']) ? $options['tags'] : "";
+ $sort = isset($options['sort']) ? $options['sort'] : "date";
+ $limit = isset($options['limit']) ? $options['limit'] : "";
+
+ $snippets = $this->SnipplrRest->post('snippet.list', compact('tags','sort','limit'));
+ return $snippets;
+ }
+
+ /*
+ Gets all languages that Snipplr uses.
+
+ Returns and array of languages with following fields
+ - slug This id can be used when adding snippets
+ - name The more human meaningful name of the language
+
+ Params: -
+
+ */
+ function getAllLanguages() {
+ $snippets = $this->SnipplrRest->post('languages.list');
+ return $snippets;
+ }
+}
+?>
View
72 tests/snipplr.core.cakemate.test.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Tests for snipplr.core.php
+ * This test case is specific for CakePHP and requires CakeMate (Textmate plugin) in order to be run.
+ * It allows you to easily debug the output of method calls and also validate that you config settings
+ * are valid and working correctly.
+ *
+ * CakeMate URL: http://mark-story.com/posts/view/running-cakephp-unit-tests-with-textmate
+ */
+
+require_once('..'.DIRECTORY_SEPARATOR.'snipplr.core.php');
+
+class SnipplrCoreTest extends UnitTestCase {
+ var $SnipplrCore;
+
+
+ function setup() {
+ $this->SnipplrCore = new SnipplrCore();
+ }
+
+ function testGet() {
+ $snippet = $this->SnipplrCore->get("18153");
+ $this->assertTrue(isset($snippet['id']));
+ //debug($snippet);
+ }
+
+ function testGetNotFound() {
+ $snippet = $this->SnipplrCore->get("00000");
+ $this->assertTrue(empty($snippet));
+ //debug($snippet);
+ }
+
+ function testGetAll() {
+ $snippets = $this->SnipplrCore->getAll();
+ $this->assertTrue(isset($snippets[0]['id']));
+ $this->assertTrue(isset($snippets[1]['id']));
+ //debug($snippets);
+ }
+
+ function testGetAllOptionTags() {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $snippets = $this->SnipplrCore->getAll(array('tags' => 'css'));
+ //debug($snippets);
+ }
+
+ function testGetAllOptionSortTitle() {
+ $snippets = $this->SnipplrCore->getAll(array('sort' => 'title'));
+ // check its in alphabetical order against php sort method
+ $titles = array();
+ foreach($snippets as $snippet) {
+ $titles[] = strtoupper($snippet['title']);
+ }
+ $sort_titles = $titles;
+ sort($sort_titles);
+ $this->assertEqual($titles, $sort_titles);
+ //debug($snippets);
+ }
+
+ function testGetAllOptionLimit() {
+ $snippets = $this->SnipplrCore->getAll(array('limit' => '4'));
+ $this->assertEqual(sizeof($snippets), 4);
+ //debug($snippets);
+ }
+
+ function testGetAllLanguages() {
+ $languages = $this->SnipplrCore->getAllLanguages();
+ $this->assertEqual($languages[0]['slug'], 'actionscript');
+ $this->assertEqual($languages[0]['name'], 'ActionScript');
+ //debug($languages);
+ }
+}
+?>
View
73 tests/snipplr.core.phpunit.test.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Tests for snipplr.core.php
+ * This test case is specific for PHPUnit and requires the phpunit PEAR package.
+ * It allows you to easily debug the output of method calls and also validate that you config settings
+ * are valid and working correctly.
+ *
+ * Command line: phpunit SnipplrCoreTest snipplr.core.phpunit.test.php
+ */
+
+require_once 'PHPUnit'.DIRECTORY_SEPARATOR.'Framework.php';
+require_once '..'.DIRECTORY_SEPARATOR.'snipplr.core.php';
+
+class SnipplrCoreTest extends PHPUnit_Framework_TestCase
+{
+ protected $SnipplrCore = null;
+
+ function setUp() {
+ $this->SnipplrCore = new SnipplrCore();
+ }
+
+ function testGet() {
+ $snippet = $this->SnipplrCore->get("18153");
+ $this->assertTrue(isset($snippet['id']));
+ //print_r($snippet);
+ }
+
+ function testGetNotFound() {
+ $snippet = $this->SnipplrCore->get("00000");
+ $this->assertTrue(empty($snippet));
+ //print_r($snippet);
+ }
+
+ function testGetAll() {
+ $snippets = $this->SnipplrCore->getAll();
+ $this->assertTrue(isset($snippets[0]['id']));
+ $this->assertTrue(isset($snippets[1]['id']));
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionTags() {
+ // Multiple tags don't seem to work in the Snipplr API. Only the last tag will be used.
+ $snippets = $this->SnipplrCore->getAll(array('tags' => 'css'));
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionSortTitle() {
+ $snippets = $this->SnipplrCore->getAll(array('sort' => 'title'));
+ // check its in alphabetical order against php sort method
+ $titles = array();
+ foreach($snippets as $snippet) {
+ $titles[] = strtoupper($snippet['title']);
+ }
+ $sort_titles = $titles;
+ sort($sort_titles);
+ $this->assertEquals($titles, $sort_titles);
+ //print_r($snippets);
+ }
+
+ function testGetAllOptionLimit() {
+ $snippets = $this->SnipplrCore->getAll(array('limit' => '4'));
+ $this->assertEquals(sizeof($snippets), 4);
+ //print_r($snippets);
+ }
+
+ function testGetAllLanguages() {
+ $languages = $this->SnipplrCore->getAllLanguages();
+ $this->assertEquals($languages[0]['slug'], 'actionscript');
+ $this->assertEquals($languages[0]['name'], 'ActionScript');
+ //print_r($languages);
+ }
+}
+?>

0 comments on commit c5b4fbf

Please sign in to comment.
Something went wrong with that request. Please try again.