Skip to content

ahgDisplayPlugin - Technical Documentation

Version: 1.3.0 Category: Display Dependencies: atom-framework, ahgCorePlugin


Overview

Context-aware display system for GLAM (Galleries, Libraries, Archives, Museums) institutions. Provides automatic type detection, domain-specific display profiles, multiple layout modes, and Elasticsearch 7 integration for faceted searching and browsing.


Architecture

+-----------------------------------------------------------------------+
|                        ahgDisplayPlugin                                |
+-----------------------------------------------------------------------+
|                                                                        |
|  +---------------------------+      +----------------------------+    |
|  |     Plugin Configuration  |      |     Event Dispatching      |    |
|  |  ahgDisplayPluginConfig   |      |  * routing.load_config     |    |
|  |  * PSR-4 autoloader       |      |  * template.filter_params  |    |
|  |  * Module registration    |      |  * QubitIO.save/insert     |    |
|  +---------------------------+      +----------------------------+    |
|               |                                  |                     |
|               V                                  V                     |
|  +------------------------------------------------------------+       |
|  |                    Core Services                            |       |
|  +------------------------------------------------------------+       |
|  |                         |                        |          |       |
|  |  DisplayService         |  DisplayTypeDetector   |  Display |       |
|  |  * getObjectDisplay()   |  * detect()            |  Registry|       |
|  |  * getLevels()          |  * detectAndSave()     |  * ext   |       |
|  |  * setObjectType()      |  * getProfile()        |  actions |       |
|  |                         |                        |          |       |
|  +------------------------------------------------------------+       |
|               |                                  |                     |
|               V                                  V                     |
|  +---------------------------+      +----------------------------+    |
|  |    Display Preferences    |      |   Elasticsearch Service    |    |
|  |  DisplayModeService       |      |  DisplayElasticsearchSvc   |    |
|  |  * getDisplaySettings()   |      |  * search()                |    |
|  |  * switchMode()           |      |  * browseByType()          |    |
|  |  * renderToggleButtons()  |      |  * reindexDisplayData()    |    |
|  +---------------------------+      +----------------------------+    |
|               |                                  |                     |
|               V                                  V                     |
|  +------------------------------------------------------------+       |
|  |                     Database Layer                          |       |
|  |   display_profile, display_level, display_object_config,    |       |
|  |   display_field, display_collection_type, display_mode_global|      |
|  |   user_display_preference                                   |       |
|  +------------------------------------------------------------+       |
|                                                                        |
+-----------------------------------------------------------------------+

Database Schema

ERD Diagram

+---------------------------+       +---------------------------+
|   display_collection_type |       |    display_profile        |
+---------------------------+       +---------------------------+
| PK id INT                 |       | PK id INT                 |
|    code VARCHAR(30) UK    |       |    code VARCHAR(50) UK    |
|    parent_id INT          |       |    domain VARCHAR(20)     |
|    icon VARCHAR(50)       |       |    layout_mode ENUM       |
|    color VARCHAR(20)      |       |    thumbnail_size ENUM    |
| FK default_profile_id INT |------>|    thumbnail_position ENUM|
|    sort_order INT         |       |    identity_fields JSON   |
|    is_active TINYINT      |       |    description_fields JSON|
|    created_at DATETIME    |       |    context_fields JSON    |
+---------------------------+       |    access_fields JSON     |
         |                          |    technical_fields JSON  |
         V                          |    hidden_fields JSON     |
+---------------------------+       |    field_labels JSON      |
| display_collection_type_  |       |    available_actions JSON |
|        i18n               |       |    css_class VARCHAR(100) |
+---------------------------+       |    is_default TINYINT     |
| FK id INT                 |       |    is_active TINYINT      |
|    culture VARCHAR(10)    |       |    sort_order INT         |
|    name VARCHAR(100)      |       |    created_at DATETIME    |
|    description TEXT       |       +---------------------------+
+---------------------------+                    |
                                                 V
                                    +---------------------------+
                                    |   display_profile_i18n    |
                                    +---------------------------+
                                    | FK id INT                 |
                                    |    culture VARCHAR(10)    |
                                    |    name VARCHAR(100)      |
                                    |    description TEXT       |
                                    +---------------------------+

