[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Zend Framework (http://framework.zend.com/) 4 * 5 * @link http://github.com/zendframework/zf2 for the canonical source repository 6 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10 namespace Zend\Code\Generator; 11 12 use Zend\Code\DeclareStatement; 13 use Zend\Code\Exception\InvalidArgumentException; 14 use Zend\Code\Reflection\Exception as ReflectionException; 15 use Zend\Code\Reflection\FileReflection; 16 17 use function array_key_exists; 18 use function array_merge; 19 use function count; 20 use function current; 21 use function dirname; 22 use function file_put_contents; 23 use function in_array; 24 use function is_array; 25 use function is_string; 26 use function is_writable; 27 use function method_exists; 28 use function preg_match; 29 use function preg_replace; 30 use function property_exists; 31 use function reset; 32 use function sprintf; 33 use function str_repeat; 34 use function str_replace; 35 use function strrpos; 36 use function strtolower; 37 use function substr; 38 use function token_get_all; 39 40 class FileGenerator extends AbstractGenerator 41 { 42 /** 43 * @var string 44 */ 45 protected $filename; 46 47 /** 48 * @var DocBlockGenerator 49 */ 50 protected $docBlock; 51 52 /** 53 * @var array 54 */ 55 protected $requiredFiles = []; 56 57 /** 58 * @var string 59 */ 60 protected $namespace; 61 62 /** 63 * @var array 64 */ 65 protected $uses = []; 66 67 /** 68 * @var array 69 */ 70 protected $classes = []; 71 72 /** 73 * @var string 74 */ 75 protected $body; 76 77 /** 78 * @var DeclareStatement[] 79 */ 80 protected $declares = []; 81 82 /** 83 * Passes $options to {@link setOptions()}. 84 * 85 * @param array|\Traversable $options 86 */ 87 public function __construct($options = null) 88 { 89 if (null !== $options) { 90 $this->setOptions($options); 91 } 92 } 93 94 /** 95 * Use this if you intend on generating code generation objects based on the same file. 96 * This will keep previous changes to the file in tact during the same PHP process 97 * 98 * @param string $filePath 99 * @param bool $includeIfNotAlreadyIncluded 100 * @throws ReflectionException\InvalidArgumentException If file does not exists 101 * @throws ReflectionException\RuntimeException If file exists but is not included or required 102 * @return FileGenerator 103 */ 104 public static function fromReflectedFileName($filePath, $includeIfNotAlreadyIncluded = true) 105 { 106 $fileReflector = new FileReflection($filePath, $includeIfNotAlreadyIncluded); 107 $codeGenerator = static::fromReflection($fileReflector); 108 109 return $codeGenerator; 110 } 111 112 /** 113 * @param FileReflection $fileReflection 114 * @return FileGenerator 115 */ 116 public static function fromReflection(FileReflection $fileReflection) 117 { 118 $file = new static(); 119 120 $file->setSourceContent($fileReflection->getContents()); 121 $file->setSourceDirty(false); 122 123 $uses = $fileReflection->getUses(); 124 125 foreach ($fileReflection->getClasses() as $class) { 126 $phpClass = ClassGenerator::fromReflection($class); 127 $phpClass->setContainingFileGenerator($file); 128 129 foreach ($uses as $fileUse) { 130 $phpClass->addUse($fileUse['use'], $fileUse['as']); 131 } 132 133 $file->setClass($phpClass); 134 } 135 136 $namespace = $fileReflection->getNamespace(); 137 138 if ($namespace != '') { 139 $file->setNamespace($namespace); 140 } 141 142 if ($uses) { 143 $file->setUses($uses); 144 } 145 146 if ($fileReflection->getDocComment() != '') { 147 $docBlock = $fileReflection->getDocBlock(); 148 $file->setDocBlock(DocBlockGenerator::fromReflection($docBlock)); 149 } 150 151 return $file; 152 } 153 154 /** 155 * @param array $values 156 * @return FileGenerator 157 */ 158 public static function fromArray(array $values) 159 { 160 $fileGenerator = new static(); 161 foreach ($values as $name => $value) { 162 switch (strtolower(str_replace(['.', '-', '_'], '', $name))) { 163 case 'filename': 164 $fileGenerator->setFilename($value); 165 break; 166 case 'class': 167 $fileGenerator->setClass( 168 $value instanceof ClassGenerator 169 ? $value 170 : ClassGenerator::fromArray($value) 171 ); 172 break; 173 case 'requiredfiles': 174 $fileGenerator->setRequiredFiles($value); 175 break; 176 case 'declares': 177 $fileGenerator->setDeclares(array_map(static function ($directive, $value) { 178 return DeclareStatement::fromArray([$directive => $value]); 179 }, array_keys($value), $value)); 180 break; 181 default: 182 if (property_exists($fileGenerator, $name)) { 183 $fileGenerator->{$name} = $value; 184 } elseif (method_exists($fileGenerator, 'set' . $name)) { 185 $fileGenerator->{'set' . $name}($value); 186 } 187 } 188 } 189 190 return $fileGenerator; 191 } 192 193 /** 194 * @param DocBlockGenerator|array|string $docBlock 195 * @throws Exception\InvalidArgumentException 196 * @return FileGenerator 197 */ 198 public function setDocBlock($docBlock) 199 { 200 if (is_string($docBlock)) { 201 $docBlock = ['shortDescription' => $docBlock]; 202 } 203 204 if (is_array($docBlock)) { 205 $docBlock = new DocBlockGenerator($docBlock); 206 } elseif (! $docBlock instanceof DocBlockGenerator) { 207 throw new Exception\InvalidArgumentException(sprintf( 208 '%s is expecting either a string, array or an instance of %s\DocBlockGenerator', 209 __METHOD__, 210 __NAMESPACE__ 211 )); 212 } 213 214 $this->docBlock = $docBlock; 215 return $this; 216 } 217 218 /** 219 * @return DocBlockGenerator 220 */ 221 public function getDocBlock() 222 { 223 return $this->docBlock; 224 } 225 226 /** 227 * @param array $requiredFiles 228 * @return FileGenerator 229 */ 230 public function setRequiredFiles(array $requiredFiles) 231 { 232 $this->requiredFiles = $requiredFiles; 233 return $this; 234 } 235 236 /** 237 * @return array 238 */ 239 public function getRequiredFiles() 240 { 241 return $this->requiredFiles; 242 } 243 244 /** 245 * @return string 246 */ 247 public function getNamespace() 248 { 249 return $this->namespace; 250 } 251 252 /** 253 * @param string $namespace 254 * @return FileGenerator 255 */ 256 public function setNamespace($namespace) 257 { 258 $this->namespace = (string) $namespace; 259 return $this; 260 } 261 262 /** 263 * Returns an array with the first element the use statement, second is the as part. 264 * If $withResolvedAs is set to true, there will be a third element that is the 265 * "resolved" as statement, as the second part is not required in use statements 266 * 267 * @param bool $withResolvedAs 268 * @return array 269 */ 270 public function getUses($withResolvedAs = false) 271 { 272 $uses = $this->uses; 273 if ($withResolvedAs) { 274 for ($useIndex = 0, $count = count($uses); $useIndex < $count; $useIndex++) { 275 if ($uses[$useIndex][1] == '') { 276 if (($lastSeparator = strrpos($uses[$useIndex][0], '\\')) !== false) { 277 $uses[$useIndex][2] = substr($uses[$useIndex][0], $lastSeparator + 1); 278 } else { 279 $uses[$useIndex][2] = $uses[$useIndex][0]; 280 } 281 } else { 282 $uses[$useIndex][2] = $uses[$useIndex][1]; 283 } 284 } 285 } 286 287 return $uses; 288 } 289 290 /** 291 * @param array $uses 292 * @return FileGenerator 293 */ 294 public function setUses(array $uses) 295 { 296 foreach ($uses as $use) { 297 $use = (array) $use; 298 if (array_key_exists('use', $use) && array_key_exists('as', $use)) { 299 $import = $use['use']; 300 $alias = $use['as']; 301 } elseif (count($use) == 2) { 302 list($import, $alias) = $use; 303 } else { 304 $import = current($use); 305 $alias = null; 306 } 307 $this->setUse($import, $alias); 308 } 309 return $this; 310 } 311 312 /** 313 * @param string $use 314 * @param null|string $as 315 * @return FileGenerator 316 */ 317 public function setUse($use, $as = null) 318 { 319 if (! in_array([$use, $as], $this->uses)) { 320 $this->uses[] = [$use, $as]; 321 } 322 return $this; 323 } 324 325 /** 326 * @param array $classes 327 * @return FileGenerator 328 */ 329 public function setClasses(array $classes) 330 { 331 foreach ($classes as $class) { 332 $this->setClass($class); 333 } 334 335 return $this; 336 } 337 338 /** 339 * @param string $name 340 * @return ClassGenerator 341 */ 342 public function getClass($name = null) 343 { 344 if ($name === null) { 345 reset($this->classes); 346 347 return current($this->classes); 348 } 349 350 return $this->classes[(string) $name]; 351 } 352 353 /** 354 * @param array|string|ClassGenerator $class 355 * @throws Exception\InvalidArgumentException 356 * @return FileGenerator 357 */ 358 public function setClass($class) 359 { 360 if (is_array($class)) { 361 $class = ClassGenerator::fromArray($class); 362 } elseif (is_string($class)) { 363 $class = new ClassGenerator($class); 364 } elseif (! $class instanceof ClassGenerator) { 365 throw new Exception\InvalidArgumentException(sprintf( 366 '%s is expecting either a string, array or an instance of %s\ClassGenerator', 367 __METHOD__, 368 __NAMESPACE__ 369 )); 370 } 371 372 // @todo check for dup here 373 $className = $class->getName(); 374 $this->classes[$className] = $class; 375 376 return $this; 377 } 378 379 /** 380 * @param string $filename 381 * @return FileGenerator 382 */ 383 public function setFilename($filename) 384 { 385 $this->filename = (string) $filename; 386 return $this; 387 } 388 389 /** 390 * @return string 391 */ 392 public function getFilename() 393 { 394 return $this->filename; 395 } 396 397 /** 398 * @return ClassGenerator[] 399 */ 400 public function getClasses() 401 { 402 return $this->classes; 403 } 404 405 /** 406 * @param string $body 407 * @return FileGenerator 408 */ 409 public function setBody($body) 410 { 411 $this->body = (string) $body; 412 return $this; 413 } 414 415 /** 416 * @return string 417 */ 418 public function getBody() 419 { 420 return $this->body; 421 } 422 423 public function setDeclares(array $declares) 424 { 425 foreach ($declares as $declare) { 426 if (! $declare instanceof DeclareStatement) { 427 throw new InvalidArgumentException(sprintf( 428 '%s is expecting an array of %s objects', 429 __METHOD__, 430 DeclareStatement::class 431 )); 432 } 433 434 if (! array_key_exists($declare->getDirective(), $this->declares)) { 435 $this->declares[$declare->getDirective()] = $declare; 436 } 437 } 438 439 return $this; 440 } 441 442 /** 443 * @return bool 444 */ 445 public function isSourceDirty() 446 { 447 $docBlock = $this->getDocBlock(); 448 if ($docBlock && $docBlock->isSourceDirty()) { 449 return true; 450 } 451 452 foreach ($this->classes as $class) { 453 if ($class->isSourceDirty()) { 454 return true; 455 } 456 } 457 458 return parent::isSourceDirty(); 459 } 460 461 /** 462 * @return string 463 */ 464 public function generate() 465 { 466 if ($this->isSourceDirty() === false) { 467 return $this->sourceContent; 468 } 469 470 $output = ''; 471 472 // @note body gets populated when FileGenerator created 473 // from a file. @see fromReflection and may also be set 474 // via FileGenerator::setBody 475 $body = $this->getBody(); 476 477 // start with the body (if there), or open tag 478 if (preg_match('#(?:\s*)<\?php#', $body) == false) { 479 $output = '<?php' . self::LINE_FEED; 480 } 481 482 // if there are markers, put the body into the output 483 if (preg_match('#/\* Zend_Code_Generator_Php_File-(.*?)Marker:#m', $body)) { 484 $tokens = token_get_all($body); 485 foreach ($tokens as $token) { 486 if (is_array($token) && in_array($token[0], [T_OPEN_TAG, T_COMMENT, T_DOC_COMMENT, T_WHITESPACE])) { 487 $output .= $token[1]; 488 } 489 } 490 $body = ''; 491 } 492 493 // Add file DocBlock, if any 494 if (null !== ($docBlock = $this->getDocBlock())) { 495 $docBlock->setIndentation(''); 496 497 if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $output)) { 498 // @codingStandardsIgnoreStart 499 $output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $docBlock->generate(), $output, 1); 500 // @codingStandardsIgnoreEnd 501 } else { 502 $output .= $docBlock->generate() . self::LINE_FEED; 503 } 504 } 505 506 // newline 507 $output .= self::LINE_FEED; 508 509 // namespace, if any 510 $namespace = $this->getNamespace(); 511 if ($namespace) { 512 $namespace = sprintf('namespace %s;%s', $namespace, str_repeat(self::LINE_FEED, 2)); 513 if (preg_match('#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $output)) { 514 $output = preg_replace( 515 '#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', 516 $namespace, 517 $output, 518 1 519 ); 520 } else { 521 $output .= $namespace; 522 } 523 } 524 525 // declares, if any 526 if ($this->declares) { 527 $declareStatements = ''; 528 529 foreach ($this->declares as $declare) { 530 $declareStatements .= $declare->getStatement() . self::LINE_FEED; 531 } 532 533 if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m', $output)) { 534 $output = preg_replace( 535 '#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m', 536 $declareStatements, 537 $output, 538 1 539 ); 540 } else { 541 $output .= $declareStatements; 542 } 543 544 $output .= self::LINE_FEED; 545 } 546 547 // process required files 548 // @todo marker replacement for required files 549 $requiredFiles = $this->getRequiredFiles(); 550 if (! empty($requiredFiles)) { 551 foreach ($requiredFiles as $requiredFile) { 552 $output .= 'require_once \'' . $requiredFile . '\';' . self::LINE_FEED; 553 } 554 555 $output .= self::LINE_FEED; 556 } 557 558 $classes = $this->getClasses(); 559 $classUses = []; 560 //build uses array 561 foreach ($classes as $class) { 562 //check for duplicate use statements 563 $uses = $class->getUses(); 564 if (! empty($uses) && is_array($uses)) { 565 $classUses = array_merge($classUses, $uses); 566 } 567 } 568 569 // process import statements 570 $uses = $this->getUses(); 571 if (! empty($uses)) { 572 $useOutput = ''; 573 574 foreach ($uses as $use) { 575 list($import, $alias) = $use; 576 if (null === $alias) { 577 $tempOutput = sprintf('%s', $import); 578 } else { 579 $tempOutput = sprintf('%s as %s', $import, $alias); 580 } 581 582 //don't duplicate use statements 583 if (! in_array($tempOutput, $classUses)) { 584 $useOutput .= 'use ' . $tempOutput . ';'; 585 $useOutput .= self::LINE_FEED; 586 } 587 } 588 $useOutput .= self::LINE_FEED; 589 590 if (preg_match('#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $output)) { 591 $output = preg_replace( 592 '#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', 593 $useOutput, 594 $output, 595 1 596 ); 597 } else { 598 $output .= $useOutput; 599 } 600 } 601 602 // process classes 603 if (! empty($classes)) { 604 foreach ($classes as $class) { 605 // @codingStandardsIgnoreStart 606 $regex = str_replace('&', $class->getName(), '/\* Zend_Code_Generator_Php_File-ClassMarker: \{[A-Za-z0-9\\\]+?&\} \*/'); 607 // @codingStandardsIgnoreEnd 608 if (preg_match('#' . $regex . '#m', $output)) { 609 $output = preg_replace('#' . $regex . '#', $class->generate(), $output, 1); 610 } else { 611 if ($namespace) { 612 $class->setNamespaceName(null); 613 } 614 $output .= $class->generate() . self::LINE_FEED; 615 } 616 } 617 } 618 619 if (! empty($body)) { 620 // add an extra space between classes and 621 if (! empty($classes)) { 622 $output .= self::LINE_FEED; 623 } 624 625 $output .= $body; 626 } 627 628 return $output; 629 } 630 631 /** 632 * @return FileGenerator 633 * @throws Exception\RuntimeException 634 */ 635 public function write() 636 { 637 if ($this->filename == '' || ! is_writable(dirname($this->filename))) { 638 throw new Exception\RuntimeException('This code generator object is not writable.'); 639 } 640 file_put_contents($this->filename, $this->generate()); 641 642 return $this; 643 } 644 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |