/**
  * Extracts the model's attributes, per JSON API spec.
  *
  * @param   array           $data
  * @param   EntityMetadata  $metadata
  * @return  array
  */
 protected function extractAttributes(array $data, EntityMetadata $metadata)
 {
     $flattened = [];
     if (!isset($data['attributes']) || !is_array($data['attributes'])) {
         return $flattened;
     }
     $keyMap = array_flip(array_keys($data['attributes']));
     foreach ($metadata->getAttributes() as $key => $attrMeta) {
         if (!isset($keyMap[$key])) {
             continue;
         }
         $flattened[$key] = $data['attributes'][$key];
     }
     return $flattened;
 }
 /**
  * Validates entity attributes on EntityMetadata.
  *
  * @param   EntityMetadata  $metadata
  * @param   MetadataFactory $mf
  * @return  bool
  * @throws  MetadataException
  */
 public function validateMetadataAttributes(EntityMetadata $metadata, MetadataFactory $mf)
 {
     foreach ($metadata->getAttributes() as $key => $attribute) {
         if ($key != $attribute->key) {
             throw MetadataException::invalidMetadata($metadata->type, sprintf('Attribute key mismtach. "%s" !== "%s"', $key, $attribute->key));
         }
         if (false === $this->isFieldKeyValid($attribute->key)) {
             throw MetadataException::invalidMetadata($metadata->type, sprintf('The attribute key "%s" is invalid based on the configured name format "%s"', $attribute->key, $this->config->getFieldKeyFormat()));
         }
         if (false === $this->typeFactory->hasType($attribute->dataType)) {
             throw MetadataException::invalidMetadata($metadata->type, sprintf('The data type "%s" for attribute "%s" is invalid', $attribute->dataType, $attribute->key));
         }
         if (true === $metadata->isChildEntity()) {
             $parent = $mf->getMetadataForType($metadata->extends);
             if ($parent->hasAttribute($attribute->key)) {
                 throw MetadataException::invalidMetadata($metadata->type, sprintf('Parent entity type "%s" already contains attribute field "%s"', $parent->type, $attribute->key));
             }
         }
         // @todo Determine how to validate object and array
         $todo = ['object', 'array'];
         if (in_array($attribute->dataType, $todo)) {
             throw MetadataException::invalidMetadata($metadata->type, 'NYI: Object and array attribute types still need expanding!!');
         }
         if (true === $attribute->isCalculated()) {
             if (false === class_exists($attribute->calculated['class']) || false === method_exists($attribute->calculated['class'], $attribute->calculated['method'])) {
                 throw MetadataException::invalidMetadata($metadata->type, sprintf('The attribute field "%s" is calculated, but was unable to find method "%s:%s"', $attribute->key, $attribute->calculated['class'], $attribute->calculated['method']));
             }
         }
     }
     return true;
 }