+---------------------------+       +---------------------------+
|      display_level        |       |     display_field         |
+---------------------------+       +---------------------------+
| PK id INT                 |       | PK id INT                 |
|    code VARCHAR(30) UK    |       |    code VARCHAR(50) UK    |
|    parent_code VARCHAR(30)|       |    field_group ENUM       |
|    domain VARCHAR(20)     |       |    data_type ENUM         |
|    valid_parent_codes JSON|       |    source_table VARCHAR   |
|    valid_child_codes JSON |       |    source_column VARCHAR  |
|    icon VARCHAR(50)       |       |    source_i18n TINYINT    |
|    color VARCHAR(20)      |       |    property_type_id INT   |
|    sort_order INT         |       |    taxonomy_id INT        |
|    is_active TINYINT      |       |    relation_type_id INT   |
|    atom_term_id INT       |       |    event_type_id INT      |
|    created_at DATETIME    |       |    isad_element VARCHAR   |
+---------------------------+       |    spectrum_unit VARCHAR  |
         |                          |    dc_element VARCHAR     |
         V                          |    sort_order INT         |
+---------------------------+       |    is_active TINYINT      |
|   display_level_i18n      |       |    created_at DATETIME    |
+---------------------------+       +---------------------------+
| FK id INT                 |                    |
|    culture VARCHAR(10)    |                    V
|    name VARCHAR(100)      |       +---------------------------+
|    description TEXT       |       |   display_field_i18n      |
+---------------------------+       +---------------------------+
                                    | FK id INT                 |
                                    |    culture VARCHAR(10)    |
                                    |    name VARCHAR(100)      |
                                    |    help_text TEXT         |
                                    +---------------------------+

+---------------------------+       +---------------------------+
|  display_object_config    |       |  display_object_profile   |
+---------------------------+       +---------------------------+
| PK id INT                 |       | PK id INT                 |
| FK object_id INT UK       |----+  | FK object_id INT          |
|    object_type VARCHAR(30)|    |  | FK profile_id INT         |
| FK primary_profile_id INT |    |  |    context VARCHAR(30)    |
|    created_at DATETIME    |    |  |    is_primary TINYINT     |
|    updated_at DATETIME    |    |  |    created_at DATETIME    |
+---------------------------+    |  +---------------------------+
         |                       |
         | FK to information_object
         V

+---------------------------+       +---------------------------+
|   display_mode_global     |       | user_display_preference   |
+---------------------------+       +---------------------------+
| PK id INT                 |       | PK id INT                 |
|    module VARCHAR(100) UK |       | FK user_id INT            |
|    display_mode VARCHAR   |       |    module VARCHAR(100)    |
|    items_per_page INT     |       |    display_mode VARCHAR   |
|    sort_field VARCHAR     |       |    items_per_page INT     |
|    sort_direction ENUM    |       |    sort_field VARCHAR     |
|    show_thumbnails TINYINT|       |    sort_direction ENUM    |
|    show_descriptions TINY |       |    show_thumbnails TINYINT|
|    card_size ENUM         |       |    show_descriptions TINY |
|    available_modes JSON   |       |    card_size ENUM         |
|    allow_user_override TIN|       |    is_custom TINYINT      |
|    is_active TINYINT      |       |    created_at DATETIME    |
|    created_at DATETIME    |       |    updated_at DATETIME    |
|    updated_at DATETIME    |       +---------------------------+
+---------------------------+       | UK (user_id, module)      |
                                    +---------------------------+

Table Descriptions

Table Purpose
display_collection_type GLAM type definitions (archive, museum, gallery, library, dam)
display_profile Layout configurations per domain with field mappings
display_level Extended levels of description (40+ levels across all domains)
display_field Field definitions mapping to AtoM tables/properties
display_object_config Per-object type assignment and profile override
display_object_profile Object-to-profile assignments with context
display_mode_global System-wide default view settings per module
user_display_preference Per-user view preferences

GLAM Type Detection

Detection Hierarchy

+-----------------------------------------------------------------------+
|                     TYPE DETECTION FLOW                                |
+-----------------------------------------------------------------------+
|                                                                        |
|  Information Object                                                    |
|         |                                                              |
|         V                                                              |
|  1. Check display_object_config (cached assignment)                    |
|         |                                                              |
|         | (not found)                                                  |
|         V                                                              |
|  2. Detect by Level of Description                                     |
|     +----------------------------------------------------------+      |
|     | Level Name    ->  Domain                                 |      |
|     +----------------------------------------------------------+      |
|     | fonds, series, file, item          ->  archive           |      |
|     | object, specimen, artefact         ->  museum            |      |
|     | artwork, painting, sculpture       ->  gallery           |      |
|     | book, periodical, volume           ->  library           |      |
|     | photograph, album, negative        ->  dam               |      |
|     | collection                         ->  universal         |      |
|     +----------------------------------------------------------+      |
|         |                                                              |
|         | (no match)                                                   |
|         V                                                              |
|  3. Inherit from Parent                                                |
|     Check parent's display_object_config.object_type                   |
|         |                                                              |
|         | (no parent type)                                             |
|         V                                                              |
|  4. Detect by Events                                                   |
|     +----------------------------------------------------------+      |
|     | Event Type         ->  Domain                            |      |
|     +----------------------------------------------------------+      |
|     | photographer       ->  dam                               |      |
|     | artist, painter    ->  gallery                           |      |
|     | author, writer     ->  library                           |      |
|     | production         ->  museum                            |      |
|     +----------------------------------------------------------+      |
|         |                                                              |
|         | (no match)                                                   |
|         V                                                              |
|  5. Default to 'archive'                                               |
|         |                                                              |
|         V                                                              |
|  Save to display_object_config                                         |
|                                                                        |
+-----------------------------------------------------------------------+

Service Classes

DisplayService

namespace AhgDisplay\Services;

class DisplayService
{
    // Singleton
    public static function getInstance(): self

    // Main display data retrieval
    public function getObjectDisplay(int $objectId): array
    // Returns: ['object', 'type', 'profile', 'fields', 'extensions']

    // Object data
    public function getObjectData(int $objectId): ?object

    // Profile and field management
    public function getFieldsForProfile(?object $profile): array
    public function getLevels(?string $domain = null): array
    public function getCollectionTypes(): array

    // Type assignment
    public function setObjectType(int $objectId, string $type): void
    public function setObjectTypeRecursive(int $parentId, string $type): int

    // Profile assignment
    public function assignProfile(
        int $objectId,
        int $profileId,
        string $context = 'default',
        bool $primary = false
    ): void

    // Extension registry integration
    public function getActionsForEntity(object $entity, array $context = []): array
    public function getPanelsForEntity(object $entity, array $context = []): array
    public function getBadgesForEntity(object $entity, array $context = []): array
    public function renderActions(object $entity, array $context = []): string
    public function renderBadges(object $entity, array $context = []): string
}

DisplayTypeDetector

class DisplayTypeDetector
{
    // Detection
    public static function detect(int $objectId): string
    public static function detectAndSave(int $objectId, bool $force = false): string
    public static function getType(int $objectId): string

    // Profile resolution
    public static function getProfile(int $objectId): ?object

    // Internal detection methods
    protected static function detectByLevel(?string $levelName): ?string
    protected static function detectByParent(?int $parentId): ?string
    protected static function detectByEvents(int $objectId): ?string
    protected static function saveType(int $objectId, string $type): void
}

DisplayModeService

namespace AhgDisplay\Services;

class DisplayModeService
{
    // User context
    public function setCurrentUser(?int $userId): self
    public function getCurrentUserId(): int

    // Preference retrieval
    public function getDisplaySettings(string $module): array
    public function getCurrentMode(string $module): string
    public function getSettingsSource(string $module): string
    // Source: 'user' | 'global' | 'default'

    // Preference modification
    public function switchMode(string $module, string $mode): bool
    public function savePreferences(string $module, array $prefs): bool
    public function resetToGlobal(string $module): bool
    public function hasCustomPreference(string $module): bool
    public function canOverride(string $module): bool

    // Display helpers
    public function getModeMetas(string $module): array
    public function getItemsPerPage(string $module): int
    public function getSortSettings(string $module): array
    public function getContainerClass(string $mode): string
    public function renderToggleButtons(
        string $module,
        string $baseUrl = '',
        bool $useAjax = true
    ): string

    // Admin functions
    public function getAllGlobalSettings(): Collection
    public function saveGlobalSettings(string $module, array $settings): bool
    public function resetGlobalSettings(string $module): bool
    public function getAuditLog(array $filters = [], int $limit = 100): Collection
}

DisplayRegistry

namespace AhgDisplay\Services;

class DisplayRegistry
{
    // Singleton
    public static function getInstance(): self

    // Provider management
    public function registerProvider(DisplayActionProviderInterface $provider): void
    public function getProviders(): array
    public function getProvider(string $id): ?DisplayActionProviderInterface

    // Extension retrieval
    public function getActions(object $entity, array $context = []): array
    public function getPanels(object $entity, array $context = []): array
    public function getPanelsByPosition(object $entity, string $position, array $context = []): array
    public function getBadges(object $entity, array $context = []): array

    // Discovery
    public function discover(): void
    public function reset(): void
    public function getProviderInfo(): array

    // Rendering
    public function renderActions(object $entity, array $context = [], string $template = 'buttons'): string
    public function renderBadges(object $entity, array $context = []): string
}

Elasticsearch 7 Integration

Index Mapping

{
  "display_object_type": {
    "type": "keyword"
  },
  "display_profile": {
    "type": "keyword"
  },
  "display_level_code": {
    "type": "keyword"
  },
  "display": {
    "type": "object",
    "properties": {
      "identifier": { "type": "keyword" },
      "title": { "type": "text" },
      "level": { "type": "keyword" },
      "extent": { "type": "text" },
      "scope_content": { "type": "text" },
      "description": { "type": "text" },
      "creator": { "type": "text" },
      "creator_keyword": { "type": "keyword" },
      "artist": { "type": "text" },
      "artist_keyword": { "type": "keyword" },
      "author": { "type": "text" },
      "photographer": { "type": "text" },
      "date_display": { "type": "text" },
      "date_start": { "type": "date" },
      "date_end": { "type": "date" },
      "has_digital_object": { "type": "boolean" },
      "thumbnail_path": { "type": "keyword" },
      "master_path": { "type": "keyword" },
      "mime_type": { "type": "keyword" },
      "media_type": { "type": "keyword" },
      "subjects": { "type": "keyword" },
      "places": { "type": "keyword" },
      "genres": { "type": "keyword" },
      "child_count": { "type": "integer" },
      "ancestor_ids": { "type": "integer" },
      "ancestor_slugs": { "type": "keyword" },
      "parent_title": { "type": "text" },
      "object_number": { "type": "keyword" },
      "object_name": { "type": "text" },
      "materials": { "type": "text" },
      "dimensions": { "type": "text" },
      "medium": { "type": "text" },
      "technique": { "type": "text" },
      "call_number": { "type": "keyword" },
      "isbn": { "type": "keyword" }
    }
  }
}

DisplayElasticsearchService

class DisplayElasticsearchService
{
    // Mapping management
    public function updateMapping(): bool
    public function hasDisplayMapping(): bool

    // Indexing
    public function getIndexData(int $objectId): array
    public function indexDocument(int $objectId, array $existingBody = []): array
    public function reindexDisplayData(
        int $batchSize = 100,
        ?callable $progressCallback = null
    ): int

    // Searching
    public function search(array $params): array
    /*
     * $params:
     *   query           - Search query string
     *   object_type     - GLAM type filter
     *   has_digital_object - Boolean filter
     *   media_type      - image|video|audio|document
     *   date_from/to    - Date range
     *   subjects        - Subject term IDs
     *   places          - Place term IDs
     *   sort            - title_asc|title_desc|date_asc|date_desc|relevance
     *   from            - Pagination offset
     *   size            - Results per page
     *   aggregations    - Include facets (bool)
     */

    // Browse
    public function browseByType(string $objectType, array $params = []): array

    // Facets
    public function getFacets(array $filters = []): array

    // Autocomplete
    public function autocomplete(string $query, int $size = 10): array
}

Search Result Format

[
    'total' => 1234,
    'hits' => [
        [
            'id' => 123,
            'score' => 15.23,
            'slug' => 'example-record',
            'identifier' => 'REF/001',
            'title' => 'Example Record',
            'object_type' => 'archive',
            'profile' => 'isad_full',
            'level' => 'File',
            'creator' => 'John Smith',
            'date' => '1985-1990',
            'description' => 'Truncated description...',
            'has_digital_object' => true,
            'thumbnail_path' => '/uploads/...',
            'media_type' => 'image',
            'subjects' => ['History', 'Local'],
            'child_count' => 15,
        ],
        // ...
    ],
    'aggregations' => [
        'object_types' => [
            ['key' => 'archive', 'count' => 500],
            ['key' => 'museum', 'count' => 234],
        ],
        'media_types' => [...],
        'levels' => [...],
        'subjects' => [...],
        'creators' => [...],
        'has_digital' => [...],
    ],
    'from' => 0,
    'size' => 20,
]

Display Action Registry

Extensibility Pattern

Other plugins can register display actions, panels, and badges via their extension.json:

