Skip to content

Commit

Permalink
Merge pull request tripal#1931 from tripal/tv4g1-issue1930-publish-ti…
Browse files Browse the repository at this point in the history
…tle-difference

Remove double-space collapse for publish
  • Loading branch information
laceysanderson authored Aug 23, 2024
2 parents 0661de6 + 00fdcb1 commit 2d7d298
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 29 deletions.
39 changes: 37 additions & 2 deletions tripal/src/Entity/TripalEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Drupal\field\Entity\FieldConfig;
use Symfony\Component\Routing\Route;
use Drupal\tripal\TripalField\TripalFieldItemBase;
use \Drupal\tripal\Services\TripalTokenParser;

/**
* Defines the Tripal Content entity.
Expand Down Expand Up @@ -121,16 +122,19 @@ public function label() {
*/
public function setTitle($title = NULL, $cache = []) {

// Get the bundle object.
if (isset($cache['bundle'])) {
$bundle = $cache['bundle'];
}
else {
$bundle = \Drupal\tripal\Entity\TripalEntityType::load($this->getType());
}

$title = $bundle->getTitleFormat();
$title = $this->replaceTokens($title, $bundle);
// Get the values of the current entity.
$entity_values = $this->getFieldValues();

// Use the token parser directly.
$title = TripalTokenParser::getEntityTitle($bundle, $entity_values);
$this->title = $title;
}

Expand Down Expand Up @@ -246,6 +250,37 @@ public function setPublished($published) {
return $this;
}

/**
* Retrieves the values of the current entity as a nested array.
*
* @return array
* This is a nested array with the first keys being field names. Within each
* array for a given field the keys are delta and the values are an array of
* the property names => values for that field delta.
*/
public function getFieldValues() {
$values = [];

$field_defs = $this->getFieldDefinitions();
foreach ($field_defs as $field_name => $field_def) {
/** @var \Drupal\Core\Field\FieldItemList $items **/
$items = $this->get($field_name);
$values[$field_name] = [];
/** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item **/
foreach ($items as $delta => $item) {
$values[$field_name][$delta] = [];
/** @var \Drupal\Core\TypedData\TypedDataInterface $prop **/
$props = $item->getProperties();
if (is_array($props)) {
foreach ($props as $prop) {
$values[$field_name][$delta][$prop->getName()] = $prop->getValue();
}
}
}
}
return $values;
}

/**
* Replaces tokens in a given tokens in URL Aliases and Titles.
*
Expand Down
34 changes: 12 additions & 22 deletions tripal/src/Services/TripalPublish.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Drupal\tripal\Services;

use \Drupal\tripal\TripalStorage\StoragePropertyValue;
use \Drupal\tripal\Services\TripalTokenParser;
use \Drupal\tripal\Services\TripalJob;

class TripalPublish {
Expand Down Expand Up @@ -497,32 +498,21 @@ protected function getEntityTitles($matches) {
$titles = [];
$title_format = $this->entity_type->getTitleFormat();

// Iterate through the results and build the bulk SQL statements that
// will publish the records.
// Iterate through each match we are checking for an existing entity for.
foreach ($matches as $match) {
$entity_title = $title_format;
foreach ($match as $field_name => $deltas) {
if (preg_match("/\[$field_name\]/", $title_format)) {

// There should only be one delta for the fields that
// are used for title formats so default this to 0.
$delta = 0;
$field = $this->field_info[$field_name]['instance'];
$main_prop = $field->mainPropertyName();
$value = '';
if (array_key_exists($delta, $match[$field_name])) {
$value = $match[$field_name][$delta][$main_prop]['value']->getValue();
// Collapse match array to follow the format expected by getEntityTitle.
$entity_values = [];
foreach ($match as $field_name => $field_items) {
foreach($field_items as $delta => $properties) {
foreach ($properties as $property_name => $prop_deets) {
$entity_values[$field_name][$delta][$property_name] = $prop_deets['value']->getValue();
}
if ($value === NULL) {
$value = '';
}
$entity_title = trim(preg_replace("/\[$field_name\]/", $value, $entity_title));
}
}
// Trim any trailing spaces and remove double spaces. Double spaces
// can occur if a token replacement has no value but there are spaces
// around it.
$entity_title = trim(preg_replace('/\s\s+/', ' ', $entity_title));

// Now that we've gotten the values out of the property value objects,
// we can use the token parser to get the title!
$entity_title = TripalTokenParser::getEntityTitle($this->entity_type, $entity_values);
$titles[] = $entity_title;
}
return $titles;
Expand Down
72 changes: 70 additions & 2 deletions tripal/src/Services/TripalTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,62 @@ class TripalTokenParser {
*/
protected $values = [];

