Unique fields in structure?

Hello there,
for a client I am having a structure field on a page which can contains entries in the following way:

  • ID
  • Name

As the data is relatively simple, a structure field is working well. The problem is, that it’s possible to create multiple entries with the same ID (which is user-defined). What’s the best way to block saving when there are two or more items with the same ID value?

I’ve tried it with a hook and panel->alert('Duplicate ID') with the redirect coming after, but this still allows the saving process of the page. I’ve read about custom validators, but it seems that they require manual input in the blueprint, there’s no way of setting the page itself as value to validate.

So, what’s the best way for solving this problem?

What is the purpose of the ID?

How about assigning a unique ID automatically? I created a plugin for that:

The purpose of the ID is the internal identifier. We have several bicycles in our company, many of them of the same type and size. To the visitor only the “master bike” is visible, but we need to manage them in the backend with their serial numbers, which are their ID. As this is given by the manufacturer, it can’t be created automatically.

Then a custom validator would be the way to go that checks if the ID has already been used. But for this to work you’d probably have to set up a custom field that checks the state of the other structure fields on the fly via JS.

Otherwise, your validator could only ever check against what has already been saved to file.

I have thought about it some more and I think this could work:

v::$validators['unique'] = function($value, $field) {
  $values = array_column(yaml($value), $field);
  return count($values) === count(array_flip($values));
  // or
  // return count($values) !== count(array_unique($values));

};

Blueprint:

fields:
  products:
    label: Products
    type: structure
    style: table
    validate:
      unique: id
    help: Make sure all ID fields contain unique numbers otherwise an error is thrown if you save the page.
    fields:
      id:
        label: ID
        type: number
        # etc.

Where unique is the name of the validator and id the name of the field you want to validate.

However, this solution would only validate when the page is saved, not when the user adds a new entry.

This code works as expected, it’s enough for me to notify the user when saving.
I adapted it a bit to tell explicitely which entry is duplicated using the validator below:

v::$validators['unique'] = function($value, $field) {
	$values = array_column(yaml($value), $field);
	$ids = array();

	foreach ($values as $value) {
		if (in_array($value, $ids)) {
			$replace = array(
				'panel/'    => "",
				url::home() => ""
			);
			panel()->alert('Doppelter Eintrag: '.$value);
			panel()->redirect(str_replace(array_keys($replace), array_values($replace), url::current()));
			return false;
		} else {
			$ids[] = $value;
		}
	}

	return true;
};

This works in my case, as I know that I won’t use the validator somewhere else. Thanks again for helping! :slight_smile:

1 Like