Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve: Generate inverse relations #25 #26

Merged
merged 17 commits into from
Nov 12, 2024
Merged
10 changes: 9 additions & 1 deletion src/generator/default/dbmodel.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function rules()
public function get<?= $relation->getCamelName() ?>()
{
return $this-><?= $relation->getMethod() ?>(\<?= trim($relationNamespace, '\\') ?>\<?= $relation->getClassName() ?>::class, <?php
echo $relation->linkToString()?>);
echo $relation->linkToString()?>)<?= $relation->getInverse() ? '->inverseOf(\''.$relation->getInverse().'\')' : '' ?>;
}
<?php endforeach; ?>
<?php foreach ($model->many2many as $relation): ?>
Expand All @@ -103,4 +103,12 @@ public function get<?= $relation->getCamelName() ?>()
<?php endif;?>
}
<?php endforeach; ?>
<?php $i = 1; foreach ($model->inverseRelations as $relationName => $relation): ?>

public function get<?= $relation->getCamelName().($i===1 ? '' : $i) ?>()
{
return $this-><?= $relation->getMethod() ?>(\<?= trim($relationNamespace, '\\') ?>\<?= $relation->getClassName() ?>::class, <?php
echo $relation->linkToString() ?>)->inverseOf('<?= $relation->getInverse() ?>');
}
<?php $i++; endforeach; ?>
}
202 changes: 107 additions & 95 deletions src/lib/AttributeResolver.php

Large diffs are not rendered by default.

71 changes: 46 additions & 25 deletions src/lib/SchemaToDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@

namespace cebe\yii2openapi\lib;

use cebe\openapi\exceptions\IOException;
use cebe\openapi\exceptions\TypeErrorException;
use cebe\openapi\exceptions\UnresolvableReferenceException;
use cebe\yii2openapi\lib\exceptions\InvalidDefinitionException;
use cebe\yii2openapi\lib\items\AttributeRelation;
use cebe\yii2openapi\lib\items\DbModel;
use cebe\yii2openapi\lib\items\JunctionSchemas;
use cebe\yii2openapi\lib\openapi\ComponentSchema;
use Yii;
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\helpers\StringHelper;
use function count;

Expand Down Expand Up @@ -55,28 +62,30 @@
*/
class SchemaToDatabase
{
/**
* @var \cebe\yii2openapi\lib\Config
*/
protected $config;
protected Config $config;

public function __construct(Config $config)
{
$this->config = $config;
}

/**
* @return array|\cebe\yii2openapi\lib\items\DbModel[]
* @throws \cebe\openapi\exceptions\IOException
* @throws \cebe\openapi\exceptions\TypeErrorException
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
* @throws \cebe\yii2openapi\lib\exceptions\InvalidDefinitionException
* @throws \yii\base\Exception
* @throws \yii\base\InvalidConfigException
* @return array|DbModel[]
* @throws IOException
* @throws TypeErrorException
* @throws UnresolvableReferenceException
* @throws InvalidDefinitionException
* @throws Exception
* @throws InvalidConfigException
*/
public function prepareModels():array
public function prepareModels(): array
{
/** @var DbModel[] $models */
$models = [];

/** @var AttributeResolver[] $resolvers */
$resolvers = [];

$openApi = $this->config->getOpenApi();
$junctions = $this->findJunctionSchemas();
foreach ($openApi->components->schemas as $schemaName => $openApiSchema) {
Expand All @@ -88,11 +97,25 @@ public function prepareModels():array
if ($junctions->isJunctionSchema($schemaName)) {
$schemaName = $junctions->trimPrefix($schemaName);
}
/**@var \cebe\yii2openapi\lib\AttributeResolver $resolver */
/**@var AttributeResolver $resolver */
$resolver = Yii::createObject(AttributeResolver::class, [$schemaName, $schema, $junctions, $this->config]);
$models[$schemaName] = $resolver->resolve();

// $models[$schemaName] = $resolver->resolve();
$resolvers[$schemaName] = $resolver;
$models[$schemaName] = $resolvers[$schemaName]->resolve();
}
foreach ($models as $model) {

// handle inverse relation
foreach ($resolvers as $aResolver) {
foreach ($aResolver->inverseRelations as $name => $relations) {
foreach ($relations as $relation) {
/** @var AttributeRelation $relation */
$models[$name]->inverseRelations[] = $relation;
}
}
}

foreach ($models as $model) {
foreach ($model->many2many as $relation) {
if (isset($models[$relation->viaModelName])) {
$relation->hasViaModel = true;
Expand All @@ -102,20 +125,18 @@ public function prepareModels():array
}
}

// TODO generate inverse relations

return $models;
}

/**
* @return \cebe\yii2openapi\lib\items\JunctionSchemas
* @throws \cebe\openapi\exceptions\IOException
* @throws \cebe\openapi\exceptions\TypeErrorException
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
* @throws \yii\base\Exception
* @throws \yii\base\InvalidConfigException
* @return JunctionSchemas
* @throws IOException
* @throws TypeErrorException
* @throws UnresolvableReferenceException
* @throws Exception
* @throws InvalidConfigException|InvalidDefinitionException
*/
public function findJunctionSchemas():JunctionSchemas
public function findJunctionSchemas(): JunctionSchemas
{
$junctions = [];
$openApi = $this->config->getOpenApi();
Expand Down Expand Up @@ -195,7 +216,7 @@ public function findJunctionSchemas():JunctionSchemas
return Yii::createObject(JunctionSchemas::class, [$junctions]);
}

private function canGenerateModel(string $schemaName, ComponentSchema $schema):bool
private function canGenerateModel(string $schemaName, ComponentSchema $schema): bool
{
// only generate tables for schemas of type object and those who have defined properties
if ($schema->isObjectSchema() && !$schema->hasProperties()) {
Expand Down
86 changes: 43 additions & 43 deletions src/lib/items/AttributeRelation.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

namespace cebe\yii2openapi\lib\items;

use cebe\yii2openapi\lib\traits\ForeignKeyConstraints;
use yii\helpers\Inflector;
use yii\helpers\VarDumper;
use function reset;
use cebe\yii2openapi\lib\traits\ForeignKeyConstraints;

class AttributeRelation
{
Expand All @@ -19,40 +19,29 @@ class AttributeRelation
public const HAS_ONE = 'hasOne';
public const HAS_MANY = 'hasMany';

/**
* @var string $name
**/
private $name;
private string $name;

/**
* @var string $tableName
**/
private $tableName;
private ?string $tableName;

/**
* @var string $className
**/
private $className;
private ?string $className;

/**
* @var string $method (hasOne/hasMany)
**/
private $method;
* hasOne/hasMany
*/
private ?string $method;

/**
* @var array
**/
private $link = [];
private array $link;

private bool $selfReference = false;

/**@var bool */
private $selfReference = false;
private ?string $inverse = null;

public function __construct(
string $name,
string $name,
?string $tableName = null,
?string $className = null,
?string $method = null,
array $link = []
array $link = []
) {
$this->name = $name;
$this->tableName = $tableName;
Expand All @@ -65,7 +54,7 @@ public function __construct(
* @param string $name
* @return AttributeRelation
*/
public function setName(string $name):AttributeRelation
public function setName(string $name): AttributeRelation
{
$this->name = $name;
return $this;
Expand All @@ -75,7 +64,7 @@ public function setName(string $name):AttributeRelation
* @param string $tableName
* @return AttributeRelation
*/
public function setTableName(string $tableName):AttributeRelation
public function setTableName(string $tableName): AttributeRelation
{
$this->tableName = $tableName;
return $this;
Expand All @@ -85,113 +74,124 @@ public function setTableName(string $tableName):AttributeRelation
* @param string $className
* @return AttributeRelation
*/
public function setClassName(string $className):AttributeRelation
public function setClassName(string $className): AttributeRelation
{
$this->className = $className;
return $this;
}

public function asSelfReference():AttributeRelation
public function asSelfReference(): AttributeRelation
{
$this->selfReference = true;
return $this;
}

public function asHasOne(array $link):AttributeRelation
public function asHasOne(array $link): AttributeRelation
{
$this->method = self::HAS_ONE;
$this->link = $link;
return $this;
}

public function asHasMany(array $link):AttributeRelation
public function asHasMany(array $link): AttributeRelation
{
$this->method = self::HAS_MANY;
$this->link = $link;
return $this;
}

public function isHasOne():bool
public function isHasOne(): bool
{
return $this->method === self::HAS_ONE;
}

public function isSelfReferenced():bool
public function isSelfReferenced(): bool
{
return $this->selfReference;
}

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

/**
* @return string
*/
public function getTableName():string
public function getTableName(): string
{
return $this->tableName;
}

public function getTableAlias():string
public function getTableAlias(): string
{
return "{{%$this->tableName}}";
}

/**
* @return string
*/
public function getClassName():string
public function getClassName(): string
{
return $this->className;
}

public function getClassKey():string
public function getClassKey(): string
{
return Inflector::camel2id($this->getClassName());
}

/**
* @return string
*/
public function getMethod():string
public function getMethod(): string
{
return $this->method;
}

/**
* @return array
*/
public function getLink():array
public function getLink(): array
{
return $this->link;
}

public function getCamelName():string
public function getCamelName(): string
{
return Inflector::camelize($this->name);
}

public function getColumnName():string
public function getColumnName(): string
{
return reset($this->link);
}

public function getForeignName():string
public function getForeignName(): string
{
return key($this->link);
}

public function linkToString():string
public function linkToString(): string
{
return str_replace(
[',', '=>', ', ]'],
[', ', ' => ', ']'],
preg_replace('~\s+~', '', VarDumper::export($this->getLink()))
);
}

public function setInverse(string $inverse): AttributeRelation
{
$this->inverse = $inverse;
return $this;
}

public function getInverse(): ?string
{
return $this->inverse;
}
}
Loading
Loading