blob: 354aebd2a8c24499b1abdadaf05416ff91bcda0e [file] [log] [blame]
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Apache\Avro\Schema;
/**
* @package Avro
*/
class AvroRecordSchema extends AvroNamedSchema
{
/**
* @var AvroNamedSchema[] array of AvroNamedSchema field definitions of
* this AvroRecordSchema
*/
private $fields;
/**
* @var array map of field names to field objects.
* @internal Not called directly. Memoization of AvroRecordSchema->fieldsHash()
*/
private $fieldsHash;
/**
* @param AvroName $name
* @param string $namespace
* @param string $doc
* @param array $fields
* @param AvroNamedSchemata &$schemata
* @param string $schema_type schema type name
* @throws AvroSchemaParseException
*/
public function __construct(
$name,
$doc,
$fields,
&$schemata = null,
$schema_type = AvroSchema::RECORD_SCHEMA,
$aliases = null
) {
if (is_null($fields)) {
throw new AvroSchemaParseException(
'Record schema requires a non-empty fields attribute'
);
}
if (AvroSchema::REQUEST_SCHEMA == $schema_type) {
parent::__construct($schema_type, $name);
} else {
parent::__construct($schema_type, $name, $doc, $schemata, $aliases);
}
[$x, $namespace] = $name->nameAndNamespace();
$this->fields = self::parseFields($fields, $namespace, $schemata);
}
/**
* @param mixed $field_data
* @param string $default_namespace namespace of enclosing schema
* @param AvroNamedSchemata &$schemata
* @returns AvroField[]
* @throws AvroSchemaParseException
*/
public static function parseFields($field_data, $default_namespace, &$schemata)
{
$fields = array();
$field_names = array();
$alias_names = [];
foreach ($field_data as $index => $field) {
$name = $field[AvroField::FIELD_NAME_ATTR] ?? null;
$type = $field[AvroSchema::TYPE_ATTR] ?? null;
$order = $field[AvroField::ORDER_ATTR] ?? null;
$aliases = $field[AvroField::ALIASES_ATTR] ?? null;
$default = null;
$has_default = false;
if (array_key_exists(AvroField::DEFAULT_ATTR, $field)) {
$default = $field[AvroField::DEFAULT_ATTR];
$has_default = true;
}
if (in_array($name, $field_names)) {
throw new AvroSchemaParseException(
sprintf("Field name %s is already in use", $name)
);
}
$is_schema_from_schemata = false;
$field_schema = null;
if (
is_string($type)
&& $field_schema = $schemata->schemaByName(
new AvroName($type, null, $default_namespace)
)
) {
$is_schema_from_schemata = true;
} else {
$field_schema = self::subparse($type, $default_namespace, $schemata);
}
$new_field = new AvroField(
$name,
$field_schema,
$is_schema_from_schemata,
$has_default,
$default,
$order,
$aliases
);
$field_names[] = $name;
if ($new_field->hasAliases() && array_intersect($alias_names, $new_field->getAliases())) {
throw new AvroSchemaParseException("Alias already in use");
}
if ($new_field->hasAliases()) {
array_push($alias_names, ...$new_field->getAliases());
}
$fields[] = $new_field;
}
return $fields;
}
/**
* @returns mixed
*/
public function toAvro()
{
$avro = parent::toAvro();
$fields_avro = array();
foreach ($this->fields as $field) {
$fields_avro[] = $field->toAvro();
}
if (AvroSchema::REQUEST_SCHEMA === $this->type) {
return $fields_avro;
}
$avro[AvroSchema::FIELDS_ATTR] = $fields_avro;
return $avro;
}
/**
* @returns array the schema definitions of the fields of this AvroRecordSchema
*/
public function fields()
{
return $this->fields;
}
/**
* @returns array a hash table of the fields of this AvroRecordSchema fields
* keyed by each field's name
*/
public function fieldsHash()
{
if (is_null($this->fieldsHash)) {
$hash = array();
foreach ($this->fields as $field) {
$hash[$field->name()] = $field;
}
$this->fieldsHash = $hash;
}
return $this->fieldsHash;
}
public function fieldsByAlias()
{
$hash = [];
foreach ($this->fields as $field) {
if ($field->hasAliases()) {
foreach ($field->getAliases() as $a) {
$hash[$a] = $field;
}
}
}
return $hash;
}
}