{
  "name": "My Plugin",
  "machine_name": "myPlugin",
  "display_actions": [
    {
      "id": "my_action",
      "label": "My Action",
      "icon": "fa-star",
      "url": "/my/action/{slug}",
      "contexts": ["informationobject"],
      "permission": "update",
      "weight": 50
    }
  ],
  "display_panels": [
    {
      "id": "my_panel",
      "title": "My Panel",
      "template": "myPlugin/templates/panels/_myPanel.php",
      "position": "sidebar",
      "contexts": ["informationobject"],
      "weight": 30
    }
  ],
  "display_badges": [
    {
      "id": "my_badge",
      "label": "Special",
      "icon": "fa-certificate",
      "class": "badge bg-warning",
      "check_method": "MyPlugin\\BadgeChecker::isSpecial",
      "contexts": ["informationobject"],
      "weight": 20
    }
  ]
}

DisplayActionRegistry

namespace AhgDisplay\Registry;

class DisplayActionRegistry
{
    // Registration (called automatically from extension.json)
    public static function registerAction(string $plugin, array $config): void
    public static function registerPanel(string $plugin, array $config): void
    public static function registerBadge(string $plugin, array $config): void

    // Retrieval
    public static function getActionsForContext(string $context, $resource = null): array
    public static function getPanelsForContext(string $context, ?string $position = null, $resource = null): array
    public static function getBadgesForContext(string $context, $resource = null): array

    // All items
    public static function getAllActions(): array
    public static function getAllPanels(): array
    public static function getAllBadges(): array

    // Rendering
    public static function renderAction(array $action, $resource = null): string
    public static function renderPanel(array $panel, $resource = null): string
    public static function renderBadge(array $badge, $resource = null): string

    // Utility
    public static function clear(): void
}

CLI Commands

display:reindex

Reindex display data in Elasticsearch.

php symfony display:reindex [options]

Options:
  --batch=100          Batch size for bulk updates
  --update-mapping     Update ES mapping before reindexing

Examples:
  php symfony display:reindex
  php symfony display:reindex --batch=200
  php symfony display:reindex --update-mapping
  php symfony display:reindex --update-mapping --batch=50

display:auto-detect

Auto-detect GLAM types for all information objects.

php symfony display:auto-detect

Output:
  display: Starting auto-detection...
  display: Processed 100 objects...
  display: Processed 200 objects...
  display: Complete! Processed 2341 objects:
  display:   archive: 1523
  display:   museum: 234
  display:   library: 156
  display:   dam: 312
  display:   gallery: 89
  display:   universal: 27

Modules and Routes

display Module (Admin)

Route Action Description
/display index Admin dashboard with stats
/display/browse browse Main GLAM browse interface
/display/profiles profiles View/manage display profiles
/display/levels levels View extended levels by domain
/display/fields fields View field mappings
/display/bulkSetType bulkSetType Bulk type assignment form
/display/setType setType Set single object type
/display/changeType changeType Change type (AJAX)
/display/assignProfile assignProfile Assign profile to object
/display/print print Print view (up to 500)
/display/exportCsv exportCsv Export filtered results

displaySearch Module

Route Action Description
/displaySearch/search search ES-powered search with facets
/displaySearch/browse browse Browse by object type
/displaySearch/autocomplete autocomplete AJAX autocomplete
/displaySearch/facets facets AJAX facet updates
/displaySearch/reindex reindex ES reindex admin form
/displaySearch/updateMapping updateMapping Update ES mapping

Layout Templates

Available Layouts

Layout Template Best For
card _card.php Search results, mixed content
catalog _catalog.php Print catalogs, reports
detail _detail.php Single record full view
gallery _gallery.php Artworks, hero images
grid _grid.php Photos, thumbnails
hierarchy _hierarchy.php Archival tree view
list _list.php Reference lists, tables
masonry _masonry.php Variable-size images

Template Variables

All layout templates receive:

$object          // Information object data
$objectType      // GLAM type string
$profile         // Display profile object
$digitalObject   // Digital object (if exists)
$fields          // Organized field groups
$data            // Profile settings (actions, thumbnail_size, etc.)

Configuration

extension.json

{
  "name": "Display Plugin",
  "machine_name": "ahgDisplayPlugin",
  "version": "1.3.0",
  "description": "GLAM browser and display modes for archival content",
  "author": "The Archive and Heritage Group",
  "license": "GPL-3.0",
  "category": "display",
  "requires": {
    "atom_framework": ">=1.0.0",
    "atom": ">=2.8",
    "php": ">=8.1"
  },
  "dependencies": ["ahgCorePlugin"],
  "provides": {
    "services": [
      "AhgDisplay\\Services\\DisplayService",
      "AhgDisplay\\Services\\DisplayRegistry"
    ]
  },
  "tables": [
    "display_profile",
    "display_profile_i18n",
    "display_object_config",
    "display_collection_type",
    "display_field",
    "display_level",
    "display_mode_global",
    "user_display_preference"
  ]
}

