public function __set($name, $value)
{
if (!$this->_init) {
// The constructor must always be called first
$this->__construct();
// This object is about to be loaded by mysql_fetch_object() or similar
$this->state('loading');
}
if (!isset($this->_fields[$name])) {
throw new Sprig_Exception(':name model does not have a field :field', array(':name' => get_class($this), ':field' => $name));
}
// Get the field object
$field = $this->_fields[$name];
if ($this->state() === 'loading') {
// Set the original value directly
$this->_original[$name] = $field->value($value);
// No extra processing necessary
return;
} elseif ($field instanceof Sprig_Field_ManyToMany) {
if (!isset($this->_original[$name])) {
$model = Sprig::factory($field->model);
if (isset($field->left_foreign_key) and $field->left_foreign_key) {
$fk = $field->left_foreign_key;
} else {
$fk = $model->fk();
}
$result = DB::select(array($model->field($model->pk())->_database_unwrap($fk), $model->fk()))->from($field->through)->where($fk, '=', $this->_fields[$this->_primary_key]->_database_wrap($this->{$this->_primary_key}))->execute($this->_db);
// The original value for the relationship must be defined
// before we can tell if the value has been changed
$this->_original[$name] = $field->value($result->as_array(NULL, $model->fk()));
}
} elseif ($field instanceof Sprig_Field_HasMany) {
foreach ($value as $key => $val) {
if (!$val instanceof Sprig) {
$model = Sprig::factory($field->model);
$pk = $model->pk();
if (!is_array($val)) {
// Assume the value is a primary key
$val = array($pk => $val);
}
if (isset($val[$pk])) {
// Load the record so that changed values can be determined
$model->values(array($pk => $val[$pk]))->load();
}
$value[$key] = $model->values($val);
}
}
// Set the related objects to this value
$this->_related[$name] = $value;
// No extra processing necessary
return;
} elseif ($field instanceof Sprig_Field_BelongsTo) {
// Pass
} elseif ($field instanceof Sprig_Field_ForeignKey) {
throw new Sprig_Exception('Cannot change relationship of :model->:field using __set()', array(':model' => $this->_model, ':field' => $name));
}
// Get the correct type of value
$changed = $field->value($value);
if (isset($field->hash_with) and $changed) {
$changed = call_user_func($field->hash_with, $changed);
}
$re_changed = array_key_exists($name, $this->_changed) && $changed !== $this->_changed[$name];
$original = $changed === $this->_original[$name];
if ($re_changed or !$original) {
if (isset($this->_related[$name])) {
// Clear stale related objects
unset($this->_related[$name]);
}
if ($original) {
// Simply pretend the change never happened
unset($this->_changed[$name]);
} else {
// Set a changed value
$this->_changed[$name] = $changed;
if ($field instanceof Sprig_Field_ForeignKey and is_object($value)) {
// Store the related object for later use
$this->_related[$name] = $value;
}
}
}
}