Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Commit 54aa988

Browse files
authored
Merge pull request #95 from Insolita/91-fix
91 fix
2 parents c8327d2 + 66b23d8 commit 54aa988

21 files changed

+471
-24
lines changed

src/lib/AttributeResolver.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Yii;
2020
use yii\helpers\Inflector;
2121
use yii\helpers\StringHelper;
22+
use yii\helpers\VarDumper;
2223
use function explode;
2324
use function strpos;
2425
use function strtolower;
@@ -204,6 +205,10 @@ protected function resolveProperty(PropertySchema $property, bool $isRequired):v
204205
}
205206

206207
$fkProperty = $property->getTargetProperty();
208+
if (!$fkProperty && !$property->getRefSchema()->isObjectSchema()) {
209+
$this->resolvePropertyRef($property, $attribute);
210+
return;
211+
}
207212
if (!$fkProperty) {
208213
return;
209214
}
@@ -388,4 +393,28 @@ protected function prepareIndexes(array $indexes):array
388393
}
389394
return $dbIndexes;
390395
}
396+
397+
/**
398+
* @param \cebe\yii2openapi\lib\openapi\PropertySchema $property
399+
* @param \cebe\yii2openapi\lib\items\Attribute $attribute
400+
* @return void
401+
* @throws \yii\base\InvalidConfigException
402+
*/
403+
protected function resolvePropertyRef(PropertySchema $property, Attribute $attribute):void
404+
{
405+
$fkProperty = new PropertySchema(
406+
$property->getRefSchema()->getSchema(),
407+
$property->getName(),
408+
$this->schema
409+
);
410+
[$min, $max] = $fkProperty->guessMinMax();
411+
$attribute->setPhpType($fkProperty->guessPhpType())
412+
->setDbType($fkProperty->guessDbType(true))
413+
->setSize($fkProperty->getMaxLength())
414+
->setDescription($fkProperty->getAttr('description'))
415+
->setDefault($fkProperty->guessDefault())
416+
->setLimits($min, $max, $fkProperty->getMinLength());
417+
$this->attributes[$property->getName()] =
418+
$attribute->setFakerStub($this->guessFakerStub($attribute, $fkProperty));
419+
}
391420
}