/**
* Uses this tokenparser to get the title of an entity based on its
* bundle title format and the fields values in the entity.
*
* @param TripalEntityType $bundle
* The bundle for the entity whose title we want to generate.
* @param array $entity_values
* The field values for the entity whom we want to generate the title for.
* This is a nested array with the first keys being field names. Within each
* array for a given field the keys are delta and the values are an array of
* the property names => values for that field delta.
*
* @return string
* The title format string with all the tokens replaced.
*/
public static function getEntityTitle(TripalEntityType $bundle, array $entity_values) {

// Initialize the Tripal token parser service.
/** @var \Drupal\tripal\Services\TripalTokenParser $token_parser **/
$token_parser = \Drupal::service('tripal.token_parser');
$token_parser->initParser($bundle);
$token_parser->clearValues();

// Iterate through each field to add it's property values to the token parser.
foreach ($entity_values as $field_name => $field_values) {
// We currently only support single value fields so check for that here.
if (sizeof($field_values) == 1) {
// Grab the first and only delta for this field.
$item = $field_values[0];
// Iterate through the properties and add each to the token parser.
foreach ($item as $property_name => $property_value) {
$token_parser->addFieldValue(
$field_name,
$property_name,
$property_value
);
}
}
}

// Now that the token parser is set up, we can get the title by replacing
// the tokens in the title format.
$title = $bundle->getTitleFormat();
$replaced = $token_parser->replaceTokens([$title]);

// Since this is a single entity, we return the only title.
// Replace tokens returns an array to handle recursive situations.
return $replaced[0];
}

/**
* Returns bundle object given to the parser.
*
* @return \Drupal\tripal\Entity\TripalEntityType
*/
public function getBunde() {
public function getBundle() {
return $this->bundle;
}

Expand All @@ -51,6 +101,15 @@ public function getValues() {
return $this->values;
}

/**
* Empties the values saved for each token.
*
* This should be done between replacing tokens for different entities.
*/
public function clearValues() {
$this->values = [];
}

/**
* Returns the entity given to the parser.
*
Expand Down Expand Up @@ -116,6 +175,9 @@ public function initParser(TripalEntityType $bundle, TripalEntity $entity = NULL
$this->fields[$field_name] = $field;
}
}

// Ensure there is no bleed through of values from previous substitutions.
$this->clearValues();
}

/**
Expand Down Expand Up @@ -175,11 +237,17 @@ public function replaceTokens(array $tokenized_strings) {
$field = $this->fields[$token];
$key = $field->mainPropertyName();
if (array_key_exists($token, $this->values)) {
$value = $this->values[$token][$key];
$value = @$this->values[$token][$key];
if (!is_null($value)) {
$replaced[$index] = trim(preg_replace("/\[$token\]/", $value, $replaced[$index]));
}
else {
// If the value is null then we remove the token.
$replaced[$index] = trim(preg_replace("/\[$token\]/", '', $replaced[$index]));
}
}
// If we get here then this is a field related token but the token
// value wasn't set with addFieldValue() method. Leave the token as-is.
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions tripal/tests/src/Functional/Services/TripalTokenParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Drupal\Core\Test\FunctionalTestSetupTrait;
use Drupal\tripal\TripalStorage\TripalStorageBase;
use Drupal\tripal\TripalVocabTerms\TripalTerm;
use \Drupal\tripal\Services\TripalTokenParser;

/**
* Tests the basic functions of the TripalContentTypes Service.
Expand Down Expand Up @@ -414,11 +415,11 @@ public function testTripalTokenParser() {
/** @var \Drupal\tripal\Services\TripalTokenParser $token_parser **/
$token_parser = \Drupal::service('tripal.token_parser');
$token_parser->initParser($organism);
$this->assertTrue($token_parser->getBunde()->getId() === 'organism', "The tripal token parser didn't set the bundle properly.");
$this->assertTrue($token_parser->getBundle()->getId() === 'organism', "The tripal token parser didn't set the bundle properly.");
$this->assertTrue(is_null($token_parser->getEntity()), "The tripal token parser should have a null entity.");
$field_names = $token_parser->getFieldNames();

// Mkae sure all of the fields are present in the token parser.
// Make sure all of the fields are present in the token parser.
// This ensures that the bundle was found and it was able to
// create instances of all the fields attached to it.
$this->assertTrue(in_array('organism_genus', $field_names), 'The tripal token parser is missing the organism_genus field.');
Expand Down Expand Up @@ -514,5 +515,15 @@ public function testTripalTokenParser() {
$this->assertTrue($replaced[1] == 'Organism', 'The [TripalEntityType__label] token is not being replaced.');
$this->assertTrue($replaced[2] == '1', 'The [TripalEntity__entity_id] token is not being replaced.');

// Test calling the getFieldValues() function directly
$field_values = $entity->getFieldValues();
$this->assertIsArray($field_values, "getFieldValues did not return an array.");
$this->assertEquals(14, count($field_values), "getFieldValues returned an array of unexpected size.");
$value = $field_values['organism_infraspecific_type'][0]['value'] ?? NULL;
$this->assertEquals('subspecies', $value, "getFieldValues did not return the correct infraspecific type.");

// Test calling the getEntityTitle() function directly
$entity_title = $token_parser->getEntityTitle($token_parser->getBundle(), $field_values);
$this->assertEquals('Oryza sativa subspecies Japonica', $entity_title, "getEntityTitle did not return the correct title");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ public function testChadoTripalPublishService() {
'comment' => 'Gorilla'
]);
$entities = $publish->publish();
$this->assertEquals('<em>Gorilla gorilla</em> <em></em>', array_values($entities)[0],
// Token parser will not remove a token if it is not in the field values.
$this->assertEquals('<em>Gorilla gorilla</em> <em>[organism_infraspecific_name]</em>', array_values($entities)[0],
'The title of Chado organism with missing tokens is incorrect after publishing');


Expand Down

0 comments on commit 2d7d298

Please sign in to comment.