Skip to content

Add typed accessors for patternProperties and additionalProperties #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
/.travis.yml export-ignore
/phpunit.xml export-ignore
/phpstan.neon export-ignore
/.gitlab-ci.yml export-ignore
37 changes: 37 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
before_script:
- apt-get update -yqq
- apt-get install git unzip -yqq
- curl https://composer.github.io/installer.sig | tr -d '\n' > installer.sig
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php -r "if (hash_file('SHA384', 'composer-setup.php') === file_get_contents('installer.sig')) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
- php composer-setup.php
- php -r "unlink('composer-setup.php'); unlink('installer.sig');"
- php composer.phar install --prefer-dist --no-ansi --no-interaction --no-progress

test:5.6:
image: php:5.6
script:
- pecl install xdebug-2.5.5
- docker-php-ext-enable xdebug
- vendor/bin/phpunit --configuration phpunit.xml -v --coverage-text --colors=never --stderr

test:7.0:
image: php:7.0
script:
- pecl install xdebug
- docker-php-ext-enable xdebug
- vendor/bin/phpunit --configuration phpunit.xml -v --coverage-text --colors=never --stderr

test:7.1:
image: php:7.1
script:
- pecl install xdebug
- docker-php-ext-enable xdebug
- vendor/bin/phpunit --configuration phpunit.xml -v --coverage-text --colors=never --stderr

test:7.2:
image: php:7.2
script:
- pecl install xdebug
- docker-php-ext-enable xdebug
- vendor/bin/phpunit --configuration phpunit.xml -v --coverage-text --colors=never --stderr
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
}
],
"require": {
"ext-json": "*",
"swaggest/json-schema": "^0.12.0",
"swaggest/code-builder": "^0.3.1",
"php": ">=5.5.0"
Expand Down
24 changes: 22 additions & 2 deletions src/JsonSchema/PhpBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@
use Swaggest\PhpCodeBuilder\PhpAnyType;
use Swaggest\PhpCodeBuilder\PhpClass;
use Swaggest\PhpCodeBuilder\PhpClassProperty;
use Swaggest\PhpCodeBuilder\PhpCode;
use Swaggest\PhpCodeBuilder\PhpConstant;
use Swaggest\PhpCodeBuilder\PhpDoc;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
use Swaggest\PhpCodeBuilder\PhpNamedVar;
use Swaggest\PhpCodeBuilder\PhpCode;
use Swaggest\PhpCodeBuilder\Property\AdditionalPropertiesGetter;
use Swaggest\PhpCodeBuilder\Property\AdditionalPropertySetter;
use Swaggest\PhpCodeBuilder\Property\Getter;
use Swaggest\PhpCodeBuilder\Property\PatternPropertiesGetter;
use Swaggest\PhpCodeBuilder\Property\PatternPropertySetter;
use Swaggest\PhpCodeBuilder\Property\Setter;
use Swaggest\PhpCodeBuilder\Types\TypeOf;

Expand Down Expand Up @@ -173,6 +178,21 @@ private function makeClass($schema, $path)
}
}

if ($schema->additionalProperties instanceof Schema) {
$class->addMethod(new AdditionalPropertiesGetter($this->getType($schema->additionalProperties)));
$class->addMethod(new AdditionalPropertySetter($this->getType($schema->additionalProperties)));
}

if ($schema->patternProperties) {
foreach ($schema->patternProperties as $pattern => $patternProperty) {
$const = new PhpConstant(PhpCode::makePhpConstantName($pattern . '_PROPERTY_PATTERN'), $pattern);
$class->addConstant($const);

$class->addMethod(new PatternPropertiesGetter($const, $this->getType($patternProperty)));
$class->addMethod(new PatternPropertySetter($const, $this->getType($patternProperty)));
}
}

