Skip to content

Commit

Permalink
added StepLabel class to avoid issues with labels that are also PHP…
Browse files Browse the repository at this point in the history
… function names
  • Loading branch information
craue committed Mar 23, 2016
1 parent 03b0604 commit 7519ee8
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 22 deletions.
11 changes: 11 additions & 0 deletions Exception/StepLabelCallableInvalidReturnValueException.php
@@ -0,0 +1,11 @@
<?php

namespace Craue\FormFlowBundle\Exception;

/**
* @author Christian Raue <christian.raue@gmail.com>
* @copyright 2011-2016 Christian Raue
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class StepLabelCallableInvalidReturnValueException extends \RuntimeException {
}
27 changes: 14 additions & 13 deletions Form/Step.php
Expand Up @@ -3,6 +3,7 @@
namespace Craue\FormFlowBundle\Form;

use Craue\FormFlowBundle\Exception\InvalidTypeException;
use Craue\FormFlowBundle\Exception\StepLabelCallableInvalidReturnValueException;
use Symfony\Component\Form\FormTypeInterface;

/**
Expand All @@ -18,7 +19,7 @@ class Step implements StepInterface {
protected $number;

/**
* @var string|callable|null
* @var string|StepLabel|null
*/
protected $label = null;

Expand Down Expand Up @@ -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;
}

/**
Expand Down
83 changes: 83 additions & 0 deletions Form/StepLabel.php
@@ -0,0 +1,83 @@
<?php

namespace Craue\FormFlowBundle\Form;

use Craue\FormFlowBundle\Exception\InvalidTypeException;
use Craue\FormFlowBundle\Exception\StepLabelCallableInvalidReturnValueException;

/**
* @author Christian Raue <christian.raue@gmail.com>
* @copyright 2011-2016 Christian Raue
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class StepLabel {

/**
* @var boolean If <code>$value</code> 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;
}

}
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -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.
Expand Down Expand Up @@ -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'),
Expand Down
106 changes: 106 additions & 0 deletions Tests/Form/StepLabelTest.php
@@ -0,0 +1,106 @@
<?php

namespace Craue\FormFlowBundle\Tests\Form;

use Craue\FormFlowBundle\Form\StepLabel;
use Craue\FormFlowBundle\Tests\UnitTestCase;

/**
* @group unit
*
* @author Christian Raue <christian.raue@gmail.com>
* @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;
}

}
15 changes: 9 additions & 6 deletions Tests/Form/StepTest.php
Expand Up @@ -4,6 +4,7 @@

use Craue\FormFlowBundle\Form\FormFlowInterface;
use Craue\FormFlowBundle\Form\Step;
use Craue\FormFlowBundle\Form\StepLabel;
use Craue\FormFlowBundle\Tests\UnitTestCase;

/**
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -131,6 +132,7 @@ public function testSetGetLabel($label) {
public function dataSetGetLabel() {
return array(
array('label'),
array('date'),
array(null),
);
}
Expand All @@ -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());
Expand Down Expand Up @@ -206,6 +208,7 @@ public function dataSetGetLabel_invalidArguments() {
return array(
array(true),
array(1.1),
array(function() { return 'label'; }),
);
}

Expand Down Expand Up @@ -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;
},
}),
));
}

Expand Down

0 comments on commit 7519ee8

Please sign in to comment.