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

[WIP] 1.2 Release #424

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open

[WIP] 1.2 Release #424

wants to merge 21 commits into from

Conversation

koenpunt
Copy link
Collaborator

andyleap and others added 21 commits November 17, 2014 22:29
The default PHP boolean-to-string casting does not work for some
database connection types (e.g. PostgreSQL).  Added a BOOLEAN
type to the Column class, and then the cast() method delegates
to the a new boolean_to_string() method in the Connection class.

By default the boolean_to_string() method returns the standard
PHP string cast for the boolean, retaining the original behavior.
This method can be overridden in adapter classes to provides custom
casting of boolean values.

Added an overridden boolean_to_string() method into the
adapters/PgsqlAdapter.php class which casts the boolean values
false and true to the strings "0" and "1" respectively.  These
string values are then recognized by the Postgres database as
boolean values, as opposed to the values "" and "1" generated
by the standard PHP cast.
Updated the ColumnTest::assert_cast() to test that boolean values are
being casted using the Connection boolean_to_string() method.

Added a PostgreSQL specific test to ensure that boolean values are
being casted as the correct string value.
Modified the boolean_to_string() method in the PgsqlAdapter class to
properly convert values that PHP considers a boolean, as well as
what PostgreSQL considers a boolean value.

E.g., PostgreSQL considers the values 'f', 'false', 'n', 'no', and
'off' as valid values for `false`, but PHP does not.  The original
implementation of this method would return `true` for one of these
values which is incorrect for a PostgreSQL database.

Also modified the base Connection class boolean_to_string() method
to first cast its `$value` parameter as a boolean before casting
it to a string.  This will account for PHP's loose type-casting
and make sure the method returns a consistent casted value.
While the previous version was explicit and descriptive, it wasn't
that elegant.  This is much nicer.
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.
* The native types array were missing 'real','bigint','smallint', 'double precision', 'decimal' and 'numeric'.  See: http://www.postgresql.org/docs/9.1/static/datatype-numeric.html
* Both 0 and the empty string "" are valid defaults but were not being recognized.  Changed to check explicitly for NULL defaults.
Changed ActiveRecord\Model so that the __get() method will look for
a method with the same name as the property requested, in addition
to looking for the get_property_name() getter method.

Changed ActiveRecord\Serialization so that the check_methods() method
will look for a getter method in the form of "get_method_name" if it
can't find a method "method_name" in the class. This allows custom
attributes to be easily included in serialization.
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.

3 participants