$schemaBuilder = new SchemaBuilder($schema, '$ownerSchema', $path, $this, false);
if ($this->skipSchemaDescriptions) {
$schemaBuilder->skipProperty(JsonSchema::names()->description);
Expand All @@ -188,7 +208,7 @@ private function makeClass($schema, $path)
$phpDoc->add(
PhpDoc::TAG_METHOD,
new PlaceholderString(
'static :type import($data, :context $options=null)',
'static :type import($data, :context $options = null)',
array(
':type' => new TypeOf($type, true),
':context' => new TypeOf(PhpClass::byFQN(Context::class))
Expand Down
7 changes: 3 additions & 4 deletions src/JsonSchema/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

use Swaggest\CodeBuilder\PlaceholderString;
use Swaggest\JsonSchema\Constraint\Type;
use Swaggest\JsonSchema\JsonSchema;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;
use Swaggest\JsonSchema\Structure\ObjectItem;
Expand Down Expand Up @@ -99,7 +98,7 @@ private function processType()
break;

default:
$types = var_export($this->schema->type, true);
$types = PhpCode::varExport($this->schema->type);
$result = $this->createVarName
? "{$this->varName} = (new ::schema())->setType($types);"
: "{$this->varName}->type = $types;";
Expand Down Expand Up @@ -347,11 +346,11 @@ private function processOther()
//$value = $value->jsonSerialize();
$export = 'new \stdClass()';
} elseif ($value instanceof \stdClass) {
$export = '(object)' . var_export((array)$value, 1);
$export = '(object)' . PhpCode::varExport((array)$value);
} elseif (is_string($value)) {
$export = '"' . str_replace(array('\\', "\n", "\r", "\t", '"'), array('\\\\', '\n', '\r', '\t', '\"'), $value) . '"';
} else {
$export = var_export($value, 1);
$export = PhpCode::varExport($value);
}

$key = PhpCode::makePhpName($key);
Expand Down
7 changes: 5 additions & 2 deletions src/JsonSchema/TypeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,27 @@ private function processArrayType()
}
}

private function isSchema($var) {
private function isSchema($var)
{
return $var instanceof Schema;
}

private function processObjectType()
{
if ($this->schema->patternProperties !== null) {
foreach ($this->schema->patternProperties as $pattern => $schema) {
$this->result->add(new ArrayOf($this->phpBuilder->getType($schema, $this->path . '->' . $pattern)));
//$this->result->add(new ArrayOf($this->phpBuilder->getType($schema, $this->path . '->' . $pattern)));
}
}


if ($this->schema->additionalProperties instanceof Schema) {
$this->result->add(new ArrayOf($this->phpBuilder->getType(
$this->schema->additionalProperties,
$this->path . '->' . (string)Schema::names()->additionalProperties)
));
}

}

private function typeSwitch($type)
Expand Down
3 changes: 2 additions & 1 deletion src/PhpClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ protected function toString()
$content = $this->indentLines(trim($content));

return <<<PHP
{$this->renderHeadComment()}{$this->renderIsAbstract()}class {$this->name}{$this->renderExtends()}{$this->renderImplements()} {
{$this->renderHeadComment()}{$this->renderIsAbstract()}class {$this->name}{$this->renderExtends()}{$this->renderImplements()}
{
$content
}
PHP;
Expand Down
22 changes: 19 additions & 3 deletions src/PhpCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,16 @@ public static function fromCamelCase($input)
{
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
$ret = $matches[0];
$index = array();
foreach ($ret as &$match) {
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
$index[$match] = '_' . ($match == strtoupper($match) ? strtolower($match) : lcfirst($match));
}
return implode('_', $ret);
krsort($index);
$result = strtr($input, $index);
if ($input[0] !== '_' && $result[0] === '_') {
$result = substr($result, 1);
}
return preg_replace('/_+/', '_', $result);
}


Expand Down Expand Up @@ -100,7 +106,7 @@ public static function makePhpNamespaceName(array $nsItems)
public static function makePhpConstantName($rawName)
{
$phpName = preg_replace("/([^a-zA-Z0-9_]+)/", "_", $rawName);

$phpName = trim($phpName, '_');
$phpName = self::fromCamelCase($phpName);

if (in_array(strtolower($phpName), self::$keywords)) {
Expand All @@ -115,4 +121,14 @@ public static function makePhpConstantName($rawName)
return strtoupper($phpName);
}


public static function varExport($value)
{
$result = var_export($value, 1);
$result = str_replace("array (\n", "array(\n", $result);
$result = str_replace(' ', ' ', $result);
$result = str_replace("array(\n)", "array()", $result);
return $result;
}

}
4 changes: 4 additions & 0 deletions src/PhpTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@

abstract class PhpTemplate extends AbstractTemplate
{
public function indentLines($text)
{
return $this->padLines(' ', $text, false);
}

}
34 changes: 34 additions & 0 deletions src/Property/AdditionalPropertiesGetter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Swaggest\PhpCodeBuilder\Property;


use Swaggest\PhpCodeBuilder\PhpAnyType;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
use Swaggest\PhpCodeBuilder\Types\ArrayOf;

class AdditionalPropertiesGetter extends PhpFunction
{
public function __construct(PhpAnyType $type)
{
parent::__construct('getAdditionalPropertyValues', PhpFlags::VIS_PUBLIC);

$this->skipCodeCoverage = true;

$this->setResult(new ArrayOf($type));
$this->setBody(
<<<'PHP'
$result = array();
if (!$names = $this->getAdditionalPropertyNames()) {
return $result;
}
foreach ($names as $name) {
$result[$name] = $this->$name;
}
return $result;

PHP
);
}
}
33 changes: 33 additions & 0 deletions src/Property/AdditionalPropertySetter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Swaggest\PhpCodeBuilder\Property;


use Swaggest\PhpCodeBuilder\PhpAnyType;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
use Swaggest\PhpCodeBuilder\PhpNamedVar;
use Swaggest\PhpCodeBuilder\PhpStdType;

class AdditionalPropertySetter extends PhpFunction
{
public function __construct(PhpAnyType $type)
{
parent::__construct('setAdditionalPropertyValue', PhpFlags::VIS_PUBLIC);

$this->addArgument(new PhpNamedVar('name', PhpStdType::string()));
$this->addArgument(new PhpNamedVar('value', $type));

$this->skipCodeCoverage = true;

$this->setResult(PhpStdType::tSelf());
$this->setBody(
<<<'PHP'
$this->addAdditionalPropertyName($name);
$this->{$name} = $value;
return $this;

PHP
);
}
}
1 change: 0 additions & 1 deletion src/Property/Getter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Swaggest\PhpCodeBuilder\Property;


use Swaggest\PhpCodeBuilder\PhpClassProperty;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
Expand Down
37 changes: 37 additions & 0 deletions src/Property/PatternPropertiesGetter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Swaggest\PhpCodeBuilder\Property;


use Swaggest\PhpCodeBuilder\PhpAnyType;
use Swaggest\PhpCodeBuilder\PhpCode;
use Swaggest\PhpCodeBuilder\PhpConstant;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
use Swaggest\PhpCodeBuilder\Types\ArrayOf;

class PatternPropertiesGetter extends PhpFunction
{
public function __construct(PhpConstant $patternConst, PhpAnyType $type)
{
$name = PhpCode::makePhpName($patternConst->getValue(), false);
parent::__construct('get' . $name . 'Values', PhpFlags::VIS_PUBLIC);

$this->skipCodeCoverage = true;

$this->setResult(new ArrayOf($type));
$this->setBody(
<<<PHP
\$result = array();
if (!\$names = \$this->getPatternPropertyNames(self::{$patternConst->getName()})) {
return \$result;
}
foreach (\$names as \$name) {
\$result[\$name] = \$this->\$name;
}
return \$result;

PHP
);
}
}
51 changes: 51 additions & 0 deletions src/Property/PatternPropertySetter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Swaggest\PhpCodeBuilder\Property;


use Swaggest\CodeBuilder\PlaceholderString;
use Swaggest\JsonSchema\Exception\StringException;
use Swaggest\JsonSchema\Helper;
use Swaggest\JsonSchema\InvalidValue;
use Swaggest\PhpCodeBuilder\PhpAnyType;
use Swaggest\PhpCodeBuilder\PhpClass;
use Swaggest\PhpCodeBuilder\PhpCode;
use Swaggest\PhpCodeBuilder\PhpConstant;
use Swaggest\PhpCodeBuilder\PhpFlags;
use Swaggest\PhpCodeBuilder\PhpFunction;
use Swaggest\PhpCodeBuilder\PhpNamedVar;
use Swaggest\PhpCodeBuilder\PhpStdType;
use Swaggest\PhpCodeBuilder\Types\TypeOf;

class PatternPropertySetter extends PhpFunction
{
public function __construct(PhpConstant $patternConst, PhpAnyType $type)
{
$name = PhpCode::makePhpName($patternConst->getValue(), false);
parent::__construct('set' . $name . 'Value', PhpFlags::VIS_PUBLIC);

$this->addArgument(new PhpNamedVar('name', PhpStdType::string()));
$this->addArgument(new PhpNamedVar('value', $type));

$this->skipCodeCoverage = true;
$this->addThrows(PhpClass::byFQN(InvalidValue::class));

$this->setResult(PhpStdType::tSelf());
$this->setBody(
new PlaceholderString(<<<PHP
if (preg_match(:helper::toPregPattern(self::{$patternConst->getName()}), \$name)) {
throw new StringException('Pattern mismatch', :stringException::PATTERN_MISMATCH);
}
\$this->addPatternPropertyName(self::{$patternConst->getName()}, \$name);
\$this->{\$name} = \$value;
return \$this;

PHP
,
array(
':stringException' => new TypeOf(PhpClass::byFQN(StringException::class)),
':helper' => new TypeOf(PhpClass::byFQN(Helper::class)),
))
);
}
}
Loading