src/lib/SchemaToDatabase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function prepareModels():array
8080
$openApi = $this->config->getOpenApi();
8181
$junctions = $this->findJunctionSchemas();
8282
foreach ($openApi->components->schemas as $schemaName => $openApiSchema) {
83-
$schema = Yii::createObject(ComponentSchema::class, [$openApiSchema]);
83+
$schema = Yii::createObject(ComponentSchema::class, [$openApiSchema, $schemaName]);
8484

8585
if (!$this->canGenerateModel($schemaName, $schema)) {
8686
continue;
@@ -121,7 +121,7 @@ public function findJunctionSchemas():JunctionSchemas
121121
$openApi = $this->config->getOpenApi();
122122
foreach ($openApi->components->schemas as $schemaName => $openApiSchema) {
123123
/**@var ComponentSchema $schema */
124-
$schema = Yii::createObject(ComponentSchema::class, [$openApiSchema]);
124+
$schema = Yii::createObject(ComponentSchema::class, [$openApiSchema, $schemaName]);
125125
if ($schema->isNonDb()) {
126126
continue;
127127
}

src/lib/items/FractalAction.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ public function shouldUseCustomFindForModel():bool
246246

247247
public function getIdParamType(): string
248248
{
249+
if (!isset($this->params[$this->idParam]['type'])) {
250+
return 'string';
251+
}
249252
return $this->params[$this->idParam]['type'] === 'integer' ? 'int' : 'string';
250253
}
251254
}

src/lib/openapi/ComponentSchema.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class ComponentSchema
2424
*/
2525
private $schema;
2626

27+
/**
28+
* @var string
29+
**/
30+
private $name;
31+
2732
/**
2833
* @var bool
2934
*/
@@ -43,7 +48,7 @@ class ComponentSchema
4348
/**
4449
* @throws \cebe\openapi\exceptions\UnresolvableReferenceException
4550
*/
46-
public function __construct(SpecObjectInterface $openApiSchema)
51+
public function __construct(SpecObjectInterface $openApiSchema, string $name)
4752
{
4853
if ($openApiSchema instanceof Reference) {
4954
$this->isReference = true;
@@ -52,6 +57,7 @@ public function __construct(SpecObjectInterface $openApiSchema)
5257
} else {
5358
$this->schema = $openApiSchema;
5459
}
60+
$this->name = $name;
5561
$this->pkName = $this->schema->{CustomSpecAttr::PRIMARY_KEY} ?? 'id';
5662
$this->requiredProps = $this->schema->required ?? [];
5763
$this->indexes = $this->schema->{CustomSpecAttr::INDEXES} ?? [];
@@ -62,6 +68,11 @@ public function getSchema()
6268
return $this->schema;
6369
}
6470

71+
public function getName()
72+
{
73+
return $this->name;
74+
}
75+
6576
public function isReference():bool
6677
{
6778
return $this->isReference;

src/lib/openapi/PropertySchema.php

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use cebe\openapi\spec\Reference;
1313
use cebe\openapi\SpecObjectInterface;
1414
use cebe\yii2openapi\lib\CustomSpecAttr;
15+
use cebe\yii2openapi\lib\exceptions\InvalidDefinitionException;
1516
use Throwable;
1617
use Yii;
1718
use yii\db\Schema as YiiDbSchema;
@@ -20,7 +21,6 @@
2021
use yii\helpers\StringHelper;
2122
use function is_int;
2223
use function strpos;
23-
use function substr;
2424

2525
class PropertySchema
2626
{
@@ -61,6 +61,7 @@ class PropertySchema
6161
* @param \cebe\openapi\SpecObjectInterface $property
6262
* @param string $name
6363
* @param \cebe\yii2openapi\lib\openapi\ComponentSchema $schema
64+
* @throws \cebe\yii2openapi\lib\exceptions\InvalidDefinitionException
6465
* @throws \yii\base\InvalidConfigException
6566
*/
6667
public function __construct(SpecObjectInterface $property, string $name, ComponentSchema $schema)
@@ -82,21 +83,24 @@ public function __construct(SpecObjectInterface $property, string $name, Compone
8283
}
8384

8485
/**
86+
* @throws \cebe\yii2openapi\lib\exceptions\InvalidDefinitionException
8587
* @throws \yii\base\InvalidConfigException
8688
*/
8789
private function initReference():void
8890
{
8991
$this->isReference = true;
9092
$this->refPointer = $this->property->getJsonReference()->getJsonPointer()->getPointer();
93+
$refSchemaName = $this->getRefSchemaName();
9194
if ($this->isRefPointerToSelf()) {
9295
$this->refSchema = $this->schema;
9396
} elseif ($this->isRefPointerToSchema()) {
9497
$this->property->getContext()->mode = ReferenceContext::RESOLVE_MODE_ALL;
95-
$this->refSchema = Yii::createObject(ComponentSchema::class, [$this->property->resolve()]);
98+
$this->refSchema = Yii::createObject(ComponentSchema::class, [$this->property->resolve(), $refSchemaName]);
9699
}
97100
}
98101

99102
/**
103+
* @throws \cebe\yii2openapi\lib\exceptions\InvalidDefinitionException
100104
* @throws \yii\base\InvalidConfigException
101105
*/
102106
private function initItemsReference():void
@@ -111,7 +115,7 @@ private function initItemsReference():void
111115
$this->refSchema = $this->schema;
112116
} elseif ($this->isRefPointerToSchema()) {
113117
$items->getContext()->mode = ReferenceContext::RESOLVE_MODE_ALL;
114-
$this->refSchema = Yii::createObject(ComponentSchema::class, [$items->resolve()]);
118+
$this->refSchema = Yii::createObject(ComponentSchema::class, [$items->resolve(), $this->getRefSchemaName()]);
115119
}
116120
}
117121

@@ -135,6 +139,11 @@ public function getProperty():SpecObjectInterface
135139
return $this->property;
136140
}
137141

142+
public function getRefPointer(): string
143+
{
144+
return $this->refPointer ?? '';
145+
}
146+
138147
public function getRefSchema():ComponentSchema
139148
{
140149
if (!$this->isReference && !$this->isItemsReference) {
@@ -174,18 +183,23 @@ public function isRefPointerToSchema():bool
174183

175184
public function isRefPointerToSelf():bool
176185
{
177-
return $this->isRefPointerToSchema() && strpos($this->refPointer, '/properties/') !== false;
186+
return $this->isRefPointerToSchema()
187+
&& strpos($this->refPointer, '/' . $this->schema->getName() . '/') !== false
188+
&& strpos($this->refPointer, '/properties/') !== false;
178189
}
179190

180-
181-
182191
public function getRefSchemaName():string
183192
{
184193
if (!$this->isReference && !$this->isItemsReference) {
185194
throw new BadMethodCallException('Property should be a reference or contains items with reference');
186195
}
187-
$name = substr($this->refPointer, self::REFERENCE_PATH_LEN);
188-
return $this->isRefPointerToSelf() ? substr($name, 0, strpos($name, '/properties/')) : $name;
196+
$pattern = strpos($this->refPointer, '/properties/') !== false ?
197+
'~^'.self::REFERENCE_PATH.'(?<schemaName>.+)/properties/(?<propName>.+)$~'
198+
: '~^'.self::REFERENCE_PATH.'(?<schemaName>.+)$~';
199+
if (!\preg_match($pattern, $this->refPointer, $matches)) {
200+
throw new InvalidDefinitionException('Invalid schema reference');
201+
}
202+
return $matches['schemaName'];
189203
}
190204

191205
public function getRefClassName():string

tests/docker/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ RUN curl -o /tmp/composer-setup.php https://getcomposer.org/installer \
6161
# Enable Xdebug
6262
ENV XDEBUGINI_PATH=/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
6363

64-
RUN echo "xdebug.idekey=PHPSTORM" >> $XDEBUGINI_PATH && \
64+
RUN echo "xdebug.idekey=PHP_STORM" >> $XDEBUGINI_PATH && \
6565
echo "xdebug.default_enable=1" >> $XDEBUGINI_PATH && \
6666
echo "xdebug.remote_enable=1" >> $XDEBUGINI_PATH && \
67-
echo "xdebug.remote_connect_back=0" >> $XDEBUGINI_PATH && \
67+
echo "xdebug.remote_connect_back=1" >> $XDEBUGINI_PATH && \
6868
echo "xdebug.remote_log=1" >> $XDEBUGINI_PATH && \
6969
echo "xdebug.remote_port=9000" >> $XDEBUGINI_PATH && \
70-
echo "xdebug.remote_autostart=0" >> $XDEBUGINI_PATH
70+
echo "xdebug.remote_autostart=1" >> $XDEBUGINI_PATH
7171

7272
WORKDIR /app

tests/fixtures/non-db.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<?php
2+
//Data provider for AttributeResolver test for ref_noobject.yml spec
3+
24
use cebe\yii2openapi\lib\items\Attribute;
35
use cebe\yii2openapi\lib\items\AttributeRelation;
46
use cebe\yii2openapi\lib\items\DbModel;
@@ -23,6 +25,20 @@
2325
'relations' => [
2426
'parentPet' => new AttributeRelation('parentPet', 'pets', 'Pet', 'hasOne', ['id' => 'parentPet_id']),
2527
'favoritePets' => new AttributeRelation('favoritePets', 'pets', 'Pet', 'hasMany', ['pet_statistic_id' => 'id']),
28+
]]),
29+
'personWatch' => new DbModel([
30+
'pkName' => 'id',
31+
'name' => 'PersonWatch',
32+
'tableName' => '',
33+
'description' => 'Information about a user watching a Person',
34+
'isNotDb' => true,
35+
'attributes' => [
36+
'personId' => (new Attribute('personId', ['phpType' => 'string', 'dbType' => 'string']))
37+
->setReadOnly(false)->setRequired(false)->setDescription('The MongoDB Identifier'),
38+
'userId' => (new Attribute('userId', ['phpType' => 'string', 'dbType' => 'string']))
39+
->setReadOnly(false)->setRequired(false)->setDescription('The MongoDB Identifier'),
40+
'someProp' => (new Attribute('someProp', ['phpType' => 'int', 'dbType' => 'integer']))
41+
->setReadOnly(false)->setRequired(false)
2642
]
2743
])
2844
];

