1: <?php declare(strict_types=1);
2:
3: namespace PhpParser\Builder;
4:
5: use PhpParser\Builder;
6: use PhpParser\BuilderHelpers;
7: use PhpParser\Modifiers;
8: use PhpParser\Node;
9: use PhpParser\Node\Stmt;
10:
11: class TraitUseAdaptation implements Builder {
12: private const TYPE_UNDEFINED = 0;
13: private const TYPE_ALIAS = 1;
14: private const TYPE_PRECEDENCE = 2;
15:
16: protected int $type;
17: protected ?Node\Name $trait;
18: protected Node\Identifier $method;
19: protected ?int $modifier = null;
20: protected ?Node\Identifier $alias = null;
21: /** @var Node\Name[] */
22: protected array $insteadof = [];
23:
24: /**
25: * Creates a trait use adaptation builder.
26: *
27: * @param Node\Name|string|null $trait Name of adapted trait
28: * @param Node\Identifier|string $method Name of adapted method
29: */
30: public function __construct($trait, $method) {
31: $this->type = self::TYPE_UNDEFINED;
32:
33: $this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait);
34: $this->method = BuilderHelpers::normalizeIdentifier($method);
35: }
36:
37: /**
38: * Sets alias of method.
39: *
40: * @param Node\Identifier|string $alias Alias for adapted method
41: *
42: * @return $this The builder instance (for fluid interface)
43: */
44: public function as($alias) {
45: if ($this->type === self::TYPE_UNDEFINED) {
46: $this->type = self::TYPE_ALIAS;
47: }
48:
49: if ($this->type !== self::TYPE_ALIAS) {
50: throw new \LogicException('Cannot set alias for not alias adaptation buider');
51: }
52:
53: $this->alias = BuilderHelpers::normalizeIdentifier($alias);
54: return $this;
55: }
56:
57: /**
58: * Sets adapted method public.
59: *
60: * @return $this The builder instance (for fluid interface)
61: */
62: public function makePublic() {
63: $this->setModifier(Modifiers::PUBLIC);
64: return $this;
65: }
66:
67: /**
68: * Sets adapted method protected.
69: *
70: * @return $this The builder instance (for fluid interface)
71: */
72: public function makeProtected() {
73: $this->setModifier(Modifiers::PROTECTED);
74: return $this;
75: }
76:
77: /**
78: * Sets adapted method private.
79: *
80: * @return $this The builder instance (for fluid interface)
81: */
82: public function makePrivate() {
83: $this->setModifier(Modifiers::PRIVATE);
84: return $this;
85: }
86:
87: /**
88: * Adds overwritten traits.
89: *
90: * @param Node\Name|string ...$traits Traits for overwrite
91: *
92: * @return $this The builder instance (for fluid interface)
93: */
94: public function insteadof(...$traits) {
95: if ($this->type === self::TYPE_UNDEFINED) {
96: if (is_null($this->trait)) {
97: throw new \LogicException('Precedence adaptation must have trait');
98: }
99:
100: $this->type = self::TYPE_PRECEDENCE;
101: }
102:
103: if ($this->type !== self::TYPE_PRECEDENCE) {
104: throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider');
105: }
106:
107: foreach ($traits as $trait) {
108: $this->insteadof[] = BuilderHelpers::normalizeName($trait);
109: }
110:
111: return $this;
112: }
113:
114: protected function setModifier(int $modifier): void {
115: if ($this->type === self::TYPE_UNDEFINED) {
116: $this->type = self::TYPE_ALIAS;
117: }
118:
119: if ($this->type !== self::TYPE_ALIAS) {
120: throw new \LogicException('Cannot set access modifier for not alias adaptation buider');
121: }
122:
123: if (is_null($this->modifier)) {
124: $this->modifier = $modifier;
125: } else {
126: throw new \LogicException('Multiple access type modifiers are not allowed');
127: }
128: }
129:
130: /**
131: * Returns the built node.
132: *
133: * @return Node The built node
134: */
135: public function getNode(): Node {
136: switch ($this->type) {
137: case self::TYPE_ALIAS:
138: return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias);
139: case self::TYPE_PRECEDENCE:
140: return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof);
141: default:
142: throw new \LogicException('Type of adaptation is not defined');
143: }
144: }
145: }
146: