From ec40d08307310a5944d0fe727cb2af2efe0f75d7 Mon Sep 17 00:00:00 2001 From: Nicolas Eeckeloo Date: Tue, 21 Apr 2015 19:28:58 +0200 Subject: [PATCH 1/5] Temporal expression builder implementation --- src/TemporalExpression/Builder.php | 132 ++++++++++++++++++ .../Exception/UnexpectedValueException.php | 8 ++ tests/TemporalExpression/BuilderTest.php | 36 +++++ 3 files changed, 176 insertions(+) create mode 100644 src/TemporalExpression/Builder.php create mode 100644 src/TemporalExpression/Exception/UnexpectedValueException.php create mode 100644 tests/TemporalExpression/BuilderTest.php diff --git a/src/TemporalExpression/Builder.php b/src/TemporalExpression/Builder.php new file mode 100644 index 0000000..8ded35e --- /dev/null +++ b/src/TemporalExpression/Builder.php @@ -0,0 +1,132 @@ + DayInMonth::class, + 'dayInWeek' => DayInWeek::class, + 'monthInYear' => MonthInYear::class, + 'semester' => Semester::class, + 'trimester' => Trimester::class, + 'year' => Year::class, + ]; + + /** + * @param string $name + * @param TemporalExpressionInterface $expression + * @return self + */ + public function addTemporalExpression($name, TemporalExpressionInterface $expression) + { + if ($this->hasTemporalExpression($name)) { + throw new Exception\UnexpectedValueException(sprintf( + 'The temporal expression "%s" already exists', + $name + )); + } + + $this->temporalExpressions[$name] = $expression; + return $this; + } + + /** + * @param string $name + * @return self + */ + public function hasTemporalExpression($name) + { + return array_key_exists($name, $this->temporalExpressions); + } + + /** + * @return Union + */ + public function union() + { + $union = new Union(); + + $expressions = func_get_args(); + foreach ($expressions as $expression) { + $union->addElement($expression); + } + + return $union; + } + + /** + * @return Intersection + */ + public function intersect() + { + $intersection = new Intersection(); + + $expressions = func_get_args(); + foreach ($expressions as $expression) { + $intersection->addElement($expression); + } + + return $intersection; + } + + public function __call($name, $arguments) + { + return $this->createTemporalExpression($name, $arguments); + } + + private function createTemporalExpression($name, array $params = []) + { + if (!$this->hasTemporalExpression($name)) { + throw new Exception\UnexpectedValueException(sprintf( + 'Temporal expression "%s" does not exists', + $name + )); + } + + $class = new \ReflectionClass($this->temporalExpressions[$name]); + + return $class->newInstanceArgs($params); + } +} diff --git a/src/TemporalExpression/Exception/UnexpectedValueException.php b/src/TemporalExpression/Exception/UnexpectedValueException.php new file mode 100644 index 0000000..9a79baa --- /dev/null +++ b/src/TemporalExpression/Exception/UnexpectedValueException.php @@ -0,0 +1,8 @@ +union( + // tous les lundi du mois de mars + $builder->intersect($builder->dayInWeek(Builder::MONDAY), $builder->monthInYear(Builder::MARCH)), + + // tous les jours du mois de mai + $builder->monthInYear(Builder::MAY), + + // tous les jours de l'année 2016 + $builder->year(2016), + + // tous les jours du 1er semestre 2017 + $builder->intersect($builder->semester(1), $builder->year(2017)) + ); + + $this->assertInstanceOf(TemporalExpressionInterface::class, $temporalExpression); + + $this->assertTrue($temporalExpression->includes(new \DateTime('2015-03-02'))); + $this->assertTrue($temporalExpression->includes(new \DateTime('2015-03-09'))); + $this->assertFalse($temporalExpression->includes(new \DateTime('2015-03-03'))); + $this->assertFalse($temporalExpression->includes(new \DateTime('2015-04-02'))); + $this->assertTrue($temporalExpression->includes(new \DateTime('2015-05-15'))); + $this->assertTrue($temporalExpression->includes(new \DateTime('2016-09-15'))); + } +} From d0002ff0a018b4156a6822660fe4aaf124cb2aa8 Mon Sep 17 00:00:00 2001 From: Nicolas Eeckeloo Date: Wed, 22 Apr 2015 09:48:51 +0200 Subject: [PATCH 2/5] Rewrite builder --- src/TemporalExpression/Builder.php | 120 +++++++++++------- .../Exception/BadMethodCallException.php | 9 ++ src/TemporalExpression/Factory.php | 65 ++++++++++ tests/TemporalExpression/BuilderTest.php | 35 +++-- 4 files changed, 171 insertions(+), 58 deletions(-) create mode 100644 src/TemporalExpression/Exception/BadMethodCallException.php create mode 100644 src/TemporalExpression/Factory.php diff --git a/src/TemporalExpression/Builder.php b/src/TemporalExpression/Builder.php index 8ded35e..52752c2 100644 --- a/src/TemporalExpression/Builder.php +++ b/src/TemporalExpression/Builder.php @@ -42,91 +42,121 @@ class Builder const FRIDAY = 5; const SATURDAY = 6; + /** + * @var Factory + */ + protected $factory; + + /** + * @var TemporalExpressionInterface + */ + protected $expression; + /** * @var array */ - protected $temporalExpressions = [ - 'dayInMonth' => DayInMonth::class, - 'dayInWeek' => DayInWeek::class, - 'monthInYear' => MonthInYear::class, - 'semester' => Semester::class, - 'trimester' => Trimester::class, - 'year' => Year::class, - ]; + protected $stack; /** - * @param string $name - * @param TemporalExpressionInterface $expression * @return self */ - public function addTemporalExpression($name, TemporalExpressionInterface $expression) + public function startUnion() { - if ($this->hasTemporalExpression($name)) { - throw new Exception\UnexpectedValueException(sprintf( - 'The temporal expression "%s" already exists', - $name - )); - } + $this->stack[] = new Union(); - $this->temporalExpressions[$name] = $expression; return $this; } /** - * @param string $name * @return self */ - public function hasTemporalExpression($name) + public function endUnion() { - return array_key_exists($name, $this->temporalExpressions); + return $this->endComposite(); } /** - * @return Union + * @return self */ - public function union() + public function startIntersect() { - $union = new Union(); + $this->stack[] = new Intersection(); - $expressions = func_get_args(); - foreach ($expressions as $expression) { - $union->addElement($expression); - } + return $this; + } - return $union; + /** + * @return self + */ + public function endIntersect() + { + return $this->endComposite(); } /** - * @return Intersection + * @return self */ - public function intersect() + private function endComposite() { - $intersection = new Intersection(); + $expression = array_pop($this->stack); + + if (empty($this->stack)) { + $this->expression = $expression; + } else { + $composite = end($this->stack); + $composite->addElement($expression); + } - $expressions = func_get_args(); - foreach ($expressions as $expression) { - $intersection->addElement($expression); + return $this; + } + + /** + * @return TemporalExpressionInterface + */ + public function getExpression() + { + if (!empty($this->stack)) { + throw new Exception\BadMethodCallException('The expression cannot be created.'); } - return $intersection; + return $this->expression; } public function __call($name, $arguments) { - return $this->createTemporalExpression($name, $arguments); + $expression = $this->getFactory()->createTemporalExpression($name, $arguments); + + if (empty($this->stack)) { + $this->expression = $expression; + return $this; + } + + $composite = end($this->stack); + $composite->addElement($expression); + + $key = key($this->stack); + $this->stack[$key] = $composite; + + return $this; } - private function createTemporalExpression($name, array $params = []) + /** + * @return Factory + */ + public function getFactory() { - if (!$this->hasTemporalExpression($name)) { - throw new Exception\UnexpectedValueException(sprintf( - 'Temporal expression "%s" does not exists', - $name - )); + if (!$this->factory) { + $this->factory = new Factory(); } - $class = new \ReflectionClass($this->temporalExpressions[$name]); + return $this->factory; + } - return $class->newInstanceArgs($params); + /** + * @param Factory $factory + */ + public function setFactory(Factory $factory) + { + $this->factory = $factory; } } diff --git a/src/TemporalExpression/Exception/BadMethodCallException.php b/src/TemporalExpression/Exception/BadMethodCallException.php new file mode 100644 index 0000000..bc457c2 --- /dev/null +++ b/src/TemporalExpression/Exception/BadMethodCallException.php @@ -0,0 +1,9 @@ + DayInMonth::class, + 'dayInWeek' => DayInWeek::class, + 'monthInYear' => MonthInYear::class, + 'semester' => Semester::class, + 'trimester' => Trimester::class, + 'year' => Year::class, + ]; + + /** + * @param string $name + * @param TemporalExpressionInterface $expression + * @return self + */ + public function addTemporalExpression($name, TemporalExpressionInterface $expression) + { + if ($this->hasTemporalExpression($name)) { + throw new Exception\UnexpectedValueException(sprintf( + 'The temporal expression "%s" already exists', + $name + )); + } + + $this->expressions[$name] = $expression; + + return $this; + } + + /** + * @param string $name + * @return self + */ + public function hasTemporalExpression($name) + { + return array_key_exists($name, $this->expressions); + } + + /** + * @param string $name + * @param array $params + * @return TemporalExpressionInterface + * @throws Exception\UnexpectedValueException + */ + public function createTemporalExpression($name, array $params = []) + { + if (!$this->hasTemporalExpression($name)) { + throw new Exception\UnexpectedValueException(sprintf( + 'Temporal expression "%s" does not exists', + $name + )); + } + + $class = new \ReflectionClass($this->expressions[$name]); + + return $class->newInstanceArgs($params); + } +} diff --git a/tests/TemporalExpression/BuilderTest.php b/tests/TemporalExpression/BuilderTest.php index 66fc616..a1a95cf 100644 --- a/tests/TemporalExpression/BuilderTest.php +++ b/tests/TemporalExpression/BuilderTest.php @@ -10,19 +10,28 @@ public function testIncludesDateWhenProvidedDateAtSameMonthDayShouldReturnTrue() { $builder = new Builder(); - $temporalExpression = $builder->union( - // tous les lundi du mois de mars - $builder->intersect($builder->dayInWeek(Builder::MONDAY), $builder->monthInYear(Builder::MARCH)), - - // tous les jours du mois de mai - $builder->monthInYear(Builder::MAY), - - // tous les jours de l'année 2016 - $builder->year(2016), - - // tous les jours du 1er semestre 2017 - $builder->intersect($builder->semester(1), $builder->year(2017)) - ); + $temporalExpression = $builder + ->startUnion() + // tous les lundi du mois de mars + ->startIntersect() + ->dayInWeek(Builder::MONDAY) + ->monthInYear(Builder::MARCH) + ->endIntersect() + + // tous les jours du mois de mai + ->monthInYear(Builder::MAY) + + // tous les jours de l'année 2016 + ->year(2016) + + // tous les jours du 1er semestre 2017 + ->startIntersect() + ->semester(1) + ->year(2017) + ->endIntersect() + + ->endUnion() + ->getExpression(); $this->assertInstanceOf(TemporalExpressionInterface::class, $temporalExpression); From 7af7d09c6a6876b294859ada0ff97f49a4aedb96 Mon Sep 17 00:00:00 2001 From: Nicolas Eeckeloo Date: Wed, 22 Apr 2015 10:39:12 +0200 Subject: [PATCH 3/5] Use SplStack --- src/TemporalExpression/Builder.php | 101 ++++++++++++++++------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/src/TemporalExpression/Builder.php b/src/TemporalExpression/Builder.php index 52752c2..773ca2a 100644 --- a/src/TemporalExpression/Builder.php +++ b/src/TemporalExpression/Builder.php @@ -10,6 +10,7 @@ use Riskio\Schedule\TemporalExpression\TemporalExpressionInterface; use Riskio\Schedule\TemporalExpression\Trimester; use Riskio\Schedule\TemporalExpression\Year; +use SplStack; /** * @method DayInWeek dayInWeek() dayInWeek(int $dayIndex) @@ -53,110 +54,118 @@ class Builder protected $expression; /** - * @var array + * @var SplStack */ protected $stack; + public function __construct() + { + $this->stack = new SplStack(); + } + /** - * @return self + * @return Factory */ - public function startUnion() + public function getFactory() { - $this->stack[] = new Union(); + if (!$this->factory) { + $this->factory = new Factory(); + } - return $this; + return $this->factory; } /** - * @return self + * @param Factory $factory */ - public function endUnion() + public function setFactory(Factory $factory) { - return $this->endComposite(); + $this->factory = $factory; } /** * @return self */ - public function startIntersect() + public function startUnion() { - $this->stack[] = new Intersection(); + $this->stack->push(new Union()); return $this; } /** * @return self + * @throws Exception\BadMethodCallException */ - public function endIntersect() + public function endUnion() { - return $this->endComposite(); + $expression = $this->stack->pop(); + if (!$expression instanceof Union) { + throw new Exception\BadMethodCallException('Another composite must be ended before'); + } + + $this->aggregateExpression($expression); + + return $this; } /** * @return self */ - private function endComposite() + public function startIntersect() { - $expression = array_pop($this->stack); - - if (empty($this->stack)) { - $this->expression = $expression; - } else { - $composite = end($this->stack); - $composite->addElement($expression); - } + $this->stack->push(new Intersection()); return $this; } /** - * @return TemporalExpressionInterface + * @return self + * @throws Exception\BadMethodCallException */ - public function getExpression() + public function endIntersect() { - if (!empty($this->stack)) { - throw new Exception\BadMethodCallException('The expression cannot be created.'); + $expression = $this->stack->pop(); + if (!$expression instanceof Intersection) { + throw new Exception\BadMethodCallException('Another composite must be ended before'); } - return $this->expression; + $this->aggregateExpression($expression); + + return $this; } public function __call($name, $arguments) { $expression = $this->getFactory()->createTemporalExpression($name, $arguments); - if (empty($this->stack)) { - $this->expression = $expression; - return $this; - } - - $composite = end($this->stack); - $composite->addElement($expression); - - $key = key($this->stack); - $this->stack[$key] = $composite; + $this->aggregateExpression($expression); return $this; } /** - * @return Factory + * @return TemporalExpressionInterface + * @throws Exception\BadMethodCallException */ - public function getFactory() + public function getExpression() { - if (!$this->factory) { - $this->factory = new Factory(); + if ($this->stack->count() > 0) { + throw new Exception\BadMethodCallException('The expression cannot be created'); } - return $this->factory; + return $this->expression; } - /** - * @param Factory $factory - */ - public function setFactory(Factory $factory) + private function aggregateExpression(TemporalExpressionInterface $expression) { - $this->factory = $factory; + if ($this->stack->count() == 0) { + $this->expression = $expression; + } else { + $this->stack->rewind(); + + $composite = $this->stack->current(); + $composite->addElement($expression); + } } } From cf7aa586ab3b62521a474b4eccd0f69e22547da8 Mon Sep 17 00:00:00 2001 From: Nicolas Eeckeloo Date: Wed, 22 Apr 2015 10:41:23 +0200 Subject: [PATCH 4/5] Update stack property name --- src/TemporalExpression/Builder.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/TemporalExpression/Builder.php b/src/TemporalExpression/Builder.php index 773ca2a..651ef7a 100644 --- a/src/TemporalExpression/Builder.php +++ b/src/TemporalExpression/Builder.php @@ -56,11 +56,11 @@ class Builder /** * @var SplStack */ - protected $stack; + protected $expressionStack; public function __construct() { - $this->stack = new SplStack(); + $this->expressionStack = new SplStack(); } /** @@ -88,7 +88,7 @@ public function setFactory(Factory $factory) */ public function startUnion() { - $this->stack->push(new Union()); + $this->expressionStack->push(new Union()); return $this; } @@ -99,7 +99,7 @@ public function startUnion() */ public function endUnion() { - $expression = $this->stack->pop(); + $expression = $this->expressionStack->pop(); if (!$expression instanceof Union) { throw new Exception\BadMethodCallException('Another composite must be ended before'); } @@ -114,7 +114,7 @@ public function endUnion() */ public function startIntersect() { - $this->stack->push(new Intersection()); + $this->expressionStack->push(new Intersection()); return $this; } @@ -125,7 +125,7 @@ public function startIntersect() */ public function endIntersect() { - $expression = $this->stack->pop(); + $expression = $this->expressionStack->pop(); if (!$expression instanceof Intersection) { throw new Exception\BadMethodCallException('Another composite must be ended before'); } @@ -150,7 +150,7 @@ public function __call($name, $arguments) */ public function getExpression() { - if ($this->stack->count() > 0) { + if ($this->expressionStack->count() > 0) { throw new Exception\BadMethodCallException('The expression cannot be created'); } @@ -159,12 +159,12 @@ public function getExpression() private function aggregateExpression(TemporalExpressionInterface $expression) { - if ($this->stack->count() == 0) { + if ($this->expressionStack->count() == 0) { $this->expression = $expression; } else { - $this->stack->rewind(); + $this->expressionStack->rewind(); - $composite = $this->stack->current(); + $composite = $this->expressionStack->current(); $composite->addElement($expression); } } From 61d12f4a5f8ffe90a06637663baaa97b4e68b42f Mon Sep 17 00:00:00 2001 From: Nicolas Eeckeloo Date: Wed, 22 Apr 2015 10:43:11 +0200 Subject: [PATCH 5/5] Minor fix --- src/TemporalExpression/Factory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TemporalExpression/Factory.php b/src/TemporalExpression/Factory.php index 62ac5cc..b133204 100644 --- a/src/TemporalExpression/Factory.php +++ b/src/TemporalExpression/Factory.php @@ -36,7 +36,7 @@ public function addTemporalExpression($name, TemporalExpressionInterface $expres /** * @param string $name - * @return self + * @return bool */ public function hasTemporalExpression($name) {