*/ namespace oat\taoTests\models\runner\time; /** * Class TimePoint * * Describes a temporal point by storing a timestamp with microseconds and some flags. * A TimePoint can describe a START or a END temporal point used to define a time range. * Each TimePoint can be related to a target (CLIENT or SERVER). * A list of tags can be attached to a TimePoint to explain its role or its context. * * @package oat\taoTests\models\runner\time */ class TimePoint implements ArraySerializable, \Serializable, \JsonSerializable { /** * Type of TimePoint: start of range */ const TYPE_START = 1; /** * Type of TimePoint: end of range */ const TYPE_END = 2; /** * Represents all types of TimePoint */ const TYPE_ALL = 3; /** * Type of TimePoint target: client side */ const TARGET_CLIENT = 1; /** * Type of TimePoint target: server side */ const TARGET_SERVER = 2; /** * Represents all types of TimePoint targets */ const TARGET_ALL = 3; /** * The decimal precision used to compare timestamps */ const PRECISION = 10000; /** * The timestamp representing the TimePoint * @var float */ protected $timestamp = 0.0; /** * A collection of tags attached to the TimePoint * @var array */ protected $tags = []; /** * The type of TimePoint. Must be a value from TYPE_START or TYPE_END constants. * @var int */ protected $type = 0; /** * The type of target. Must be a value from TARGET_CLIENT or TARGET_SERVER constants. * @var int */ protected $target = 0; /** * The unique reference to name the TimePoint * @var string */ protected $ref; /** * QtiTimePoint constructor. * @param string|array $tags * @param float $timestamp * @param int $type * @param int $target */ public function __construct($tags = null, $timestamp = null, $type = null, $target = null) { if (isset($tags)) { $this->setTags($tags); } if (isset($timestamp)) { $this->setTimestamp($timestamp); } if (isset($type)) { $this->setType($type); } if (isset($target)) { $this->setTarget($target); } } /** * Exports the internal state to an array * @return array */ public function toArray() { return [ 'ts' => $this->getTimestamp(), 'type' => $this->getType(), 'target' => $this->getTarget(), 'tags' => $this->getTags(), ]; } /** * Imports the internal state from an array * @param array $data */ public function fromArray($data) { if ($data) { if (isset($data['tags'])) { $this->setTags($data['tags']); } if (isset($data['ts'])) { $this->setTimestamp($data['ts']); } if (isset($data['type'])) { $this->setType($data['type']); } if (isset($data['target'])) { $this->setTarget($data['target']); } } } /** * Specify data which should be serialized to JSON * @link http://php.net/manual/en/jsonserializable.jsonserialize.php * @return mixed data which can be serialized by json_encode, * which is a value of any type other than a resource. * @since 5.4.0 */ public function jsonSerialize() { return $this->toArray(); } /** * String representation of object * @link http://php.net/manual/en/serializable.serialize.php * @return string the string representation of the object or null * @since 5.1.0 */ public function serialize() { return serialize($this->toArray()); } /** * Constructs the object * @link http://php.net/manual/en/serializable.unserialize.php * @param string $serialized
* The string representation of the object. *
* @return void * @since 5.1.0 */ public function unserialize($serialized) { $this->fromArray(unserialize($serialized)); } /** * Sets the timestamp of the TimePoint * @param float $timestamp * @return TimePoint */ public function setTimestamp($timestamp) { $this->timestamp = floatval($timestamp); return $this; } /** * Gets the timestamp of the TimePoint * @return float */ public function getTimestamp() { return $this->timestamp; } /** * Gets the normalized value of the timestamp. This value is the result of: * `normalized_timestamp = timestamp_with_microseconds * precision` * @return int */ public function getNormalizedTimestamp() { return round($this->getTimestamp() * self::PRECISION); } /** * Sets the type of TimePoint * @param int $type Must be a value from TYPE_START or TYPE_END constants. * @return TimePoint */ public function setType($type) { $this->type = intval($type); return $this; } /** * Gets the type of TimePoint * @return int */ public function getType() { return $this->type; } /** * Sets the target type of the TimePoint * @param int $target Must be a value from TARGET_CLIENT or TARGET_SERVER constants. * @return TimePoint */ public function setTarget($target) { $this->target = intval($target); return $this; } /** * Gets the target type of the TimePoint * @return int */ public function getTarget() { return $this->target; } /** * Adds another tag to the TimePoint * @param string $tag * @return TimePoint */ public function addTag($tag) { $this->tags[] = (string)$tag; $this->ref = null; return $this; } /** * Removes a tag from the TimePoint * @param string $tag * @return TimePoint */ public function removeTag($tag) { $index = array_search($tag, $this->tags); if ($index !== false) { array_splice($this->tags, $index, 1); $this->ref = null; } return $this; } /** * Gets a tag from the TimePoint. By default, it will return the first tag. * @param int $index * @return string */ public function getTag($index = 0) { $index = min(max(0, $index), count($this->tags)); return $this->tags[$index]; } /** * Sets the tags of the TimePoint * @param string|array $tags * @return TimePoint */ public function setTags($tags) { $this->tags = []; $this->ref = null; if (is_array($tags)) { foreach ($tags as $tag) { $this->addTag($tag); } } else { $this->addTag($tags); } return $this; } /** * Gets all tags from the TimePoint * @return array */ public function getTags() { return $this->tags; } /** * Gets a unique reference to name the TimePoint * @return string */ public function getRef() { if (is_null($this->ref)) { $tags = $this->tags; sort($tags); $this->ref = md5(implode('-', $tags)); } return $this->ref; } /** * Checks if a TimePoint matches the criteria * @param array $tags * @param int $target * @param int $type * @return bool */ public function match(array $tags = null, $target = self::TARGET_ALL, $type = self::TYPE_ALL) { $match = ($this->getType() & $type) && ($this->getTarget() & $target); if ($match && isset($tags)) { $match = (count(array_intersect($tags, $this->getTags())) == count($tags)); } return $match; } /** * Compares the TimePoint with another instance. * The comparison is made in this order: * - reference * - target * - timestamp * - type * * CAUTION!: The result order is not based on chronological order. * Its goal is to gather TimePoint by reference and target, then sort by type and timestamp. * * @param TimePoint $point * @return int */ public function compare(TimePoint $point) { $diff = strcmp($this->getRef(), $point->getRef()); if ($diff == 0) { $diff = $this->getTarget() - $point->getTarget(); if ($diff == 0) { $diff = $this->getNormalizedTimestamp() - $point->getNormalizedTimestamp(); if ($diff == 0) { $diff = $this->getType() - $point->getType(); } } } return $diff; } /** * Sorts a range of TimePoint * @param array $range * @return array */ public static function sort(array &$range) { usort($range, function (TimePoint $a, TimePoint $b) { return $a->compare($b); }); return $range; } }