1

I have a custom module with three entities. The first represents a chemical compound. The second is a list of the periodic table of elements. The third is a many-to-many binding between these two, and also contains a "quantity" field. This last entity is to be able to create each chemical's chemical formula.

Example-combining the quantities and element symbols to produce CH4O

Entity:chemicals
id   name
1    Methanol

Entity:elements
id    symbol   name
1      H       Hydrogen
2      C       Carbon
3      O       Oxygen

Entity:chemical_formulas
id     element    chemical   quantity
1        2          1           1
2        1          1           4
3        3          1           1

I have the three entities working to the point that I can get all the correct data in the database. However, retrieving has proven a challenge.

My ChemicalFormulas class contains this function, and this seems to be where the problem is because it always returns 'null'. The ChemicalFormulas->getQuantity() function is basically the same, and it works fine.

//in the ChemicalFormulas class
public function getElement() {
   return $this->get('element')->value;
}

The field is defined as

$fields['element'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('Element'))
  ->setDescription(t('The Element.'))
  ->setRevisionable(TRUE)
  ->setSetting('target_type', 'elements')
  ->setSetting('handler', 'default')
  ->setDisplayOptions('view', array(
    'label' => 'above',
    'type' => 'string',
    'weight' => 0,
  ))
  ->setDisplayOptions('form', array(
    'type' => 'entity_reference_autocomplete',
    'weight' => 5,
    'settings' => array(
      'match_operator' => 'CONTAINS',
      'size' => '60',
      'autocomplete_type' => 'tags',
      'placeholder' => '',
    ),
  ))
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayConfigurable('view', TRUE);

I am trying to produce the formula with this function

public function getFormula(){
  $query = \Drupal::entityQuery('chemical_formulas')
    ->condition('chemical', $this->id());

  $ids = $query->execute();
  $entries = entity_load_multiple('chemical_formulas', $ids);
  $formula = "";
  foreach ($entries as $entry){
    //Is element supposed to be an entity or the id of an entity?
    //$element = $entry->getElement(); //If it's an entity
    $element = entity_load('elements', $entry->getElement()); //If it's an integer.
    $symbol = $element->getSymbol();
    $quantity = $entry->getQuantity();
    if ($quantity == 1) {
      $quantity = "";
    }
    $formula .= $symbol . $quantity;
  }
  return $formula;
}

2 Answers 2

0

Entities part:

I think (as much you showed) your entity definition is wrong:

  1. Entity names should be always SINGULAR: Chemical, Element, Chemical Formula
  2. Your Chemical Formula should have the ability to hold reference to MULTIPLE elements (H20 for example, has H and O elements). Which means you won't able to store this information in this entity table, but you will have to create an external table to hold this information. You can find example for this in core entities (like taxonomy_terms, if I remember good).
  3. If you make this changes right, you won't have query anything, since the referenced entity ids (elements, chemical) will be present in your entity. You only have to load via EntityTypeManager.

Final hint again: always examine core / contrib entities. Node, Taxonomy terms are pretty good examples.

3
  • Thanks for the advice on the singular names for the coding standards..but that's not the problem. Commented Jun 9, 2016 at 13:36
  • What about the other parts?
    – ssibal
    Commented Jun 9, 2016 at 13:40
  • Looked at taxonomy, but it was out of my league. It uses some custom storage class that I don't understand. Commented Jun 9, 2016 at 13:50
0

This gets the function to work the way it is.

public function getElement() {
  return $this->get('element')->entity;
}

public function getElementId() {
  return $this->get('element')->target_id;
}

If anyone has any suggestions on a better way to design the system to make it behave more optimally, let me know. For example, is there a built in drupal8 way to create many-to-many relationships without having to explicitly define the connecting table as a separate entity?

6
  • There is, if you add fields via the interface. It will be pretty easy then. Then you can still write functions, to retrieve target id's, you only have to make checks, whether the field is an entity_reference field, and if it has multiple values enabled.
    – ssibal
    Commented Jun 9, 2016 at 13:41
  • You said, "add fields via the interface". Can this not be done in code? Commented Jun 9, 2016 at 13:47
  • Of course it can, but you need to understand, that you can't (shouldn't force t) store a multiple valued field in one column. And when you are defining your base fields, you will have to use an external table for "elements". You will also have to store each element quantity. This will lead to custom solutions. I don't think it's that bad, from future perspective it's wise to go custom entities, but it will be slow in the beginning.
    – ssibal
    Commented Jun 9, 2016 at 13:54
  • I come from a straight SQL background, and my current table design (entity relationship design) is how it would be done there. My field definitions in the ChemicalFormula class DOES contain a quantity field as shown above, so I AM storing the quantity, and it's not in "one column". I have no idea what an "external table" is in Drupal. I guess I have to read more tutorials. Commented Jun 9, 2016 at 14:02
  • Since this problem is getting pretty custom and also complex, am glad to help you in private!
    – ssibal
    Commented Jun 9, 2016 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.