diff --git a/Exception/StepLabelCallableInvalidReturnValueException.php b/Exception/StepLabelCallableInvalidReturnValueException.php new file mode 100644 index 00000000..23d77ada --- /dev/null +++ b/Exception/StepLabelCallableInvalidReturnValueException.php @@ -0,0 +1,11 @@ + + * @copyright 2011-2016 Christian Raue + * @license http://opensource.org/licenses/mit-license.php MIT License + */ +class StepLabelCallableInvalidReturnValueException extends \RuntimeException { +} diff --git a/Form/Step.php b/Form/Step.php index 9b90d7b8..d2c0d81d 100644 --- a/Form/Step.php +++ b/Form/Step.php @@ -3,6 +3,7 @@ namespace Craue\FormFlowBundle\Form; use Craue\FormFlowBundle\Exception\InvalidTypeException; +use Craue\FormFlowBundle\Exception\StepLabelCallableInvalidReturnValueException; use Symfony\Component\Form\FormTypeInterface; /** @@ -18,7 +19,7 @@ class Step implements StepInterface { protected $number; /** - * @var string|callable|null + * @var string|StepLabel|null */ protected $label = null; @@ -92,34 +93,34 @@ public function getNumber() { } /** - * @param string|callable|null $label + * @param string|StepLabel|null $label */ public function setLabel($label) { - if ($label === null || is_string($label) || is_callable($label)) { + if (is_string($label)) { + $this->label = StepLabel::createStringLabel($label); + + return; + } + + if ($label === null || $label instanceof StepLabel) { $this->label = $label; return; } - throw new InvalidTypeException($label, array('null', 'string', 'callable')); + throw new InvalidTypeException($label, array('null', 'string', 'Craue\FormFlowBundle\Form\StepLabel')); } /** * {@inheritDoc} */ public function getLabel() { - if (is_callable($this->label)) { - $returnValue = call_user_func($this->label); - - if ($returnValue === null || is_string($returnValue)) { - return $returnValue; - } - + try { + return $this->label !== null ? $this->label->getText() : null; + } catch (StepLabelCallableInvalidReturnValueException $e) { throw new \RuntimeException(sprintf('The label callable for step %d did not return a string or null value.', $this->number)); } - - return $this->label; } /** diff --git a/Form/StepLabel.php b/Form/StepLabel.php new file mode 100644 index 00000000..a3159042 --- /dev/null +++ b/Form/StepLabel.php @@ -0,0 +1,83 @@ + + * @copyright 2011-2016 Christian Raue + * @license http://opensource.org/licenses/mit-license.php MIT License + */ +class StepLabel { + + /** + * @var boolean If $value is callable. + */ + private $callable; + + /** + * @var string|callable|null + */ + private $value = null; + + /** + * @param string|null $value + */ + public static function createStringLabel($value) { + return new static($value); + } + + /** + * @param callable $value + */ + public static function createCallableLabel($value) { + return new static($value, true); + } + + /** + * @return string|null + */ + public function getText() { + if ($this->callable) { + $returnValue = call_user_func($this->value); + + if ($returnValue === null || is_string($returnValue)) { + return $returnValue; + } + + throw new StepLabelCallableInvalidReturnValueException(); + } + + return $this->value; + } + + /** + * @param string|callable|null $value + * @param boolean $callable + */ + private function __construct($value, $callable = false) { + $this->setValue($value, $callable); + } + + /** + * @param string|callable|null $value + * @param boolean $callable + */ + private function setValue($value, $callable = false) { + if ($callable) { + if (!is_callable($value)) { + throw new InvalidTypeException($value, array('callable')); + } + } else { + if ($value !== null && !is_string($value)) { + throw new InvalidTypeException($value, array('null', 'string')); + } + } + + $this->callable = $callable; + $this->value = $value; + } + +} diff --git a/README.md b/README.md index d45984e6..6f497dcf 100644 --- a/README.md +++ b/README.md @@ -355,9 +355,9 @@ The array returned by that method is used to create all steps of the flow. The first item will be the first step. You can, however, explicitly index the array for easier readability. Valid options per step are: -- `label` (`string`|`callable`|`null`) +- `label` (`string`|`StepLabel`|`null`) - If you'd like to render an overview of all steps you have to set the `label` option for each step. - - If using a callable, it has to return a string value or `null`. + - If using a callable on a `StepLabel` instance, it has to return a string value or `null`. - By default, the labels will be translated using the `messages` domain when rendered in Twig. - `form_type` (`FormTypeInterface`|`string`|`null`) - The form type used to build the form for that step. @@ -397,7 +397,7 @@ protected function loadStepsConfig() { 'form_type' => 'MyCompany\MyBundle\Form\CreateVehicleStep1Form', ), 2 => array( - 'label' => 'engine', + 'label' => StepLabel::createCallableLabel(function() { return 'engine'; }) 'form_type' => 'MyCompany\MyBundle\Form\CreateVehicleStep2Form', 'form_options' => array( 'validation_groups' => array('Default'), diff --git a/Tests/Form/StepLabelTest.php b/Tests/Form/StepLabelTest.php new file mode 100644 index 00000000..47febfe7 --- /dev/null +++ b/Tests/Form/StepLabelTest.php @@ -0,0 +1,106 @@ + + * @copyright 2011-2016 Christian Raue + * @license http://opensource.org/licenses/mit-license.php MIT License + */ +class StepLabelTest extends UnitTestCase { + + /** + * @dataProvider dataCreateStringLabel + */ + public function testCreateStringLabel($value) { + $this->assertSame($value, StepLabel::createStringLabel($value)->getText()); + } + + public function dataCreateStringLabel() { + return array( + array('label'), + array('date'), + array(null), + ); + } + + /** + * @dataProvider dataCreateStringLabel_invalidArgument + * @expectedException \Craue\FormFlowBundle\Exception\InvalidTypeException + */ + public function testCreateStringLabel_invalidArgument($value) { + StepLabel::createStringLabel($value); + } + + public function dataCreateStringLabel_invalidArgument() { + return array( + array(true), + array(1.1), + array(function() { return 'country'; }), + ); + } + + /** + * @dataProvider dataCreateCallableLabel + */ + public function testCreateCallableLabel($value, $expectedText) { + $this->assertSame($expectedText, StepLabel::createCallableLabel($value)->getText()); + } + + public function dataCreateCallableLabel() { + return array( + array('Craue\FormFlowBundle\Tests\Form\StepLabelTest::_returnString', 'label'), + array('Craue\FormFlowBundle\Tests\Form\StepLabelTest::_returnNull', null), + array(function() { return 'label'; }, 'label'), + ); + } + + /** + * @dataProvider dataCreateCallableLabel_invalidArgument + * @expectedException \InvalidArgumentException + */ + public function testCreateCallableLabel_invalidArgument($value) { + StepLabel::createCallableLabel($value)->getText(); + } + + public function dataCreateCallableLabel_invalidArgument() { + return array( + array('label'), + array('UnknownClass::unknownMethod'), + array(null), + ); + } + + /** + * @dataProvider dataGetText_callableInvalidReturnValue + * @expectedException Craue\FormFlowBundle\Exception\StepLabelCallableInvalidReturnValueException + */ + public function testGetText_callableInvalidReturnValue($value) { + StepLabel::createCallableLabel($value)->getText(); + } + + public function dataGetText_callableInvalidReturnValue() { + return array( + array('Craue\FormFlowBundle\Tests\Form\StepLabelTest::_returnOne'), + array(function() { return 1; }), + ); + } + + public static function _returnString() { + return 'label'; + } + + public static function _returnNull() { + return; + } + + public static function _returnOne() { + return 1; + } + +} diff --git a/Tests/Form/StepTest.php b/Tests/Form/StepTest.php index 80b348d4..9b6514ca 100644 --- a/Tests/Form/StepTest.php +++ b/Tests/Form/StepTest.php @@ -4,6 +4,7 @@ use Craue\FormFlowBundle\Form\FormFlowInterface; use Craue\FormFlowBundle\Form\Step; +use Craue\FormFlowBundle\Form\StepLabel; use Craue\FormFlowBundle\Tests\UnitTestCase; /** @@ -33,9 +34,9 @@ public function testCreateFromConfig() { $this->assertEquals('country', $step->getLabel()); $step = Step::createFromConfig(1, array( - 'label' => function() { + 'label' => StepLabel::createCallableLabel(function() { return 'country'; - }, + }), )); $this->assertEquals('country', $step->getLabel()); @@ -131,6 +132,7 @@ public function testSetGetLabel($label) { public function dataSetGetLabel() { return array( array('label'), + array('date'), array(null), ); } @@ -151,9 +153,9 @@ public function testSetGetLabel_callableReturnValueDependsOnFlowData() { ; $step = Step::createFromConfig(1, array( - 'label' => function() use ($flow) { + 'label' => StepLabel::createCallableLabel(function() use ($flow) { return $flow->getFormData() === 'special' ? 'special label' : 'default label'; - }, + }), )); $this->assertSame('special label', $step->getLabel()); @@ -206,6 +208,7 @@ public function dataSetGetLabel_invalidArguments() { return array( array(true), array(1.1), + array(function() { return 'label'; }), ); } @@ -331,9 +334,9 @@ public function dataEvaluateSkipping_invalidReturnValueFromCallable() { protected function createStepWithLabelCallable($number, $returnValue) { return Step::createFromConfig($number, array( - 'label' => function() use ($returnValue) { + 'label' => StepLabel::createCallableLabel(function() use ($returnValue) { return $returnValue; - }, + }), )); }