Display Mode Settings

// Available display modes
$modes = [
    'tree'     => 'Hierarchy view with parent-child relationships',
    'grid'     => 'Thumbnail grid with cards',
    'gallery'  => 'Large images for visual browsing',
    'list'     => 'Compact table/list view',
    'timeline' => 'Chronological timeline view',
];

// Card sizes
$cardSizes = ['small', 'medium', 'large'];

// Sort directions
$sortDirections = ['asc', 'desc'];

Preference Fallback Chain

+-----------------------------------------------------------------------+
|                    PREFERENCE RESOLUTION                               |
+-----------------------------------------------------------------------+
|                                                                        |
|  1. User Preference (user_display_preference)                          |
|     - Only if is_custom = 1                                            |
|     - Only if global.allow_user_override = 1                           |
|              |                                                         |
|              V (not found or not allowed)                              |
|  2. Global Setting (display_mode_global)                               |
|     - Per-module defaults set by admin                                 |
|              |                                                         |
|              V (not found)                                              |
|  3. Hardcoded Defaults                                                 |
|     - informationobject: list, 30 items                                |
|     - digitalobject: grid, 24 items                                    |
|     - gallery: gallery, 12 items                                       |
|     - dam: grid, 24 items                                              |
|                                                                        |
+-----------------------------------------------------------------------+

Integration Points

Symfony Events

// Plugin configuration hooks into these events:
$this->dispatcher->connect('routing.load_configuration', [$this, 'loadRoutes']);
$this->dispatcher->connect('template.filter_parameters', [$this, 'onTemplateFilterParameters']);
$this->dispatcher->connect('QubitInformationObject.save', [$this, 'onInformationObjectSave']);
$this->dispatcher->connect('QubitInformationObject.insert', [$this, 'onInformationObjectSave']);

Template Integration

// In templates, access display data via:
$display_type    // Auto-detected GLAM type
$display_profile // Current display profile object

// Use helper functions:
get_type_color($objectType)  // Bootstrap color class
get_type_icon($objectType)   // FontAwesome icon class
format_field_value($field)   // Format field for display

Default Profiles

Code Domain Layout Use Case
isad_full archive detail Full archival description
isad_hierarchy archive hierarchy Tree/hierarchy view
isad_list archive list Compact reference list
spectrum_full museum detail Full Spectrum object
spectrum_card museum card Object cards
spectrum_catalog museum catalog Print catalog
gallery_full gallery gallery Artwork detail
gallery_wall gallery gallery Gallery wall view
gallery_catalog gallery catalog Exhibition catalog
book_full library detail Full bibliographic
book_list library list Library listing
book_card library card Book cards
photo_full dam detail Full photo details
photo_grid dam grid Photo grid
photo_lightbox dam masonry Lightbox/masonry
search_result universal card Search results
print_record universal detail Print-ready view

Extended Levels of Description

The plugin provides 40+ levels organized by domain:

Domain Levels
universal repository, collection
archive fonds, subfonds, series, subseries, file, item, piece
museum holding, object_group, object, component, specimen
gallery artist_archive, artwork_series, artwork, study, edition, impression
library book_collection, book, periodical, volume, issue, chapter, pamphlet, map
dam photo_collection, album, shoot, photograph, negative, slide, digital_asset
archive (AV) av_collection, film, recording, reel, segment

Security

Permission Checks

// Browse actions check publication status for guests
if (!$this->isAuthenticated) {
    $query->whereExists(function($q) {
        $q->select(DB::raw(1))
          ->from('status')
          ->whereRaw('status.object_id = io.id')
          ->where('status.type_id', 158)    // publication status
          ->where('status.status_id', 160);  // Published
    });
}

Module Security

# modules/display/config/security.yml
all:
  is_secure: false

index:
  is_secure: true
  credentials: editor

bulkSetType:
  is_secure: true
  credentials: administrator

Performance Considerations

  1. Type Detection Caching: Detected types are stored in display_object_config and not re-computed
  2. ES Bulk Updates: Reindexing uses bulk API with configurable batch sizes
  3. Lazy Loading: Extension registry discovery happens once per request
  4. Facet Counts: Use ES aggregations instead of MySQL COUNT queries

Part of the AtoM AHG Framework