Shifting to that NoSQL life

Dropped the database abstraction layer, added a rudimentary MongoDB class,
dopped all of the interface classes for the OAuth2 library and updated the
dependencies to use @bshaffer's OAuth2 class as it has MongoDB support out of
the box.
This commit is contained in:
Josh Sherman 2014-10-19 09:16:11 -04:00
parent 76611eb7da
commit 6414644f35
16 changed files with 67 additions and 2279 deletions

View file

@ -23,7 +23,7 @@
},
"require": {
"php": ">=5.4",
"league/oauth2-server": "4.0.x-dev"
"bshaffer/oauth2-server-php": "v1.5"
},
"autoload": {
"psr-4": {

View file

@ -1,221 +0,0 @@
<?php
/**
* Caching System
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
/**
* Cache Class
*
* Wrapper class for Memcache() to allow for better error handling when the
* Memcached server is unavailable. Designed around the syntax for Memcached()
* to allow for an easier transistion to the aforementioned in the future. I
* don't entirely remember specifics, but the reason for not using Memcached()
* was due to an unexplainable bug in the version in the repository for Ubuntu
* 10.04 LTS. Memcached() does support more of the memcached protocol and will
* eventually be what Pickles uses. Keys are forced to be uppercase for
* consistencies sake as I've been burned by the case sensitivity due to typos
* in my code.
*
* Requires php5-memcache
*
* @link http://us.php.net/manual/en/book.memcache.php
* @link http://packages.ubuntu.com/lucid/php5-memcache
* @link http://www.memcached.org/
*/
class Cache extends Object
{
/**
* Namespace (prefix)
*
* @access private
* @var string
*/
private $namespace = '';
/**
* Servers
*
* @access private
* @var integer
*/
private $servers = 0;
/**
* Connection resource to Memcached
*
* @access private
* @var object
*/
private $connection = null;
/**
* Constructor
*
* Sets up our connection variables.
*
* @param string $hostname optional hostname to connect to
* @param string $database optional port to use
*/
public function __construct()
{
parent::__construct();
// @todo Shouldn't need the isset() but Travis is failing some tests
if (isset($this->config['pickles']['cache']) && $this->config['pickles']['cache'])
{
$datasources = $this->config['pickles']['cache'];
if (!is_array($datasources))
{
$datasources = [$datasources];
}
$this->connection = new \Memcache();
foreach ($datasources as $name)
{
if (isset($this->config['datasources'][$name]))
{
$datasource = $this->config['datasources'][$name];
$this->connection->addServer($datasource['hostname'], $datasource['port']);
$this->servers++;
if (isset($datasource['namespace']))
{
$this->namespace = $datasource['namespace'];
}
}
}
}
if ($this->namespace != '')
{
$this->namespace .= '-';
}
}
/**
* Destructor
*
* Closes the connection when the object dies.
*/
public function __destruct()
{
if ($this->servers)
{
$this->connection->close();
}
}
/**
* Get Instance
*
* Let's the parent class do all the work.
*
* @static
* @param string $class name of the class to instantiate
* @return object self::$instance instance of the Cache class
*/
public static function getInstance($class = 'Cache')
{
return parent::getInstance($class);
}
/**
* Get Key
*
* Gets the value of the key(s) and returns it.
*
* @param mixed $keys key(s) to retrieve
* @return mixed value(s) of the requested key(s), false if not set
*/
public function get($keys)
{
if (is_array($keys))
{
foreach ($keys as $index => $key)
{
$keys[$index] = strtoupper($this->namespace . $key);
}
}
else
{
$keys = strtoupper($this->namespace . $keys);
}
return $this->connection->get($keys);
}
/**
* Set Key
*
* Sets key to the specified value. I've found that compression can lead to
* issues with integers and can slow down the storage and retrieval of data
* (defeats the purpose of caching if you ask me) and isn't supported. I've
* also been burned by data inadvertantly being cached for infinity, but
* have had great success caching data for a full day, hence defaulting the
* expiration to a full day.
*
* @param string $key key to set
* @param mixed $value value to set
* @param integer $expiration optional expiration, defaults to 1 day
* @return boolean status of writing the data to the key
*/
public function set($key, $value, $expire = Time::DAY)
{
$key = strtoupper($key);
return $this->connection->set(strtoupper($this->namespace . $key), $value, 0, $expire);
}
/**
* Delete Key
*
* Deletes the specified key(s).
*
* @param mixed $keys key(s) to delete
* @return boolean status of deleting the key
*/
public function delete($keys)
{
if (!is_array($keys))
{
$keys = [$keys];
}
// Memcache() doesn't let you pass an array to delete all records the same way you can with get()
foreach ($keys as $key)
{
$this->connection->delete(strtoupper($this->namespace . $key));
}
return true;
}
/**
* Increment Key
*
* Increments the value of an existing key.
*
* @param string $key key to increment
* @return boolean status of incrementing the key
* @todo Check if it's set as Memcache() doesn't and won't inc if it doesn't exist
*/
public function increment($key)
{
return $this->connection->increment(strtoupper($this->namespace . $key));
}
}

View file

@ -138,9 +138,9 @@ class Config extends \ArrayObject
// Defaults expected Pickles variables to false
foreach (['auth', 'cache', 'profiler'] as $variable)
{
if (!isset($config['pickles'][$variable]))
if (!isset($config[$variable]))
{
$config['pickles'][$variable] = false;
$config[$variable] = false;
}
}

View file

@ -1,393 +0,0 @@
<?php
/**
* Database Abstraction Layer
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
* @todo Drop driver, hardcode drivers based on the type
* @todo More assumptions for the datasource variables
*/
namespace Pickles;
/**
* Database Class
*
* Database interaction all in one place. Allows for object reuse and contains
* functions to ease interacting with databases. Common assumptions about PDO
* attributes are baked in. Only support PDO.
*/
class Database extends Object
{
/**
* DSN format
*
* @access protected
* @var string
*/
protected $dsn;
/**
* PDO Attributes
*
* @access protected
* @var string
*/
protected $attributes = [
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::NULL_EMPTY_STRING => true,
];
/**
* Driver
*
* @var string
*/
public $driver = null;
/**
* Hostname for the server
*
* @var string
*/
public $hostname = 'localhost';
/**
* Port number for the server
*
* @var integer
*/
public $port = null;
/**
* UNIX socket for the server
*
* @var integer
*/
public $socket = null;
/**
* Username for the server
*
* @var string
*/
public $username = null;
/**
* Password for the server
*
* @var string
*/
public $password = null;
/**
* Database name for the server
*
* @var string
*/
public $database = null;
/**
* Whether or not to use caching
*
* @var boolean
*/
public $cache = false;
/**
* Connection resource
*
* @var object
*/
public $connection = null;
/**
* Results object for the executed statement
*
* @var object
*/
public $results = null;
/**
* Get Instance
*
* Instantiates a new instance of the Database class or returns the
* previously instantiated copy.
*
* @static
* @param string $datasource_name name of the datasource
* @return object instance of the class
*/
public static function getInstance($datasource_name = false)
{
$config = Config::getInstance();
// Tries to load a datasource if one wasn't specified
if (!$datasource_name)
{
if (isset($config['pickles']['datasource']))
{
$datasource_name = $config['pickles']['datasource'];
}
elseif (is_array($config['datasources']))
{
$datasources = $config['datasources'];
foreach ($datasources as $name => $datasource)
{
if (isset($datasource['driver']))
{
$datasource_name = $name;
}
}
}
}
// Attempts to validate the datasource
if ($datasource_name)
{
if (!isset(self::$instances['Database'][$datasource_name]))
{
if (!isset($config['datasources'][$datasource_name]))
{
throw new \Exception('The specified datasource is not defined in the config.');
}
$datasource = $config['datasources'][$datasource_name];
if (!isset($datasource['driver']))
{
throw new \Exception('The specified datasource lacks a driver.');
}
$datasource['driver'] = strtolower($datasource['driver']);
// Checks the driver is legit and scrubs the name
switch ($datasource['driver'])
{
case 'pdo_mysql':
$attributes = [
'dsn' => 'mysql:host=[[hostname]];port=[[port]];unix_socket=[[socket]];dbname=[[database]]',
'port' => 3306,
];
break;
case 'pdo_pgsql':
$attributes = [
'dsn' => 'pgsql:host=[[hostname]];port=[[port]];dbname=[[database]];user=[[username]];password=[[password]]',
'port' => 5432,
];
break;
case 'pdo_sqlite':
$attributes = ['dsn' => 'sqlite:[[hostname]]'];
break;
default:
throw new \Exception('Datasource driver "' . $datasource['driver'] . '" is invalid');
break;
}
// Instantiates our database class
$instance = new Database();
// Sets our database parameters
if (is_array($datasource))
{
$datasource = array_merge($attributes, $datasource);
foreach ($datasource as $variable => $value)
{
$instance->$variable = $value;
}
}
// Caches the instance for possible reuse later
self::$instances['Database'][$datasource_name] = $instance;
}
// Returns the instance
return self::$instances['Database'][$datasource_name];
}
return false;
}
/**
* Opens database connection
*
* Establishes a connection to the database based on the set configuration
* options.
*
* @return boolean true on success, throws an exception overwise
*/
public function open()
{
if ($this->connection === null)
{
switch ($this->driver)
{
case 'pdo_mysql':
// Resolves "Invalid UTF-8 sequence" issues when encoding as JSON
// @todo Didn't resolve that issue, borked some other characters though
//$this->attributes[\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8';
break;
case 'pdo_pgsql':
// This combats a bug: https://bugs.php.net/bug.php?id=62571&edit=1
$this->attributes[\PDO::ATTR_PERSISTENT] = false;
// This allows for multiple prepared queries
$this->attributes[\PDO::ATTR_EMULATE_PREPARES] = true;
break;
}
if (isset($this->username, $this->password, $this->database))
{
// Swaps out any variables with values in the DSN
$this->dsn = str_replace(
['[[hostname]]', '[[port]]', '[[socket]]', '[[username]]', '[[password]]', '[[database]]'],
[$this->hostname, $this->port, $this->socket, $this->username, $this->password, $this->database],
$this->dsn
);
// Strips any empty parameters in the DSN
$this->dsn = str_replace(['host=;', 'port=;', 'unix_socket=;'], '', $this->dsn);
// Attempts to establish a connection
$this->connection = new \PDO(
$this->dsn, $this->username, $this->password, $this->attributes
);
}
else
{
throw new \Exception('There was an error loading the database configuration.');
}
}
return true;
}
/**
* Closes database connection
*
* Sets the connection to null regardless of state.
*
* @return boolean always true
*/
public function close()
{
$this->connection = null;
return true;
}
/**
* Executes an SQL Statement
*
* Executes a standard or prepared query based on passed parameters. All
* queries are logged to a file as well as timed and logged in the
* execution time is over 1 second.
*
* @param string $sql statement to execute
* @param array $input_parameters optional key/values to be bound
* @return integer ID of the last inserted row or sequence number
*/
public function execute($sql, $input_parameters = null, $explain = false)
{
$this->open();
$sql = trim($sql);
// Checks if the query is blank
if ($sql != '')
{
// Establishes if we're working on an EXPLAIN
if ($this->config['pickles']['profiler'])
{
$explain_results = preg_match('/^SELECT /i', $sql);
}
else
{
$explain_results = false;
}
// Executes a standard query
if ($input_parameters === null)
{
// Explains the query
if ($explain_results)
{
$explain_results = $this->fetch('EXPLAIN ' . $sql, null, true);
}
$start_time = microtime(true);
$this->results = $this->connection->query($sql);
}
// Executes a prepared statement
else
{
// Explains the query
if ($explain_results)
{
$explain_results = $this->fetch('EXPLAIN ' . $sql, $input_parameters, true);
}
$start_time = microtime(true);
$this->results = $this->connection->prepare($sql);
$this->results->execute($input_parameters);
}
$end_time = microtime(true);
$duration = $end_time - $start_time;
// Logs the information to the profiler
if ($this->config['pickles']['profiler'] && !$explain)
{
Profiler::query(
$sql,
$input_parameters,
$this->results->fetchAll(\PDO::FETCH_ASSOC),
$duration,
$explain_results
);
}
}
else
{
throw new \Exception('No query to execute.');
}
return $this->connection->lastInsertId();
}
/**
* Fetch records from the database
*
* @param string $sql statement to be executed
* @param array $input_parameters optional key/values to be bound
* @param string $return_type optional type of return set
* @return mixed based on return type
*/
public function fetch($sql = null, $input_parameters = null, $explain = false)
{
$this->open();
if ($sql !== null)
{
$this->execute($sql, $input_parameters, $explain);
}
// Pulls the results based on the type
$results = $this->results->fetchAll(\PDO::FETCH_ASSOC);
return $results;
}
}

50
src/Mongo.php Normal file
View file

@ -0,0 +1,50 @@
<?php
/**
* Mongo Abstraction Layer
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @copyright Copyright 2007-2014, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @link https://github.com/joshtronic/pickles
* @package Pickles
*/
namespace Pickles;
class Mongo extends Object
{
public static function getInstance($class = 'Mongo')
{
$config = Config::getInstance();
if (!isset(self::$instances['Mongo']))
{
if (!isset($config['mongo'], $config['mongo']['database']))
{
throw new \Exception('The “mongo” datasource is not defined in the configuration.', 500);
}
$mongo = $config['mongo'];
// Defaults to the local server on the default port
if (!isset($mongo['server']))
{
$mongo['server'] = 'mongodb://localhost:27017';
}
// Instantiates our Mongo client
$instance = new \MongoClient($mongo['server']);
$instance->selectDB($mongo['database']);
// Caches the instance for possible reuse later
self::$instances['Mongo'] = $instance;
}
// Returns the instance
return self::$instances['Mongo'];
}
}

View file

@ -1,84 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\AbstractTokenEntity;
use \League\OAuth2\Server\Entity\AccessTokenEntity;
use \League\OAuth2\Server\Entity\ScopeEntity;
use \League\OAuth2\Server\Storage\AccessTokenInterface;
class AccessTokenStorage extends StorageAdapter implements AccessTokenInterface
{
public function get($token)
{
$sql = 'SELECT oauth_access_tokens.*'
. ' FROM oauth_access_tokens'
. ' WHERE access_token = ?'
. ' AND expires_at >= ?;';
$results = $this->db->fetch($sql, [$token, time()]);
if (count($results) === 1)
{
return (new AccessTokenEntity($this->server))
->setId($results[0]['access_token'])
->setExpireTime($results[0]['expires_at']);
}
return null;
}
public function getScopes(AbstractTokenEntity $token)
{
$sql = 'SELECT oauth_scopes.id, oauth_scopes.description'
. ' FROM oauth_access_token_scopes'
. ' INNER JOIN oauth_scopes'
. ' ON oauth_access_token_scopes.scope_id = oauth_scopes.id'
. ' WHERE oauth_access_token_scopes.access_token_id = ?;';
$results = $this->db->fetch($sql, [$token->getId()]);
$response = [];
if (count($results) > 0)
{
foreach ($results as $row)
{
$response[] = (new ScopeEntity($this->server))->hydrate([
'id' => $row['id'],
'description' => $row['description']
]);
}
}
return $response;
}
public function create($token, $expiration, $session_id)
{
$sql = 'INSERT INTO oauth_access_tokens'
. ' (access_token, session_id, expires_at)'
. ' VALUES'
. ' (?, ?, ?);';
$this->db->execute($sql, [$token, $session_id, $expiration]);
}
public function associateScope(AbstractTokenEntity $token, ScopeEntity $scope)
{
$sql = 'INSERT INTO oauth_access_token_scopes'
. ' (access_token, scope)'
. ' VALUES'
. ' (?, ?);';
$this->db->execute($sql, [$token->getId(), $scope->getId()]);
}
public function delete(AbstractTokenEntity $token)
{
$sql = 'DELETE FROM oauth_access_token_scopes'
. ' WHERE access_token = ?;';
$this->db->execute($sql, [$token->getId()]);
}
}

View file

@ -1,81 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\ClientEntity;
use \League\OAuth2\Server\Entity\SessionEntity;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\ClientInterface;
class ClientStorage extends StorageAdapter implements ClientInterface
{
public function get($client_id, $client_secret = null, $redirect_uri = null, $grant_type = null)
{
$sql = 'SELECT oauth_clients.*';
if ($redirect_uri)
{
$sql .= ', oauth_client_redirect_uris.*'
. ' INNER JOIN oauth_redirect_uris'
. ' ON oauth_clients.id = oauth_redirect_uris.client_id';
}
$sql .= ' FROM oauth_clients WHERE oauth_clients.id = ?';
$parameters = [$client_id];
if ($client_secret)
{
$sql .= ' AND oauth_clients.secret = ?';
$parameters[] = $client_secret;
}
if ($redirect_uri)
{
$sql .= 'AND oauth_redirect_uris.redirect_uri = ?';
$parameters[] = $redirect_uri;
}
$results = $this->db->fetch($sql, $parameters);
if (count($results) === 1)
{
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $results[0]['id'],
'name' => $results[0]['name']
]);
return $client;
}
return null;
}
public function getBySession(SessionEntity $session)
{
$sql = 'SELECT oauth_clients.id, oauth_clients.name'
. ' FROM oauth_clients'
. ' INNER JOIN oauth_sessions'
. ' ON oauth_clients.id = oauth_sessions.client_id'
. ' WHERE oauth_sessions.id = ?';
$results = $this->db->fetch($sql, [$session->getId()]);
if (count($results) === 1)
{
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $results[0]['id'],
'name' => $results[0]['name']
]);
return $client;
}
return null;
}
}

View file

@ -1,56 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\RefreshTokenEntity;
use \League\OAuth2\Server\Storage\RefreshTokenInterface;
class RefreshTokenStorage extends StorageAdapter implements RefreshTokenInterface
{
public function get($token)
{
$sql = 'SELECT oauth_refresh_tokens.*'
. ' FROM oauth_refresh_tokens'
. ' WHERE refresh_token = ?'
. ' AND expires_at >= ?;';
$results = $this->db->fetch($sql, [$token, time()]);
if (count($results) === 1)
{
return (new RefreshTokenEntity($this->server))
->setId($results[0]['refresh_token'])
->setExpireTime($results[0]['expires_at'])
->setAccessTokenId($results[0]['access_token_id']);
}
return null;
}
public function create($token, $expiration, $access_token)
{
$sql = 'SELECT id FROM oauth_access_tokens WHERE access_token = ?;';
$results = $this->db->fetch($sql, [$access_token]);
$token_id = $results[0]['id'];
$sql = 'INSERT INTO oauth_refresh_tokens'
. ' (refresh_token, access_token_id, expires_at, client_id)'
. ' VALUES'
. ' (?, ?, ?, ?);';
$this->db->execute($sql, [
$token,
$token_id,
$expiration,
$this->server->getRequest()->request->get('client_id', null),
]);
}
public function delete(RefreshTokenEntity $token)
{
$sql = 'DELETE FROM oauth_refresh_tokens WHERE refresh_token = ?;';
$this->db->execute($sql, [$token->getId()]);
}
}

