Skip to content
This repository was archived by the owner on Jan 8, 2020. It is now read-only.

Commit dae42ac

Browse files
committed
Merge branch 'hotfix/#6302-fix-#4747-file-generator-properly-generates-files' into develop
Forward port #6302
2 parents d904f43 + a0b2308 commit dae42ac

File tree

2 files changed

+157
-74
lines changed

2 files changed

+157
-74
lines changed

library/Zend/Code/Generator/FileGenerator.php

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -103,27 +103,6 @@ public static function fromReflection(FileReflection $fileReflection)
103103
}
104104

105105
$file->setClass($phpClass);
106-
107-
$classStartLine = $class->getStartLine(true);
108-
$classEndLine = $class->getEndLine();
109-
110-
$bodyLines = explode("\n", $body);
111-
$bodyReturn = array();
112-
for ($lineNum = 1, $count = count($bodyLines); $lineNum <= $count; $lineNum++) {
113-
if ($lineNum == $classStartLine) {
114-
$bodyReturn[] = str_replace(
115-
'?',
116-
$class->getName(),
117-
'/* Zend_Code_Generator_Php_File-ClassMarker: {?} */'
118-
);
119-
120-
$lineNum = $classEndLine;
121-
} else {
122-
$bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion
123-
}
124-
}
125-
$body = implode("\n", $bodyReturn);
126-
unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine);
127106
}
128107

129108
$namespace = $fileReflection->getNamespace();
@@ -139,27 +118,8 @@ public static function fromReflection(FileReflection $fileReflection)
139118
if (($fileReflection->getDocComment() != '')) {
140119
$docBlock = $fileReflection->getDocBlock();
141120
$file->setDocBlock(DocBlockGenerator::fromReflection($docBlock));
142-
143-
$bodyLines = explode("\n", $body);
144-
$bodyReturn = array();
145-
for ($lineNum = 1, $count = count($bodyLines); $lineNum <= $count; $lineNum++) {
146-
if ($lineNum == $docBlock->getStartLine()) {
147-
$bodyReturn[] = str_replace(
148-
'?',
149-
$class->getName(),
150-
'/* Zend_Code_Generator_FileGenerator-DocBlockMarker */'
151-
);
152-
$lineNum = $docBlock->getEndLine();
153-
} else {
154-
$bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion
155-
}
156-
}
157-
$body = implode("\n", $bodyReturn);
158-
unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine);
159121
}
160122

161-
$file->setBody($body);
162-
163123
return $file;
164124
}
165125

@@ -244,19 +204,6 @@ public function getRequiredFiles()
244204
return $this->requiredFiles;
245205
}
246206

247-
/**
248-
* @param array $classes
249-
* @return FileGenerator
250-
*/
251-
public function setClasses(array $classes)
252-
{
253-
foreach ($classes as $class) {
254-
$this->setClass($class);
255-
}
256-
257-
return $this;
258-
}
259-
260207
/**
261208
* @return string
262209
*/
@@ -338,6 +285,19 @@ public function setUse($use, $as = null)
338285
return $this;
339286
}
340287

288+
/**
289+
* @param array $classes
290+
* @return FileGenerator
291+
*/
292+
public function setClasses(array $classes)
293+
{
294+
foreach ($classes as $class) {
295+
$this->setClass($class);
296+
}
297+
298+
return $this;
299+
}
300+
341301
/**
342302
* @param string $name
343303
* @return ClassGenerator
@@ -453,14 +413,18 @@ public function generate()
453413

454414
$output = '';
455415

456-
// start with the body (if there), or open tag
416+
// @note body gets populated when FileGenerator created
417+
// from a file. @see fromReflection and may also be set
418+
// via FileGenerator::setBody
457419
$body = $this->getBody();
420+
421+
// start with the body (if there), or open tag
458422
if (preg_match('#(?:\s*)<\?php#', $body) == false) {
459423
$output = '<?php' . self::LINE_FEED;
460424
}
461425

462426
// if there are markers, put the body into the output
463-
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-(.*?)Marker:#', $body)) {
427+
if (preg_match('#/\* Zend_Code_Generator_Php_File-(.*?)Marker:#m', $body)) {
464428
$tokens = token_get_all($body);
465429
foreach ($tokens as $token) {
466430
if (is_array($token) && in_array($token[0], array(T_OPEN_TAG, T_COMMENT, T_DOC_COMMENT, T_WHITESPACE))
@@ -475,8 +439,8 @@ public function generate()
475439
if (null !== ($docBlock = $this->getDocBlock())) {
476440
$docBlock->setIndentation('');
477441

478-
if (preg_match('#/* Zend_Code_Generator_FileGenerator-DocBlockMarker */#', $output)) {
479-
$output = preg_replace('#/* Zend_CodeGenerator_Php_File-DocBlockMarker */#', $docBlock->generate(),
442+
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $output)) {
443+
$output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $docBlock->generate(),
480444
$output, 1);
481445
} else {
482446
$output .= $docBlock->generate() . self::LINE_FEED;
@@ -489,7 +453,13 @@ public function generate()
489453
// namespace, if any
490454
$namespace = $this->getNamespace();
491455
if ($namespace) {
492-
$output .= sprintf('namespace %s;%s', $namespace, str_repeat(self::LINE_FEED, 2));
456+
$namespace = sprintf('namespace %s;%s', $namespace, str_repeat(self::LINE_FEED, 2));
457+
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $output)) {
458+
$output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $namespace,
459+
$output, 1);
460+
} else {
461+
$output .= $namespace;
462+
}
493463
}
494464

495465
// process required files
@@ -503,28 +473,53 @@ public function generate()
503473
$output .= self::LINE_FEED;
504474
}
505475

476+
$classes = $this->getClasses();
477+
$classUses = array();
478+
//build uses array
479+
foreach ($classes as $class) {
480+
//check for duplicate use statements
481+
$uses = $class->getUses();
482+
if(!empty($uses) && is_array($uses)) {
483+
$classUses = array_merge($classUses, $uses);
484+
}
485+
}
486+
506487
// process import statements
507488
$uses = $this->getUses();
508489
if (!empty($uses)) {
490+
$useOutput = '';
491+
509492
foreach ($uses as $use) {
510493
list($import, $alias) = $use;
511494
if (null === $alias) {
512-
$output .= sprintf('use %s;%s', $import, self::LINE_FEED);
495+
$tempOutput = sprintf('%s', $import);
513496
} else {
514-
$output .= sprintf('use %s as %s;%s', $import, $alias, self::LINE_FEED);
497+
$tempOutput = sprintf('%s as %s', $import, $alias);
498+
}
499+
500+
//don't duplicate use statements
501+
if(!in_array($tempOutput, $classUses)) {
502+
$useOutput .= "use ". $tempOutput .";";
503+
$useOutput .= self::LINE_FEED;
515504
}
516505
}
517-
$output .= self::LINE_FEED;
506+
$useOutput .= self::LINE_FEED;
507+
508+
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $output)) {
509+
$output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $useOutput,
510+
$output, 1);
511+
} else {
512+
$output .= $useOutput;
513+
}
514+
518515
}
519516

520517
// process classes
521-
$classes = $this->getClasses();
522518
if (!empty($classes)) {
523519
foreach ($classes as $class) {
524-
$regex = str_replace('?', $class->getName(),
525-
'/* Zend_Code_Generator_FileGenerator-ClassMarker: {?} */');
526-
$regex = preg_quote($regex, '#');
527-
if (preg_match('#' . $regex . '#', $output)) {
520+
$regex = str_replace('&', $class->getName(),
521+
'/\* Zend_Code_Generator_Php_File-ClassMarker: \{[A-Za-z0-9\\\]+?&\} \*/');
522+
if (preg_match('#' . $regex . '#m', $output)) {
528523
$output = preg_replace('#' . $regex . '#', $class->generate(), $output, 1);
529524
} else {
530525
if ($namespace) {

tests/ZendTest/Code/Generator/FileGeneratorTest.php

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ public function testFromReflection()
9797

9898
public function testFromFileReflection()
9999
{
100-
$this->markTestIncomplete('Some scanning capabilities are incomplete, including file DocBlock comment retrieval and method scanning');
101-
102100
$file = __DIR__ . '/TestAsset/TestSampleSingleClass.php';
103101
require_once $file;
104102

@@ -115,15 +113,10 @@ public function testFromFileReflection()
115113
*/
116114
117115
118-
119-
/* Zend_Code_Generator_FileGenerator-ClassMarker: {ZendTest\Code\Generator\TestAsset\TestSampleSingleClass} */
120-
121-
122116
namespace ZendTest\Code\Generator\TestAsset;
123117
124118
/**
125119
* class docblock
126-
*
127120
*/
128121
class TestSampleSingleClass
129122
{
@@ -132,7 +125,6 @@ class TestSampleSingleClass
132125
* Enter description here...
133126
*
134127
* @return bool
135-
*
136128
*/
137129
public function someMethod()
138130
{
@@ -148,9 +140,13 @@ public function foobar()
148140
149141
150142
EOS;
143+
151144
$this->assertEquals($expectedOutput, $codeGenFileFromDisk->generate());
152145
}
153146

147+
/**
148+
* @group test
149+
*/
154150
public function testFileLineEndingsAreAlwaysLineFeed()
155151
{
156152
$codeGenFile = FileGenerator::fromArray(array(
@@ -305,4 +301,96 @@ public function testGeneratedClassesHaveUses()
305301

306302
$this->assertEquals($expectedUses, $class->getUses());
307303
}
304+
305+
/**
306+
* @group 4747
307+
*/
308+
public function testIssue4747FileGenerationWithAddedMethodIsCorrectlyFormatted()
309+
{
310+
$g = new \Zend\Code\Generator\FileGenerator();
311+
$g = $g->fromReflectedFileName(__DIR__ . '/TestAsset/ClassWithUses.php');
312+
$g->setFilename('/tmp/result_class.php');
313+
$g->getClass()->addMethod('added');
314+
$g->write();
315+
316+
$expected = <<<'CODE'
317+
<?php
318+
/**
319+
* Zend Framework (http://framework.zend.com/)
320+
*
321+
* @link http://github.com/zendframework/zf2 for the canonical source
322+
* repository
323+
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc.
324+
* (http://www.zend.com)
325+
* @license http://framework.zend.com/license/new-bsd New BSD License
326+
*/
327+
328+
329+
namespace ZendTest\Code\Generator\TestAsset;
330+
331+
332+
use ZendTest\Code\Generator\TestAsset\ClassWithNamespace;
333+
334+
class ClassWithUses
335+
{
336+
337+
public function added()
338+
{
339+
}
340+
341+
342+
}
343+
344+
345+
CODE;
346+
$actual = file_get_contents('/tmp/result_class.php');
347+
$this->assertEquals($expected, $actual);
348+
}
349+
350+
/**
351+
* @group 4747
352+
*/
353+
public function testCanAppendToBodyOfReflectedFile()
354+
{
355+
$g = new \Zend\Code\Generator\FileGenerator();
356+
$g = $g->fromReflectedFileName(__DIR__ . '/TestAsset/ClassWithUses.php');
357+
$g->setFilename('/tmp/result_class.php');
358+
$g->getClass()->addMethod('added');
359+
$g->setBody("\$foo->bar();");
360+
$g->write();
361+
362+
$expected = <<<'CODE'
363+
<?php
364+
/**
365+
* Zend Framework (http://framework.zend.com/)
366+
*
367+
* @link http://github.com/zendframework/zf2 for the canonical source
368+
* repository
369+
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc.
370+
* (http://www.zend.com)
371+
* @license http://framework.zend.com/license/new-bsd New BSD License
372+
*/
373+
374+
375+
namespace ZendTest\Code\Generator\TestAsset;
376+
377+
378+
use ZendTest\Code\Generator\TestAsset\ClassWithNamespace;
379+
380+
class ClassWithUses
381+
{
382+
383+
public function added()
384+
{
385+
}
386+
387+
388+
}
389+
390+
391+
$foo->bar();
392+
CODE;
393+
$actual = file_get_contents('/tmp/result_class.php');
394+
$this->assertEquals($expected, $actual);
395+
}
308396
}

0 commit comments

Comments
 (0)