-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Having separate value objects for options makes it easier to understand what options are available to a command and simplifies the validation process. This change was implemented as separate classes so that usage can be upgraded incrementally and version 2.0 can remove the deprecated things.
- Loading branch information
1 parent
241c723
commit 71e4405
Showing
12 changed files
with
530 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
namespace Equip\Command; | ||
|
||
abstract class Command | ||
{ | ||
/** | ||
* @var OptionsInterface | ||
*/ | ||
private $options; | ||
|
||
/** | ||
* Execute the command using the current options. | ||
* | ||
* @return mixed | ||
*/ | ||
abstract public function execute(); | ||
|
||
/** | ||
* Allow usage as a callable. | ||
* | ||
* @see Command::execute() | ||
* | ||
* @return mixed | ||
*/ | ||
final public function __invoke() | ||
{ | ||
return $this->execute(); | ||
} | ||
|
||
/** | ||
* Get the currently defined options. | ||
* | ||
* @return OptionsInterface | ||
* | ||
* @throws CommandException | ||
* If no options have been added to the command. | ||
*/ | ||
final public function options() | ||
{ | ||
if (!$this->options) { | ||
throw CommandException::needsOptions($this); | ||
} | ||
|
||
return $this->options; | ||
} | ||
|
||
/** | ||
* Get a copy with new options. | ||
* | ||
* @param OptionsInterface $options | ||
* | ||
* @return static | ||
*/ | ||
final public function withOptions(OptionsInterface $options) | ||
{ | ||
$copy = clone $this; | ||
$copy->options = $options; | ||
|
||
return $copy; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
namespace Equip\Command; | ||
|
||
use LogicException; | ||
|
||
class ImmutableException extends LogicException | ||
{ | ||
const CANNOT_MODIFY = 1; | ||
|
||
/** | ||
* @param object $object | ||
* | ||
* @return static | ||
*/ | ||
public static function cannotModify($object) | ||
{ | ||
return new static( | ||
sprintf( | ||
'Object `%s` is immutable and cannot be modified', | ||
get_class($object) | ||
), | ||
static::CANNOT_MODIFY | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
namespace Equip\Command; | ||
|
||
/** | ||
* A general purpose value object for command options. | ||
* | ||
* When constructed, all required options must be passed. | ||
* | ||
* If any required options are missing, a `CommandException` must be thrown. | ||
*/ | ||
interface OptionsInterface | ||
{ | ||
/** | ||
* Get a list of all required options. | ||
* | ||
* return [ | ||
* 'email', | ||
* 'password', | ||
* ]; | ||
* | ||
* @return array | ||
*/ | ||
public function required(); | ||
|
||
/** | ||
* Get a list of all valid options. | ||
* | ||
* @return array | ||
*/ | ||
public function valid(); | ||
|
||
/** | ||
* Get all options as an array. | ||
* | ||
* @return array | ||
*/ | ||
public function toArray(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
|
||
namespace Equip\Command; | ||
|
||
trait OptionsTrait /* implements OptionsInterface */ | ||
{ | ||
/** | ||
* Check that all required options are defined, then hydrate. | ||
* | ||
* @param array $values | ||
*/ | ||
public function __construct(array $values) | ||
{ | ||
// Remove any values that are invalid for this set of options | ||
$values = array_intersect_key( | ||
$values, | ||
array_flip($this->valid()) | ||
); | ||
|
||
$this->ensureRequired($values); | ||
|
||
foreach ($values as $key => $value) { | ||
$this->$key = $value; | ||
} | ||
} | ||
|
||
/** | ||
* Provide read-only access to attributes. | ||
* | ||
* @param string $key | ||
* | ||
* @return mixed | ||
*/ | ||
final public function __get($key) | ||
{ | ||
return $this->{$key}; | ||
} | ||
|
||
/** | ||
* Prevent modification. | ||
* | ||
* @throws ImmutableException | ||
* | ||
* @param string $key | ||
* @param mixed $value | ||
* | ||
* @return void | ||
*/ | ||
final public function __set($key, $value) | ||
{ | ||
throw ImmutableException::cannotModify($this); | ||
} | ||
|
||
/** | ||
* Prevent modification. | ||
* | ||
* @throws ImmutableException | ||
* | ||
* @param string $key | ||
* | ||
* @return void | ||
*/ | ||
final public function __unset($key) | ||
{ | ||
throw ImmutableException::cannotModify($this); | ||
} | ||
|
||
/** | ||
* Ensure that all required options are included in the given values. | ||
* | ||
* @param array $values | ||
* | ||
* @return void | ||
* | ||
* @throws CommandException | ||
* If any required options have not been defined. | ||
*/ | ||
private function ensureRequired(array $values) | ||
{ | ||
$defined = array_filter($values, static function ($value) { | ||
return $value !== null; | ||
}); | ||
|
||
$missing = array_diff($this->required(), array_keys($defined)); | ||
|
||
if ($missing) { | ||
throw CommandException::missingOptions($missing); | ||
} | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function valid() | ||
{ | ||
return array_keys($this->toArray()); | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function toArray() | ||
{ | ||
return get_object_vars($this); | ||
} | ||
} |
Oops, something went wrong.