Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into 1.1-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
koenpunt committed Jun 3, 2017
2 parents 352e1b6 + f56c77e commit 494d55e
Show file tree
Hide file tree
Showing 19 changed files with 394 additions and 30 deletions.
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.php]
indent_style = tab
indent_size = 4

[*.{xml,xml.dist}]
indent_size = 4
1 change: 1 addition & 0 deletions ActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require __DIR__.'/lib/Singleton.php';
require __DIR__.'/lib/Config.php';
require __DIR__.'/lib/Utils.php';
require __DIR__.'/lib/DateTimeInterface.php';
require __DIR__.'/lib/DateTime.php';
require __DIR__.'/lib/Model.php';
require __DIR__.'/lib/Table.php';
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"phpunit/phpunit": "4.*",
"pear/pear_exception": "1.0-beta1",
"pear/log": "~1.12"
},
Expand Down
10 changes: 8 additions & 2 deletions lib/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,17 @@ public function cast($value, $connection)
if (!$value)
return null;

if ($value instanceof DateTime)
$date_class = Config::instance()->get_date_class();

if ($value instanceof $date_class)
return $value;

if ($value instanceof \DateTime)
return new DateTime($value->format('Y-m-d H:i:s T'));
return $date_class::createFromFormat(
Connection::DATETIME_TRANSLATE_FORMAT,
$value->format(Connection::DATETIME_TRANSLATE_FORMAT),
$value->getTimezone()
);

return $connection->string_to_datetime($value);
}
Expand Down
30 changes: 30 additions & 0 deletions lib/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ class Config extends Singleton
*/
private $logger;

/**
* Contains the class name for the Date class to use. Must have a public format() method and a
* public static createFromFormat($format, $time) method
*
* @var string
*/
private $date_class = 'ActiveRecord\\DateTime';

/**
* The format to serialize DateTime values into.
*
Expand Down Expand Up @@ -289,6 +297,28 @@ public function get_logger()
return $this->logger;
}

public function set_date_class($date_class)
{
try {
$klass = Reflections::instance()->add($date_class)->get($date_class);
} catch (\ReflectionException $e) {
throw new ConfigException("Cannot find date class");
}

if (!$klass->hasMethod('format') || !$klass->getMethod('format')->isPublic())
throw new ConfigException('Given date class must have a "public format($format = null)" method');

if (!$klass->hasMethod('createFromFormat') || !$klass->getMethod('createFromFormat')->isPublic())
throw new ConfigException('Given date class must have a "public static createFromFormat($format, $time)" method');

$this->date_class = $date_class;
}

public function get_date_class()
{
return $this->date_class;
}

/**
* @deprecated
*/
Expand Down
21 changes: 19 additions & 2 deletions lib/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
abstract class Connection
{

/**
* The DateTime format to use when translating other DateTime-compatible objects.
*
* NOTE!: The DateTime "format" used must not include a time-zone (name, abbreviation, etc) or offset.
* Including one will cause PHP to ignore the passed in time-zone in the 3rd argument.
* See bug: https://bugs.php.net/bug.php?id=61022
*
* @var string
*/
const DATETIME_TRANSLATE_FORMAT = 'Y-m-d\TH:i:s';

/**
* The PDO connection object.
* @var mixed
Expand Down Expand Up @@ -469,7 +480,7 @@ public function datetime_to_string($datetime)
* Converts a string representation of a datetime into a DateTime object.
*
* @param string $string A datetime in the form accepted by date_create()
* @return DateTime
* @return object The date_class set in Config
*/
public function string_to_datetime($string)
{
Expand All @@ -479,7 +490,13 @@ public function string_to_datetime($string)
if ($errors['warning_count'] > 0 || $errors['error_count'] > 0)
return null;

return new DateTime($date->format(static::$datetime_format));
$date_class = Config::instance()->get_date_class();

return $date_class::createFromFormat(
static::DATETIME_TRANSLATE_FORMAT,
$date->format(static::DATETIME_TRANSLATE_FORMAT),
$date->getTimezone()
);
}

/**
Expand Down
70 changes: 62 additions & 8 deletions lib/DateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* @package ActiveRecord
* @see http://php.net/manual/en/class.datetime.php
*/
class DateTime extends \DateTime
class DateTime extends \DateTime implements DateTimeInterface
{
/**
* Default format used for format() and __toString()
Expand Down Expand Up @@ -113,11 +113,40 @@ public static function get_format($format=null)
return $format;
}

/**
* This needs to be overriden so it returns an instance of this class instead of PHP's \DateTime.
* See http://php.net/manual/en/datetime.createfromformat.php
*/
public static function createFromFormat($format, $time, $tz = null)
{
$phpDate = $tz ? parent::createFromFormat($format, $time, $tz) : parent::createFromFormat($format, $time);
if (!$phpDate)
return false;
// convert to this class using the timestamp
$ourDate = new static(null, $phpDate->getTimezone());
$ourDate->setTimestamp($phpDate->getTimestamp());
return $ourDate;
}

public function __toString()
{
return $this->format();
}

/**
* Handle PHP object `clone`.
*
* This makes sure that the object doesn't still flag an attached model as
* dirty after cloning the DateTime object and making modifications to it.
*
* @return void
*/
public function __clone()
{
$this->model = null;
$this->attribute_name = null;
}

private function flag_dirty()
{
if ($this->model)
Expand All @@ -127,24 +156,49 @@ private function flag_dirty()
public function setDate($year, $month, $day)
{
$this->flag_dirty();
call_user_func_array(array($this,'parent::setDate'),func_get_args());
return parent::setDate($year, $month, $day);
}

public function setISODate($year, $week , $day=null)
public function setISODate($year, $week , $day = 1)
{
$this->flag_dirty();
call_user_func_array(array($this,'parent::setISODate'),func_get_args());
return parent::setISODate($year, $week, $day);
}

public function setTime($hour, $minute, $second=null)
public function setTime($hour, $minute, $second = 0)
{
$this->flag_dirty();
call_user_func_array(array($this,'parent::setTime'),func_get_args());
return parent::setTime($hour, $minute, $second);
}

public function setTimestamp($unixtimestamp)
{
$this->flag_dirty();
call_user_func_array(array($this,'parent::setTimestamp'),func_get_args());
return parent::setTimestamp($unixtimestamp);
}
}

public function setTimezone($timezone)
{
$this->flag_dirty();
return parent::setTimezone($timezone);
}

public function modify($modify)
{
$this->flag_dirty();
return parent::modify($modify);
}

public function add($interval)
{
$this->flag_dirty();
return parent::add($interval);
}

public function sub($interval)
{
$this->flag_dirty();
return parent::sub($interval);
}

}
35 changes: 35 additions & 0 deletions lib/DateTimeInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/**
* @package ActiveRecord
*/
namespace ActiveRecord;

/**
* Interface for the ActiveRecord\DateTime class so that ActiveRecord\Model->assign_attribute() will
* know to call attribute_of() on passed values. This is so the DateTime object can flag the model
* as dirty via $model->flag_dirty() when one of its setters is called.
*
* @package ActiveRecord
* @see http://php.net/manual/en/class.datetime.php
*/
interface DateTimeInterface
{
/**
* Indicates this object is an attribute of the specified model, with the given attribute name.
*
* @param Model $model The model this object is an attribute of
* @param string $attribute_name The attribute name
* @return void
*/
public function attribute_of($model, $attribute_name);

/**
* Formats the DateTime to the specified format.
*/
public function format($format=null);

/**
* See http://php.net/manual/en/datetime.createfromformat.php
*/
public static function createFromFormat($format, $time, $tz = null);
}
19 changes: 13 additions & 6 deletions lib/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,19 @@ public function assign_attribute($name, $value)
}

// convert php's \DateTime to ours
if ($value instanceof \DateTime)
$value = new DateTime($value->format('Y-m-d H:i:s T'));
if ($value instanceof \DateTime) {
$date_class = Config::instance()->get_date_class();
if (!($value instanceof $date_class))
$value = $date_class::createFromFormat(
Connection::DATETIME_TRANSLATE_FORMAT,
$value->format(Connection::DATETIME_TRANSLATE_FORMAT),
$value->getTimezone()
);
}

// make sure DateTime values know what model they belong to so
// dirty stuff works when calling set methods on the DateTime object
if ($value instanceof DateTime)
if ($value instanceof DateTimeInterface)
// Tell the Date object that it's associated with this model and attribute. This is so it
// has the ability to flag this model as dirty if a field in the Date object changes.
$value->attribute_of($this,$name);

// only update the attribute if it isn't set or has changed
Expand Down Expand Up @@ -991,7 +998,7 @@ protected function cache_key()
* Delete all using a string:
*
* <code>
* YourModel::delete_all(array('conditions' => 'name = "Tito"));
* YourModel::delete_all(array('conditions' => 'name = "Tito"'));
* </code>
*
* An options array takes the following parameters:
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ final protected function options_to_a($key)
*/
final public function to_a()
{
$date_class = Config::instance()->get_date_class();
foreach ($this->attributes as &$value)
{
if ($value instanceof \DateTime)
if ($value instanceof $date_class)
$value = $value->format(self::$DATETIME_FORMAT);
}
return $this->attributes;
Expand Down
5 changes: 3 additions & 2 deletions lib/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,10 @@ private function &process_data($hash)
if (!$hash)
return $hash;

$date_class = Config::instance()->get_date_class();
foreach ($hash as $name => &$value)
{
if ($value instanceof \DateTime)
if ($value instanceof $date_class || $value instanceof \DateTime)
{
if (isset($this->columns[$name]) && $this->columns[$name]->type == Column::DATE)
$hash[$name] = $this->conn->date_to_string($value);
Expand Down Expand Up @@ -518,7 +519,7 @@ private function set_associations()
foreach (wrap_strings_in_arrays($definitions) as $definition)
{
$relationship = null;
$definition += compact('namespace');
$definition += array('namespace' => $namespace);

switch ($name)
{
Expand Down
2 changes: 1 addition & 1 deletion lib/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public static function is_blank($var)
'/(bu)s$/i' => "$1ses",
'/(alias)$/i' => "$1es",
'/(octop)us$/i' => "$1i",
'/(ax|test)is$/i' => "$1es",
'/(cris|ax|test)is$/i' => "$1es",
'/(us)$/i' => "$1es",
'/s$/i' => "s",
'/$/' => "s"
Expand Down
6 changes: 3 additions & 3 deletions lib/Validations.php
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ public function validates_format_of($attrs)
$attribute = $options[0];
$var = $this->model->$attribute;

if (is_null($options['with']) || !is_string($options['with']) || !is_string($options['with']))
if (is_null($options['with']) || !is_string($options['with']))
throw new ValidationsArgumentError('A regular expression must be supplied as the [with] option of the configuration array.');
else
$expression = $options['with'];
Expand Down Expand Up @@ -600,7 +600,7 @@ public function validates_uniqueness_of($attrs)
continue;

$pk = $this->model->get_primary_key();
$pk_value = $this->model->$pk[0];
$pk_value = $this->model->{$pk[0]};

if (is_array($options[0]))
{
Expand Down Expand Up @@ -979,4 +979,4 @@ public function getIterator()
{
return new ArrayIterator($this->full_messages());
}
}
}
Loading

0 comments on commit 494d55e

Please sign in to comment.