Chris@0: Chris@0: * Marcello Duarte Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Prophecy\Argument\Token; Chris@0: Chris@0: use Prophecy\Exception\InvalidArgumentException; Chris@0: Chris@0: /** Chris@0: * Array entry token. Chris@0: * Chris@0: * @author Boris Mikhaylov Chris@0: */ Chris@0: class ArrayEntryToken implements TokenInterface Chris@0: { Chris@0: /** @var \Prophecy\Argument\Token\TokenInterface */ Chris@0: private $key; Chris@0: /** @var \Prophecy\Argument\Token\TokenInterface */ Chris@0: private $value; Chris@0: Chris@0: /** Chris@0: * @param mixed $key exact value or token Chris@0: * @param mixed $value exact value or token Chris@0: */ Chris@0: public function __construct($key, $value) Chris@0: { Chris@0: $this->key = $this->wrapIntoExactValueToken($key); Chris@0: $this->value = $this->wrapIntoExactValueToken($value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Scores half of combined scores from key and value tokens for same entry. Capped at 8. Chris@0: * If argument implements \ArrayAccess without \Traversable, then key token is restricted to ExactValueToken. Chris@0: * Chris@0: * @param array|\ArrayAccess|\Traversable $argument Chris@0: * Chris@0: * @throws \Prophecy\Exception\InvalidArgumentException Chris@0: * @return bool|int Chris@0: */ Chris@0: public function scoreArgument($argument) Chris@0: { Chris@0: if ($argument instanceof \Traversable) { Chris@0: $argument = iterator_to_array($argument); Chris@0: } Chris@0: Chris@0: if ($argument instanceof \ArrayAccess) { Chris@0: $argument = $this->convertArrayAccessToEntry($argument); Chris@0: } Chris@0: Chris@0: if (!is_array($argument) || empty($argument)) { Chris@0: return false; Chris@0: } Chris@0: Chris@0: $keyScores = array_map(array($this->key,'scoreArgument'), array_keys($argument)); Chris@0: $valueScores = array_map(array($this->value,'scoreArgument'), $argument); Chris@0: $scoreEntry = function ($value, $key) { Chris@0: return $value && $key ? min(8, ($key + $value) / 2) : false; Chris@0: }; Chris@0: Chris@0: return max(array_map($scoreEntry, $valueScores, $keyScores)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns false. Chris@0: * Chris@0: * @return boolean Chris@0: */ Chris@0: public function isLast() Chris@0: { Chris@0: return false; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns string representation for token. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: public function __toString() Chris@0: { Chris@0: return sprintf('[..., %s => %s, ...]', $this->key, $this->value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns key Chris@0: * Chris@0: * @return TokenInterface Chris@0: */ Chris@0: public function getKey() Chris@0: { Chris@0: return $this->key; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns value Chris@0: * Chris@0: * @return TokenInterface Chris@0: */ Chris@0: public function getValue() Chris@0: { Chris@0: return $this->value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Wraps non token $value into ExactValueToken Chris@0: * Chris@0: * @param $value Chris@0: * @return TokenInterface Chris@0: */ Chris@0: private function wrapIntoExactValueToken($value) Chris@0: { Chris@0: return $value instanceof TokenInterface ? $value : new ExactValueToken($value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Converts instance of \ArrayAccess to key => value array entry Chris@0: * Chris@0: * @param \ArrayAccess $object Chris@0: * Chris@0: * @return array|null Chris@0: * @throws \Prophecy\Exception\InvalidArgumentException Chris@0: */ Chris@0: private function convertArrayAccessToEntry(\ArrayAccess $object) Chris@0: { Chris@0: if (!$this->key instanceof ExactValueToken) { Chris@0: throw new InvalidArgumentException(sprintf( Chris@0: 'You can only use exact value tokens to match key of ArrayAccess object'.PHP_EOL. Chris@0: 'But you used `%s`.', Chris@0: $this->key Chris@0: )); Chris@0: } Chris@0: Chris@0: $key = $this->key->getValue(); Chris@0: Chris@0: return $object->offsetExists($key) ? array($key => $object[$key]) : array(); Chris@0: } Chris@0: }