Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.15% covered (success)
96.15%
25 / 26
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
RelationGridMetadata
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
2 / 2
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromRow
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Engine\Domain\Model;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11/**
12 * Relation Grid Metadata Value Object.
13 *
14 * Immutable value object representing a widget placement instance on a module GRID view
15 * from a_core_relation_grid_records. Defines Gridstack coordinates, dimension, lock status,
16 * runtime parameters, and optional linked WidgetMetadata.
17 *
18 * @package App\Core\Engine\Domain\Model
19 */
20final readonly class RelationGridMetadata
21{
22    /**
23     * RelationGridMetadata constructor.
24     *
25     * @param int                  $id           Relation primary key.
26     * @param string               $name         Unique machine name for placement.
27     * @param string               $label        Human-readable widget tile title.
28     * @param int                  $moduleId     FK to a_core_module_records.
29     * @param int|null             $gridFilterId FK to a_core_filter_grid_records (optional).
30     * @param int                  $widgetId     FK to a_core_widget_records.
31     * @param int                  $posX         Gridstack column offset (0-11).
32     * @param int                  $posY         Gridstack row index.
33     * @param int                  $width        Gridstack column width (1-12).
34     * @param int                  $height       Gridstack row span.
35     * @param bool                 $isLocked     Whether the tile position is fixed.
36     * @param array<string, mixed> $widgetParams Runtime dynamic parameters JSON.
37     * @param bool                 $isActive     Whether relation is active.
38     * @param int                  $sortOrder    Evaluation and rendering order.
39     * @param WidgetMetadata|null  $widget       Optional joined widget definition.
40     * @param string|null          $moduleName   Optional joined source module name.
41     */
42    public function __construct(
43        public int             $id,
44        public string          $name,
45        public string          $label,
46        public int             $moduleId,
47        public ?int            $gridFilterId = null,
48        public int             $widgetId = 1,
49        public int             $posX = 0,
50        public int             $posY = 0,
51        public int             $width = 12,
52        public int             $height = 8,
53        public bool            $isLocked = false,
54        public array           $widgetParams = [],
55        public bool            $isActive = true,
56        public int             $sortOrder = 10,
57        public ?WidgetMetadata $widget = null,
58        public ?string         $moduleName = null,
59    ) {
60    }
61
62    /**
63     * Creates a RelationGridMetadata instance from a raw database row array.
64     *
65     * @param array<string, mixed> $row    Raw database row from a_core_relation_grid_records.
66     * @param WidgetMetadata|null  $widget Optional joined widget metadata.
67     * @return self Hydrated RelationGridMetadata value object.
68     */
69    public static function fromRow(array $row, ?WidgetMetadata $widget = null): self
70    {
71        $params = [];
72        if (isset($row['widget_params']) && is_string($row['widget_params'])) {
73            $decoded = json_decode($row['widget_params'], true);
74            $params = is_array($decoded) ? $decoded : [];
75        } elseif (is_array($row['widget_params'] ?? null)) {
76            $params = $row['widget_params'];
77        }
78
79        return new self(
80            id:           (int)    $row['id'],
81            name:         (string) $row['name'],
82            label:        (string) $row['label'],
83            moduleId:     (int)    $row['module_id'],
84            gridFilterId: isset($row['grid_filter_id']) ? (int) $row['grid_filter_id'] : null,
85            widgetId:     (int)    ($row['widget_id'] ?? 1),
86            posX:         (int)    ($row['pos_x'] ?? 0),
87            posY:         (int)    ($row['pos_y'] ?? 0),
88            width:        (int)    ($row['width'] ?? 12),
89            height:       (int)    ($row['height'] ?? 8),
90            isLocked:     (bool)   ($row['is_locked'] ?? false),
91            widgetParams: $params,
92            isActive:     (bool)   ($row['is_active'] ?? true),
93            sortOrder:    (int)    ($row['sort_order'] ?? 10),
94            widget:       $widget,
95            moduleName:   isset($row['source_module_name']) ? (string) $row['source_module_name'] : null,
96        );
97    }
98}