Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
FileGenerator.php
001 <?php
002 /**
003 * Zend Framework (http://framework.zend.com/)
004 *
005 * @link http://github.com/zendframework/zf2 for the canonical source repository
006 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
007 * @license http://framework.zend.com/license/new-bsd New BSD License
008 */
009
010 namespace Zend\Code\Generator;
011
012 use Zend\Code\DeclareStatement;
013 use Zend\Code\Exception\InvalidArgumentException;
014 use Zend\Code\Reflection\Exception as ReflectionException;
015 use Zend\Code\Reflection\FileReflection;
016
017 use function array_key_exists;
018 use function array_merge;
019 use function count;
020 use function current;
021 use function dirname;
022 use function file_put_contents;
023 use function in_array;
024 use function is_array;
025 use function is_string;
026 use function is_writable;
027 use function method_exists;
028 use function preg_match;
029 use function preg_replace;
030 use function property_exists;
031 use function reset;
032 use function sprintf;
033 use function str_repeat;
034 use function str_replace;
035 use function strrpos;
036 use function strtolower;
037 use function substr;
038 use function token_get_all;
039
040 class FileGenerator extends AbstractGenerator
041 {
042 /**
043 * @var string
044 */
045 protected $filename;
046
047 /**
048 * @var DocBlockGenerator
049 */
050 protected $docBlock;
051
052 /**
053 * @var array
054 */
055 protected $requiredFiles = [];
056
057 /**
058 * @var string
059 */
060 protected $namespace;
061
062 /**
063 * @var array
064 */
065 protected $uses = [];
066
067 /**
068 * @var array
069 */
070 protected $classes = [];
071
072 /**
073 * @var string
074 */
075 protected $body;
076
077 /**
078 * @var DeclareStatement[]
079 */
080 protected $declares = [];
081
082 /**
083 * Passes $options to {@link setOptions()}.
084 *
085 * @param array|\Traversable $options
086 */
087 public function __construct($options = null)
088 {
089 if (null !== $options) {
090 $this->setOptions($options);
091 }
092 }
093
094 /**
095 * Use this if you intend on generating code generation objects based on the same file.
096 * This will keep previous changes to the file in tact during the same PHP process
097 *
098 * @param string $filePath
099 * @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 }
645