Skip to content
This repository has been archived by the owner on Apr 30, 2020. It is now read-only.

Commit

Permalink
Closed #11 Added date period stats
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyFreeAgent committed Dec 23, 2012
1 parent c0a7095 commit d632371
Show file tree
Hide file tree
Showing 6 changed files with 662 additions and 2 deletions.
64 changes: 62 additions & 2 deletions src/FreeAgent/Bitter/Bitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace FreeAgent\Bitter;

use \DateTime;
use \Exception;
use FreeAgent\Bitter\Date\DatePeriod;
use FreeAgent\Bitter\Event\Year;
use FreeAgent\Bitter\Event\Month;
use FreeAgent\Bitter\Event\Week;
use FreeAgent\Bitter\Event\Day;
Expand Down Expand Up @@ -61,6 +64,7 @@ public function mark($eventName, $id, DateTime $dateTime = null)
$dateTime = is_null($dateTime) ? new DateTime : $dateTime;

$eventData = array(
new Year($eventName, $dateTime),
new Month($eventName, $dateTime),
new Week($eventName, $dateTime),
new Day($eventName, $dateTime),
Expand All @@ -72,7 +76,7 @@ public function mark($eventName, $id, DateTime $dateTime = null)
$this->getRedisClient()->setbit($key, $id, 1);
$this->getRedisClient()->sadd($this->prefixKey . 'keys', $key);
}

return $this;
}

Expand All @@ -95,7 +99,7 @@ public function in($id, $key)
*
* @param mixed $key The key or the event
* @return integer The value of the count result
*/
*/
public function count($key)
{
$key = $key instanceof EventInterface ? $this->prefixKey . $key->getKey() : $this->prefixTempKey . $key;
Expand Down Expand Up @@ -130,6 +134,62 @@ public function bitOpXor($destKey, $keyOne, $keyTwo)
return $this->bitOp('XOR', $destKey, $keyOne, $keyTwo);
}

public function bitDatePeriod($key, $destKey, DateTime $from, DateTime $to)
{
if ($from > $to) {
throw new Exception("DateTime from (" . $from->format('Y-m-d H:i:s') . ") must be anterior to DateTime to (" . $to->format('Y-m-d H:i:s') . ").");
}

$this->getRedisClient()->del($this->prefixTempKey . $destKey);

// Hours
$hoursFrom = DatePeriod::createForHour($from, $to, DatePeriod::CREATE_FROM);
foreach ($hoursFrom as $date) {
$this->bitOpOr($destKey, new Hour($key, $date), $destKey);
}
$hoursTo = DatePeriod::createForHour($from, $to, DatePeriod::CREATE_TO);
if (array_diff($hoursTo->toArray(true), $hoursFrom->toArray(true)) !== array_diff($hoursFrom->toArray(true), $hoursTo->toArray(true))) {
foreach ($hoursTo as $date) {
$this->bitOpOr($destKey, new Hour($key, $date), $destKey);
}
}

// Days
$daysFrom = DatePeriod::createForDay($from, $to, DatePeriod::CREATE_FROM);
foreach ($daysFrom as $date) {
$this->bitOpOr($destKey, new Day($key, $date), $destKey);
}
$daysTo = DatePeriod::createForDay($from, $to, DatePeriod::CREATE_TO);
if (array_diff($daysTo->toArray(true), $daysFrom->toArray(true)) !== array_diff($daysFrom->toArray(true), $daysTo->toArray(true))) {
foreach ($daysTo as $date) {
$this->bitOpOr($destKey, new Day($key, $date), $destKey);
}
}

// Months
$monthsFrom = DatePeriod::createForMonth($from, $to, DatePeriod::CREATE_FROM);
foreach ($monthsFrom as $date) {
$this->bitOpOr($destKey, new Month($key, $date), $destKey);
}
$monthsTo = DatePeriod::createForMonth($from, $to, DatePeriod::CREATE_TO);
if (array_diff($monthsTo->toArray(true), $monthsFrom->toArray(true)) !== array_diff($monthsFrom->toArray(true), $monthsTo->toArray(true))) {
foreach ($monthsTo as $date) {
$this->bitOpOr($destKey, new Month($key, $date), $destKey);
}
}

// Years
$years = DatePeriod::createForYear($from, $to);
foreach ($years as $date) {
$this->bitOpOr($destKey, new Year($key, $date), $destKey);
}

$this->getRedisClient()->sadd($this->prefixTempKey . 'keys', $destKey);
$this->getRedisClient()->expire($destKey, $this->expireTimeout);

return $this;
}

/**
* Removes all Bitter keys
*/
Expand Down
105 changes: 105 additions & 0 deletions src/FreeAgent/Bitter/Date/DatePeriod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace FreeAgent\Bitter\Date;

use \DateTime;
use \DateInterval;

/**
* @author Jérémy Romey <jeremy@free-agent.fr>
*/
class DatePeriod extends \DatePeriod
{
const CREATE_FROM = 'from';
const CREATE_TO = 'to';

public function toArray($dateToString = false)
{
$dates = array();
foreach ($this as $date) {
$dates[] = true === $dateToString ? $date->format('Y-m-d H:i:s') : $date;
}

return $dates;
}

public static function createForHour(DateTime $from, DateTime $to, $fromOrTo = self::CREATE_FROM)
{
if ($from->format('Y-m-d') != $to->format('Y-m-d')) {
if (self::CREATE_TO !== $fromOrTo) {
$from->setTime($from->format('H'), 0, 0);
$to = clone($from);
$to->setTime(24, 0, 0);
} else {
$from = clone($to);
$from->setTime(0, 0, 0);
$to->setTime($to->format('H'), 0, 0);
}
} else {
$from->setTime($from->format('H'), 0, 0);
$to->setTime($to->format('H'), 0, 0);
}

return new DatePeriod($from, new DateInterval('PT1H'), $to);
}

public static function createForDay(DateTime $from, DateTime $to, $fromOrTo = self::CREATE_FROM)
{
$mFrom = $from;
$mTo = $to;
if ($mFrom->format('Y-m') != $mTo->format('Y-m')) {
if (self::CREATE_TO !== $fromOrTo) {
$mFrom->setTime(0, 0, 0);
$mFrom->setDate($mFrom->format('Y'), $mFrom->format('m'), $mFrom->format('d'));
$mTo = clone($mFrom);
$mTo->setDate($mFrom->format('Y'), $mFrom->format('m') + 1, 1);
} else {
$mTo->setTime(0, 0, 0);
$mFrom = clone($mTo);
$mFrom->setDate($mFrom->format('Y'), $mFrom->format('m'), 1);
$mTo->setDate($mTo->format('Y'), $mTo->format('m'), $mTo->format('d'));
}
} else {
$mFrom->setTime(0, 0, 0);
$mTo->setTime(0, 0, 0);
}

return new DatePeriod($mFrom, new DateInterval('P1D'), $mTo, self::CREATE_TO !== $fromOrTo || $from->format('Y-m') == $to->format('Y-m') ? self::EXCLUDE_START_DATE : null);
}

public static function createForMonth(DateTime $from, DateTime $to, $fromOrTo = self::CREATE_FROM)
{
$mFrom = $from;
$mTo = $to;
if ($mFrom->format('Y') != $to->format('Y')) {
if (self::CREATE_TO !== $fromOrTo) {
$mFrom->setTime(0, 0, 0);
$mFrom->setDate($mFrom->format('Y'), $mFrom->format('m'), 1);
$mTo = clone($mFrom);
$mTo->setDate($mFrom->format('Y'), 13, 1);
} else {
$mTo->setTime(0, 0, 0);
$mFrom = clone($mTo);
$mFrom->setDate($mFrom->format('Y'), 1, 1);
$mTo->setDate($mTo->format('Y'), $mTo->format('m'), 1);
}
} else {
$mFrom->setDate($mFrom->format('Y'), $mFrom->format('m'), 1);
$mFrom->setTime(0, 0, 0);
$mTo->setDate($mTo->format('Y'), $mTo->format('m'), 1);
$mTo->setTime(0, 0, 0);
}

return new DatePeriod($mFrom, new DateInterval('P1M'), $mTo, self::CREATE_TO !== $fromOrTo || $from->format('Y') == $to->format('Y') ? self::EXCLUDE_START_DATE : null);
}

public static function createForYear(DateTime $from, DateTime $to)
{
$from->setDate($from->format('Y'), 1, 1);
$from->setTime(0, 0, 0);
$to->setDate($to->format('Y'), 1, 1);
$to->setTime(0, 0, 0);

return new DatePeriod($from, new DateInterval('P1Y'), $to, self::EXCLUDE_START_DATE);
}
}
14 changes: 14 additions & 0 deletions src/FreeAgent/Bitter/Event/Year.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace FreeAgent\Bitter\Event;

/**
* @author Jérémy Romey <jeremy@free-agent.fr>
*/
class Year extends AbstractEvent implements EventInterface
{
public function getDateTimeFormated()
{
return sprintf('%s', $this->getDateTime()->format('Y'));
}
}
66 changes: 66 additions & 0 deletions tests/units/Bitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,72 @@ public function testbitOpXor($redisClient)
$this->removeAll($redisClient);
}

/**
* @dataProvider dataProviderTestedClients
*/
public function testBitDatePeriod($redisClient)
{
$bitter = new TestedBitter($redisClient, $this->getPrefixKey(), $this->getPrefixTempKey());

$this->removeAll($redisClient);

$dateTime = DateTime::createFromFormat('Y-m-d H:i:s', '2011-11-06 15:30:45');
$bitter->mark('drink_a_bitter_beer', 1, $dateTime);
$dateTime = DateTime::createFromFormat('Y-m-d H:i:s', '2012-10-12 15:30:45');
$bitter->mark('drink_a_bitter_beer', 2, $dateTime);

$this
->if($from = DateTime::createFromFormat('Y-m-d H:i:s', '2012-10-05 15:30:45'))
->and($to = DateTime::createFromFormat('Y-m-d H:i:s', '2012-12-07 15:30:45'))
->and($bitter->bitDatePeriod('drink_a_bitter_beer', 'test_create_date_period', $from, $to))
->then()
->object($bitter->bitDatePeriod('drink_a_bitter_beer', 'test_create_date_period', $from, $to))
->isIdenticalTo($bitter)
;

$this
->if($prefixKey = $this->getPrefixKey())
->and($prefixTempKey = $this->getPrefixTempKey())
->exception(
function() use ($redisClient, $prefixKey, $prefixTempKey) {
$bitter = new TestedBitter($redisClient, $prefixKey, $prefixTempKey);
$from = DateTime::createFromFormat('Y-m-d H:i:s', '2012-12-07 15:30:45');
$to = DateTime::createFromFormat('Y-m-d H:i:s', '2012-12-07 14:30:45');
$bitter->bitDatePeriod('drink_a_bitter_beer', 'test_create_date_period', $from, $to);
}
)
->hasMessage("DateTime from (2012-12-07 15:30:45) must be anterior to DateTime to (2012-12-07 14:30:45).")
;

$this
->if($from = DateTime::createFromFormat('Y-m-d H:i:s', '2010-10-05 20:30:45'))
->and($to = DateTime::createFromFormat('Y-m-d H:i:s', '2012-12-07 12:30:45'))
->and($bitter->bitDatePeriod('drink_a_bitter_beer', 'test_create_date_period', $from, $to))
->then()
->boolean($bitter->in(1, 'test_create_date_period'))
->isTrue()
->boolean($bitter->in(2, 'test_create_date_period'))
->isTrue()
->integer($bitter->count('test_create_date_period'))
->isEqualTo(2)
;

$this
->if($from = DateTime::createFromFormat('Y-m-d H:i:s', '2012-09-05 20:30:45'))
->and($to = DateTime::createFromFormat('Y-m-d H:i:s', '2012-12-07 12:30:45'))
->and($bitter->bitDatePeriod('drink_a_bitter_beer', 'test_create_date_period', $from, $to))
->then()
->boolean($bitter->in(1, 'test_create_date_period'))
->isFalse()
->boolean($bitter->in(2, 'test_create_date_period'))
->isTrue()
->integer($bitter->count('test_create_date_period'))
->isEqualTo(1)
;

$this->removeAll($redisClient);
}

/**
* @dataProvider dataProviderTestedClients
*/
Expand Down
Loading

0 comments on commit d632371

Please sign in to comment.