Skip to content

Commit

Permalink
Merge pull request #26 from wol-soft/RefactorPropertyLateBinding
Browse files Browse the repository at this point in the history
Resolve properties during rendering instead of processing for correct usage of the PropertyProxy
  • Loading branch information
wol-soft authored Dec 17, 2020
2 parents 8097b0c + 9f326ae commit 9e8901a
Show file tree
Hide file tree
Showing 44 changed files with 403 additions and 180 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ php:
- 7.2
- 7.3
- 7.4
- 8.0
- nightly

install:
Expand Down
97 changes: 97 additions & 0 deletions src/Model/Property/AbstractProperty.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

namespace PHPModelGenerator\Model\Property;

use PHPModelGenerator\Exception\SchemaException;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchemaTrait;

/**
* Class AbstractProperty
*
* @package PHPModelGenerator\Model\Property
*/
abstract class AbstractProperty implements PropertyInterface
{
use JsonSchemaTrait;

/** @var string */
protected $name = '';
/** @var string */
protected $attribute = '';

/**
* Property constructor.
*
* @param string $name
* @param JsonSchema $jsonSchema
*
* @throws SchemaException
*/
public function __construct(string $name, JsonSchema $jsonSchema)
{
$this->name = $name;
$this->jsonSchema = $jsonSchema;

$this->attribute = $this->processAttributeName($name);
}

/**
* @inheritdoc
*/
public function getName(): string
{
return $this->name;
}

/**
* @inheritdoc
*/
public function getAttribute(): string
{
return ($this->isInternal() ? '_' : '') . $this->attribute;
}

/**
* Convert a name of a JSON-field into a valid PHP variable name to be used as class attribute
*
* @param string $name
*
* @return string
*
* @throws SchemaException
*/
protected function processAttributeName(string $name): string
{
$attributeName = preg_replace_callback(
'/([a-z][a-z0-9]*)([A-Z])/',
function ($matches) {
return "{$matches[1]}-{$matches[2]}";
},
$name
);

$elements = array_map(
function ($element) {
return ucfirst(strtolower($element));
},
preg_split('/[^a-z0-9]/i', $attributeName)
);

$attributeName = lcfirst(join('', $elements));

if (empty($attributeName)) {
throw new SchemaException(
sprintf(
"Property name '%s' results in an empty attribute name in file %s",
$name,
$this->jsonSchema->getFile()
)
);
}

return $attributeName;
}
}
15 changes: 13 additions & 2 deletions src/Model/Property/CompositionPropertyDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace PHPModelGenerator\Model\Property;

use PHPModelGenerator\Exception\SchemaException;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
use PHPModelGenerator\Model\SchemaDefinition\ResolvedDefinitionsCollection;

/**
Expand All @@ -26,11 +28,20 @@ class CompositionPropertyDecorator extends PropertyProxy
/**
* CompositionPropertyDecorator constructor.
*
* @param string $propertyName
* @param JsonSchema $jsonSchema
* @param PropertyInterface $property
*
* @throws SchemaException
*/
public function __construct(PropertyInterface $property)
public function __construct(string $propertyName, JsonSchema $jsonSchema, PropertyInterface $property)
{
parent::__construct(new ResolvedDefinitionsCollection([self::PROPERTY_KEY => $property]), self::PROPERTY_KEY);
parent::__construct(
$propertyName,
$jsonSchema,
new ResolvedDefinitionsCollection([self::PROPERTY_KEY => $property]),
self::PROPERTY_KEY
);
}

/**
Expand Down
76 changes: 5 additions & 71 deletions src/Model/Property/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PHPModelGenerator\Exception\SchemaException;
use PHPModelGenerator\Model\Schema;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchemaTrait;
use PHPModelGenerator\Model\Validator;
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
use PHPModelGenerator\PropertyProcessor\Decorator\Property\PropertyDecoratorInterface;
Expand All @@ -18,14 +17,8 @@
*
* @package PHPModelGenerator\Model\Property
*/
class Property implements PropertyInterface
class Property extends AbstractProperty
{
use JsonSchemaTrait;

/** @var string */
protected $name = '';
/** @var string */
protected $attribute = '';
/** @var string */
protected $type = 'null';
/** @var string|null */
Expand Down Expand Up @@ -62,28 +55,10 @@ class Property implements PropertyInterface
*/
public function __construct(string $name, string $type, JsonSchema $jsonSchema, string $description = '')
{
$this->name = $name;
parent::__construct($name, $jsonSchema);

$this->type = $type;
$this->jsonSchema = $jsonSchema;
$this->description = $description;

$this->attribute = $this->processAttributeName($name);
}

/**
* @inheritdoc
*/
public function getName(): string
{
return $this->name;
}

/**
* @inheritdoc
*/
public function getAttribute(): string
{
return ($this->isInternal() ? '_' : '') . $this->attribute;
}

/**
Expand Down Expand Up @@ -229,50 +204,9 @@ public function resolveDecorator(string $input, bool $nestedProperty): string
/**
* @inheritdoc
*/
public function hasDecorators(): bool
{
return count($this->decorators) > 0;
}

/**
* Convert a name of a JSON-field into a valid PHP variable name to be used as class attribute
*
* @param string $name
*
* @return string
*
* @throws SchemaException
*/
protected function processAttributeName(string $name): string
public function getDecorators(): array
{
$attributeName = preg_replace_callback(
'/([a-z][a-z0-9]*)([A-Z])/',
function ($matches) {
return "{$matches[1]}-{$matches[2]}";
},
$name
);

$elements = array_map(
function ($element) {
return ucfirst(strtolower($element));
},
preg_split('/[^a-z0-9]/i', $attributeName)
);

$attributeName = lcfirst(join('', $elements));

if (empty($attributeName)) {
throw new SchemaException(
sprintf(
"Property name '%s' results in an empty attribute name in file %s",
$name,
$this->jsonSchema->getFile()
)
);
}

return $attributeName;
return $this->decorators;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Model/Property/PropertyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ public function addDecorator(PropertyDecoratorInterface $decorator): PropertyInt
public function resolveDecorator(string $input, bool $nestedProperty): string;

/**
* @return bool
* @return PropertyDecoratorInterface[]
*/
public function hasDecorators(): bool;
public function getDecorators(): array;

/**
* @param bool $isPropertyRequired
Expand Down
53 changes: 29 additions & 24 deletions src/Model/Property/PropertyProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PHPModelGenerator\Model\Property;

use PHPModelGenerator\Exception\SchemaException;
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
use PHPModelGenerator\Model\SchemaDefinition\ResolvedDefinitionsCollection;
use PHPModelGenerator\Model\Schema;
Expand All @@ -16,21 +17,35 @@
*
* @package PHPModelGenerator\Model
*/
class PropertyProxy implements PropertyInterface
class PropertyProxy extends AbstractProperty
{
/** @var string */
protected $key;
/** @var string */
protected $name;
/** @var ResolvedDefinitionsCollection */
protected $definitionsCollection;

/**
* PropertyProxy constructor.
*
* @param string $name The name must be provided separately as the name is not bound to the structure of a
* referenced schema. Consequently two properties with different names can refer an identical schema utilizing the
* PropertyProxy. By providing a name to each of the proxies the resulting properties will get the correct names.
* @param JsonSchema $jsonSchema
* @param ResolvedDefinitionsCollection $definitionsCollection
* @param string $key
* @param string $key
*
* @throws SchemaException
*/
public function __construct(ResolvedDefinitionsCollection $definitionsCollection, string $key)
{
public function __construct(
string $name,
JsonSchema $jsonSchema,
ResolvedDefinitionsCollection $definitionsCollection,
string $key
) {
parent::__construct($name, $jsonSchema);

$this->key = $key;
$this->definitionsCollection = $definitionsCollection;
}
Expand All @@ -45,22 +60,6 @@ protected function getProperty(): PropertyInterface
return $this->definitionsCollection->offsetGet($this->key);
}

/**
* @inheritdoc
*/
public function getName(): string
{
return $this->getProperty()->getName();
}

/**
* @inheritdoc
*/
public function getAttribute(): string
{
return $this->getProperty()->getAttribute();
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -130,7 +129,9 @@ public function filterValidators(callable $filter): PropertyInterface
*/
public function getOrderedValidators(): array
{
return $this->getProperty()->getOrderedValidators();
return array_map(function (PropertyValidatorInterface $propertyValidator): PropertyValidatorInterface {
return $propertyValidator->withProperty($this);
}, $this->getProperty()->getOrderedValidators());
}

/**
Expand All @@ -146,15 +147,19 @@ public function addDecorator(PropertyDecoratorInterface $decorator): PropertyInt
*/
public function resolveDecorator(string $input, bool $nestedProperty): string
{
return $this->getProperty()->resolveDecorator($input, $nestedProperty);
foreach ($this->getProperty()->getDecorators() as $decorator) {
$input = $decorator->decorate($input, $this, $nestedProperty);
}

return $input;
}

/**
* @inheritdoc
*/
public function hasDecorators(): bool
public function getDecorators(): array
{
return $this->getProperty()->hasDecorators();
return $this->getProperty()->getDecorators();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Model/SchemaDefinition/SchemaDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,6 @@ public function resolveReference(
}
}

return new PropertyProxy($this->resolvedPaths, $key);
return new PropertyProxy($propertyName, $this->source, $this->resolvedPaths, $key);
}
}
Loading

0 comments on commit 9e8901a

Please sign in to comment.