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

Issue/46 - Fix magic methods not working as intended #47

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
219 changes: 195 additions & 24 deletions src/Database/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
*/
class Base {

/**
* The private data object used to store class attributes, so that magic
* methods work as intended.
*
* @since 1.1.0
* @var object
*/
private $data;

/**
* The name of the PHP global that contains the primary database interface.
*
Expand Down Expand Up @@ -60,7 +69,7 @@ class Base {
/** Public ****************************************************************/

/**
* Magic isset'ter for immutability.
* Magic isset method.
*
* @since 1.0.0
*
Expand All @@ -69,20 +78,23 @@ class Base {
*/
public function __isset( $key = '' ) {

// No more uppercase ID properties ever
if ( 'ID' === $key ) {
$key = 'id';
// Validate the key
$key = $this->validate_key( $key );

// Bail if invalid key
if ( empty( $key ) ) {
return false;
}

// Class method to try and call
$method = "get_{$key}";
$method = "__get_{$key}";

// Return property if exists
// Return true if method exists
if ( method_exists( $this, $method ) ) {
return true;

// Return get method results if exists
} elseif ( property_exists( $this, $key ) ) {
// Return true if data exists
} elseif ( isset( $this->data->{$key} ) ) {
return true;
}

Expand All @@ -91,34 +103,101 @@ public function __isset( $key = '' ) {
}

/**
* Magic getter for immutability.
* Magic unset method.
*
* @since 1.1.0
*
* @param string $key User meta key to unset.
*/
public function __unset( $key = '' ) {

// Validate the key
$key = $this->validate_key( $key );

// Bail if invalid key
if ( empty( $key ) ) {
return false;
}

// Maybe unset from data array
if ( isset( $this->data->{$key} ) ) {
unset( $this->data->{$key} );
}
}

/**
* Magic set method.
*
* @since 1.1.0
*
* @param string $key
* @return mixed
*/
public function __set( $key = '', $value = '' ) {

// Validate the key
$key = $this->validate_key( $key );

// Bail if invalid key
if ( empty( $key ) ) {
return false;
}

// Class method to try and call
$method = "__set_{$key}";

// Maybe override the value
if ( method_exists( $this, $method ) ) {
$value = call_user_func( array( $this, $method ), $value );
}

// Set the key to the value
$this->data->{$key} = $value;
}

/**
* Magic get method.
*
* @since 1.0.0
*
* @param string $key
* @return mixed
*/
public function __get( $key = '' ) {
public function &__get( $key = '' ) {

// No more uppercase ID properties ever
if ( 'ID' === $key ) {
$key = 'id';
// Validate the key
$key = $this->validate_key( $key );

// Bail if invalid key
if ( empty( $key ) ) {
return false;
}

// Default return value
$retval = null;

// Class method to try and call
$method = "get_{$key}";
$method = "__get_{$key}";

// Return property if exists
// Return from method if exists
if ( method_exists( $this, $method ) ) {
return call_user_func( array( $this, $method ) );
$retval = call_user_func( array( $this, $method ) );

// Return from data array if set
} elseif ( isset( $this->data->{$key} ) ) {
$retval = $this->data->{$key};
}

// Return get method results if exists
} elseif ( property_exists( $this, $key ) ) {
return $this->{$key};
// Return if not null
if ( ! is_null( $retval ) ) {
return $retval;
}

// Return null if not exists
return null;
// Set key to null, so array operations work correctly
$this->data->{$key} = $retval;

// Return variable byref
return $this->data->{$key};
}

/**
Expand All @@ -129,7 +208,28 @@ public function __get( $key = '' ) {
* @return array Array version of the given object.
*/
public function to_array() {
return get_object_vars( $this );
return get_object_vars( $this->data );
}

/**
* Get this objects default properties and set them up in the private data
* array. Use this in the Constructor in any class that extends this class.
*
* @since 1.1.0
*/
public function set_defaults() {

// Get the hard-coded object variables
$r = get_object_vars( $this );

// Data is private, so don't set it recursively
unset( $r['data'] );

// Set those vars
$this->set_vars( $r );

// Unset those vars
$this->unset_vars( $r );
}

/** Protected *************************************************************/
Expand Down Expand Up @@ -252,6 +352,11 @@ protected function sanitize_table_name( $name = '' ) {
/**
* Set class variables from arguments.
*
* This method accepts a key/value array of class variables to set, and is
* used by set_defaults() to prepare a class for magic property overrides.
*
* It can also be called directly to set multiple class variables.
*
* @since 1.0.0
* @param array $args
*/
Expand All @@ -267,9 +372,44 @@ protected function set_vars( $args = array() ) {
$args = (array) $args;
}

// Set empty class
$this->data = new \stdClass();

// Set all properties
foreach ( $args as $key => $value ) {
$this->{$key} = $value;
$this->data->{$key} = $value;
}
}

/**
* Unset class variables from arguments.
*
* This method accepts a key/value array of class variables to unset, and is
* used by set_defaults() to prepare a class for magic property overrides.
*
* It can also be called directly to unset multiple class variables.
*
* @since 1.0.0
* @param array $args
*/
protected function unset_vars( $args = array() ) {

// Bail if no vars to clean
if ( empty( $args ) ) {
return;
}

// Cast to an array
if ( ! is_array( $args ) ) {
$args = (array) $args;
}

// Get keys
$keys = array_keys( $args );

// Cleanup class properties
foreach ( $keys as $key ) {
unset( $this->{$key} );
}
}

Expand All @@ -288,7 +428,7 @@ protected function get_db() {
$retval = false;

// Look for a commonly used global database interface
if ( isset( $GLOBALS[ $this->db_global ] ) ) {
if ( ! empty( $this->db_global ) && isset( $GLOBALS[ $this->db_global ] ) ) {
$retval = $GLOBALS[ $this->db_global ];
}

Expand Down Expand Up @@ -340,4 +480,35 @@ protected function is_success( $result = false ) {
// Return the result
return (bool) $retval;
}

/** Private ***************************************************************/

/**
* Validate a data key.
*
* @since 1.0.0
*
* @param string $key
* @return boolean|string
*/
private function validate_key( $key = '' ) {

// Bail if empty key
if ( empty( $key ) ) {
return false;
}

// Bail if setting data
if ( 'data' === $key ) {
return false;
}

// No more uppercase ID properties ever
if ( 'ID' === $key ) {
return 'id';
}

// Return the original key
return $key;
}
}
7 changes: 5 additions & 2 deletions src/Database/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ class Column extends Base {
*/
public function __construct( $args = array() ) {

// Setup the defaults
$this->set_defaults();

// Parse arguments
$r = $this->parse_args( $args );

Expand Down Expand Up @@ -538,7 +541,7 @@ private function validate_args( $args = array() ) {
foreach ( $args as $key => $value ) {

// Callback is callable
if ( isset( $callbacks[ $key ] ) && is_callable( $callbacks[ $key ] ) ) {
if ( ! empty( $callbacks[ $key ] ) && is_callable( $callbacks[ $key ] ) ) {
$r[ $key ] = call_user_func( $callbacks[ $key ], $value );

// Callback is malformed so just let it through to avoid breakage
Expand Down Expand Up @@ -721,7 +724,7 @@ private function sanitize_pattern( $pattern = '%s' ) {
private function sanitize_validation( $callback = '' ) {

// Return callback if it's callable
if ( is_callable( $callback ) ) {
if ( ! empty( $callback ) && is_callable( $callback ) ) {
return $callback;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Database/Queries/Compare.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,4 @@ public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' )
// Return
return $sql_chunks;
}
}
}
8 changes: 7 additions & 1 deletion src/Database/Queries/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ class Date extends Base {
*/
public function __construct( $date_query = array() ) {

// Setup the defaults
$this->set_defaults();

// Bail if empty or not an array.
if ( empty( $date_query ) || ! is_array( $date_query ) ) {
return;
Expand Down Expand Up @@ -1281,8 +1284,11 @@ public function build_time_query( $column, $compare, $hour = null, $minute = nul
// Build the SQL
$query = "DATE_FORMAT( {$column}, %s ) {$compare} %f";

// Get the return value
$retval = $this->get_db()->prepare( $query, $format, $time );

// Return the prepared SQL
return $this->get_db()->prepare( $query, $format, $time );
return $retval;
}

/**
Expand Down
Loading