From 8a104508b98a51e91cf8209089409b6b4599234a Mon Sep 17 00:00:00 2001 From: Thibaut Date: Wed, 9 Mar 2022 10:21:08 +0100 Subject: [PATCH 01/10] Add php8.1 enum support --- spec/SM/DummyEnumState.php | 11 ++++++++ spec/SM/StateMachine/StateMachineSpec.php | 24 +++++++++++++++++ src/SM/StateMachine/StateMachine.php | 32 ++++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 spec/SM/DummyEnumState.php diff --git a/spec/SM/DummyEnumState.php b/spec/SM/DummyEnumState.php new file mode 100644 index 0000000..7907d6c --- /dev/null +++ b/spec/SM/DummyEnumState.php @@ -0,0 +1,11 @@ +getPossibleTransitions()->shouldReturn(array('create', 'confirm')); } + + + + function it_should_return_back_enum_value($object) + { + $object->getState()->shouldBeCalled()->willReturn(DummyEnumState::Checkout); + $this->setEnumClass(DummyEnumState::class); + $this->getState()->shouldReturn(DummyEnumState::Checkout->value); + } + + function it_throws_exeception_if_enum_class_in_not_backed($object) + { + $this->shouldThrow(SMException::class)->during('setEnumClass', array('dummy_string')); + } + + function it_not_throws_an_exception_during_apply_when_state_is_back_enum($object, $callbackFactory, CallbackInterface $guard, $dispatcher) + { + $object->getState()->shouldBeCalled()->willReturn(DummyEnumState::Checkout); + $this->setEnumClass(DummyEnumState::class); + $dispatcher->dispatch(Argument::any())->shouldNotBeCalled(); + $this->shouldNotThrow(SMException::class)->during('apply',array(DummyEnumState::Pending)); + } + } diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 2868d4f..15d8edf 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -35,6 +35,9 @@ class StateMachine implements StateMachineInterface /** @var CallbackFactoryInterface */ protected $callbackFactory; + /** @var ?string */ + protected $enumClass; + /** * @param object $object Underlying object for the state machine * @param array $config Config array of the graph @@ -59,6 +62,8 @@ public function __construct( $this->config = $config; + $this->setEnumClass(isset($config['enumClass']) ? $config['enumClass'] : null); + // Test if the given object has the given state property path if (!$this->hasObjectProperty($object, $config['property_path'])) { throw new SMException(sprintf( @@ -147,7 +152,13 @@ public function apply(string $transition, $soft = false): bool public function getState(): string { $accessor = new PropertyAccessor(); - return $accessor->getValue($this->object, $this->config['property_path']); + $state = $accessor->getValue($this->object, $this->config['property_path']); + + if(($enumClass = $this->getEnumClass()) && is_a($state,$enumClass,true)){ + return (string) $state->value; + } + + return $state; } /** @@ -195,6 +206,10 @@ protected function setState($state): void )); } + if($enumClass = $this->getEnumClass()){ + $state = $enumClass::from($state); + } + $accessor = new PropertyAccessor(); $accessor->setValue($this->object, $this->config['property_path'], $state); } @@ -223,4 +238,19 @@ protected function hasObjectProperty($object, string $property): bool { return (new PropertyAccessor())->isReadable($object, $property); } + + public function getEnumClass() : ?string + { + return $this->enumClass; + } + + public function setEnumClass(?string $class) : self + { + if($class && !is_a($class,\BackedEnum::class,true)){ + throw new SMException(sprintf('Enum class should be a BackedEnum')); + } + + $this->enumClass = $class; + return $this; + } } From 33eb90679f2f677c6b03558d9273bc7021a3f84b Mon Sep 17 00:00:00 2001 From: Thibaut Date: Wed, 9 Mar 2022 16:03:18 +0100 Subject: [PATCH 02/10] php<8.1 phpspec compatibility --- spec/SM/DummyEnumState.php | 24 +++++++++++++------ spec/SM/StateMachine/StateMachineSpec.php | 28 +++++++++++++++++------ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/spec/SM/DummyEnumState.php b/spec/SM/DummyEnumState.php index 7907d6c..8eafe20 100644 --- a/spec/SM/DummyEnumState.php +++ b/spec/SM/DummyEnumState.php @@ -2,10 +2,20 @@ namespace spec\SM; -enum DummyEnumState:string -{ - case Checkout = 'checkout'; - case Pending = 'pending'; - case Confirmed = 'confirmed'; - case Cancelled = 'cancelled'; -} \ No newline at end of file +if (version_compare(PHP_VERSION, '8.1', '>=')) { + enum DummyEnumState: string + { + case Checkout = 'checkout'; + case Pending = 'pending'; + case Confirmed = 'confirmed'; + case Cancelled = 'cancelled'; + } +} else { + class DummyEnumState + { + const Checkout = 'checkout'; + const Pending = 'pending'; + const Confirmed = 'confirmed'; + const Cancelled = 'cancelled'; + } +} diff --git a/spec/SM/StateMachine/StateMachineSpec.php b/spec/SM/StateMachine/StateMachineSpec.php index 6b59571..0868576 100644 --- a/spec/SM/StateMachine/StateMachineSpec.php +++ b/spec/SM/StateMachine/StateMachineSpec.php @@ -10,7 +10,6 @@ use SM\Event\TransitionEvent; use SM\SMException; use SM\StateMachine\StateMachine; -use spec\SM\DummyEnumState; use spec\SM\DummyObject; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -214,22 +213,37 @@ function it_returns_possible_transitions($object, $callbackFactory, CallbackInte function it_should_return_back_enum_value($object) { - $object->getState()->shouldBeCalled()->willReturn(DummyEnumState::Checkout); - $this->setEnumClass(DummyEnumState::class); - $this->getState()->shouldReturn(DummyEnumState::Checkout->value); + if (version_compare(PHP_VERSION, '8.1', '<')) { + return; + } + + $object->getState()->shouldBeCalled()->willReturn(\spec\SM\DummyEnumState::Checkout); + $this->setEnumClass(\spec\SM\DummyEnumState::class); + $state = \spec\SM\DummyEnumState::Checkout; + if(property_exists($state,'value')){ + $this->getState()->shouldReturn($state->value); + } } function it_throws_exeception_if_enum_class_in_not_backed($object) { + if (version_compare(PHP_VERSION, '8.1', '<')) { + return; + } + $this->shouldThrow(SMException::class)->during('setEnumClass', array('dummy_string')); } function it_not_throws_an_exception_during_apply_when_state_is_back_enum($object, $callbackFactory, CallbackInterface $guard, $dispatcher) { - $object->getState()->shouldBeCalled()->willReturn(DummyEnumState::Checkout); - $this->setEnumClass(DummyEnumState::class); + if (version_compare(PHP_VERSION, '8.1', '<')) { + return; + } + + $object->getState()->shouldBeCalled()->willReturn(\spec\SM\DummyEnumState::Checkout); + $this->setEnumClass(\spec\SM\DummyEnumState::class); $dispatcher->dispatch(Argument::any())->shouldNotBeCalled(); - $this->shouldNotThrow(SMException::class)->during('apply',array(DummyEnumState::Pending)); + $this->shouldNotThrow(SMException::class)->during('apply',array(\spec\SM\DummyEnumState::Pending)); } } From 826412ddb43a9f0d67240c53dad5684640c2fc18 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 16:59:22 +0200 Subject: [PATCH 03/10] Update spec/SM/StateMachine/StateMachineSpec.php Co-authored-by: Kevin Kaniaburka --- spec/SM/StateMachine/StateMachineSpec.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/SM/StateMachine/StateMachineSpec.php b/spec/SM/StateMachine/StateMachineSpec.php index 0868576..dfca18a 100644 --- a/spec/SM/StateMachine/StateMachineSpec.php +++ b/spec/SM/StateMachine/StateMachineSpec.php @@ -220,7 +220,8 @@ function it_should_return_back_enum_value($object) $object->getState()->shouldBeCalled()->willReturn(\spec\SM\DummyEnumState::Checkout); $this->setEnumClass(\spec\SM\DummyEnumState::class); $state = \spec\SM\DummyEnumState::Checkout; - if(property_exists($state,'value')){ + + if (property_exists($state, 'value')) { $this->getState()->shouldReturn($state->value); } } From d6a3b154fd9b46d167f74ecf83b145699313ad33 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 16:59:32 +0200 Subject: [PATCH 04/10] Update spec/SM/StateMachine/StateMachineSpec.php Co-authored-by: Kevin Kaniaburka --- spec/SM/StateMachine/StateMachineSpec.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/SM/StateMachine/StateMachineSpec.php b/spec/SM/StateMachine/StateMachineSpec.php index dfca18a..576adef 100644 --- a/spec/SM/StateMachine/StateMachineSpec.php +++ b/spec/SM/StateMachine/StateMachineSpec.php @@ -244,7 +244,7 @@ function it_not_throws_an_exception_during_apply_when_state_is_back_enum($object $object->getState()->shouldBeCalled()->willReturn(\spec\SM\DummyEnumState::Checkout); $this->setEnumClass(\spec\SM\DummyEnumState::class); $dispatcher->dispatch(Argument::any())->shouldNotBeCalled(); - $this->shouldNotThrow(SMException::class)->during('apply',array(\spec\SM\DummyEnumState::Pending)); + $this->shouldNotThrow(SMException::class)->during('apply', array(\spec\SM\DummyEnumState::Pending)); } } From 5ca0e3350fe27743cf9639c7191eb2a87895b481 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:00:45 +0200 Subject: [PATCH 05/10] Update src/SM/StateMachine/StateMachine.php Co-authored-by: Kevin Kaniaburka --- src/SM/StateMachine/StateMachine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 15d8edf..89004dd 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -62,7 +62,7 @@ public function __construct( $this->config = $config; - $this->setEnumClass(isset($config['enumClass']) ? $config['enumClass'] : null); + $this->setEnumClass($config['enumClass'] ?? null); // Test if the given object has the given state property path if (!$this->hasObjectProperty($object, $config['property_path'])) { From 161b395c602f091c77e3f38e2a467c70dc007e08 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:00:54 +0200 Subject: [PATCH 06/10] Update src/SM/StateMachine/StateMachine.php Co-authored-by: Kevin Kaniaburka --- src/SM/StateMachine/StateMachine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 89004dd..38da0f6 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -154,7 +154,7 @@ public function getState(): string $accessor = new PropertyAccessor(); $state = $accessor->getValue($this->object, $this->config['property_path']); - if(($enumClass = $this->getEnumClass()) && is_a($state,$enumClass,true)){ + if (($enumClass = $this->getEnumClass()) && is_a($state, $enumClass, true)) { return (string) $state->value; } From 09e0d3e64840cc01784da295773016f98481073c Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:01:04 +0200 Subject: [PATCH 07/10] Update src/SM/StateMachine/StateMachine.php Co-authored-by: Kevin Kaniaburka --- src/SM/StateMachine/StateMachine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 38da0f6..34e5208 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -206,7 +206,7 @@ protected function setState($state): void )); } - if($enumClass = $this->getEnumClass()){ + if ($enumClass = $this->getEnumClass()) { $state = $enumClass::from($state); } From e5defcf06aeddbea4c513a9f64c794dc982ef762 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:01:12 +0200 Subject: [PATCH 08/10] Update src/SM/StateMachine/StateMachine.php Co-authored-by: Kevin Kaniaburka --- src/SM/StateMachine/StateMachine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 34e5208..c08fb65 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -239,7 +239,7 @@ protected function hasObjectProperty($object, string $property): bool return (new PropertyAccessor())->isReadable($object, $property); } - public function getEnumClass() : ?string + public function getEnumClass(): ?string { return $this->enumClass; } From 5253425f545fcdff01cec3341332852d3002fac2 Mon Sep 17 00:00:00 2001 From: tdumalin <33619699+tdumalin@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:01:19 +0200 Subject: [PATCH 09/10] Update src/SM/StateMachine/StateMachine.php Co-authored-by: Kevin Kaniaburka --- src/SM/StateMachine/StateMachine.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index c08fb65..f711922 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -244,13 +244,14 @@ public function getEnumClass(): ?string return $this->enumClass; } - public function setEnumClass(?string $class) : self + public function setEnumClass(?string $class): self { - if($class && !is_a($class,\BackedEnum::class,true)){ - throw new SMException(sprintf('Enum class should be a BackedEnum')); + if ($class && !is_a($class, \BackedEnum::class, true)) { + throw new SMException('Enum class must be a BackedEnum'); } $this->enumClass = $class; + return $this; } } From a2c82449ba66f4ec92b71de751eda186dbf03010 Mon Sep 17 00:00:00 2001 From: Thibaut Date: Wed, 20 Apr 2022 17:12:07 +0200 Subject: [PATCH 10/10] add skip test depending on php version --- spec/SM/StateMachine/StateMachineSpec.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/SM/StateMachine/StateMachineSpec.php b/spec/SM/StateMachine/StateMachineSpec.php index 576adef..7d6bf61 100644 --- a/spec/SM/StateMachine/StateMachineSpec.php +++ b/spec/SM/StateMachine/StateMachineSpec.php @@ -2,6 +2,7 @@ namespace spec\SM\StateMachine; +use PhpSpec\Exception\Example\SkippingException; use PhpSpec\ObjectBehavior; use Prophecy\Argument; use SM\Callback\CallbackFactoryInterface; @@ -237,9 +238,7 @@ function it_throws_exeception_if_enum_class_in_not_backed($object) function it_not_throws_an_exception_during_apply_when_state_is_back_enum($object, $callbackFactory, CallbackInterface $guard, $dispatcher) { - if (version_compare(PHP_VERSION, '8.1', '<')) { - return; - } + $this->checkPhpMinimumVersion('8.1'); $object->getState()->shouldBeCalled()->willReturn(\spec\SM\DummyEnumState::Checkout); $this->setEnumClass(\spec\SM\DummyEnumState::class); @@ -247,4 +246,10 @@ function it_not_throws_an_exception_during_apply_when_state_is_back_enum($object $this->shouldNotThrow(SMException::class)->during('apply', array(\spec\SM\DummyEnumState::Pending)); } + private function checkPhpMinimumVersion($version) + { + if (version_compare(PHP_VERSION, $version, '<')) { + throw new SkippingException(sprintf("Minimum php version: %s", $version)); + } + } }