'foreign_id', 'keyField' => 'key', 'valueField' => 'value', 'defaults' => null, // looks for `public $keyValueDefaults` property in the model, 'validate' => null, // looks for `public $keyValueValidate` property in the model 'defaultOnEmpty' => false, // if nothing is posted, delete (0 is not nothing) 'deleteIfDefault' => false, // if default value is posted, delete ); /** * Setup * * @param object AppModel * @param array $config */ public function setup(Model $Model, $config = array()) { $settings = array_merge($this->_defaults, $config); $this->settings[$Model->alias] = $settings; if (!$this->KeyValue) { $this->KeyValue = ClassRegistry::init('Tools.KeyValue'); } /* if ($this->settings[$Model->alias]['validate']) { foreach ($this->settings[$Model->alias]['validate'] as $key => $validate) { $this->KeyValue->validate[$key] = $validate; } } */ } /** * Returns details for named section * * @var string * @var string * @return mixed */ public function getSection(Model $Model, $foreignKey, $section = null, $key = null) { extract($this->settings[$Model->alias]); $results = $this->KeyValue->find('all', array( 'recursive' => -1, 'conditions' => array($foreignKeyField => $foreignKey), 'fields' => array('key', 'value') )); $defaultValues = $this->defaultValues($Model); $detailArray = array(); foreach ($results as $value) { $keyArray = preg_split('/\./', $value[$this->KeyValue->alias]['key'], 2); $detailArray[$keyArray[0]][$keyArray[1]] = $value[$this->KeyValue->alias]['value']; } $detailArray = Set::merge($defaultValues, $detailArray); if ($section === null) { return $detailArray; } if ($key === null) { return $detailArray[$section]; } if (!isset($detailArray[$section][$key])) { return null; } return $detailArray[$section][$key]; } /** * Save details for named section * * TODO: validate * * @var string * @var array * @var string * @return bool $success */ public function saveSection(Model $Model, $foreignKey, $data, $section = null) { if (!$this->validateSection($Model, $data)) { return false; } extract($this->settings[$Model->alias]); foreach ($data as $model => $details) { foreach ($details as $field => $value) { $newDetail = array(); $section = $section ? $section : $model; $key = $section . '.' . $field; if ($defaultOnEmpty && (String)$value === '' || $deleteIfDefault && (String)$value === (String)$this->defaultValues($Model, $section, $field)) { return $this->resetSection($Model, $foreignKey, $section, $field); } $tmp = $this->KeyValue->find('first', array( 'recursive' => -1, 'conditions' => array($foreignKeyField => $foreignKey, $keyField => $key), 'fields' => array('id'))); $newDetail[$this->KeyValue->alias]['id'] = $tmp[$this->KeyValue->alias]['id']; $newDetail[$this->KeyValue->alias][$foreignKeyField] = $foreignKey; $newDetail[$this->KeyValue->alias][$keyField] = $key; $newDetail[$this->KeyValue->alias][$valueField] = $value; $this->KeyValue->save($newDetail, false); } } return true; } /** * @return bool $success */ public function validateSection(Model $Model, $data) { $validate = $this->settings[$Model->alias]['validate']; if ($validate === null) { $validate = 'keyValueValidate'; } if (empty($Model->{$validate})) { return true; } $rules = $Model->keyValueValidate; $res = true; foreach ($data as $model => $array) { if (empty($rules[$model])) { continue; } $this->KeyValue->{$model} = ClassRegistry::init(array('class'=>'AppModel', 'alias'=>$model)); $this->KeyValue->{$model}->validate = $rules[$model]; $this->KeyValue->{$model}->set($array); $res = $res && $this->KeyValue->{$model}->validates(); } return $res; } public function defaultValues(Model $Model, $section = null, $key = null) { $defaults = $this->settings[$Model->alias]['defaults']; if ($defaults === null) { $defaults = 'keyValueDefaults'; } $defaultValues = array(); if (!empty($Model->{$defaults})) { $defaultValues = $Model->{$defaults}; } if ($section !== null) { if ($key !== null) { return isset($defaultValues[$section][$key]) ? $defaultValues[$section][$key] : null; } return isset($defaultValues[$section]) ? $defaultValues[$section] : null; } return $defaultValues; } /** * resets the custom data for the specific domains (model, foreign_id) * careful: passing both null values will result in a complete truncate command * * @return bool $success * 2012-08-08 ms */ public function resetSection(Model $Model, $foreignKey = null, $section = null, $key = null) { extract($this->settings[$Model->alias]); $conditions = array(); if ($foreignKey !== null) { $conditions[$foreignKeyField] = $foreignKey; } if ($section !== null) { if ($key !== null) { $conditions[$keyField] = $section . '.'. $key; } else { $conditions[$keyField.' LIKE'] = $section.'.%'; } } if (empty($conditions)) { return $this->KeyValue->truncate(); } return (bool)$this->KeyValue->deleteAll($conditions, false); } }