1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Data\Reference;
6:
7: use Atk4\Data\Exception;
8: use Atk4\Data\Field;
9: use Atk4\Data\Model;
10: use Atk4\Data\Reference;
11:
12: abstract class ContainsBase extends Reference
13: {
14: use ContainsSeedHackTrait;
15:
16: public bool $checkTheirType = false;
17:
18: /** Field type. */
19: public string $type = 'json';
20:
21: /** Is it system field? */
22: public bool $system = true;
23:
24: /** @var array<string, mixed> Array with UI flags like editable, visible and hidden. */
25: public array $ui = [];
26:
27: /** @var string Required! We need table alias for internal use only. */
28: protected $tableAlias = 'tbl';
29:
30: #[\Override]
31: protected function init(): void
32: {
33: parent::init();
34:
35: if (!$this->ourField) {
36: $this->ourField = $this->link;
37: }
38:
39: $ourModel = $this->getOurModel(null);
40:
41: $ourField = $this->getOurFieldName();
42: if (!$ourModel->hasField($ourField)) {
43: $ourModel->addField($ourField, [
44: 'type' => $this->type,
45: 'referenceLink' => $this->link,
46: 'system' => $this->system,
47: 'caption' => $this->caption, // it's reference models caption, but we can use it here for field too
48: 'ui' => array_merge([
49: 'visible' => false, // not visible in UI Table, Grid and Crud
50: 'editable' => true, // but should be editable in UI Form
51: ], $this->ui),
52: ]);
53: }
54:
55: // TODO https://github.com/atk4/data/issues/881
56: // prevent unmanaged ContainsXxx data modification (/wo proper normalize, hooks, ...)
57: $this->onHookToOurModel($ourModel, Model::HOOK_NORMALIZE, function (Model $ourModel, Field $field, $value) {
58: if (!$field->hasReference() || $field->shortName !== $this->getOurFieldName() || $value === null) {
59: // this code relies on Field::$referenceLink set
60: // also, allowing null value to be set will not fire any HOOK_BEFORE_DELETE/HOOK_AFTER_DELETE hook
61: return;
62: }
63:
64: foreach (array_slice(debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS), 1) as $frame) {
65: if (($frame['class'] ?? null) === static::class) {
66: return; // allow load/save from ContainsOne hooks
67: }
68: }
69:
70: throw new Exception('ContainsXxx does not support unmanaged data modification');
71: });
72: }
73: }
74: