1<?php declare(strict_types=1); 2 3namespace PhpParser\Builder; 4 5use PhpParser\Builder; 6use PhpParser\BuilderHelpers; 7use PhpParser\Modifiers; 8use PhpParser\Node; 9use PhpParser\Node\Stmt; 10 11class 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