/** * @param AvroSchema $schema The rules to conform to. * @param mixed $datum The value to validate against $schema. * @return string|string[] An error or list of errors in the * provided $datum. When no errors exist the empty array is * returned. */ public static function getErrors(AvroSchema $schema, $datum) { switch ($schema->type) { case AvroSchema::NULL_TYPE: if (!is_null($datum)) { return self::wrongType('null', $datum); } return array(); case AvroSchema::BOOLEAN_TYPE: if (!is_bool($datum)) { return self::wrongType('boolean', $datum); } return array(); case AvroSchema::STRING_TYPE: case AvroSchema::BYTES_TYPE: if (!is_string($datum)) { return self::wrongType('string', $datum); } return array(); case AvroSchema::INT_TYPE: if (!is_int($datum)) { return self::wrongType('integer', $datum); } if (AvroSchema::INT_MIN_VALUE > $datum || $datum > AvroSchema::INT_MAX_VALUE) { return self::outOfRange(AvroSchema::INT_MIN_VALUE, AvroSchema::INT_MAX_VALUE, $datum); } return array(); case AvroSchema::LONG_TYPE: if (!is_int($datum)) { return self::wrongType('integer', $datum); } if (AvroSchema::LONG_MIN_VALUE > $datum || $datum > AvroSchema::LONG_MAX_VALUE) { return self::outOfRange(AvroSchema::LONG_MIN_VALUE, AvroSchema::LONG_MAX_VALUE, $datum); } return array(); case AvroSchema::FLOAT_TYPE: case AvroSchema::DOUBLE_TYPE: if (!is_float($datum) && !is_int($datum)) { return self::wrongType('float or integer', $datum); } return array(); case AvroSchema::ARRAY_SCHEMA: if (!is_array($datum)) { return self::wrongType('array', $datum); } $errors = array(); foreach ($datum as $d) { $result = $this->validate($schema->items(), $d); if ($result) { $errors[] = $result; } } if ($errors) { return $errors; } return array(); case AvroSchema::MAP_SCHEMA: if (!is_array($datum)) { return self::wrongType('array', $datum); } $errors = array(); foreach ($datum as $k => $v) { if (!is_string($k)) { $errors[] = self::wrongType('string key', $k); } $result = self::getErrors($schema->values(), $v); if ($result) { $errors[$k] = $result; } } return $errors; case AvroSchema::UNION_SCHEMA: $errors = array(); foreach ($schema->schemas() as $schema) { $result = self::getErrors($schema, $datum); if (!$result) { return array(); } $errors[] = $result; } if ($errors) { return array("Expected any one of these to be true", $errors); } return "No schemas provided to union"; case AvroSchema::ENUM_SCHEMA: if (!in_array($datum, $schema->symbols())) { $symbols = implode(', ', $schema->symbols); return "Expected one of {$symbols} but recieved {$datum}"; } return array(); case AvroSchema::FIXED_SCHEMA: if (!is_string($datum)) { return self::wrongType('string', $datum); } $len = strlen($datum); if ($len !== $schema->size()) { return "Expected string of length {$schema->size()}, " . "but recieved one of length {$len}"; } return array(); case AvroSchema::RECORD_SCHEMA: case AvroSchema::ERROR_SCHEMA: case AvroSchema::REQUEST_SCHEMA: if (!is_array($datum)) { return self::wrongType('array', $datum); } $errors = array(); foreach ($schema->fields() as $field) { $name = $field->name(); if (!array_key_exists($name, $datum)) { $errors[$name] = 'Missing expected field'; continue; } $result = self::getErrors($field->type(), $datum[$name]); if ($result) { $errors[$name] = $result; } } return $errors; default: return "Unknown avro schema type: {$schema->type}"; } }