Welcome to the Cookbook

loading...

3.9.2 An Example

Here is a simple example of how to use Datasources and HttpSocket to implement a very basic Twitter source that allows querying the Twitter API as well as posting new status updates to a configured account.

This example will only work in PHP 5.2 and above, due to the use of json_decode for the parsing of JSON formatted data.

You would place the Twitter datasource in app/models/datasources/twitter_source.php:

<?php
/**
 * Twitter DataSource
 *
 * Used for reading and writing to Twitter, through models.
 *
 * PHP Version 5.x
 *
 * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
 * Copyright 2005-2009, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @copyright     Copyright 2009, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
 */
App::import('Core', 'HttpSocket');
class TwitterSource extends DataSource {
	protected $_schema = array(
		'tweets' => array(
			'id' => array(
				'type' => 'integer',
				'null' => true,
				'key' => 'primary',
				'length' => 11,
			),
			'text' => array(
				'type' => 'string',
				'null' => true,
				'key' => 'primary',
				'length' => 140
			),
			'status' => array(
				'type' => 'string',
				'null' => true,
				'key' => 'primary',
				'length' => 140
			),
		)
	);
	public function __construct($config) {
		$auth = "{$config['login']}:{$config['password']}";
		$this->connection = new HttpSocket(
			"http://{$auth}@twitter.com/"
		);
		parent::__construct($config);
	}
	public function listSources() {
		return array('tweets');
	}
	public function read($model, $queryData = array()) {
		if (!isset($queryData['conditions']['username'])) {
			$queryData['conditions']['username'] = $this->config['login'];
		}
		$url = "/statuses/user_timeline/";
		$url .= "{$queryData['conditions']['username']}.json";
 
		$response = json_decode($this->connection->get($url), true);
		$results = array();
 
		foreach ($response as $record) {
			$record = array('Tweet' => $record);
			$record['User'] = $record['Tweet']['user'];
			unset($record['Tweet']['user']);
			$results[] = $record;
		}
		return $results;
	}
	public function create($model, $fields = array(), $values = array()) {
		$data = array_combine($fields, $values);
		$result = $this->connection->post('/statuses/update.json', $data);
		$result = json_decode($result, true);
		if (isset($result['id']) && is_numeric($result['id'])) {
			$model->setInsertId($result['id']);
			return true;
		}
		return false;
	}
	public function describe($model) {
		return $this->_schema['tweets'];
	}
}
?>
  1. <?php
  2. /**
  3. * Twitter DataSource
  4. *
  5. * Used for reading and writing to Twitter, through models.
  6. *
  7. * PHP Version 5.x
  8. *
  9. * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
  10. * Copyright 2005-2009, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  11. *
  12. * Licensed under The MIT License
  13. * Redistributions of files must retain the above copyright notice.
  14. *
  15. * @filesource
  16. * @copyright Copyright 2009, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  17. * @link http://cakephp.org CakePHP(tm) Project
  18. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  19. */
  20. App::import('Core', 'HttpSocket');
  21. class TwitterSource extends DataSource {
  22. protected $_schema = array(
  23. 'tweets' => array(
  24. 'id' => array(
  25. 'type' => 'integer',
  26. 'null' => true,
  27. 'key' => 'primary',
  28. 'length' => 11,
  29. ),
  30. 'text' => array(
  31. 'type' => 'string',
  32. 'null' => true,
  33. 'key' => 'primary',
  34. 'length' => 140
  35. ),
  36. 'status' => array(
  37. 'type' => 'string',
  38. 'null' => true,
  39. 'key' => 'primary',
  40. 'length' => 140
  41. ),
  42. )
  43. );
  44. public function __construct($config) {
  45. $auth = "{$config['login']}:{$config['password']}";
  46. $this->connection = new HttpSocket(
  47. "http://{$auth}@twitter.com/"
  48. );
  49. parent::__construct($config);
  50. }
  51. public function listSources() {
  52. return array('tweets');
  53. }
  54. public function read($model, $queryData = array()) {
  55. if (!isset($queryData['conditions']['username'])) {
  56. $queryData['conditions']['username'] = $this->config['login'];
  57. }
  58. $url = "/statuses/user_timeline/";
  59. $url .= "{$queryData['conditions']['username']}.json";
  60. $response = json_decode($this->connection->get($url), true);
  61. $results = array();
  62. foreach ($response as $record) {
  63. $record = array('Tweet' => $record);
  64. $record['User'] = $record['Tweet']['user'];
  65. unset($record['Tweet']['user']);
  66. $results[] = $record;
  67. }
  68. return $results;
  69. }
  70. public function create($model, $fields = array(), $values = array()) {
  71. $data = array_combine($fields, $values);
  72. $result = $this->connection->post('/statuses/update.json', $data);
  73. $result = json_decode($result, true);
  74. if (isset($result['id']) && is_numeric($result['id'])) {
  75. $model->setInsertId($result['id']);
  76. return true;
  77. }
  78. return false;
  79. }
  80. public function describe($model) {
  81. return $this->_schema['tweets'];
  82. }
  83. }
  84. ?>

Your model implementation could be as simple as:

<?php
class Tweet extends AppModel {
	public $useDbConfig = 'twitter';
}
?>
  1. <?php
  2. class Tweet extends AppModel {
  3. public $useDbConfig = 'twitter';
  4. }
  5. ?>

If we had not defined our schema in the datasource itself, you would get an error message to that effect here.

And the configuration settings in your app/config/database.php would resemble something like this:

<?php
	var $twitter = array(
		'datasource' => 'twitter',
		'login' => 'username',
		'password' => 'password',
	);
?>
  1. <?php
  2. var $twitter = array(
  3. 'datasource' => 'twitter',
  4. 'login' => 'username',
  5. 'password' => 'password',
  6. );
  7. ?>

Using the familiar model methods from a controller:

<?php
// Will use the username defined in the $twitter as shown above:
$tweets = $this->Tweet->find('all');

// Finds tweets by another username
$conditions= array('username' => 'caketest');
$otherTweets = $this->Tweet->find('all', compact('conditions'));
?>
  1. <?php
  2. // Will use the username defined in the $twitter as shown above:
  3. $tweets = $this->Tweet->find('all');
  4. // Finds tweets by another username
  5. $conditions= array('username' => 'caketest');
  6. $otherTweets = $this->Tweet->find('all', compact('conditions'));
  7. ?>

Similarly, saving a new status update:

<?php
$this->Tweet->save(array('status' => 'This is an update'));
?>
  1. <?php
  2. $this->Tweet->save(array('status' => 'This is an update'));
  3. ?>