src/Utils/RenderHelper.php
<?php
declare(strict_types = 1);
namespace PHPModelGenerator\Utils;
use PHPModelGenerator\Model\GeneratorConfiguration;
use PHPModelGenerator\Model\Property\PropertyInterface;
use PHPModelGenerator\Model\Schema;
use PHPModelGenerator\Model\Validator\ExtractedMethodValidator;
use PHPModelGenerator\Model\Validator\PropertyTemplateValidator;
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
/**
* Class RenderHelper
*
* @package PHPModelGenerator\Utils
*/
class RenderHelper
{
public function __construct(protected GeneratorConfiguration $generatorConfiguration) {}
public function ucfirst(string $value): string
{
return ucfirst($value);
}
public function isNull(mixed $value): bool
{
return $value === null;
}
public function getSimpleClassName(string $fqcn): string
{
$parts = explode('\\', $fqcn);
return end($parts);
}
public function joinClassNames(array $fqcns): string
{
return join(', ', array_map([$this, 'getSimpleClassName'], $fqcns));
}
/**
* Resolve all associated decorators of a property
*/
public function resolvePropertyDecorator(PropertyInterface $property, bool $nestedProperty = false): string
{
if (!$property->getDecorators()) {
return '';
}
return '$value = ' . $property->resolveDecorator('$value', $nestedProperty) . ';';
}
/**
* Generate code to handle a validation error
*/
public function validationError(PropertyValidatorInterface $validator): string
{
$exceptionConstructor = sprintf(
'new \%s($value ?? null, ...%s)',
$validator->getExceptionClass(),
preg_replace('/\'&(\$\w+)\'/i', '$1', var_export($validator->getExceptionParams(), true)),
);
if ($this->generatorConfiguration->collectErrors()) {
return "\$this->_errorRegistry->addError($exceptionConstructor);";
}
return "throw $exceptionConstructor;";
}
/**
* check if the property may contain/accept null
* - if the property is required the property may never contain null (if it's a null property null is already
* contained in the proprety type hints)
* - if the output type is requested null may be contained (if the property was not set)
* if implicitNull is enabled null may be set for the property
* - except the property contains a default value and implicit null is disabled. in this case null is not
* possible
*/
public function isPropertyNullable(PropertyInterface $property, bool $outputType = false): bool
{
return !$property->isRequired()
&& ($outputType || $this->generatorConfiguration->isImplicitNullAllowed())
&& !($property->getDefaultValue() !== null && !$this->generatorConfiguration->isImplicitNullAllowed());
}
public function getType(PropertyInterface $property, bool $outputType = false): string
{
$type = $property->getType($outputType);
if (!$type) {
return '';
}
$nullable = ($type->isNullable() ?? $this->isPropertyNullable($property, $outputType)) ? '?' : '';
return "$nullable{$type->getName()}";
}
public function getTypeHintAnnotation(PropertyInterface $property, bool $outputType = false): string
{
$typeHint = $property->getTypeHint($outputType);
$hasDefinedNullability = ($type = $property->getType($outputType)) && $type->isNullable() !== null;
if ((($hasDefinedNullability && $type->isNullable())
|| (!$hasDefinedNullability && $this->isPropertyNullable($property, $outputType))
) && !strstr($typeHint, 'mixed')
) {
$typeHint = "$typeHint|null";
}
return implode('|', array_unique(explode('|', $typeHint)));
}
public function renderValidator(PropertyValidatorInterface $validator, Schema $schema): string
{
// scoping of the validator might be required as validators from a composition might be transferred to a
// different schema
if ($validator instanceof PropertyTemplateValidator) {
$validator->setScope($schema);
}
if (!$validator instanceof ExtractedMethodValidator) {
return "
{$validator->getValidatorSetUp()}
if ({$validator->getCheck()}) {
{$this->validationError($validator)}
}
";
}
if (!$schema->hasMethod($validator->getExtractedMethodName())) {
$schema->addMethod($validator->getExtractedMethodName(), $validator->getMethod());
}
return "\$this->{$validator->getExtractedMethodName()}(\$value, \$modelData);";
}
public function renderMethods(Schema $schema): string
{
$renderedMethods = '';
// don't change to a foreach loop as the render process of a method might add additional methods
for ($i = 0; $i < count($schema->getMethods()); $i++) {
$renderedMethods .= $schema->getMethods()[array_keys($schema->getMethods())[$i]]->getCode() . "\n\n";
}
return $renderedMethods;
}
public function isMutableBaseValidator(GeneratorConfiguration $generatorConfiguration, bool $isBaseValidator): bool
{
return !$generatorConfiguration->isImmutable() && $isBaseValidator;
}
public static function varExportArray(array $values): string
{
return preg_replace('(\d+\s=>)', '', var_export($values, true));
}
}