Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking attribute changes #352

Closed
wants to merge 4 commits into from
Closed

Tracking attribute changes #352

wants to merge 4 commits into from

Conversation

leightonshank
Copy link

This PR contains 2 updates to implement tracking changed attributes in ActiveRecord\Model, based on the Rails ActiveRecord implementation.

  1. Updated the assign_attribute() method so that attributes are only flagged as dirty if the attribute value changes.
  2. Added some new methods and structures to track the changes to an attribute:
$model->changed_attributes()
# Returns a hash of all attributes that have changed and their original
# values.
# Example: $changed_attributes[$attribute] = $original_value;

$model->changes()
# Returns a hash of attributes that have changed with the original and
# current values.
# Example: $changes[$attribute] = array($original_value, $current_value)

$model->previous_changes()
# Returns the changes to a model's attributes before it was saved.

$model->attribute_was($attribute)
# Returns the original value of an attribute before it was changed

Attributes should only be flagged as dirty if the assigned attribute
has changed.  Assigning the same value to an attribute as the current
value should not flag the value as dirty.
To complement the flagging of dirty attributes, added functionality
similar to Rails which will track the values of changed attributes.

Added the following methods:
- $model->changed_attributes()
  Returns a hash of all attributes that have changed and their original
  values.
  #=> $changed_attributes[$attribute] = $original_value;

- $model->changes()
  Returns a hash of attributes that have changed with the original and
  current values.
  #=> $changes[$attribute] = array($original_value, $current_value)

- $model->previous_changes()
  Returns the changes to a model's attributes before it was saved.

- $model->attribute_was($attribute)
  Returns the original value of an attribute before it was changed

Also made a change to the read_attribute() method.  It seems that
there is a quirk in PHP when the return value of the __get() method
is passed by reference and you are trying to set a value using one
of the 'combined assignment' operators (e.g. .=).  If the return
value of the __get() method is a reference to an array element then
a weird thing happens - the value passed to the __set() method
is the same as the current value.  That's a super confusing
explanation, so an example will clear it up:

class Person {
    private $attributes = array('name' => "John");
    public function &__get($name) {
        return $this->attributes[$name];
    }
    public function __set($name, $value) {
        echo "original value: {$this->attributes[$name]}\n";
        $this->attributes[$name] = $value;
        echo "new value: {$this->attributes[$name]}\n";
    }
}

$person = new Person();
$person->name .= " Doe";

A simple change to the __get() method:
public function &__get($name) {
    $value = $this->attributes[$name];
    return $value;
}

seems to clear up the issue.  So I applied that same logic to the
Model::read_attribute() method, assigning the $this->attributes[$name]
value to a variable, and then returning that.

I don't think that should mess anything up, all unit tests still pass.
Took out the conversion of DateTime objects to strings, that is
just unnecessary.  DateTime objects should be kept as they are.

Also added test to make sure that changing a DateTime attribute
tracks a change.
@al-the-x
Copy link
Collaborator

This looks good, sir, and good work on the tests. Since this isn't a critical feature addition, I recommend pushing to 1.2... Any objection?

@leightonshank
Copy link
Author

Sure, 1.2 sounds good

@jpfuentes2
Copy link
Owner

@leightonshank, I just realized you live in Richmond, VA too! Now I have to accept this PR, right? : )

@leightonshank
Copy link
Author

@jpfuentes2 Ha, I didn't know you were in Richmond either, that's cool that you're local. So if it helps get this PR in then I'm all for it!

What do you do in RVA?

@jpfuentes2
Copy link
Owner

@leightonshank, as you can see I don't do much PHP or PHP-ActiveRecord : ). I work remotely primarily doing back-end work in a slew of different languages.

I'm going to make sure this is on the 1.2 road map.

@koenpunt
Copy link
Collaborator

Closing in favor of #427

@koenpunt koenpunt closed this Jul 21, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants