diff --git a/README.md b/README.md index 3828272..694f5a1 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,18 @@ The following list explains the directory structure in more detail: - `logs/` - log files - `runtime/` - temporary runtime files + +# Development + +Below commands are helpful while developing this project: + +```bash +./yii gii/api --openApiPath=/app/openapi/schema.yaml --generateMigrations=0 --generateControllers=0 --generateUrls=0 + +./yii gii/api --openApiPath=/app/openapi/schema.yaml --generateMigrations=1 --generateControllers=0 --generateUrls=0 --generateModels=0 --generateModelFaker=0 +``` + + # Support **Need help with your API project?** diff --git a/config/gii-generators.php b/config/gii-generators.php index a890af5..fe63a72 100644 --- a/config/gii-generators.php +++ b/config/gii-generators.php @@ -11,6 +11,5 @@ 'modelNamespace' => 'common\\models', 'fakerNamespace' => 'common\\models\\faker', 'migrationPath' => '@common/migrations', - ], ]; diff --git a/console/commands/FakerController.php b/console/commands/FakerController.php index d7941b5..8cf8b65 100644 --- a/console/commands/FakerController.php +++ b/console/commands/FakerController.php @@ -4,7 +4,7 @@ use yii\console\Controller; use yii\helpers\Console; -use yii\helpers\FileHelper; +use yii\helpers\{FileHelper, VarDumper}; use yii\helpers\StringHelper; /** @@ -19,9 +19,11 @@ public function actionIndex() 'except' => ['BaseModelFaker.php'], ]); - foreach($fakers as $fakerFile) { - $className = 'common\\models\\faker\\' . StringHelper::basename($fakerFile, '.php'); - $this->stdout('Generating fake data for ' . StringHelper::basename($fakerFile, 'Faker.php') . '...'); + $sortedFakersModels = static::sortModels($fakers, '\\common\\models\\faker\\'); + + foreach($sortedFakersModels as $justModelClassName) { + $className = 'common\\models\\faker\\' . StringHelper::basename($justModelClassName, '.php').'Faker'; + $this->stdout('Generating fake data for ' . StringHelper::basename($justModelClassName, 'Faker.php') . '...'); $faker = new $className; for($i = 0; $i < 10; $i++) { $model = $faker->generateModel(); @@ -33,4 +35,70 @@ public function actionIndex() $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); } } + + public static function sortModels(array $fakers, string $fakerNamespace = 'app\\models\\') + { + $modelsDependencies = []; + foreach($fakers as $fakerFile) { + $className = $fakerNamespace . StringHelper::basename($fakerFile, '.php'); + $faker = new $className; + + $modelClassName = str_replace( + 'Faker', + '', + StringHelper::basename($fakerFile, '.php') + ); + + if (!method_exists($className, 'dependentOn')) { + $modelsDependencies[$modelClassName] = null; + } else { + $modelsDependencies[$modelClassName] = $className::dependentOn(); + } + } + + $standalone = array_filter($modelsDependencies, function ($elm) { + return $elm === null; + }); + + $dependent = array_filter($modelsDependencies, function ($elm) { + return $elm !== null; + }); + + $justDepenentModels = array_keys($dependent); + $sortedDependentModels = $justDepenentModels; + + foreach ($justDepenentModels as $model) { + if ($modelsDependencies[$model] !== null) { + foreach ($modelsDependencies[$model] as $dependentOn) { + if ($modelsDependencies[$dependentOn] !== null) { + // move $dependentOn before $model + + // move model to sort/order + // in that function if it is already before (sorted) then avoid it + static::moveModel($sortedDependentModels, $dependentOn, $model); + } + } + } + } + + $finalSortedModels = array_merge(array_keys($standalone), $sortedDependentModels); + return $finalSortedModels; + } + + public static function moveModel(&$sortedDependentModels, $dependentOn, $model) + { + $modelKey = array_search($model, $sortedDependentModels); + $depKey = array_search($dependentOn, $sortedDependentModels); + if ($depKey < $modelKey) { + return; + } + + unset($sortedDependentModels[$depKey]); + + $restRight = array_slice($sortedDependentModels, $modelKey); + $theKey = (($modelKey) < 0) ? 0 : ($modelKey); + $restLeft = array_slice($sortedDependentModels, 0, $theKey); + + $sortedDependentModels = array_merge($restLeft, [$dependentOn], $restRight); + } } diff --git a/openapi/schema.yaml b/openapi/schema.yaml new file mode 100644 index 0000000..d50402b --- /dev/null +++ b/openapi/schema.yaml @@ -0,0 +1,203 @@ +openapi: 3.0.3 +# Edit this schema and start your project +# This is sample schema +# To generate code which is based on this schema +# run commands mentioned Development section in README.md file +info: + title: 'Proxy-Service' + description: "" + version: 1.0.0 + contact: + name: '...' + email: you@example.com +servers: + - url: 'http://localhost:8937' + description: 'Local Dev API' +security: + - BasicAuth: [] +components: + securitySchemes: + BasicAuth: + type: http + scheme: basic + schemas: + Account: + description: user account + type: object + required: + - id + - name + properties: + id: + type: integer + name: + description: account name + type: string + maxLength: 40 + x-faker: 'substr($faker->userName(), 0, 40)' + + Domain: + description: domain + type: object + required: + - id + - name + - account + - created_at + properties: + id: + type: integer + name: + description: domain or sub-domain name, in DNS syntax, IDN are converted + type: string + maxLength: 128 + x-faker: '$faker->domainName' + account: + $ref: '#/components/schemas/Account' + + routings: + type: array + items: + $ref: '#/components/schemas/Routing' + + created_at: + readOnly: true + type: string + format: datetime + x-db-type: datetime + nullable: false + + Routing: + description: rounting specification + type: object + required: + - id + - domain + properties: + id: + type: integer + domain: + $ref: '#/components/schemas/Domain' + path: + type: string + maxLength: 255 + x-faker: '$faker->randomElement(["/", "/", "/", "/", "/api", "/tools", "/assets/web"])' + + ssl: + type: boolean + redirect_to_ssl: + type: boolean + + service: + type: string + maxLength: 255 + x-faker: '"http://tador.cebe.net/" . $faker->domainName' + + created_at: + readOnly: true + type: string + format: datetime + x-db-type: datetime + nullable: true + d123: + $ref: '#/components/schemas/D123' + a123: + $ref: '#/components/schemas/A123' + + D123: + description: desc + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + A123: + description: desc + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + b123: + $ref: '#/components/schemas/B123' + B123: + description: desc + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + c123: + $ref: '#/components/schemas/C123' + C123: + description: desc + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + E123: + description: desc + type: object + required: + - id + properties: + id: + type: integer + name: + type: string + b123: + $ref: '#/components/schemas/B123' + + +paths: + /: + get: + responses: [] + description: none + + + +# Dependencies: +# 'E123' => [ +# 0 => 'B123' +# ] +# 'Account' => null +# 'C123' => null +# 'Domain' => [ +# 0 => 'Account' +# ] +# 'B123' => [ +# 0 => 'C123' +# ] +# 'Routing' => [ +# 0 => 'Domain' +# 1 => 'D123' +# 2 => 'A123' +# ] +# 'D123' => null +# 'A123' => [ +# 0 => 'B123' +# ] + +# Sorted: +# 'Account', +# 'C123', +# 'D123', +# 'B123', +# 'E123', +# 'Domain', +# 'A123', +# 'Routing',