Skip to content

Commit b9ba6d0

Browse files
committed
Add magic get/setters for non-base fields (#948)
1 parent 5be41b8 commit b9ba6d0

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

src/Entity/FieldableEdgeEntityBase.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
use Drupal\Core\Entity\EntityTypeInterface;
2727
use Drupal\Core\Field\BaseFieldDefinition;
2828
use Drupal\Core\Field\FieldStorageDefinitionInterface;
29+
use Drupal\Core\Language\LanguageInterface;
30+
use Drupal\Core\TypedData\TypedDataInterface;
2931

3032
/**
3133
* Base field support for Apigee Entities without making them content entities.
@@ -536,4 +538,128 @@ public function getIterator(): \Traversable {
536538
return new \ArrayIterator($this->getFields());
537539
}
538540

541+
/**
542+
* The plain data values of the contained fields.
543+
*
544+
* This always holds the original, unchanged values of the entity. The values
545+
* are keyed by language code to follow core's suit, regardless that
546+
* Apigee Edge entities are NOT translatable.
547+
*
548+
* @todo: Add methods for getting original fields and for determining
549+
* changes.
550+
* @todo: Provide a better way for defining default values.
551+
*
552+
* @var array
553+
*/
554+
private $values = [];
555+
556+
/**
557+
* Implements the magic method for getting object properties.
558+
*
559+
* @see https://www.drupal.org/project/drupal/issues/3281720
560+
* @see \Drupal\Core\Entity\ContentEntityBase
561+
*/
562+
public function &__get($name) {
563+
// If this is an entity field, handle it accordingly. We first check whether
564+
// a field object has been already created. If not, we create one.
565+
if (isset($this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED])) {
566+
return $this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED];
567+
}
568+
// Inline getFieldDefinition() to speed things up.
569+
if (!isset($this->fieldDefinitions)) {
570+
$this->getFieldDefinitions();
571+
}
572+
// Apigee base fields are special, so they need special treatment.
573+
if (isset($this->fieldDefinitions[$name]) && !($this->fieldDefinitions[$name] instanceof BaseFieldDefinition)) {
574+
$return = $this->getField($name);
575+
return $return;
576+
}
577+
// Else directly read/write plain values. That way, non-field entity
578+
// properties can always be accessed directly.
579+
if (!isset($this->values[$name])) {
580+
$this->values[$name] = NULL;
581+
}
582+
return $this->values[$name];
583+
}
584+
585+
/**
586+
* Implements the magic method for setting object properties.
587+
*
588+
* Uses default language always.
589+
*/
590+
public function __set($name, $value) {
591+
// Inline getFieldDefinition() to speed things up.
592+
if (!isset($this->fieldDefinitions)) {
593+
$this->getFieldDefinitions();
594+
}
595+
// Handle Field API fields.
596+
if (isset($this->fieldDefinitions[$name])) {
597+
// Support setting values via property objects.
598+
if ($value instanceof TypedDataInterface) {
599+
$value = $value->getValue();
600+
}
601+
// If a FieldItemList object already exists, set its value.
602+
if (isset($this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED])) {
603+
$this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED]->setValue($value);
604+
}
605+
// If not, create one.
606+
else {
607+
$this->getField($name)->setValue($value);
608+
}
609+
}
610+
// Directly write non-field values.
611+
else {
612+
$this->values[$name] = $value;
613+
}
614+
}
615+
616+
/**
617+
* Implements the magic method for isset().
618+
*/
619+
public function __isset($name) {
620+
// "Official" Field API fields are always set. For non-field properties,
621+
// check the internal values.
622+
return $this->hasField($name) ? TRUE : isset($this->values[$name]);
623+
}
624+
625+
/**
626+
* Implements the magic method for unset().
627+
*/
628+
public function __unset($name) {
629+
// Unsetting a field means emptying it.
630+
if ($this->hasField($name)) {
631+
$this->get($name)->setValue([]);
632+
}
633+
// For non-field properties, unset the internal value.
634+
else {
635+
unset($this->values[$name]);
636+
}
637+
}
638+
639+
/**
640+
* Gets a non-translatable field.
641+
*
642+
* @return \Drupal\Core\Field\FieldItemListInterface
643+
*/
644+
private function getField($name) {
645+
// Populate $this->fields to speed-up further look-ups and to keep track of
646+
// fields objects, possibly holding changes to field values.
647+
if (!isset($this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED])) {
648+
$definition = $this->getFieldDefinition($name);
649+
if (!$definition) {
650+
throw new \InvalidArgumentException("Field $name is unknown.");
651+
}
652+
// Non-translatable fields are always stored with
653+
// LanguageInterface::LANGCODE_DEFAULT as key.
654+
$value = NULL;
655+
if (isset($this->values[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED])) {
656+
$value = $this->values[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED];
657+
}
658+
$field = \Drupal::service('plugin.manager.field.field_type')->createFieldItemList($this->getTranslation(LanguageInterface::LANGCODE_NOT_SPECIFIED), $name, $value);
659+
$field->setLangcode(LanguageInterface::LANGCODE_NOT_SPECIFIED);
660+
$this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED] = $field;
661+
}
662+
return $this->fields[$name][LanguageInterface::LANGCODE_NOT_SPECIFIED];
663+
}
664+
539665
}

0 commit comments

Comments
 (0)