Skip to content

Instantly share code, notes, and snippets.

@trichins
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trichins/1b538db7aba161f51467 to your computer and use it in GitHub Desktop.
Save trichins/1b538db7aba161f51467 to your computer and use it in GitHub Desktop.
<?php
App::uses('CakeTestFixture', 'TestSuite/Fixture');
class AppTestFixture extends CakeTestFixture {
public function __construct() {
// Handle custom datasources by making sure the
if ($this->useDbConfig && $this->isNonSqlDatasource($this->useDbConfig)) {
$reflection = new ReflectionClass($this);
if (!is_array($this->import)) {
$this->import = array('model' => $this->import);
}
$this->import['connection'] = $this->useDbConfig;
}
parent::__construct();
}
/**
* Creates the table schema.
*
* Overridden because creating is not needed for non-sql datasources
*
* @param Datasource $db
* @return boolean
*/
public function create($db) {
if ($this->isNonSqlDatasource($db->configKeyName)) {
$this->created[] = $db->configKeyName;
return true;
} else {
return parent::create($db);
}
}
/**
* Inserts the records
*
* @param Datasource $db
* @return boolean
*/
public function insert($db) {
if ($this->isNonSqlDatasource($db->configKeyName)) {
if (!isset($this->_insert)) {
if (isset($this->records) && !empty($this->records)) {
$modelClass = $this->import['model'];
$model = new $modelClass(null, null, $this->import['connection']);
$fields = array();
foreach ($this->records as $record) {
$fields = array_merge($fields, array_keys(array_intersect_key($record, $this->fields)));
}
$fields = array_unique($fields);
foreach ($this->records as $record) {
$default = array_fill_keys($fields, null);
$values = array_values(array_merge($default, $record));
$db->create($model, $fields, $values);
}
}
}
return true;
} else {
return parent::insert($db);
}
}
/**
* Drops the table
*
* @param Datasource $db
* @return boolean
*/
public function drop($db) {
if ($this->isNonSqlDatasource($db->configKeyName)) {
return $db->truncate($this->table);
} else {
return parent::drop($db);
}
}
/**
* Determine if this is a non DboSource datasource
*
* @param string $config
* @return boolean
*/
protected function isNonSqlDatasource($config) {
if (strpos($config, 'test_') === 0) {
return true;
} else {
return false;
}
}
}
<?php
class DATABASE_CONFIG
{
public $default = array(
'datasource' => 'Database/Sqlite',
'persistent' => false,
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'database_name',
'prefix' => '',
//'encoding' => 'utf8',
);
public $test = array(
'datasource' => 'Database/Sqlite',
'persistent' => false,
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'test_database_name',
'prefix' => '',
//'encoding' => 'utf8',
);
public $FileSource = array(
'datasource' => 'FileSource',
);
public $test_FileSource = array(
'datasource' => 'FileSource',
'location' => '/tmp/file_source',
);
}
<?php
App::uses('DataSource', 'Model/Datasource');
/**
* FileSource
*
* This datasource handles reading/writing config files
* This only handles single column models
*
* @uses DataSource
* @package DataSource
* @subpackage File
*/
class FileSource extends DataSource {
/**
* Default config options.
*
* Override them in app/Config/database.php
*
* @var array
*/
public $config = array(
'location' => '',
'prefix' => '',
);
/**
* fullDebug
*
* @var boolean
*/
public $fullDebug = false;
/**
* listSources() is for caching and this source doesn't
* need caching so just return null
*
* @param mixed $data
* @return void
*/
public function listSources($data = null) {
return null;
}
/**
* Describes the lines in the file
*
* @param mixed $model
* @return array
*/
public function describe($model) {
return $model->schema();
}
/**
* Retrieves a string that will be passed to read() as the 'fields' key
* in the queryData.
*
* It is returning COUNT as a flag to run a count
*
* @param Model $model
* @param mixed $func
* @param array $params
* @return string
*/
public function calculate(Model $model, $func, $params = array()) {
return 'COUNT';
}
/**
* Reads in data from the file
*
* @param Model $model
* @param array $queryData
* @param mixed $recursive
* @return array
*/
public function read(Model $model, $queryData = array(), $recursive = null) {
if ($queryData['fields'] === 'COUNT') {
// return 1 so that the system always thinks a record exists
return array(array(array('count' => 1)));
}
$queryData = $this->scrubQueryData($model, $queryData);
$contents = file_get_contents($this->fullTableName($model));
$field = $queryData['fields'][0];
return array(array($model->alias => array($field => $contents)));
}
/**
* Cleans up the query data
*
* Figures out the fields from the read request
*
* @param array $queryData
* @return array
*/
protected function scrubQueryData(Model $model, array $queryData) {
$fields = array();
if (is_string($queryData['fields'])) {
$fields[] = $queryData['fields'];
} elseif (is_array($queryData['fields'])) {
$fields = $queryData['fields'];
} else {
$fields = array_keys($this->describe($model));
}
$queryData['fields'] = $fields;
return $queryData;
}
/**
* Writes the data.
*
* This is the method that is called when $model->id is empty but since
* a file doesn't have an 'id', both update and create will just write to
* the file.
*
* @param Model $model
* @param mixed $fields
* @param mixed $values
* @throws CakeException
* @return boolean
*/
public function create(Model $model, $fields = null, $values = null) {
$data = array_combine($fields, $values);
$field = $fields[0];
$contents = $data[$field];
$result = file_put_contents($this->fullTableName($model), $contents);
if ($result === false) {
throw new CakeException($error);
}
return true;
}
/**
* Writes the data
*
* This is the method that is called when $model->id is not empty. It just
* calls $this->create().
*
* @param Model $model
* @param mixed $fields
* @param mixed $values
* @param mixed $conditions
* @return boolean
*/
public function update(Model $model, $fields = null, $values = null, $conditions = null) {
return $this->create($model, $fields, $values);
}
/**
* Deletes the file
*
* Test fixtures require this method
*
* @param string $table
* @return boolean
*/
public function truncate($table) {
if (file_exists($table)) {
return unlink($table);
} else {
return true;
}
}
/**
* Retrieves the file location
*
* @param Model $model
* @param boolean $quote
* @param boolean $schema
* @return string
*/
public function fullTableName(Model $model, $quote = true, $schema = true) {
if ($this->config['location'] !== '') {
return $this->config['location'];
} else {
return $model->table;
}
}
}
<?php
/**
* Controls the message of the day (motd)
*/
class Motd extends AppModel {
public $useDbConfig = 'FileSource';
public $useTable = '/etc/motd';
public $validate = array(
'motd' => array(
'maxlength' => array(
'rule' => array('maxLength', 4096),
'message' => 'model.system_setting::validation.motd.maxlength',
'allowEmpty' => true
)
),
);
protected $_schema = array(
'motd' => array(
'type' => 'string',
),
);
protected static $ANSI_HTML = array(
"\033[1m" => '<b>',
"\033[22m" => '</b>',
"\033[4m" => '<u>',
"\033[24m" => '</u>'
);
public function afterFind($results, $primary = false) {
foreach ($results as $key => $result) {
if (isset($result[$this->alias]['motd'])) {
$oldMotd = $result[$this->alias]['motd'];
$results[$key][$this->alias]['motd'] = $this->toHTML(nl2br(trim($oldMotd)));
}
}
return $results;
}
/**
* Converts the text into an ANSI string
*
* Only b and u tags are allowed and a new line
* is added at the end so that /etc/motd will look
* correct on ssh login.
*
* @param array $options
* @return boolean
*/
public function beforeSave($options = array()) {
$oldMotd = $this->data[$this->alias]['motd'];
// only allow b and u tags
$motd = strip_tags(trim($oldMotd), '<b><u>');
$motd = $this->toANSI($motd);
// make sure that there is a new line at the very end
if (strlen($motd) > 0) {
if (substr($motd, -1) !== "\n") {
$motd .= "\n";
}
}
$this->data[$this->alias]['motd'] = $motd;
return true;
}
protected function toANSI($html) {
return str_replace(self::$ANSI_HTML, array_keys(self::$ANSI_HTML), $html);
}
protected function toHTML($ansi) {
return str_replace(array_keys(self::$ANSI_HTML), self::$ANSI_HTML, $ansi);
}
}
<?php
App::uses('AppTestFixture', 'TestSuite/Fixture');
class MotdFixture extends AppTestFixture {
/**
* Indicates to load the Motd schema
*
* @var string
* @access public
*/
public $import = array('model' => 'Motd', 'connection' => 'test_FileSource');
/**
* Use the test Db config
*
* @var string
* @access public
*/
public $useDbConfig = 'test_FileSource';
public $records = array(
array(
'motd' => "\033[1mBold\033[22m",
),
);
}
<?php
App::uses('CakeTestCase', 'TestSuite');
class MotdTest extends CakeTestCase {
public $fixtures = array('Motd');
public function setUp() {
parent::setUp();
$this->Motd = $this->getMockForModel('Motd', null);
$db = $this->Motd->getDataSource();
$this->fileLocation = $db->config['location'];
}
public function testAfterFindAnsiToHtml() {
$result = $this->Motd->find('first');
$this->assertEquals('<b>Bold</b>', $result[$this->Motd->alias]['motd']);
}
}
Place these in a blank CakePHP app. Run ./app/Console/cake test app Model/Motd. You'll get a MissingTableException saying that table '/etc/motd for model Motd was not found in datasource test'. It should not be using datasource test but should instead be using datasource FileSource.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment