1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Core;
6:
7: /**
8: * If class implements that interface and is added into "Container",
9: * then container will keep track of it. This method can also
10: * specify desired name of the object.
11: */
12: trait TrackableTrait
13: {
14: /** @var QuietObjectWrapper<object>|null Link to (owner) object into which we added this object. */
15: private ?QuietObjectWrapper $_owner = null;
16:
17: /** @var string Name of the object in owner's element array. */
18: public $shortName;
19:
20: public function issetOwner(): bool
21: {
22: return $this->_owner !== null;
23: }
24:
25: public function getOwner(): object
26: {
27: $owner = $this->_owner;
28: if ($owner === null) {
29: throw new Exception('Owner is not set');
30: }
31:
32: return $owner->get();
33: }
34:
35: /**
36: * @return $this
37: */
38: public function setOwner(object $owner)
39: {
40: if ($this->issetOwner()) {
41: throw new Exception('Owner is already set');
42: }
43:
44: $this->_owner = new QuietObjectWrapper($owner);
45:
46: return $this;
47: }
48:
49: /**
50: * Should be used only when object is cloned.
51: *
52: * @return $this
53: */
54: public function unsetOwner()
55: {
56: $this->getOwner(); // assert owner is set
57:
58: $this->_owner = null;
59:
60: return $this;
61: }
62:
63: /**
64: * If name of the object is omitted then it's naturally to name them
65: * after the class. You can specify a different naming pattern though.
66: */
67: public function getDesiredName(): string
68: {
69: // can be anything, but better to build meaningful name
70: $name = get_debug_type($this);
71:
72: return trim(preg_replace('~^atk4\\\\[^\\\\]+\\\\|[^0-9a-z\x7f-\xfe]+~s', '_', mb_strtolower($name)), '_');
73: }
74:
75: /**
76: * Removes object from parent, so that PHP's Garbage Collector can
77: * dispose of it.
78: */
79: public function destroy(): void
80: {
81: if ($this->_owner !== null && TraitUtil::hasContainerTrait($this->_owner->get())) {
82: $this->_owner->get()->removeElement($this->shortName);
83:
84: // GC remove reference to app is AppScope in use
85: if (TraitUtil::hasAppScopeTrait($this) && $this->issetApp()) {
86: $this->_app = null; // @phpstan-ignore-line
87: }
88:
89: // GC remove reference to owner
90: $this->_owner = null;
91: }
92: }
93: }
94: