Skip to content

Instantly share code, notes, and snippets.

@Ocramius
Created April 11, 2018 17:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ocramius/a7f99de6215a1cfa19b2fbd8873d1af9 to your computer and use it in GitHub Desktop.
Save Ocramius/a7f99de6215a1cfa19b2fbd8873d1af9 to your computer and use it in GitHub Desktop.
<?php
namespace Tab;
class Baz
{
/**
* @var string
*/
private $a = null;
/**
* @var int
*/
private $b = null;
/**
* @var \Bar\Foo
*/
private $c = null;
private $e = null;
private $f = null;
/**
* @var \Bbb\Aaa
*/
private $g = null;
/**
* @var string
*/
private $h = null;
public function withA(string $a) : \Tab\Baz
{
$instance = clone $this;
$instance->a = $a;
return $instance;
}
public function withoutA() : \Tab\Baz
{
$instance = clone $this;
$instance->a = null;
return $instance;
}
public function withB(int $b) : \Tab\Baz
{
$instance = clone $this;
$instance->b = $b;
return $instance;
}
public function withoutB() : \Tab\Baz
{
$instance = clone $this;
$instance->b = null;
return $instance;
}
public function withC(\Bar\Foo $c) : \Tab\Baz
{
$instance = clone $this;
$instance->c = $c;
return $instance;
}
public function withoutC() : \Tab\Baz
{
$instance = clone $this;
$instance->c = null;
return $instance;
}
public function withE($e) : \Tab\Baz
{
$instance = clone $this;
$instance->e = $e;
return $instance;
}
public function withoutE() : \Tab\Baz
{
$instance = clone $this;
$instance->e = null;
return $instance;
}
public function withF($f) : \Tab\Baz
{
$instance = clone $this;
$instance->f = $f;
return $instance;
}
public function withG(\Bbb\Aaa $g) : \Tab\Baz
{
$instance = clone $this;
$instance->g = $g;
return $instance;
}
public function withH(string $h) : \Tab\Baz
{
$instance = clone $this;
$instance->h = $h;
return $instance;
}
public function __construct($f, \Bbb\Aaa $g, string $h)
{
$this->f = $f;
$this->g = $g;
$this->h = $h;
}
}
<?php
namespace GoetasWebservices\Xsd\XsdToPhp\Php;
use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPClass;
use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPProperty;
use Zend\Code\Generator\ClassGenerator;
use Zend\Code\Generator\DocBlock\Tag\VarTag;
use Zend\Code\Generator\DocBlockGenerator;
use Zend\Code\Generator\MethodGenerator;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
final class ImmutableClassGenerator
{
public function generate(PHPClass $type)
{
$class = new ClassGenerator();
$class->setName($type->getFullName());
foreach ($type->getProperties() as $property) {
$propertyType = $property->getType();
$phpType = $propertyType ? $propertyType->getPhpType() : null;
$defaultValue = $property->getDefault();
$propertyGenerator = new PropertyGenerator(
$property->getName(),
$defaultValue,
PropertyGenerator::FLAG_PRIVATE
);
if ($phpType) {
// @TODO where do we get nullability from?
$propertyGenerator->setDocBlock(
(new DocBlockGenerator())
->setTag(new VarTag(null, $phpType))
);
}
$class->addPropertyFromGenerator($propertyGenerator);
$class->addMethodFromGenerator($this->makeWithMethod($type, $property));
$withoutMethod = $this->makeWithoutMethod($type, $property);
if ($withoutMethod) {
$class->addMethodFromGenerator($withoutMethod);
}
}
$class->addMethodFromGenerator($this->makeConstructor($type));
echo $class->generate();
exit(1);
}
private function makeWithMethod(PHPClass $class, PHPProperty $property) : MethodGenerator
{
$propertyType = $property->getType();
$propertyPhpType = $propertyType ? $propertyType->getPhpType() : null;
$propertyName = $property->getName();
$method = new MethodGenerator('with' . ucfirst($propertyName));
$method->setParameter(new ParameterGenerator($propertyName, $propertyPhpType));
$method->setReturnType($class->getFullName());
$method->setBody(\sprintf(
<<<'PHP'
$instance = clone $this;
$instance->%s = $%s;
return $instance;
PHP
,
$propertyName,
$propertyName
));
return $method;
}
private function makeWithoutMethod(PHPClass $class, PHPProperty $property) : ?MethodGenerator
{
if ($property->getRequired()) {
return null;
}
$propertyName = $property->getName();
$method = new MethodGenerator('without' . ucfirst($propertyName));
$method->setReturnType($class->getFullName());
$method->setBody(\sprintf(
<<<'PHP'
$instance = clone $this;
$instance->%s = null;
return $instance;
PHP
,
$propertyName
));
return $method;
}
private function makeConstructor(PHPClass $type)
{
/** @var $requiredProperties PHPProperty[] */
$requiredProperties = \array_filter(
$type->getProperties(),
function (PHPProperty $property) : bool {
return $property->getRequired();
}
);
$constructor = new MethodGenerator('__construct');
$body = '';
foreach ($requiredProperties as $requiredProperty) {
$propertyType = $requiredProperty->getType();
$propertyName = $requiredProperty->getName();
$propertyPhpType = $propertyType ? $propertyType->getPhpType() : null;
$mandatoryParameter = new ParameterGenerator(
$requiredProperty->getName(),
$propertyPhpType
);
$body .= '$this->' . $propertyName . ' = $' . $propertyName . ';' . "\n";
$constructor->setParameter($mandatoryParameter);
}
$constructor->setBody($body);
return $constructor;
}
}
<?php
namespace GoetasWebservices\Xsd\XsdToPhp\Tests\JmsSerializer\OTA;
use GoetasWebservices\Xsd\XsdToPhp\Naming\ShortNamingStrategy;
use GoetasWebservices\Xsd\XsdToPhp\Php\ClassGenerator;
use GoetasWebservices\Xsd\XsdToPhp\Php\ImmutableClassGenerator;
use GoetasWebservices\Xsd\XsdToPhp\Php\PhpConverter;
use GoetasWebservices\XML\XSDReader\SchemaReader;
use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPClass;
use GoetasWebservices\Xsd\XsdToPhp\Php\Structure\PHPProperty;
class ImmutableClassGeneratorTest extends \PHPUnit_Framework_TestCase
{
public function testFoo() : void
{
$class = new PHPClass('Baz', 'Tab');
$a = new PHPProperty('a', new PHPClass('string'));
$b = new PHPProperty('b', new PHPClass('int'));
$c = new PHPProperty('c', new PHPClass('Foo', 'Bar'));
// $d = new PHPProperty('d', new PHPClass('string[]'));
$e = new PHPProperty('e');
$f = new PHPProperty('f');
$g = new PHPProperty('g', new PHPClass('Aaa', 'Bbb'));
$h = new PHPProperty('h', new PHPClass('string'));
// $d->setDefault(['a', 'b', 'c']);
$f->setRequired(true);
$g->setRequired(true);
$h->setRequired(true);
$class
->addProperty($a)
->addProperty($b)
->addProperty($c)
// ->addProperty($d)
->addProperty($e)
->addProperty($f)
->addProperty($g)
->addProperty($h)
;
(new ImmutableClassGenerator())->generate($class);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment