From 1fc2b5152fea3d09de18466033fdb39d79455d57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pudil?= <me@jiripudil.cz>
Date: Thu, 29 Oct 2020 14:49:20 +0100
Subject: [PATCH] Table::new() expects values for required fields

---
 src/Scaffolding/Scaffolding.php    | 22 +++++++-----
 src/Scaffolding/TableDecorator.php | 58 ++++++++++++++++++++++--------
 2 files changed, 57 insertions(+), 23 deletions(-)

diff --git a/src/Scaffolding/Scaffolding.php b/src/Scaffolding/Scaffolding.php
index b76a816..bbf469c 100644
--- a/src/Scaffolding/Scaffolding.php
+++ b/src/Scaffolding/Scaffolding.php
@@ -9,9 +9,12 @@ use Grifart\ClassScaffolder\Decorators\GettersDecorator;
 use Grifart\ClassScaffolder\Decorators\InitializingConstructorDecorator;
 use Grifart\ClassScaffolder\Decorators\PropertiesDecorator;
 use Grifart\ClassScaffolder\Definition\ClassDefinitionBuilder;
+use Grifart\ClassScaffolder\Definition\Types\Type;
 use Grifart\Tables\Row;
 use Grifart\Tables\TypeMapper;
 use function Grifart\ClassScaffolder\Definition\Types\nullable;
+use function Grifart\ClassScaffolder\Definition\Types\resolve;
+
 
 final class Scaffolding
 {
@@ -40,13 +43,15 @@ final class Scaffolding
 			return self::location($schema, $table, $column);
 		};
 
-		$addTableFields = function (ClassDefinitionBuilder $builder) use ($columnsNativeTypes, $mapper, $location): ClassDefinitionBuilder {
-			foreach ($columnsNativeTypes as $column) {
-				$phpType = $mapper->mapType($location($column->getName()), $column->getType());
-				$builder->field(
-					$column->getName(),
-					$column->isNullable() ? nullable($phpType): $phpType
-				);
+		$columnsPhpTypes = [];
+		foreach ($columnsNativeTypes as $column) {
+			$phpType = resolve($mapper->mapType($location($column->getName()), $column->getType()));
+			$columnsPhpTypes[$column->getName()] = $column->isNullable() ? nullable($phpType) : $phpType;
+		}
+
+		$addTableFields = function (ClassDefinitionBuilder $builder) use ($columnsPhpTypes): ClassDefinitionBuilder {
+			foreach ($columnsPhpTypes as $name => $type) {
+				$builder->field($name, $type);
 			}
 			return $builder;
 		};
@@ -75,7 +80,8 @@ final class Scaffolding
 					$primaryKeyClass,
 					$rowClass,
 					$modificationClass,
-					$columnsNativeTypes
+					$columnsNativeTypes,
+					$columnsPhpTypes,
 				))
 				->build(),
 
diff --git a/src/Scaffolding/TableDecorator.php b/src/Scaffolding/TableDecorator.php
index ded0adb..90313f4 100644
--- a/src/Scaffolding/TableDecorator.php
+++ b/src/Scaffolding/TableDecorator.php
@@ -7,6 +7,7 @@ namespace Grifart\Tables\Scaffolding;
 use Grifart\ClassScaffolder\Decorators\ClassDecorator;
 use Grifart\ClassScaffolder\Decorators\DecoratorTools;
 use Grifart\ClassScaffolder\Definition\ClassDefinition;
+use Grifart\ClassScaffolder\Definition\Types\Type;
 use Grifart\Tables\CaseConvertion;
 use Grifart\Tables\RowNotFound;
 use Grifart\Tables\Table;
@@ -35,7 +36,13 @@ final class TableDecorator implements ClassDecorator
 	/** @var Column[] */
 	private $columnInfo;
 
-	public function __construct(string $schema, string $tableName, string $primaryKeyClass, string $rowClass, string $modificationClass, array $columnInfo)
+	/** @var array<string, Type> */
+	private $columnPhpTypes;
+
+	/**
+	 * @param array<string, Type> $columnPhpTypes
+	 */
+	public function __construct(string $schema, string $tableName, string $primaryKeyClass, string $rowClass, string $modificationClass, array $columnInfo, array $columnPhpTypes)
 	{
 		$this->schema = $schema;
 		$this->tableName = $tableName;
@@ -46,6 +53,7 @@ final class TableDecorator implements ClassDecorator
 
 		Assert::allIsInstanceOf($columnInfo, Column::class);
 		$this->columnInfo = $columnInfo;
+		$this->columnPhpTypes = $columnPhpTypes;
 	}
 
 
@@ -139,12 +147,41 @@ final class TableDecorator implements ClassDecorator
 				]
 			);
 
-		$classType->addMethod('add')
-			->setReturnType($this->modificationClass)
-			->setBody(
-				'return ?::new();',
-				[new Code\PhpLiteral($namespace->unresolveName($this->modificationClass))]
+		foreach (['add', 'new'] as $methodName) {
+			$addMethod = $classType->addMethod($methodName)
+				->setReturnType($this->modificationClass);
+
+			$fieldNames = [];
+			foreach ($this->columnInfo as $columnInfo) {
+				if ( ! $columnInfo->hasDefaultValue()) {
+					$fieldName = $columnInfo->getName();
+					$fieldType = $this->columnPhpTypes[$fieldName];
+
+					$addMethod->addParameter($fieldName)
+						->setTypeHint($fieldType->getTypeHint())
+						->setNullable($fieldType->isNullable());
+
+					if ($fieldType->requiresDocComment()) {
+						$addMethod->addComment(\sprintf(
+							'@param %s $%s%s',
+							$fieldType->getDocCommentType($namespace),
+							$fieldName,
+							$fieldType->hasComment() ? ' ' . $fieldType->getComment($namespace) : '',
+						));
+					}
+
+					$fieldNames[] = new Code\PhpLiteral('$' . $fieldName);
+				}
+			}
+
+			$addMethod->setBody(
+				'return ?::new(...?);',
+				[
+					new Code\PhpLiteral($namespace->unresolveName($this->modificationClass)),
+					$fieldNames,
+				]
 			);
+		}
 
 
 		$classType->addMethod('edit')
@@ -205,15 +242,6 @@ final class TableDecorator implements ClassDecorator
 				'$this->tableManager = $tableManager;'
 			);
 
-		$classType->addMethod('new')
-			->setBody(
-				'return ?::new();',
-				[
-					new Code\PhpLiteral($namespace->unresolveName($this->modificationClass)),
-				]
-			)
-			->setReturnType($this->modificationClass);
-
 
 
 
-- 
GitLab