1<?php 2 3/** 4 * @see https://github.com/laminas/laminas-code for the canonical source repository 5 * @copyright https://github.com/laminas/laminas-code/blob/master/COPYRIGHT.md 6 * @license https://github.com/laminas/laminas-code/blob/master/LICENSE.md New BSD License 7 */ 8 9namespace Laminas\Code\Generator; 10 11use Laminas\Code\Reflection\PropertyReflection; 12 13use function sprintf; 14use function str_replace; 15use function strtolower; 16 17class PropertyGenerator extends AbstractMemberGenerator 18{ 19 const FLAG_CONSTANT = 0x08; 20 21 /** 22 * @var bool 23 */ 24 protected $isConst; 25 26 /** 27 * @var PropertyValueGenerator 28 */ 29 protected $defaultValue; 30 31 /** 32 * @var bool 33 */ 34 private $omitDefaultValue = false; 35 36 /** 37 * @param PropertyReflection $reflectionProperty 38 * @return PropertyGenerator 39 */ 40 public static function fromReflection(PropertyReflection $reflectionProperty) 41 { 42 $property = new static(); 43 44 $property->setName($reflectionProperty->getName()); 45 46 $allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties(); 47 48 $defaultValue = $allDefaultProperties[$reflectionProperty->getName()]; 49 $property->setDefaultValue($defaultValue); 50 if ($defaultValue === null) { 51 $property->omitDefaultValue = true; 52 } 53 54 if ($reflectionProperty->getDocComment() != '') { 55 $property->setDocBlock(DocBlockGenerator::fromReflection($reflectionProperty->getDocBlock())); 56 } 57 58 if ($reflectionProperty->isStatic()) { 59 $property->setStatic(true); 60 } 61 62 if ($reflectionProperty->isPrivate()) { 63 $property->setVisibility(self::VISIBILITY_PRIVATE); 64 } elseif ($reflectionProperty->isProtected()) { 65 $property->setVisibility(self::VISIBILITY_PROTECTED); 66 } else { 67 $property->setVisibility(self::VISIBILITY_PUBLIC); 68 } 69 70 $property->setSourceDirty(false); 71 72 return $property; 73 } 74 75 /** 76 * Generate from array 77 * 78 * @configkey name string [required] Class Name 79 * @configkey const bool 80 * @configkey defaultvalue null|bool|string|int|float|array|ValueGenerator 81 * @configkey flags int 82 * @configkey abstract bool 83 * @configkey final bool 84 * @configkey static bool 85 * @configkey visibility string 86 * @configkey omitdefaultvalue bool 87 * 88 * @throws Exception\InvalidArgumentException 89 * @param array $array 90 * @return PropertyGenerator 91 */ 92 public static function fromArray(array $array) 93 { 94 if (! isset($array['name'])) { 95 throw new Exception\InvalidArgumentException( 96 'Property generator requires that a name is provided for this object' 97 ); 98 } 99 100 $property = new static($array['name']); 101 foreach ($array as $name => $value) { 102 // normalize key 103 switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { 104 case 'const': 105 $property->setConst($value); 106 break; 107 case 'defaultvalue': 108 $property->setDefaultValue($value); 109 break; 110 case 'docblock': 111 $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value); 112 $property->setDocBlock($docBlock); 113 break; 114 case 'flags': 115 $property->setFlags($value); 116 break; 117 case 'abstract': 118 $property->setAbstract($value); 119 break; 120 case 'final': 121 $property->setFinal($value); 122 break; 123 case 'static': 124 $property->setStatic($value); 125 break; 126 case 'visibility': 127 $property->setVisibility($value); 128 break; 129 case 'omitdefaultvalue': 130 $property->omitDefaultValue($value); 131 break; 132 } 133 } 134 135 return $property; 136 } 137 138 /** 139 * @param string $name 140 * @param PropertyValueGenerator|string|array $defaultValue 141 * @param int $flags 142 */ 143 public function __construct($name = null, $defaultValue = null, $flags = self::FLAG_PUBLIC) 144 { 145 if (null !== $name) { 146 $this->setName($name); 147 } 148 if (null !== $defaultValue) { 149 $this->setDefaultValue($defaultValue); 150 } 151 if ($flags !== self::FLAG_PUBLIC) { 152 $this->setFlags($flags); 153 } 154 } 155 156 /** 157 * @param bool $const 158 * @return PropertyGenerator 159 */ 160 public function setConst($const) 161 { 162 if ($const) { 163 $this->setFlags(self::FLAG_CONSTANT); 164 } else { 165 $this->removeFlag(self::FLAG_CONSTANT); 166 } 167 168 return $this; 169 } 170 171 /** 172 * @return bool 173 */ 174 public function isConst() 175 { 176 return (bool) ($this->flags & self::FLAG_CONSTANT); 177 } 178 179 /** 180 * @param PropertyValueGenerator|mixed $defaultValue 181 * @param string $defaultValueType 182 * @param string $defaultValueOutputMode 183 * 184 * @return PropertyGenerator 185 */ 186 public function setDefaultValue( 187 $defaultValue, 188 $defaultValueType = PropertyValueGenerator::TYPE_AUTO, 189 $defaultValueOutputMode = PropertyValueGenerator::OUTPUT_MULTIPLE_LINE 190 ) { 191 if (! $defaultValue instanceof PropertyValueGenerator) { 192 $defaultValue = new PropertyValueGenerator($defaultValue, $defaultValueType, $defaultValueOutputMode); 193 } 194 195 $this->defaultValue = $defaultValue; 196 197 return $this; 198 } 199 200 /** 201 * @return PropertyValueGenerator 202 */ 203 public function getDefaultValue() 204 { 205 return $this->defaultValue; 206 } 207 208 /** 209 * @throws Exception\RuntimeException 210 * @return string 211 */ 212 public function generate() 213 { 214 $name = $this->getName(); 215 $defaultValue = $this->getDefaultValue(); 216 217 $output = ''; 218 219 if (($docBlock = $this->getDocBlock()) !== null) { 220 $docBlock->setIndentation(' '); 221 $output .= $docBlock->generate(); 222 } 223 224 if ($this->isConst()) { 225 if ($defaultValue !== null && ! $defaultValue->isValidConstantType()) { 226 throw new Exception\RuntimeException(sprintf( 227 'The property %s is said to be ' 228 . 'constant but does not have a valid constant value.', 229 $this->name 230 )); 231 } 232 $output .= $this->indentation . $this->getVisibility() . ' const ' . $name . ' = ' 233 . ($defaultValue !== null ? $defaultValue->generate() : 'null;'); 234 235 return $output; 236 } 237 238 $output .= $this->indentation . $this->getVisibility() . ($this->isStatic() ? ' static' : '') . ' $' . $name; 239 240 if ($this->omitDefaultValue) { 241 return $output . ';'; 242 } 243 244 return $output . ' = ' . ($defaultValue !== null ? $defaultValue->generate() : 'null;'); 245 } 246 247 /** 248 * @param bool $omit 249 * @return PropertyGenerator 250 */ 251 public function omitDefaultValue(bool $omit = true) 252 { 253 $this->omitDefaultValue = $omit; 254 255 return $this; 256 } 257} 258