[ Index ]

PHP Cross Reference of phpBB-3.3.2-deutsch

title

Body

[close]

/vendor/zendframework/zend-code/src/Generator/ -> FileGenerator.php (source)

   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  }


Generated: Wed Nov 11 20:28:18 2020 Cross-referenced by PHPXref 0.7.1