/** * Set properties of the entity based on the request, and save the entity. * * @param \EntityDrupalWrapper $wrapper * The wrapped entity object, passed by reference. * @param array $object * The keyed array of properties sent in the payload. * @param bool $replace * Determine if properties that are missing from the request array should * be treated as NULL, or should be skipped. Defaults to FALSE, which will * set the fields to NULL. * * @throws BadRequestException * If the provided object is not valid. */ protected function setPropertyValues(\EntityDrupalWrapper $wrapper, $object, $replace = FALSE) { if (!is_array($object)) { throw new BadRequestException('Bad input data provided. Please, check your input and your Content-Type header.'); } $save = FALSE; $original_object = $object; $interpreter = new DataInterpreterEMW($this->getAccount(), $wrapper); // Keeps a list of the fields that have been set. $processed_fields = array(); $field_definitions = clone $this->fieldDefinitions; foreach ($field_definitions as $public_field_name => $resource_field) { /* @var \Drupal\restful\Plugin\resource\Field\ResourceFieldEntityInterface $resource_field */ if (!$this->methodAccess($resource_field)) { // Allow passing the value in the request. unset($original_object[$public_field_name]); continue; } $property_name = $resource_field->getProperty(); if ($resource_field->isComputed()) { // We may have for example an entity with no label property, but with a // label callback. In that case the $info['property'] won't exist, so // we skip this field. unset($original_object[$public_field_name]); continue; } $entity_property_access = $this::checkPropertyAccess($resource_field, 'edit', $interpreter); if (!array_key_exists($public_field_name, $object)) { // No property to set in the request. // Only set this to NULL if this property has not been set to a specific // value by another public field (since 2 public fields can reference // the same property). if ($replace && $entity_property_access && !in_array($property_name, $processed_fields)) { // We need to set the value to NULL. $field_value = NULL; } else { // Either we shouldn't set missing fields as NULL or access is denied // for the current property, hence we skip. continue; } } else { // Property is set in the request. // Delegate modifications on the value of the field. $field_value = $resource_field->preprocess($object[$public_field_name]); } $resource_field->set($field_value, $interpreter); // We check the property access only after setting the values, as the // access callback's response might change according to the field value. $entity_property_access = $this::checkPropertyAccess($resource_field, 'edit', $interpreter); if (!$entity_property_access) { throw new BadRequestException(format_string('Property @name cannot be set.', array('@name' => $public_field_name))); } $processed_fields[] = $property_name; unset($original_object[$public_field_name]); $save = TRUE; } if (!$save) { // No request was sent. throw new BadRequestException('No values were sent with the request'); } if ($original_object) { // Request had illegal values. $error_message = format_plural(count($original_object), 'Property @names is invalid.', 'Properties @names are invalid.', array('@names' => implode(', ', array_keys($original_object)))); throw new BadRequestException($error_message); } // Allow changing the entity just before it's saved. For example, setting // the author of the node entity. $this->entityPreSave($interpreter->getWrapper()); $this->entityValidate($interpreter->getWrapper()); $wrapper->save(); }