Skip to content

IDs, Tags, and Slugs

Each item recorded in an excavation usually has a unique tag. These tags are typically not an ideal choice for an SQL table's unique ID as they may be composites of strings and numbers. Accordingly, the software utilizes three different representations for IDs:

  • ID: a unique string stored in the database and used as a primary ID.
  • Tag: a string corresponding to the excavation's field registration tag assigned to an artifact.
  • Slug: a unique string used to identify an item as part of a URL (avoiding reserved characters, white spaces, etc.)

For example, in the Jezreel Expedition, a ceramic object may include the following:

  • Tag: 16/S/056AR5.1 (Season 2016, Area S, Locus 56, Basket 5, Artifact 1)
  • Slug: 16.S.56.AR.5.1
  • ID: 6S056AR0501

Functions to convert between the different representations are required as part of the module's configuration files. Please note that, with reasonable ID selections, referential integrity is guranteed by the DB engine.

The software ensures the integrity of records before create and update operations (from the ceramics example above):

php
namespace App\Models\Module\Specific\Ceramic;

class Ceramic extends DigModuleModel
{
   protected function derivedId(): Attribute
    {
        return Attribute::make(
            get: fn(mixed $value, array $attributes)
             => $attributes['locus_id'] . $attributes['code'] .  str_pad($attributes['basket_no'], 2, '0', STR_PAD_LEFT) .  str_pad($attributes['artifact_no'], 2, '0', STR_PAD_LEFT)
        );
    }
}

////////////

namespace App\Services\App;

class MutateService extends DigModuleService
{
    protected function save(array $fields): array
    {
        //copy the validated data from the validated array to the 'item' object.
        if ($this->model->derivedId !== $this->model->id) {
            throw new GeneralJsonException('Unable to save d/t inconsistency between id: "' . $this->model->id . '" and derived id: ' . $this->model->derivedId, 422);
        }
    }
}

In the case of composite IDs, their components are usually called for with filtering and ordering operations. Those groups are defined by the module configuration files or, if common to multiple modules, in common traits:

php
namespace App\Services\App\Services\Utils;

trait SmallFindTrait
{
    static public function discreteFilterOptions(): array
    {
        return [
            'Season' => [
                'field' => 'locus_id',
                'start' => 1,
                'length' => 1
            ],
            'Area' => [
                'field' => 'locus_id',
                'start' => 2,
                'length' => 1
            ],
            'Registration Code' => 'code',
            'Locus Id' => 'locus_id'
        ];
    }

    public static function smallFindOrderByOptions(bool $withRegCode): array
    {
        $options = [
            'Season' => [
                'field' => 'locus_id',
                'start' => 1,
                'length' => 1
            ],
            'Area' => [
                'field' => 'locus_id',
                'start' => 2,
                'length' => 1
            ],
            'Locus No.' =>            [
                'field' => 'locus_id',
                'start' => 3,
                'length' => 3
            ],
            'Registration Code' => 'code',
            'Basket No.' => 'basket_no',
            'Artifact No.' => 'artifact_no',
        ];
        if (!$withRegCode) {
            unset($options['Registration Code']);
        }
        return $options;
    }
}