|
|
|
|
@ -9,6 +9,7 @@ use Kartierung\Attribute\Id;
|
|
|
|
|
use Kartierung\Attribute\Table;
|
|
|
|
|
use ReflectionClass;
|
|
|
|
|
use ReflectionNamedType;
|
|
|
|
|
use ReflectionParameter;
|
|
|
|
|
use ReflectionProperty;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -49,7 +50,6 @@ readonly class EntityAnalyzer
|
|
|
|
|
$attrs = $refClass->getAttributes(Table::class);
|
|
|
|
|
|
|
|
|
|
if (count($attrs) !== 1) {
|
|
|
|
|
//throw new InvalidEntity('Attribute #[Table] not found on entity ' . $refClass->name);
|
|
|
|
|
return $refClass->getShortName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -63,9 +63,17 @@ readonly class EntityAnalyzer
|
|
|
|
|
*/
|
|
|
|
|
private function fields(ReflectionClass $refClass): array
|
|
|
|
|
{
|
|
|
|
|
$props = $refClass->getProperties();
|
|
|
|
|
$ctor = $refClass->getConstructor();
|
|
|
|
|
if (!$ctor) {
|
|
|
|
|
throw new InvalidEntity(
|
|
|
|
|
"Entity $this->entity does not declare a constructor. Implement one accepting all of the "
|
|
|
|
|
. "entitie's values."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return array_map(fn(ReflectionProperty $prop) => $this->fieldFromProperty($prop), $props);
|
|
|
|
|
$params = $ctor->getParameters();
|
|
|
|
|
|
|
|
|
|
return array_map(fn(ReflectionParameter $param) => $this->fieldFromParameter($param), $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -77,93 +85,61 @@ readonly class EntityAnalyzer
|
|
|
|
|
$idFields = array_filter($fields, static fn(EntityField $f) => $f->isIdField);
|
|
|
|
|
$nrIdFields = count($idFields);
|
|
|
|
|
|
|
|
|
|
if ($nrIdFields === 0 || $nrIdFields > 1) {
|
|
|
|
|
throw new InvalidEntity("Invalid number of id fields found: $nrIdFields, expected: 1");
|
|
|
|
|
if ($nrIdFields !== 1) {
|
|
|
|
|
throw new InvalidEntity(
|
|
|
|
|
"Invalid number of id fields on entity $this->entity found: $nrIdFields, expected: 1"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $idFields[array_key_first($idFields)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param ReflectionProperty $prop
|
|
|
|
|
* @return EntityField<E>
|
|
|
|
|
*/
|
|
|
|
|
private function fieldFromProperty(ReflectionProperty $prop): EntityField
|
|
|
|
|
private function fieldFromParameter(ReflectionParameter $param): EntityField
|
|
|
|
|
{
|
|
|
|
|
$attrs = $prop->getAttributes(Column::class);
|
|
|
|
|
$attrs = $param->getAttributes(Column::class);
|
|
|
|
|
|
|
|
|
|
if (count($attrs) === 1) {
|
|
|
|
|
/** @var string $name */
|
|
|
|
|
$name = $attrs[0]->getArguments()[0];
|
|
|
|
|
/** @var Column $column */
|
|
|
|
|
$column = $attrs[0]->newInstance();
|
|
|
|
|
$name = $column->name ?: $param->getName();
|
|
|
|
|
} else {
|
|
|
|
|
$name = $prop->getName();
|
|
|
|
|
$name = $param->getName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$refClass = $prop->getDeclaringClass();
|
|
|
|
|
$writeAccess = $this->writeAccess($refClass, $prop);
|
|
|
|
|
$readAccess = $this->readAccess($refClass, $prop);
|
|
|
|
|
$refClass = $param->getDeclaringClass();
|
|
|
|
|
$readAccess = $this->readAccess($refClass, $param);
|
|
|
|
|
|
|
|
|
|
return new EntityField(
|
|
|
|
|
name: $prop->name,
|
|
|
|
|
name: $param->name,
|
|
|
|
|
fqcn: $this->entity,
|
|
|
|
|
columnName: $name,
|
|
|
|
|
isIdField: count($prop->getAttributes(Id::class)) > 0,
|
|
|
|
|
writeAccess: $writeAccess,
|
|
|
|
|
isIdField: count($param->getAttributes(Id::class)) > 0,
|
|
|
|
|
readAccess: $readAccess
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param ReflectionClass<E> $refClass
|
|
|
|
|
* @param ReflectionProperty $prop
|
|
|
|
|
* @return FieldAccess
|
|
|
|
|
*/
|
|
|
|
|
public function writeAccess(ReflectionClass $refClass, ReflectionProperty $prop): FieldAccess
|
|
|
|
|
public function readAccess(ReflectionClass $refClass, ReflectionParameter $param): FieldAccess
|
|
|
|
|
{
|
|
|
|
|
$wither = FieldAccess::witherName($prop->getName());
|
|
|
|
|
$setter = FieldAccess::setterName($prop->getName());
|
|
|
|
|
|
|
|
|
|
if ($refClass->hasMethod($setter)) {
|
|
|
|
|
$writeAccess = FieldAccess::GETSET;
|
|
|
|
|
} elseif ($refClass->hasMethod($wither)) {
|
|
|
|
|
$returnType = $refClass->getMethod($wither)->getReturnType();
|
|
|
|
|
if (!$returnType instanceof ReflectionNamedType || $returnType->getName() !== 'self') {
|
|
|
|
|
throw new InvalidEntity(
|
|
|
|
|
"Field $refClass->name::$prop->name defines wither writing method with invalid return type, " .
|
|
|
|
|
"expecting `self`."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
$getter = 'get' . ucfirst($param->getName());
|
|
|
|
|
|
|
|
|
|
$writeAccess = FieldAccess::WITHER;
|
|
|
|
|
} elseif ($prop->isPublic() && !$prop->isReadOnly()) {
|
|
|
|
|
$writeAccess = FieldAccess::PUBLIC;
|
|
|
|
|
} else {
|
|
|
|
|
throw new InvalidEntity(
|
|
|
|
|
"Field $refClass->name::$prop->name has no valid writing method. "
|
|
|
|
|
. "Implement $setter, $wither or make the field public."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $writeAccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param ReflectionClass<E> $refClass
|
|
|
|
|
* @param ReflectionProperty $prop
|
|
|
|
|
* @return FieldAccess
|
|
|
|
|
*/
|
|
|
|
|
public function readAccess(ReflectionClass $refClass, ReflectionProperty $prop): FieldAccess
|
|
|
|
|
{
|
|
|
|
|
$getter = 'get' . ucfirst($prop->getName());
|
|
|
|
|
$hasPublicProp = $refClass->hasProperty($param->getName())
|
|
|
|
|
&& $refClass->getProperty($param->getName())->isPublic();
|
|
|
|
|
|
|
|
|
|
if ($refClass->hasMethod($getter)) {
|
|
|
|
|
$readAccess = FieldAccess::GETSET;
|
|
|
|
|
} elseif ($prop->isPublic()) {
|
|
|
|
|
$readAccess = FieldAccess::GETTER;
|
|
|
|
|
} elseif ($hasPublicProp) {
|
|
|
|
|
$readAccess = FieldAccess::PUBLIC;
|
|
|
|
|
} else {
|
|
|
|
|
throw new InvalidEntity(
|
|
|
|
|
"Field $refClass->name::$prop->name has no valid reading method. "
|
|
|
|
|
. "Implement $getter or make the field public."
|
|
|
|
|
"Constructor parameter of entity $this->entity '$param->name' has no valid reading method. "
|
|
|
|
|
. "Implement $getter() or make the field public."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|