Skip to content

Commit

Permalink
Merge pull request #182 from esmero/ISSUE-175
Browse files Browse the repository at this point in the history
ISSUE-175: First pass (working) on EDTF/ISO8601 validation at Key Name Provider …
  • Loading branch information
DiegoPino authored May 15, 2021
2 parents e7e14ed + 9d5ada7 commit 13a20d3
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 30 deletions.
5 changes: 4 additions & 1 deletion config/schema/strawberryfield.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ strawberryfield.strawberry_keynameprovider.jmespath:
mapping:
source_key:
type: string
label: 'A Comma separated string containing one or more JMESPaths '
label: 'A Comma separated string containing one or more JMESPaths'
is_date:
type: boolean
label: 'If the value should be considered and validated as a date'
exposed_key:
type: string
label: 'The field property we expose for the Strawberryfield'
Expand Down
3 changes: 2 additions & 1 deletion src/Plugin/DataType/StrawberryValuesFromJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class StrawberryValuesFromJson extends ItemList {
*/
protected $list = [];
public function getValue() {
if ($this->processed == NULL) {
if ($this->processed === NULL) {
$this->process();
}
$values = [];
Expand Down Expand Up @@ -79,6 +79,7 @@ public function process($langcode = NULL)
$values[] = trim($flattened[$needle]);
}
$this->processed = array_values($values);
$this->list = [];
foreach ($this->processed as $delta => $item) {
$this->list[$delta] = $this->createItem($delta, $item);
}
Expand Down
65 changes: 41 additions & 24 deletions src/Plugin/DataType/StrawberryValuesViaJmesPathFromJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Drupal\Core\TypedData\Plugin\DataType\ItemList;
use Drupal\strawberryfield\Plugin\Field\FieldType\StrawberryFieldItem;
use Drupal\strawberryfield\Tools\StrawberryfieldJsonHelper;
use EDTF\EdtfFactory;

class StrawberryValuesViaJmesPathFromJson extends ItemList {
/**
Expand All @@ -29,6 +30,7 @@ class StrawberryValuesViaJmesPathFromJson extends ItemList {
* @var \Drupal\Core\TypedData\TypedDataInterface[]
*/
protected $list = [];

public function getValue() {
if ($this->processed == NULL) {
$this->process();
Expand All @@ -48,52 +50,67 @@ public function process($langcode = NULL)
if ($this->computed == TRUE) {
return;
}
$values = [];
$item = $this->getParent();
if (!empty($item->value)) {
/* @var $item StrawberryFieldItem */
$flattened = $item->provideFlatten(FALSE);
$definition = $this->getDataDefinition();
// This key is passed by the property definition in the field class
// jsonkey in this context is a string containing one or more
// jmespath's separated by comma.
$jmespaths = $definition['settings']['jsonkey'];
$is_date = $definition['settings']['is_date'] ?? FALSE;
$jmespath_array = array_map('trim', explode(',', $jmespaths));
$jmespath_result = [];
foreach ($jmespath_array as $jmespath) {
$jmespath_result[] = $item->searchPath(trim($jmespath),FALSE);
}
$jmespath_result_to_expose = [];

foreach ($jmespath_result as $item) {
if (is_array($item)) {
if (StrawberryfieldJsonHelper::arrayIsMultiSimple($item)) {
// @TODO should we allow unicode directly?
// If its multidimensional simple json encode as a string.
// We could also just get the first order values?
// @TODO, ask the team.
$jmespath_result_to_expose[] = json_encode($item, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
} else {
$jmespath_result_to_expose = array_merge($jmespath_result_to_expose, $item);
}

foreach ($jmespath_result as $item) {
if (is_array($item)) {
if (StrawberryfieldJsonHelper::arrayIsMultiSimple($item)) {
// @TODO should we allow unicode directly?
// If its multidimensional simple json encode as a string.
// We could also just get the first order values?
// @TODO, ask the team.
$jmespath_result_to_expose[] = json_encode($item, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
} else {
$jmespath_result_to_expose = array_merge($jmespath_result_to_expose, $item);
}
else {
// If a single value, simply cast to array
$jmespath_result_to_expose[] = $item;
}
else {
// If a single value, simply cast to array
$jmespath_result_to_expose[] = $item;
}
}
// This is an array, don't double nest to make the normalizer happy.
$jmespath_result_to_expose = array_filter($jmespath_result_to_expose);
$values = array_map('trim', $jmespath_result_to_expose);
$values = array_map('stripslashes', $values);
if ($is_date) {
$values_parsed = [];
$parser = EdtfFactory::newParser();
foreach ($values as $value) {
$result = $parser->parse($value);
if ($result->isValid()) {
$date_ini = $result->getEdtfValue()->getMin();
$date_max = $result->getEdtfValue()->getMax();
$date_ini = date('c', $date_ini);
$date_max = date('c', $date_max);
$values_parsed[] = $date_ini;
$values_parsed[] = $date_max;
}
}
// This is an array, don't double nest to make the normalizer happy.
$values = array_map('trim', $jmespath_result_to_expose);
$values = array_map('stripslashes', $values);

$this->processed = array_values($values);
$values = array_unique($values_parsed);
}
$this->processed = array_filter(array_values($values));
$this->list = [];
foreach ($this->processed as $delta => $item) {
$this->list[$delta] = $this->createItem($delta, $item);
}
}
else {
$this->processed = [];
$this->list = [];
}
$this->computed = TRUE;
}
Expand Down Expand Up @@ -126,7 +143,7 @@ public function get($index) {
throw new \InvalidArgumentException('Unable to get a value with a non-numeric delta in a list.');
}
$this->ensureComputedValue();
return isset($this->list[$index]) ? $this->list[$index] : NULL;
return !empty($this->list[$index]) ? $this->list[$index] : NULL;
}
/**
* {@inheritdoc}
Expand Down
4 changes: 3 additions & 1 deletion src/Plugin/Field/FieldType/StrawberryFieldItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
->setReadOnly(TRUE);
}
else {
$is_date = $plugin_config_entity_configs[$processor_class][$property]['is_date'] ?? FALSE;
$properties[$property] = ListDataDefinition::create(
$item_types[$processor_class]
)
Expand All @@ -189,6 +190,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
->setClass($processor_class)
->setInternal(TRUE)
->setSetting('jsonkey', $keyname)
->setSetting('is_date', $is_date)
->setReadOnly(TRUE);
}
}
Expand Down Expand Up @@ -324,7 +326,7 @@ public function searchPath($expression, $force = TRUE) {
else {
if ($this->jsonjmesresults == NULL || !isset($this->jsonjmesresults[$expression]) || $force) {
$mainproperty = $this->mainPropertyName();
$jsonArray = json_decode($this->{$mainproperty}, TRUE, 50);
$jsonArray = json_decode($this->{$mainproperty}, TRUE, 64);
$searchresult = StrawberryfieldJsonHelper::searchJson($expression, $jsonArray);
$this->jsonjmesresults[$expression] = $searchresult;
return $searchresult;
Expand Down
10 changes: 10 additions & 0 deletions src/Plugin/StrawberryfieldKeyNameProvider/JmesPathNameProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function defaultConfiguration() {
'source_key' => '',
// Example hocr
'exposed_key' => '',
'is_date' => FALSE,
// The id of the config entity from where these values came from.'
'configEntity' => NULL
] + parent::defaultConfiguration();
Expand All @@ -69,6 +70,15 @@ public function settingsForm(array $parents, FormStateInterface $form_state) {
'#description' => $this->t('JMespath(s) will be evaluated against your <em>Strawberry field</em> JSON to extract data.<br> e.g. subject_loc[*].label'),
'#required' => true,
];

$element['is_date'] = [
'#id' => 'is_date',
'#type' => 'checkbox',
'#title' => $this->t('Is Date?'),
'#default_value' => $this->getConfiguration()['is_date'],
'#description' => $this->t('If checked the value coming from your <em>Strawberry field</em> JSON will be validated to be a Date.'),
'#required' => FALSE,
];
// We need the parent form structure, if any, to make machine name work.
$exposed_key_parents = $parents;
$exposed_key_parents[] = 'source_key';
Expand Down
25 changes: 22 additions & 3 deletions src/Tools/StrawberryfieldJsonHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,6 @@ public static function arrayIsMultiIterative(array $sourcearray = []) {
return false;
}



/**
*
*
Expand All @@ -363,9 +361,30 @@ public static function arrayIsMultiIterative(array $sourcearray = []) {
* @return mixed|null Returns the matching data or null
*/
public static function searchJson($expression, array $sourcearray = []) {
return JmesPath::search($expression, $sourcearray);
if (!static::jmesPathIsKey($expression)){
return JmesPath::search($expression, $sourcearray);
}
else {
$key = trim($expression,'"');
return $sourcearray[$key] ?? NULL;
}
}

/**
* Checks if a JMESPath expression is an array key in disguise.
* @param $expression
*
* @return bool
*/
public static function jmesPathIsKey($expression) {
$expression = trim($expression, '"');
if (preg_match("/(\[|\.|\*)/", $expression)) {
return FALSE;
}
else {
return TRUE;
}
}

/**
* Takes an array and generates a JMESPath Filter expression
Expand Down

0 comments on commit 13a20d3

Please sign in to comment.