Skip to content

Instantly share code, notes, and snippets.

@eberfreitas
Created March 16, 2010 16:30
Show Gist options
  • Save eberfreitas/334181 to your computer and use it in GitHub Desktop.
Save eberfreitas/334181 to your computer and use it in GitHub Desktop.
Adds some NoSQL flavour to RDBMS's that Cake supports
<?php
/**
* Adds some NoSQL flavour to any RDBMS that Cake supports
*
* Need to create a new table with the following schema...
*
* CREATE TABLE IF NOT EXISTS `options` (
* `id` int(11) NOT NULL auto_increment,
* `model` varchar(32) NOT NULL,
* `related_id` int(11) NOT NULL,
* `opt_key` varchar(32) NOT NULL,
* `opt_value` text NOT NULL,
* PRIMARY KEY (`id`),
* KEY `opt_key` (`opt_key`)
* );
*/
class OptionableBehavior extends ModelBehavior {
private $_settings = array();
private $_toSave = array();
private $_toFetch = array();
private $_toDelete = array();
public function setup(&$model, $settings = array()) {
$this->_settings[$model->alias] = array();
$defaults = array(
'model' => 'Option',
'fields' => array(),
'emptyFields' => true
);
$this->_settings[$model->alias] = $settings + $defaults;
$this->Model = ClassRegistry::init($this->_settings[$model->alias]['model']);
}
public function beforeFind(&$model, $query) {
$fetch = true;
$fields = $this->_settings[$model->alias]['fields'];
if (isset($query['options']) && $query['options'] == false) {
$fetch = false;
}
if ($fetch) {
if (isset($query['fields'])) {
foreach($fields as $field) {
if (in_array($field, (array) $query['fields'])) {
$this->_toFetch[] = $field;
} elseif (in_array($model->alias . '.' . $field, (array) $query['fields'])) {
$this->_toFetch[] = $field;
}
}
if (in_array('*', (array) $query['fields'])) {
$this->_toFetch += (array) $fields;
} elseif (in_array($model->alias . '.*', (array) $query['fields'])) {
$this->_toFetch += (array) $fields;
}
$this->_toFetch = array_unique($this->_toFetch);
if ($this->_toFetch) {
foreach ($query['fields'] as $k => $field) {
$field = (strpos($field, '.') === false)
? $field
: str_replace($model->alias . '.', '', $field);
if (in_array($field, $this->_toFetch)) {
unset($query['fields'][$k]);
}
}
}
if (!in_array('id', (array) $query['fields'])
|| !in_array($model->alias . '.id', (array) $query['fields'])) {
if (!is_array($query['fields'])) {
$query['fields'] = (array) $query['fields'];
}
$query['fields'][] = $model->alias . '.id';
}
} else {
$this->_toFetch = (array) $fields;
}
}
return $query;
}
public function afterFind(&$model, $results, $primary) {
if ($this->_toFetch) {
foreach ($results as $k => $result) {
if (isset($result[$model->alias])) {
$id = $result[$model->alias]['id'];
$return = $this->optGet($model, $id, $this->_toFetch);
$results[$k][$model->alias] += $return;
}
}
$this->_toFetch = array();
}
return $results;
}
public function beforeSave(&$model) {
$keysToSave = $toSave = $toDelete = array();
$fields = $this->_settings[$model->alias]['fields'];
$dataKeys = array_keys($model->data[$model->alias]);
$keysToSave = array_intersect($dataKeys, $fields);
if ($keysToSave) {
foreach ($keysToSave as $field) {
if (!empty($model->data[$model->alias][$field])) {
$toSave[$field] = $model->data[$model->alias][$field];
} else {
$toDelete[] = $field;
}
}
}
if ($toSave) {
$this->_toSave = $toSave;
}
if ($toDelete) {
$this->_toDelete = $toDelete;
}
return true;
}
public function afterSave(&$model, $created) {
$id = $model->id;
if (!$id) {
return;
}
if ($this->_toSave) {
$this->optSave($model, $id, $this->_toSave);
}
if ($this->_toDelete) {
$this->optDelete($model, $id, $this->_toDelete);
}
$this->_toSave = $this->_toDelete = array();
}
/*public function afterDelete(&$model) {
if ($model->id) {
return $this->Model->deleteAll(array(
'model' => $model->alias,
'related_id' => $model->id
));
}
}*/
public function optGet(&$model, $id = null, $fields = array()) {
$return = array();
if (!$id && !$fields) {
$fields = $this->_settings[$model->alias]['fields'];
$id = $model->id;
}
if (is_array($id)) {
$fields = $id;
$id = $model->id;
}
if ($id && $fields) {
$conditions = array(
'related_id' => $id,
'model' => $model->alias,
'opt_key' => $fields
);
$options = $this->Model->find('all', compact('conditions'));
if ($options) {
foreach ($options as $opt) {
$return[$opt[$this->_settings[$model->alias]['model']]['opt_key']] = unserialize($opt[$this->_settings[$model->alias]['model']]['opt_value']);
}
}
if ($this->_settings[$model->alias]['emptyFields']) {
foreach ($fields as $field) {
if (!isset($return[$field])) {
$return[$field] = null;
}
}
}
}
return $return;
}
public function optSave(&$model, $id = null, $fields = array()) {
if (is_array($id)) {
$fields = $id;
$id = $model->id;
}
if ($id && $fields) {
foreach ($fields as $key => $value) {
$bypass = false;
$value = serialize($value);
$conditions = array(
'model' => $model->alias,
'related_id' => $id,
'opt_key' => $key
);
$data = $this->Model->find('first', compact('conditions'));
if ($data) {
if ($value === $data[$this->_settings[$model->alias]['model']]['opt_value']) {
$bypass = true;
} else {
$data[$this->_settings[$model->alias]['model']]['opt_value'] = $value;
}
} else {
$conditions['opt_value'] = $value;
$data = array($this->_settings[$model->alias]['model'] => $conditions);
$this->Model->create();
}
if (!$bypass) {
$this->Model->save($data);
}
}
return true;
}
return false;
}
public function optDelete(&$model, $id = null, $fields = array()) {
if (is_array($id)) {
$fields = $id;
$id = $model->id;
}
if ($id && $fields) {
return $this->Model->deleteAll(array(
'model' => $model->alias,
'related_id' => $id,
'opt_key' => $fields
));
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment