/** * @param $object * @param $attribute * * @return null */ protected function validateAttribute($object, $attribute) { $value = $object->{$attribute}; if ($value) { if (!$value instanceof \DateTime) { if (!DateTimeHelper::isValidTimeStamp((string) $value)) { $message = Craft::t('“{object}->{attribute}” must be a DateTime object or a valid Unix timestamp.', array('object' => get_class($object), 'attribute' => $attribute)); $this->addError($object, $attribute, $message); } } } }
/** * Creates a new \Craft\DateTime object (rather than \DateTime) * * @param string $format * @param string $time * @param mixed $timezone The timezone the string is set in (defaults to UTC). * * @return DateTime */ public static function createFromFormat($format, $time, $timezone = null) { if (!$timezone) { // Default to UTC $timezone = static::UTC; } if (is_string($timezone)) { $timezone = new \DateTimeZone($timezone); } $dateTime = parent::createFromFormat($format, $time, $timezone); if ($dateTime) { $timeStamp = $dateTime->getTimestamp(); if (DateTimeHelper::isValidTimeStamp($timeStamp)) { return new DateTime('@' . $dateTime->getTimestamp()); } } return false; }
/** * Sets an attribute's value. * * @param string $name * @param mixed $value * * @return bool */ public function setAttribute($name, $value) { if (!$this->strictAttributes || in_array($name, $this->attributeNames())) { // Is this a normal attribute? if (array_key_exists($name, $this->_attributeConfigs)) { $attributes = $this->getAttributeConfigs(); $config = $attributes[$name]; // Handle special case attribute types switch ($config['type']) { case AttributeType::DateTime: if ($value) { if (!$value instanceof \DateTime) { if (DateTimeHelper::isValidTimeStamp($value)) { $value = new DateTime('@' . $value); } else { $value = DateTime::createFromString($value); } } } else { // No empty strings allowed! $value = null; } break; case AttributeType::Mixed: if ($value && is_string($value) && mb_strpos('{[', $value[0]) !== false) { // Presumably this is JSON. $value = JsonHelper::decode($value); } if (is_array($value)) { if ($config['model']) { $class = __NAMESPACE__ . '\\' . $config['model']; $value = $class::populateModel($value); } else { $value = ModelHelper::expandModelsInArray($value); } } break; } } else { if (!array_key_exists($name, $this->_extraAttributeNames)) { $this->_extraAttributeNames[] = $name; } } $this->_attributes[$name] = $value; return true; } else { return false; } }
/** * Creates a new DateTime object from a string. * * Supports the following formats: * * - An array of the date and time in the current locale's short formats * - All W3C date and time formats (http://www.w3.org/TR/NOTE-datetime) * - MySQL DATE and DATETIME formats (http://dev.mysql.com/doc/refman/5.1/en/datetime.html) * - Relaxed versions of W3C and MySQL formats (single-digit months, days, and hours) * - Unix timestamps * * @param string|array $date * @param string|null $timezone The [PHP timezone identifier](http://php.net/manual/en/timezones.php) * that $date is set to, if not already specified in $date. Defaults to 'UTC'. * @param bool $setToSystemTimeZone Whether to set the resulting DateTime object to the system timezone. * * @return DateTime|null|false */ public static function createFromString($date, $timezone = null, $setToSystemTimeZone = true) { // Was this a date/time-picker? if (is_array($date) && (isset($date['date']) || isset($date['time']))) { $dt = $date; if (empty($dt['date']) && empty($dt['time'])) { return null; } $localeData = craft()->i18n->getLocaleData(craft()->language); $dateFormatter = $localeData->getDateFormatter(); if (!empty($dt['date'])) { $date = $dt['date']; $format = $dateFormatter->getDatepickerPhpFormat(); // Valid separators are either '-', '.' or '/'. if (mb_strpos($format, '.') !== false) { $separator = '.'; } else { if (mb_strpos($format, '-') !== false) { $separator = '-'; } else { $separator = '/'; } } // Ensure that the submitted date is using the locale’s separator $date = str_replace(array('-', '.', '/'), $separator, $date); // Check for a two-digit year as well $altFormat = str_replace('Y', 'y', $format); if (static::createFromFormat($altFormat, $date) !== false) { $format = $altFormat; } } else { $date = ''; $format = ''; // Default to the current date $current = new DateTime('now', new \DateTimeZone($timezone ?: self::UTC)); $date .= $current->month() . '/' . $current->day() . '/' . $current->year(); $format .= 'n/j/Y'; } if (!empty($dt['time'])) { $timePickerPhpFormat = $dateFormatter->getTimepickerPhpFormat(); // Replace the localized "AM" and "PM" $localeData = craft()->i18n->getLocaleData(); if (preg_match('/(.*)(' . preg_quote($localeData->getAMName(), '/') . '|' . preg_quote($localeData->getPMName(), '/') . ')(.*)/u', $dt['time'], $matches)) { $dt['time'] = $matches[1] . $matches[3]; if ($matches[2] == $localeData->getAMName()) { $dt['time'] .= 'AM'; } else { $dt['time'] .= 'PM'; } $timePickerPhpFormat = str_replace('A', '', $timePickerPhpFormat) . 'A'; } $date .= ' ' . $dt['time']; $format .= ' ' . $timePickerPhpFormat; } } else { $date = trim((string) $date); if (preg_match('/^ (?P<year>\\d{4}) # YYYY (four digit year) (?: -(?P<mon>\\d\\d?) # -M or -MM (1 or 2 digit month) (?: -(?P<day>\\d\\d?) # -D or -DD (1 or 2 digit day) (?: [T\\ ](?P<hour>\\d\\d?)\\:(?P<min>\\d\\d) # [T or space]hh:mm (1 or 2 digit hour and 2 digit minute) (?: \\:(?P<sec>\\d\\d) # :ss (two digit second) (?:\\.\\d+)? # .s (decimal fraction of a second -- not supported) )? (?:[ ]?(?P<ampm>(AM|PM|am|pm))?)? # An optional space and AM or PM (?:Z|(?P<tzd>[+\\-]\\d\\d\\:\\d\\d))? # Z or [+ or -]hh:ss (UTC or a timezone offset) )? )? )?$/x', $date, $m)) { $format = 'Y-m-d H:i:s'; $date = $m['year'] . '-' . (!empty($m['mon']) ? sprintf('%02d', $m['mon']) : '01') . '-' . (!empty($m['day']) ? sprintf('%02d', $m['day']) : '01') . ' ' . (!empty($m['hour']) ? sprintf('%02d', $m['hour']) : '00') . ':' . (!empty($m['min']) ? $m['min'] : '00') . ':' . (!empty($m['sec']) ? $m['sec'] : '00'); if (!empty($m['tzd'])) { $format .= 'P'; $date .= $m['tzd']; } if (!empty($m['ampm'])) { $format .= ' A'; $date .= ' ' . $m['ampm']; } } else { if (DateTimeHelper::isValidTimeStamp((int) $date)) { $format = 'U'; } else { $format = ''; } } } if ($timezone) { $format .= ' e'; $date .= ' ' . $timezone; } $dt = static::createFromFormat('!' . $format, $date); if ($dt !== false && $setToSystemTimeZone) { $dt->setTimezone(new \DateTimeZone(craft()->getTimeZone())); } return $dt; }
/** * Prepares the model's attribute values to be saved to the database. * * @return null */ public function prepAttributesForSave() { $attributes = $this->getAttributeConfigs(); $attributes['dateUpdated'] = array('type' => AttributeType::DateTime, 'column' => ColumnType::DateTime, 'required' => true); $attributes['dateCreated'] = array('type' => AttributeType::DateTime, 'column' => ColumnType::DateTime, 'required' => true); foreach ($attributes as $name => $config) { $value = $this->getAttribute($name); if ($config['type'] == AttributeType::DateTime) { // Leaving this in because we want to allow plugin devs to save a timestamp or DateTime object. if (DateTimeHelper::isValidTimeStamp($value)) { $value = new DateTime('@' . $value); } } $this->setAttribute($name, ModelHelper::packageAttributeValue($value, true)); } // Populate dateCreated and uid if this is a new record if ($this->isNewRecord()) { $this->dateCreated = DateTimeHelper::currentTimeForDb(); $this->uid = StringHelper::UUID(); } // Update the dateUpdated $this->dateUpdated = DateTimeHelper::currentTimeForDb(); }