View file

@ -1,26 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\ScopeInterface;
class ScopeStorage extends StorageAdapter implements ScopeInterface
{
public function get($scope, $grant_type = null, $client_id = null)
{
$sql = 'SELECT * FROM oauth_scopes WHERE id = ?;';
$results = $this->db->fetch($sql, [$scope]);
if (count($results) === 0)
{
return null;
}
return (new ScopeEntity($this->server))->hydrate([
'id' => $result[0]['id'],
'description' => $result[0]['description'],
]);
}
}

View file

@ -1,106 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Entity\AccessTokenEntity;
use \League\OAuth2\Server\Entity\AuthCodeEntity;
use \League\OAuth2\Server\Entity\ScopeEntity;
use \League\OAuth2\Server\Entity\SessionEntity;
use \League\OAuth2\Server\Storage\Adapter;
use \League\OAuth2\Server\Storage\SessionInterface;
class SessionStorage extends StorageAdapter implements SessionInterface
{
public function getByAccessToken(AccessTokenEntity $access_token)
{
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
. ' oauth_sessions.client_redirect_uri'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_access_tokens'
. ' ON oauth_access_tokens.session_id = oauth_sessions.id'
. ' WHERE oauth_access_tokens.access_token = ?;';
$results = $this->db->fetch($sql, [$access_token->getId()]);
if (count($results) === 1)
{
$session = new SessionEntity($this->server);
$session->setId($result[0]['id']);
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
return $session;
}
return null;
}
public function getByAuthCode(AuthCodeEntity $auth_code)
{
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
. ' oauth_sessions.client_redirect_uri'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_authorization_codes'
. ' ON oauth_authorization_codes.session_id = oauth_sessions.id'
. ' WHERE oauth_authorization_codes.authorization_code = ?;';
$results = $this->db->fetch($sql, [$auth_code->getId()]);
if (count($results) === 1)
{
$session = new SessionEntity($this->server);
$session->setId($result[0]['id']);
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
return $session;
}
return null;
}
public function getScopes(SessionEntity $session)
{
$sql = 'SELECT oauth_sessions.*'
. ' FROM oauth_sessions'
. ' INNER JOIN oauth_access_token_scopes'
. ' ON oauth_sessions.id = oauth_access_token_scopes.access_token_id'
. ' INNER JOIN oauth_scopes'
. ' ON oauth_scopes.id = oauth_access_token_scopes.scope_id'
. ' WHERE oauth_sessions.id = ?;';
$results = $this->db->fetch($sql, [$session->getId()]);
$scopes = [];
foreach ($results as $scope)
{
$scopes[] = (new ScopeEntity($this->server))->hydrate([
'id' => $scope['id'],
'description' => $scope['description'],
]);
}
return $scopes;
}
public function create($owner_type, $owner_id, $client_id, $client_redirect_uri = null)
{
$sql = 'INSERT INTO oauth_sessions'
. ' (owner_type, owner_id, client_id)'
. ' VALUES'
. ' (?, ?, ?);';
return $this->db->execute($sql, [$owner_type, $owner_id, $client_id]);
}
public function associateScope(SessionEntity $session, ScopeEntity $scope)
{
$sql = 'INSERT INTO oauth_access_token_scopes'
. ' (access_token_id, scope_id)'
. ' VALUES'
. ' (?, ?);';
$this->db->execute($sql, [$session->getId(), $scope->getId()]);
}
}

View file

@ -1,20 +0,0 @@
<?php
namespace Pickles\OAuth2;
use \League\OAuth2\Server\Storage\Adapter;
use \Pickles\Config;
use \Pickles\Database;
class StorageAdapter extends Adapter
{
protected $config;
protected $db;
public function __construct()
{
$this->config = Config::getInstance();
$this->db = Database::getInstance();
}
}

View file

@ -39,47 +39,33 @@ class Object
public $config = null;
/**
* Instance of the Cache object
* Instance of the Mongo object
*
* @var object
*/
public $cache = null;
public $mongo = null;
/**
* Instance of the Database object
* Instance of the Redis object
*
* @var object
*/
public $db = null;
public $redis = null;
/**
* Constructor
*
* Establishes a Config instance for all children to enjoy
*/
public function __construct($objects = null)
public function __construct()
{
// @todo Lazy load these so we're not loading them on every instance
$this->config = Config::getInstance();
if ($objects)
{
if (!is_array($objects))
{
$objects = [$objects];
}
foreach ($objects as $object)
{
switch ($object)
{
case 'cache': $this->cache = Cache::getInstance(); break;
case 'db': $this->db = Database::getInstance(); break;
}
}
}
$this->mongo = Mongo::getInstance();
//$this->redis = Redis::getInstance();
// Optionally logs the constructor to the profiler
if ($this->config['pickles']['profiler'])
if ($this->config['profiler'])
{
Profiler::log($this, '__construct');
}
@ -119,7 +105,7 @@ class Object
public function __destruct()
{
// Optionally logs the destructor to the profiler
if ($this->config['pickles']['profiler'])
if ($this->config['profiler'])
{
Profiler::log($this, '__destruct');
}

View file

@ -290,7 +290,7 @@ class Resource extends Object
throw new \Exception('Missing or invalid parameters.', 400);
}
parent::__construct(['cache', 'db']);
parent::__construct();
// Checks if the request method has been implemented
if (get_class($this) != 'Pickles\\Resource')
@ -302,7 +302,7 @@ class Resource extends Object
else
{
// Starts a timer before the resource is executed
if ($this->config['pickles']['profiler'])
if ($this->config['profiler'])
{
$timer = get_class($this) . '->' . $method . '()';
Profiler::timer($timer);
@ -311,7 +311,7 @@ class Resource extends Object
$this->response = $this->$method();
// Stops the resource timer
if ($this->config['pickles']['profiler'])
if ($this->config['profiler'])
{
Profiler::timer($timer);
}
@ -374,7 +374,7 @@ class Resource extends Object
}
}
if ($this->config['pickles']['profiler'])
if ($this->config['profiler'])
{
$response['profiler'] = Profiler::report();
}

View file

@ -1,102 +0,0 @@
<?php
class CacheTest extends PHPUnit_Framework_TestCase
{
private $cache;
public function setUp()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"cache" => "mc",
],
"datasources" => [
"mc" => [
"type" => "memcache",
"hostname" => "localhost",
"port" => 11211,
"namespace" => "ns",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->cache = Pickles\Cache::getInstance();
}
public function testGetInstance()
{
$this->assertInstanceOf('Pickles\\Cache', $this->cache);
}
public function testSetAndGet()
{
$key = Pickles\String::random();
$value = Pickles\String::random();
$this->cache->set($key, $value);
$this->assertEquals($value, $this->cache->get($key));
}
public function testSetAndGetMultiple()
{
$keys = $values = $expected = [];
for ($i = 0; $i < 5; $i++)
{
$keys[] = Pickles\String::random();
$values[] = Pickles\String::random();
}
foreach ($keys as $key => $key_name)
{
$value = $values[$key];
$expected['NS-' . strtoupper($key_name)] = $value;
$this->cache->set($key_name, $value);
}
$this->assertEquals($expected, $this->cache->get($keys));
}
public function testDelete()
{
$key = Pickles\String::random();
$value = Pickles\String::random();
$this->cache->set($key, $value);
$this->cache->delete($key);
$this->assertFalse($this->cache->get($key));
}
public function testIncrement()
{
$key = Pickles\String::random();
$this->assertFalse($this->cache->increment($key));
$this->cache->set($key, 1);
$this->assertEquals(2, $this->cache->increment($key));
$this->assertEquals(3, $this->cache->increment($key));
$this->assertEquals(4, $this->cache->increment($key));
}
// Doesn't do much but test that the destructor doesn't explode
public function testDestructor()
{
$this->cache->__destruct();
}
}

View file

@ -1,526 +0,0 @@
<?php
class DatabaseTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
}
public function testGetInstanceFalse()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"datasources" => [
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertFalse(Pickles\Database::getInstance());
}
/**
* @expectedException Exception
* @expectedExceptionMessage The specified datasource is not defined in the config.
*/
public function testGetInstanceDatasourceNotDefined()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "bad",
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
Pickles\Database::getInstance();
}
/**
* @expectedException Exception
* @expectedExceptionMessage The specified datasource lacks a driver.
*/
public function testGetInstanceDatasourceLacksDriver()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "bad",
],
"datasources" => [
"bad" => [
"type" => "mysql",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Database', Pickles\Database::getInstance());
}
/**
* @expectedException Exception
* @expectedExceptionMessage There was an error loading the database configuration.
*/
public function testOpenConfigError()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "bad",
],
"datasources" => [
"bad" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$db = Pickles\Database::getInstance();
$db->open();
}
public function testGetInstanceDatasourcesArray()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "bad",
],
"datasources" => [
"bad" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Database', Pickles\Database::getInstance());
}
// Also tests the datasource being missing and selecting the first one
public function testGetInstanceMySQL()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
],
"datasources" => [
"bad" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Database', Pickles\Database::getInstance());
}
public function testOpenMySQL()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$db = Pickles\Database::getInstance();
$db->open();
}
public function testExecute()
{
$db = Pickles\Database::getInstance();
$this->assertEquals('0', $db->execute('SHOW TABLES'));
}
/**
* @expectedException Exception
* @expectedExceptionMessage No query to execute.
*/
public function testExecuteNoQuery()
{
$db = Pickles\Database::getInstance();
$db->execute(' ');
}
public function testFetch()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
"profiler" => true,
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$db = Pickles\Database::getInstance();
$this->assertEquals([], $db->fetch('SELECT * FROM pickles WHERE id != ?', ['0']));
}
public function testExplainNoInput()
{
$config = Pickles\Config::getInstance();
$db = Pickles\Database::getInstance();
$this->assertEquals([], $db->fetch('SELECT * FROM pickles WHERE id != 0'));
}
public function testSlowQuery()
{
$db = Pickles\Database::getInstance();
$this->assertEquals('0', $db->execute('SHOW DATABASES', null, true));
}
public function testCloseMySQL()
{
$db = Pickles\Database::getInstance();
$db->open();
$this->assertTrue($db->close());
}
public function testGetInstancePostgreSQL()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "pgsql",
],
"datasources" => [
"pgsql" => [
"type" => "pgsql",
"driver" => "pdo_pgsql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Database', Pickles\Database::getInstance());
}
/**
* @expectedException PDOException
* @expectedExceptionCode 7
*/
public function testOpenPostgreSQL()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "pgsql",
],
"datasources" => [
"pgsql" => [
"type" => "pgsql",
"driver" => "pdo_pgsql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
// Throws an error because I don't have PostgreSQL installed
$db = Pickles\Database::getInstance();
$db->open();
}
public function testGetInstanceSQLite()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "sqlite",
],
"datasources" => [
"sqlite" => [
"type" => "sqlite",
"driver" => "pdo_sqlite",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$this->assertInstanceOf('Pickles\\Database', Pickles\Database::getInstance());
}
/**
* @expectedException Exception
* @expectedExceptionMessage Datasource driver "pdo_invalid" is invalid
*/
public function testGetInstanceInvalidDriver()
{
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "invalid",
],
"datasources" => [
"invalid" => [
"type" => "invalid",
"driver" => "pdo_invalid",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
Pickles\Database::getInstance();
}
public function testProfilerWithoutParameters()
{
// Clears out the Config for ease of testing
Pickles\Object::$instances = [];
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"datasource" => "mysql",
"profiler" => true,
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$db = Pickles\Database::getInstance();
$db->execute('SELECT * FROM `users`');
$report = Pickles\Profiler::report();
$this->assertEquals(7, count($report));
$this->assertEquals(2, count($report['logs']));
$this->assertTrue(isset($report['logs'][1]['details']['explain']));
}
public function testProfilerWithParameters()
{
// Clears out the Config for ease of testing
Pickles\Object::$instances = [];
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"datasource" => "mysql",
"profiler" => true,
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"database" => "test",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
],
],
];
');
Pickles\Config::getInstance('/tmp/pickles.php');
$db = Pickles\Database::getInstance();
$db->execute('SELECT * FROM `users` WHERE id = ?', [1000000]);
$report = Pickles\Profiler::report();
$this->assertEquals(7, count($report));
$this->assertEquals(3, count($report['logs']));
$this->assertEquals([1000000], $report['logs'][2]['details']['parameters']);
$this->assertTrue(isset($report['logs'][2]['details']['explain']));
}
}

View file

@ -1,633 +0,0 @@
<?php
class MockModelWithoutColumns extends Pickles\Model
{
public $table = 'pickles';
public $columns = false;
}
// InnoDB
class MockModel extends Pickles\Model
{
public $table = 'pickles';
public $columns = ['created_at' => 'created_at'];
}
// MyISAM
class MyMockModel extends Pickles\Model
{
public $table = 'mypickles';
}
class ModelTest extends PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
// Clears out the Config for ease of testing
Pickles\Object::$instances = [];
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['SERVER_NAME'] = '127.0.0.1';
file_put_contents('/tmp/pickles.php', '<?php
$config = [
"environments" => [
"local" => "127.0.0.1",
"production" => "123.456.789.0",
],
"pickles" => [
"namespace" => "",
"datasource" => "mysql",
"cache" => "memcache",
],
"datasources" => [
"mysql" => [
"type" => "mysql",
"driver" => "pdo_mysql",
"hostname" => "localhost",
"username" => "root",
"password" => "",
"database" => "test",
"cache" => true,
],
"memcache" => [
"type" => "memcache",
"hostname" => "localhost",
"port" => 11211,
"namespace" => "",
],
],
];
');
$config = Pickles\Config::getInstance('/tmp/pickles.php');
for ($i = 0; $i < 5; $i++)
{
$model = new MockModel();
$model->record['field1'] = 'one';
$model->record['field2'] = 'two';
$model->record['field3'] = 'three';
$model->record['field4'] = 'four';
$model->record['field5'] = 'five';
$model->commit();
}
}
/**
* @expectedException Exception
* @expectedExceptionMessage You must set the table variable
*/
public function testNoTable()
{
new Pickles\Model();
}
public function testWithoutColumns()
{
$model = new MockModelWithoutColumns();
$columns = PHPUnit_Framework_Assert::readAttribute($model, 'columns');
$this->assertFalse($columns['is_deleted']);
}
public function testWithColumns()
{
$model = new MockModel();
$columns = PHPUnit_Framework_Assert::readAttribute($model, 'columns');
$this->assertEquals('is_deleted', $columns['is_deleted']);
}
/**
* @expectedException Exception
* @expectedExceptionMessage You cannot pass in 2 query parameter arrays
*/
public function testDoubleArray()
{
$model = new MockModel(['foo' => 'bar'], ['test' => 'ing']);
}
public function testFetchInt()
{
$model = new MockModel(1);
$this->assertEquals(1, $model->count());
$this->assertEquals(1, $model->record['id']);
}
public function testFetchIntArray()
{
$model = new MockModel([1, 2, 3]);
$this->assertEquals(3, $model->count());
}
/*
@todo Acting wonky, passes tests on just this class, fails on all
public function testFetchConditionsID()
{
$model = new MockModel(['conditions' => ['id' => 1]]);
var_dump($model->record);
$this->assertEquals(1, $model->count());
$this->assertEquals(1, $model->record['id']);
}
*/
public function testFetchCount()
{
$model = new MockModel('count');
$this->assertEquals(5, $model->record['count']);
}
public function testFetchCountConditions()
{
$model = new MockModel('count', ['conditions' => ['id' => [1, 3, 5]]]);
$this->assertEquals(3, $model->record['count']);
}
public function testFetchIndexed()
{
$model = new MockModel('indexed', ['conditions' => ['id' => [2, 4]]]);
$this->assertEquals(2, $model->count());
$this->assertEquals([2, 4], array_keys($model->records));
}
// Also tests against a full cache
public function testFetchList()
{
$model = new MockModel('list', ['conditions' => ['id' => [2, 4]]]);
$this->assertEquals(2, $model->count());
$this->assertEquals([2, 4], array_keys($model->records));
}
public function testFetchCountWithID()
{
$model = new MockModel('count', 3);
$this->assertEquals(1, $model->record['count']);
}
public function testFetchListWithID()
{
$model = new MockModel('list', 2);
$this->assertEquals(1, $model->count());
$this->assertEquals([2 => 'one'], $model->records);
}
public function testFieldValues()
{
$model = new MockModel('all');
$fields = $model->fieldValues('id');
$this->assertEquals('5', count($fields));
foreach ($fields as $value)
{
$this->assertTrue(ctype_digit($value));
}
}
public function testSort()
{
$model = new MockModel();
$this->assertTrue($model->sort('id'));
}
public function testShuffle()
{
$model = new MockModel();
$this->assertTrue($model->shuffle());
}
public function testNextPrev()
{
$model = new MockModel('all');
$model->next();
$this->assertEquals(2, $model->record['id']);
$model->prev();
$this->assertEquals(1, $model->record['id']);
}
public function testLastFirst()
{
$model = new MockModel('all');
$model->last();
$this->assertEquals(5, $model->record['id']);
$model->first();
$this->assertEquals(1, $model->record['id']);
}
public function testEndReset()
{
$model = new MockModel('all');
$model->end();
$this->assertEquals(5, $model->record['id']);
$model->reset();
$this->assertEquals(1, $model->record['id']);
}
public function testWalk()
{
$model = new MockModel('all');
$expected = 0;
while ($model->walk())
{
$expected++;
$this->assertEquals($expected, $model->record['id']);
}
}
public function testInsert()
{
$model = new MockModel();
for ($i = 1; $i <= 5; $i++)
{
$model->record['field' . $i] = Pickles\String::random();
}
$model->commit();
}
public function testInsertMultiple()
{
$model = new MockModel();
for ($i = 1; $i <= 5; $i++)
{
for ($j = 1; $j <= 5; $j++)
{
$model->record['field' . $j] = Pickles\String::random();
}
$model->queue();
}
$model->commit();
}
public function testGetFromCache()
{
$model = new MockModel(1);
$this->assertEquals('1', $model->record['id']);
}
public function testGetFromCacheConditionals()
{
$model = new MockModel(['conditions' => ['id' => 1]]);
$this->assertEquals('1', $model->record['id']);
}
public function testCacheKey()
{
$model = new MockModel('indexed', 1, 'cache-key');
$this->assertEquals([1], array_keys($model->records));
}
public function testGenerateQuery()
{
$model = new MockModelWithoutColumns([
'conditions' => [1, 2, 3],
'group' => 'id',
'having' => '1 = 1',
'order' => 'id DESC',
'limit' => 5,
'offset' => 1,
]);
$this->assertEquals('2', $model->record['id']);
}
public function testGenerateConditions()
{
$model = new MockModel();
$conditions = $model->generateConditions([
'id' => [1, 2, 3],
'NOT' => 5,
'OR id !=' => 10,
'OR NOT' => [15, 20, 25],
'id != 30',
'id IS NOT' => null,
'id !=' => false,
'id <' => true,
'id >' => null,
'id BETWEEN' => [35, 40],
]);
$this->assertEquals('id in (?, ?, ?) AND NOT = ? OR id != ? OR NOT in (?, ?, ?) AND id != 30 AND id IS NOT NULL AND id IS NOT FALSE AND id IS TRUE AND id > NULL AND id BETWEEN ? AND ?', $conditions);
}
public function testGenerateConditionsInjectValues()
{
$model = new MockModel();
$conditions = $model->generateConditions([
'id' => [1, 2, 3],
'NOT' => 5,
'OR id !=' => 10,
'OR NOT' => [15, 20, 25],
'id != 30',
'id IS NOT' => null,
'id !=' => false,
'id <' => true,
'id >' => null,
'id BETWEEN' => [35, 40],
], true);
$this->assertEquals('id in (1, 2, 3) AND NOT = 5 OR id != 10 OR NOT in (15, 20, 25) AND id != 30 AND id IS NOT NULL AND id IS NOT FALSE AND id IS TRUE AND id > NULL AND id BETWEEN 35 AND 40', $conditions);
}
public function testGenerateConditionsNoOperatorTrue()
{
$model = new MockModel();
$conditions = $model->generateConditions(['id' => true]);
$this->assertEquals('id IS TRUE', $conditions);
}
public function testGenerateConditionsNoOperatorFalse()
{
$model = new MockModel();
$conditions = $model->generateConditions(['id' => false]);
$this->assertEquals('id IS FALSE', $conditions);
}
public function testGenerateConditionsNoOperatorNull()
{
$model = new MockModel();
$conditions = $model->generateConditions(['id' => null]);
$this->assertEquals('id IS NULL', $conditions);
}
/**
* @expectedException Exception
* @expectedExceptionMessage BETWEEN expects an array with 2 values.
*/
public function testGenerateConditionsBetweenMissingValue()
{
$model = new MockModel();
$conditions = $model->generateConditions(['id BETWEEN' => [1]]);
}
/**
* @expectedException Exception
* @expectedExceptionMessage BETWEEN expects an array.
*/
public function testGenerateConditionsBetweenNotArray()
{
$model = new MockModel();
$conditions = $model->generateConditions(['id BETWEEN' => '1']);
}
public function testCommitSingleRecord()
{
$value = Pickles\String::random();
$model = new MockModel(1);
$model->record['field1'] = $value;
$model->commit();
$model = new MockModel(1);
$this->assertEquals($value, $model->record['field1']);
}
// Handles filling coverage gaps but isn't a reliable test. Would need to
// test against a table without a UID column so we can see this in action,
// else it just takes a shit because the ID isn't injected back in.
public function testCommitSingleRecordReplace()
{
$value = Pickles\String::random();
$model = new MockModel(1);
$model->replace = true;
$model->record['field1'] = $value;
$model->commit();
$model = new MockModel(1);
}
public function testCommitInsertPriority()
{
$value = Pickles\String::random();
$model = new MockModel();
$model->priority = 'low';
$model->record['field1'] = $value;
$id = $model->commit();
$model = new MockModel($id);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitInsertDelayed()
{
$value = Pickles\String::random();
$model = new MyMockModel();
$model->delayed = true;
$model->record['field1'] = $value;
$model->commit();
$model = new MyMockModel(1);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitInsertIgnore()
{
$value = Pickles\String::random();
$model = new MockModel();
$model->ignore = true;
$model->record['field1'] = $value;
$id = $model->commit();
$model = new MockModel($id);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitReplacePriority()
{
$value = Pickles\String::random();
$model = new MockModel();
$model->replace = true;
$model->priority = 'low';
$model->record['field1'] = $value;
$id = $model->commit();
$model = new MockModel($id);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitReplaceDelayed()
{
$value = Pickles\String::random();
$model = new MyMockModel();
$model->replace = true;
$model->delayed = true;
$model->record['field1'] = $value;
$model->commit();
$model = new MyMockModel(2);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitReplaceIgnore()
{
$value = Pickles\String::random();
$model = new MockModel();
$model->replace = true;
$model->ignore = true;
$model->record['field1'] = $value;
$id = $model->commit();
$model = new MockModel($id);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitMultipleFields()
{
$value1 = Pickles\String::random();
$value2 = Pickles\String::random();
$model = new MockModelWithoutColumns(1);
$model->record['field1'] = $value1;
$model->record['field2'] = $value2;
$model->commit();
$model = new MockModelWithoutColumns(1);
$this->assertEquals($value1, $model->record['field1']);
$this->assertEquals($value2, $model->record['field2']);
}
public function testCommitIncrement()
{
$model = new MockModelWithoutColumns(1);
$model->record['field1'] = 100;
$model->commit();
$model = new MockModelWithoutColumns(1);
$model->record['field1'] = '++';
$model->commit();
$model = new MockModelWithoutColumns(1);
$this->assertEquals(101, $model->record['field1']);
}
public function testCommitUpdatedID()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$value = Pickles\String::random();
$model = new MockModel(1);
$model->record['field1'] = $value;
$model->commit();
$model = new MockModel(1);
$this->assertEquals($value, $model->record['field1']);
$this->assertEquals(1, $model->record['updated_id']);
}
public function testCommitCreatedID()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$value = Pickles\String::random();
$model = new MockModel();
$model->record['field1'] = $value;
$id = $model->commit();
$model = new MockModel($id);
$this->assertEquals(1, $model->record['created_id']);
}
// Doesn't test against actual PostgreSQL instance, just for valid syntax
public function testCommitInsertPostgreSQL()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$value = Pickles\String::random();
$model = new MockModel();
$model->mysql = false;
$model->postgresql = true;
$model->record['field1'] = $value;
try
{
$model->commit();
}
catch (Exception $e)
{
}
$this->assertRegExp('/RETURNING id/', $model->db->results->queryString);
}
// Doesn't test against actual PostgreSQL instance, just for valid syntax
public function testCommitUpdatePostgreSQL()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$value = Pickles\String::random();
$model = new MockModel(1);
$model->mysql = false;
$model->postgresql = true;
$model->record['field1'] = $value;
try
{
$model->commit();
}
catch (Exception $e)
{
}
$model = new MockModel(1);
$this->assertEquals($value, $model->record['field1']);
}
public function testCommitNothing()
{
$model = new MockModel();
$this->assertFalse($model->commit());
}
public function testDeleteLogical()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$model = new MockModel(1);
$model->delete();
$model = new MockModel(1);
$this->assertEquals([], $model->record);
}
public function testDeleteActual()
{
$model = new MockModelWithoutColumns(2);
$model->delete();
$model = new MockModelWithoutColumns(2);
$this->assertEquals(0, $model->count());
}
public function testDeleteNothing()
{
$model = new MockModelWithoutColumns(100);
$this->assertFalse($model->delete());
}
public function testLoadParametersWithString()
{
$model = new MockModel();
$this->assertFalse($model->loadParameters(''));
}
public function testMultipleQueueInsert()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$model = new MockModel('count');
$count = $model->record['count'];
$model = new MockModel();
for ($i = 0; $i < 5; $i++)
{
$model->record['field1'] = Pickles\String::random();
$model->record['updated_id'] = 1;
$model->queue();
}
$model->commit();
$model = new MockModel('count');
$this->assertEquals($count + 5, $model->record['count']);
}
public function testMultipleQueueUpdate()
{
$_SESSION['__pickles']['security']['user_id'] = 1;
$model = new MockModel();
for ($i = 3; $i <= 5; $i++)
{
$model->record['id'] = $i;
$model->record['field1'] = Pickles\String::random();
$model->record['updated_id'] = 1;
$model->queue();
}
$model->commit();
}
}