Overview

Namespaces

  • None
  • Peridot
    • Leo
      • Formatter
      • Interfaces
        • Assert
      • Matcher
        • Template
      • ObjectPath
      • Responder
  • PHP

Classes

  • AbstractMatcher
  • CountableMatcher
  • EmptyMatcher
  • EqualMatcher
  • ExceptionMatcher
  • GreaterThanMatcher
  • GreaterThanOrEqualMatcher
  • InclusionMatcher
  • InstanceofMatcher
  • KeysMatcher
  • LengthMatcher
  • LessThanMatcher
  • LessThanOrEqualMatcher
  • Match
  • NullMatcher
  • PatternMatcher
  • PredicateMatcher
  • PropertyMatcher
  • RangeMatcher
  • SameMatcher
  • SubStringMatcher
  • TrueMatcher
  • TruthyMatcher
  • TypeMatcher

Interfaces

  • MatcherInterface
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: namespace Peridot\Leo\Matcher;
  3: 
  4: use Peridot\Leo\Matcher\Template\ArrayTemplate;
  5: use Peridot\Leo\Matcher\Template\TemplateInterface;
  6: use Peridot\Leo\ObjectPath\ObjectPath;
  7: use Peridot\Leo\ObjectPath\ObjectPathValue;
  8: 
  9: /**
 10:  * PropertyMatcher determines if the actual array or object has the expected property, and optionally matches
 11:  * an expected value for that property.
 12:  *
 13:  * @package Peridot\Leo\Matcher
 14:  */
 15: class PropertyMatcher extends AbstractMatcher
 16: {
 17:     /**
 18:      * @var string|int
 19:      */
 20:     protected $key;
 21: 
 22:     /**
 23:      * @var mixed
 24:      */
 25:     protected $value;
 26: 
 27:     /**
 28:      * @var mixed
 29:      */
 30:     protected $actualValue;
 31: 
 32:     /**
 33:      * @var bool
 34:      */
 35:     protected $actualValueSet = false;
 36: 
 37:     /**
 38:      * @var bool
 39:      */
 40:     protected $isDeep = false;
 41: 
 42:     /**
 43:      * @param mixed $key
 44:      * @param string $value
 45:      */
 46:     public function __construct($key, $value = "")
 47:     {
 48:         $this
 49:             ->setKey($key)
 50:             ->setValue($value);
 51:     }
 52: 
 53:     /**
 54:      * Return the expected object or array key.
 55:      *
 56:      * @return int|string
 57:      */
 58:     public function getKey()
 59:     {
 60:         return $this->key;
 61:     }
 62: 
 63:     /**
 64:      * Set the expected object or array key.
 65:      *
 66:      * @param int|string $key
 67:      * @return $this
 68:      */
 69:     public function setKey($key)
 70:     {
 71:         $this->key = $key;
 72:         return $this;
 73:     }
 74: 
 75:     /**
 76:      * Return the expected property value.
 77:      *
 78:      * @return mixed
 79:      */
 80:     public function getValue()
 81:     {
 82:         return $this->value;
 83:     }
 84: 
 85:     /**
 86:      * Set the expected property value.
 87:      *
 88:      * @param mixed $value
 89:      * @return $this
 90:      */
 91:     public function setValue($value)
 92:     {
 93:         $this->value = $value;
 94:         return $this;
 95:     }
 96: 
 97:     /**
 98:      * {@inheritdoc}
 99:      *
100:      * @return TemplateInterface
101:      */
102:     public function getDefaultTemplate()
103:     {
104:         list($default, $negated) = $this->getTemplateStrings();
105: 
106:         $template = new ArrayTemplate([
107:             'default' => $default,
108:             'negated' => $negated
109:         ]);
110: 
111:         return $template->setTemplateVars([
112:             'key' => $this->getKey(),
113:             'value' => $this->getValue(),
114:             'actualValue' => $this->getActualValue()
115:         ]);
116:     }
117: 
118:     /**
119:      * Return the actual value given to the matcher.
120:      *
121:      * @return mixed
122:      */
123:     public function getActualValue()
124:     {
125:         return $this->actualValue;
126:     }
127: 
128:     /**
129:      * Set the actual value given to the matcher. Used to
130:      * store whether or not the actual value was set.
131:      *
132:      * @param mixed $actualValue
133:      * @return $this
134:      */
135:     public function setActualValue($actualValue)
136:     {
137:         $this->actualValue = $actualValue;
138:         $this->actualValueSet = true;
139:         return $this;
140:     }
141: 
142:     /**
143:      * Return if the actual value has been set.
144:      *
145:      * @return bool
146:      */
147:     public function isActualValueSet()
148:     {
149:         return $this->actualValueSet;
150:     }
151: 
152:     /**
153:      * Tell the property matcher to match deep properties.
154:      *
155:      * return $this
156:      */
157:     public function setIsDeep($isDeep)
158:     {
159:         $this->isDeep = $isDeep;
160:         return $this;
161:     }
162: 
163:     /**
164:      * Return whether or not the matcher is matching deep properties.
165:      *
166:      * @return bool
167:      */
168:     public function isDeep()
169:     {
170:         return $this->isDeep;
171:     }
172: 
173:     /**
174:      * Matches if the actual value has a property, optionally matching
175:      * the expected value of that property. If the deep flag is set,
176:      * the matcher will use the ObjectPath utility to parse deep expressions.
177:      *
178:      * @code
179:      *
180:      * $this->doMatch('child->name->first', 'brian');
181:      *
182:      * @endcode
183:      *
184:      * @param mixed $actual
185:      * @return mixed
186:      */
187:     protected function doMatch($actual)
188:     {
189:         $this->validateActual($actual);
190: 
191:         if ($this->isDeep()) {
192:             return $this->matchDeep($actual);
193:         }
194: 
195:         $actual = $this->actualToArray($actual);
196: 
197:         return $this->matchArrayIndex($actual);
198:     }
199: 
200:     /**
201:      * Convert the actual value to an array, whether it is an object or an array.
202:      *
203:      * @param object|array $actual
204:      * @return array|object
205:      */
206:     protected function actualToArray($actual)
207:     {
208:         if (is_object($actual)) {
209:             return get_object_vars($actual);
210:         }
211:         return $actual;
212:     }
213: 
214:     /**
215:      * Match that an array index exists, and matches
216:      * the expected value if set.
217:      *
218:      * @param $actual
219:      * @return bool
220:      */
221:     protected function matchArrayIndex($actual)
222:     {
223:         if (isset($actual[$this->getKey()])) {
224:             $this->assertion->setActual($actual[$this->getKey()]);
225:             return $this->isExpected($actual[$this->getKey()]);
226:         }
227: 
228:         return false;
229:     }
230: 
231:     /**
232:      * Uses ObjectPath to parse an expression if the deep flag
233:      * is set.
234:      *
235:      * @param $actual
236:      * @return bool
237:      */
238:     protected function matchDeep($actual)
239:     {
240:         $path = new ObjectPath($actual);
241:         $value = $path->get($this->getKey());
242: 
243:         if (is_null($value)) {
244:             return false;
245:         }
246: 
247:         $this->assertion->setActual($value->getPropertyValue());
248: 
249:         return $this->isExpected($value->getPropertyValue());
250:     }
251: 
252:     /**
253:      * Check if the given value is expected.
254:      *
255:      * @param $value
256:      * @return bool
257:      */
258:     protected function isExpected($value)
259:     {
260:         if ($expected = $this->getValue()) {
261:             $this->setActualValue($value);
262:             return $this->getActualValue() === $expected;
263:         }
264: 
265:         return true;
266:     }
267: 
268:     /**
269:      * Ensure that the actual value is an object or an array.
270:      *
271:      * @param $actual
272:      */
273:     protected function validateActual($actual)
274:     {
275:         if (!is_object($actual) && !is_array($actual)) {
276:             throw new \InvalidArgumentException("PropertyMatcher expects an object or an array");
277:         }
278:     }
279: 
280:     /**
281:      * Returns the strings used in creating the template for the matcher.
282:      *
283:      * @return array
284:      */
285:     protected function getTemplateStrings()
286:     {
287:         $default = "Expected {{actual}} to have a{{deep}}property {{key}}";
288:         $negated = "Expected {{actual}} to not have a{{deep}}property {{key}}";
289:         
290:         if ($this->getValue() && $this->isActualValueSet()) {
291:             $default = "Expected {{actual}} to have a{{deep}}property {{key}} of {{value}}, but got {{actualValue}}";
292:             $negated = "Expected {{actual}} to not have a{{deep}}property {{key}} of {{value}}";
293:         }
294: 
295:         $deep = ' ';
296:         if ($this->isDeep()) {
297:             $deep = ' deep ';
298:         }
299: 
300:         return str_replace('{{deep}}', $deep, [$default, $negated]);
301:     }
302: }
303: 
Leo API documentation generated by ApiGen