Skip to content

Commit

Permalink
add execution validations for builders
Browse files Browse the repository at this point in the history
  • Loading branch information
slogsdon committed Jan 12, 2015
1 parent 3f592a0 commit 2100d9c
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 44 deletions.
67 changes: 66 additions & 1 deletion src/Builder/BuilderAbstract.php
Expand Up @@ -3,20 +3,29 @@
namespace ABC\Builder;

use \ABC\Builder\BuilderAction;
use \Exception;

abstract class BuilderAbstract
{
/** @var array(\ABC\Builder\BuilderAction) */
public $builderActions = array();

/** @var bool */
public $executed = false;

/** @var array(callable) */
public $validations = array();

/**
* @return null
*/
public function executeActions()
public function execute()
{
foreach ($this->builderActions as $action) {
call_user_func_array($action->action, $action->arguments);
}
$this->validate();
$this->executed = true;
return $this;
}

Expand All @@ -28,4 +37,60 @@ public function addAction($action)
$this->builderActions[] = $action;
return $this;
}

/**
* @throws \Exception
*/
public function checkStatus()
{
if (!$this->executed) {
throw new Exception('Builder actions not executed');
}
}

/**
* @throws \Exception
*/
protected function validate()
{
$actions = $this->compileActionCounts();
foreach ($this->validations as $validation) {
$result = call_user_func_array($validation['callback'], array($actions));
if (!$result) {
$class = $validation['exceptionType'];
throw new $class($validation['exceptionMessage']);
}
}
}

/**
* @return array
*/
protected function compileActionCounts()
{
$counts = array();

foreach ($this->builderActions as $action) {
$counts[$action->name] = isset($counts[$action->name]) ? $counts[$action->name]+1 : 1;
}

return $counts;
}

/**
* @param callable $callback
* @param string $exceptionType
* @param string $exceptionMessage
*
* @return \ABC\Builder\BuilderAbstract
*/
protected function addValidation($callback, $exceptionType, $exceptionMessage = '')
{
$this->validations[] = array(
'callback' => $callback,
'exceptionType' => $exceptionType,
'exceptionMessage' => $exceptionMessage,
);
return $this;
}
}
77 changes: 71 additions & 6 deletions src/Builder/CompanyBuilder.php
Expand Up @@ -10,17 +10,20 @@

class CompanyBuilder extends BuilderAbstract
{
/** @var \ABC\Builder\Company */
public $company = null;

public function __construct($company = null)
public function __construct()
{
if ($company != null) {
$this->company = $company;
} else {
$this->company = new Company();
}
$this->company = new Company();
$this->setUpValidations();
}

/**
* @param \ABC\Builder\Address $address
*
* @return \ABC\Builder\Company
*/
public function withAddress(Address $address)
{
$action = new CompanyBuilderAction('withAddress', array($this->company, 'appendAddress'));
Expand All @@ -29,6 +32,11 @@ public function withAddress(Address $address)
return $this;
}

/**
* @param \ABC\Builder\Person $person
*
* @return \ABC\Builder\Company
*/
public function withPerson(Person $person)
{
$action = new CompanyBuilderAction('withPerson', array($this->company, 'appendPerson'));
Expand All @@ -37,13 +45,34 @@ public function withPerson(Person $person)
return $this;
}

/**
* Returns executed object as JSON.
* Throws an exception when builder actions
* have not been executed.
*
* @throws \Exception
*
* @return string
*/
public function asJson()
{
$this->checkStatus();
return json_encode($this->company);
}

/**
* Returns executed object as XML.
* Throws an exception when builder actions
* have not been executed.
*
* @throws \Exception
*
* @return string
*/
public function asXml()
{
$this->checkStatus();

$xml = new DOMDocument('1.0', 'utf-8');
$company = $xml->createElement('Company');

Expand Down Expand Up @@ -75,4 +104,40 @@ public function asXml()

return $xml->saveXml();
}

/**
* Ensures there is at least one address.
*
* @param arraay $actionCounts
*
* @return bool
*/
public function atLeastOneAddress($actionCounts)
{
return isset($actionCounts['withAddress']) && $actionCounts['withAddress'] > 0;
}

/**
* Ensures there is at least one person.
*
* @param arraay $actionCounts
*
* @return bool
*/
public function atLeastOnePerson($actionCounts)
{
return isset($actionCounts['withPerson']) && $actionCounts['withPerson'] > 0;
}

/**
* Setups up validations for building Company objects.
*
* @return null
*/
private function setUpValidations()
{
$this
->addValidation(array($this, 'atLeastOneAddress'), 'Exception', 'Company needs at least one address')
->addValidation(array($this, 'atLeastOnePerson'), 'Exception', 'Company needs at least one person');
}
}
4 changes: 2 additions & 2 deletions tests/Builder/AddressBuilderTest.php
Expand Up @@ -14,7 +14,7 @@ public function testBuilderWithInitialValueNoActions()

$this->assertEquals($this->expectedAddress(), $builder->address);

$builder = $builder->executeActions();
$builder = $builder->execute();

$this->assertEquals($this->expectedAddress(), $builder->address);
}
Expand All @@ -23,7 +23,7 @@ public function testBuilderWithoutInitialValueNoActions()
{
$builder = new AddressBuilder();

$builder = $builder->executeActions();
$builder = $builder->execute();

$this->assertEquals(new Address(), $builder->address);
}
Expand Down

0 comments on commit 2100d9c

Please sign in to comment.