tests/specs/ref_noobject.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
return [
4+
'openApiPath' => '@specs/ref_noobject.yaml',
5+
'generateUrls' => true,
6+
'generateControllers' => true,
7+
'useJsonApi' => true,
8+
'extendableTransformers' => false,
9+
'generateModels' => true,
10+
'generateModelsOnlyXTable' => false,
11+
'generateMigrations' => true,
12+
'excludeModels' => [
13+
'Error',
14+
],
15+
];

tests/specs/ref_noobject.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
info:
2+
version: 1.0.0
3+
title: Bad reference type handling
4+
servers:
5+
- url: http://localhost:3001/api/v4
6+
tags:
7+
- name: watching
8+
#description: Operations about watching people
9+
openapi: 3.0.2
10+
paths:
11+
"/watch/{personId}":
12+
post:
13+
operationId: toggleWatch
14+
summary: "Toggle person watch"
15+
##description: ""
16+
tags:
17+
- watching
18+
parameters:
19+
- name: personId
20+
schema:
21+
$ref: "#/components/schemas/Mid"
22+
in: path
23+
required: true
24+
responses:
25+
"200":
26+
description: Successful operation
27+
content:
28+
application/json:
29+
schema:
30+
$ref: "#/components/schemas/PersonWatch"
31+
requestBody:
32+
required: true
33+
content:
34+
application/json:
35+
schema:
36+
$ref: "#/components/schemas/PersonWatch"
37+
components:
38+
schemas:
39+
Mid:
40+
description: The MongoDB Identifier
41+
type: string
42+
x-faker: false
43+
x-db-type: false
44+
pattern: ^[0-9a-f]{24}$
45+
PersonWatch:
46+
description: Information about a user watching a Person
47+
type: object
48+
x-table: false
49+
properties:
50+
personId:
51+
$ref: "#/components/schemas/Mid"
52+
userId:
53+
$ref: "#/components/schemas/Mid"
54+
someProp:
55+
type: integer
56+
x-faker: false
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
/**
3+
* OpenAPI UrlRules
4+
*
5+
* This file is auto generated.
6+
*/
7+
return [
8+
'POST watch/<personId>' => 'person-watch/create',
9+
'watch/<personId>' => 'person-watch/options',
10+
];

0 commit comments

Comments
 (0)