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

Feature: Add ability to define declare statements #169

Merged
merged 7 commits into from
Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions src/DeclareStatement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

namespace Zend\Code;

use Zend\Code\Exception\InvalidArgumentException;

class DeclareStatement
{
public const TICKS = 'ticks';
public const STRICT_TYPES = 'strict_types';
public const ENCODING = 'encoding';

private const ALLOWED = [
self::TICKS => 'integer',
self::STRICT_TYPES => 'integer',
self::ENCODING => 'string',
];

/**
* @var string
*/
protected $directive;

/**
* @var int|string
*/
protected $value;

private function __construct(string $directive, $value)
{
$this->directive = $directive;
$this->value = $value;
}

/**
* @return string
*/
public function getDirective(): string
{
return $this->directive;
}

/**
* @return int|string
*/
public function getValue()
{
return $this->value;
}

/**
* @param int $value
* @return self
*/
public static function ticks(int $value): self
{
return new self(self::TICKS, $value);
}

/**
* @param int $value
* @return self
*/
public static function strictTypes(int $value): self
{
return new self(self::STRICT_TYPES, $value);
}

/**
* @param string $value
* @return self
*/
public static function encoding(string $value): self
{
return new self(self::ENCODING, $value);
}

public static function fromArray(array $config): self
{
$directive = key($config);
$value = $config[$directive];

if (! isset(self::ALLOWED[$directive])) {
throw new InvalidArgumentException(
sprintf(
'Declare directive must be on of: %s.',
icanhazstring marked this conversation as resolved.
Show resolved Hide resolved
implode(', ', array_keys(self::ALLOWED))
)
);
}

if (gettype($value) !== self::ALLOWED[$directive]) {
throw new InvalidArgumentException(
sprintf(
'Declare value invalid. Expected %s got %s.',
icanhazstring marked this conversation as resolved.
Show resolved Hide resolved
self::ALLOWED[$directive],
gettype($value)
)
);
}

$method = str_replace('_', '', lcfirst(ucwords($directive, '_')));

return self::{$method}($value);
}

/**
* @return string
*/
public function getStatement(): string
{
$value = is_string($this->value) ? '\'' . $this->value . '\'' : $this->value;

return sprintf('declare(%s=%s);', $this->directive, $value);
}
}
53 changes: 53 additions & 0 deletions src/Generator/FileGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

namespace Zend\Code\Generator;

use Zend\Code\DeclareStatement;
use Zend\Code\Exception\InvalidArgumentException;
use Zend\Code\Reflection\Exception as ReflectionException;
use Zend\Code\Reflection\FileReflection;

Expand Down Expand Up @@ -72,6 +74,11 @@ class FileGenerator extends AbstractGenerator
*/
protected $body;

/**
* @var DeclareStatement[]
*/
protected $declares = [];

/**
* Passes $options to {@link setOptions()}.
*
Expand Down Expand Up @@ -166,6 +173,11 @@ public static function fromArray(array $values)
case 'requiredfiles':
$fileGenerator->setRequiredFiles($value);
break;
case 'declares':
$fileGenerator->setDeclares(array_map(static function ($directive, $value) {
return DeclareStatement::fromArray([$directive => $value]);
}, array_keys($value), $value));
break;
default:
if (property_exists($fileGenerator, $name)) {
$fileGenerator->{$name} = $value;
Expand Down Expand Up @@ -408,6 +420,25 @@ public function getBody()
return $this->body;
}

public function setDeclares(array $declares)
{
foreach ($declares as $declare) {
if (! $declare instanceof DeclareStatement) {
throw new InvalidArgumentException(sprintf(
'%s is expecting an array of %s objects',
__METHOD__,
DeclareStatement::class
));
}

if (! array_key_exists($declare->getDirective(), $this->declares)) {
$this->declares[$declare->getDirective()] = $declare;
}
}

return $this;
}

/**
* @return bool
*/
Expand Down Expand Up @@ -491,6 +522,28 @@ public function generate()
}
}

// declares, if any
if ($this->declares) {
$declareStatements = '';

foreach ($this->declares as $declare) {
$declareStatements .= $declare->getStatement() . self::LINE_FEED;
}

if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m', $output)) {
$output = preg_replace(
'#/\* Zend_Code_Generator_FileGenerator-DeclaresMarker \*/#m',
$declareStatements,
$output,
1
);
} else {
$output .= $declareStatements;
}

$output .= self::LINE_FEED;
}

// process required files
// @todo marker replacement for required files
$requiredFiles = $this->getRequiredFiles();
Expand Down
137 changes: 137 additions & 0 deletions test/Generator/FileGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
namespace ZendTest\Code\Generator;

use PHPUnit\Framework\TestCase;
use Zend\Code\DeclareStatement;
use Zend\Code\Exception\InvalidArgumentException;
use Zend\Code\Generator\ClassGenerator;
use Zend\Code\Generator\FileGenerator;
use Zend\Code\Reflection\FileReflection;
Expand Down Expand Up @@ -413,4 +415,139 @@ public function added()
$actual = file_get_contents(sys_get_temp_dir() . '/result_class.php');
self::assertEquals($expected, $actual);
}

public function testSingleDeclareStatement(): void
{
$generator = FileGenerator::fromArray([
'declares' => [
'strict_types' => 1,
],
'class' => [
'name' => 'SampleClass',
],
]);
$generator->setFilename(sys_get_temp_dir() . '/result_file.php');
$generator->write();

$expected = <<<EOS
<?php

declare(strict_types=1);

class SampleClass
{


}


EOS;

$actual = file_get_contents(sys_get_temp_dir() . '/result_file.php');
$this->assertEquals($expected, $actual);
}

public function testMultiDeclareStatements(): void
{
$generator = FileGenerator::fromArray([
'declares' => [
'strict_types' => 1,
'ticks' => 2,
],
'class' => [
'name' => 'SampleClass',
],
]);
$generator->setFilename(sys_get_temp_dir() . '/result_file.php');
$generator->write();

$expected = <<<EOS
<?php

declare(strict_types=1);
declare(ticks=2);

class SampleClass
{


}


EOS;

$actual = file_get_contents(sys_get_temp_dir() . '/result_file.php');
$this->assertEquals($expected, $actual);
}

public function testDeclareUnknownDirectiveShouldRaiseException(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Declare directive must be on of: ticks, strict_types, encoding.');

FileGenerator::fromArray([
'declares' => [
'fubar' => 1,
],
'class' => [
'name' => 'SampleClass',
],
]);
}

public function testDeclareWrongTypeShouldRaiseException(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Declare value invalid. Expected integer got string.');

FileGenerator::fromArray([
'declares' => [
'strict_types' => 'wrong type',
],
'class' => [
'name' => 'SampleClass',
],
]);
}

public function testDeclareDuplicatesShouldOnlyGenerateOne(): void
{
$generator = FileGenerator::fromArray([
'class' => [
'name' => 'SampleClass',
],
]);
$generator->setFilename(sys_get_temp_dir() . '/result_file.php');
$generator->setDeclares([
DeclareStatement::strictTypes(1),
DeclareStatement::strictTypes(2)
]);
$generator->write();

$expected = <<<EOS
<?php

declare(strict_types=1);

class SampleClass
{


}


EOS;

$actual = file_get_contents(sys_get_temp_dir() . '/result_file.php');
$this->assertEquals($expected, $actual);
}

public function testWrongDeclareTypeShouldRaiseException(): void
{
$generator = new FileGenerator();

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('setDeclares is expecting an array of Zend\\Code\\DeclareStatement objects');
$generator->setDeclares([new \stdClass()]);
}
}