Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions config/blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@
*/
'fake_nullables' => true,

/*
|--------------------------------------------------------------------------
| Method Return Type Declarations
|--------------------------------------------------------------------------
|
| Enable or disable method return typehinting for blueprint generated
| methods. Enabling this will enforce code strictness which increases
| readability of code and will lower maintenance cost. This will only
| Work for projects running PHP v7.0 or higher.
|
*/
'use_return_types' => false,

/*
|--------------------------------------------------------------------------
| Use Guarded
Expand Down
10 changes: 10 additions & 0 deletions src/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ public static function appPath()
return str_replace('\\', '/', config('blueprint.app_path'));
}

public static function supportsReturnTypeHits()
{
return boolval(config('blueprint.use_return_types')) && self::isPHP7OrHigher();
}

public static function isPHP7OrHigher()
{
return version_compare(PHP_VERSION, '7.0.0', '>=');
}

public static function isLaravel8OrHigher()
{
return version_compare(App::version(), '8.0.0', '>=');
Expand Down
4 changes: 4 additions & 0 deletions src/Generators/ControllerGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ protected function buildMethods(Controller $controller)
$method = str_replace('{{ body }}', trim($body), $method);
}

if (Blueprint::supportsReturnTypeHits()) {
$method = str_replace('request)', 'request): \Illuminate\Http\Response', $method);
}

$methods .= PHP_EOL.$method;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Generators/FactoryGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ protected function populateStub(string $stub, Model $model)
], "use", $stub);
}

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace('definition()', 'definition(): array', $stub);
}

$stub = str_replace('use {{ namespacedModel }};', $this->buildImports($model), $stub);

return $stub;
Expand Down
5 changes: 5 additions & 0 deletions src/Generators/MigrationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Blueprint\Generators;

use Blueprint\Blueprint;
use Blueprint\Contracts\Generator;
use Blueprint\Models\Model;
use Blueprint\Tree;
Expand Down Expand Up @@ -106,6 +107,10 @@ protected function populateStub(string $stub, Model $model)
$stub = str_replace('{{ table }}', $model->tableName(), $stub);
$stub = str_replace('{{ definition }}', $this->buildDefinition($model), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace(['up()','down()'], ['up(): void','down(): void'], $stub);
}

if ($this->hasForeignKeyConstraints) {
$stub = $this->disableForeignKeyConstraints($stub);
}
Expand Down
10 changes: 9 additions & 1 deletion src/Generators/ModelGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ protected function buildRelationships(Model $model)
}

foreach ($model->relationships() as $type => $references) {
$custom_template = $template;
foreach ($references as $reference) {
$key = null;
$class = null;
Expand Down Expand Up @@ -207,7 +208,14 @@ protected function buildRelationships(Model $model)
} elseif (in_array($type, ['hasMany', 'belongsToMany', 'morphMany'])) {
$method_name = Str::plural($column_name);
}
$method = str_replace('{{ method }}', Str::camel($method_name), $template);
if (Blueprint::supportsReturnTypeHits()) {
$custom_template = str_replace(
'{{ method }}()',
'{{ method }}(): ' . Str::of('\Illuminate\Database\Eloquent\Relations\\')->append(Str::studly($type)),
$custom_template
);
}
$method = str_replace('{{ method }}', Str::camel($method_name), $custom_template);
$method = str_replace('null', $relationship, $method);

$phpDoc = str_replace('{{ namespacedReturnClass }}', '\Illuminate\Database\Eloquent\Relations\\'.Str::ucfirst($type), $commentTemplate);
Expand Down
5 changes: 5 additions & 0 deletions src/Generators/SeederGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ protected function populateStub(string $stub, string $model)
} else {
$stub = str_replace('{{ body }}', $this->build($model), $stub);
}

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace('public function run()', 'public function run(): void', $stub);
}

return $stub;
}

Expand Down
1 change: 1 addition & 0 deletions src/Generators/StatementGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Blueprint\Generators;

use Blueprint\Blueprint;
use Blueprint\Contracts\Generator;

abstract class StatementGenerator implements Generator
Expand Down
4 changes: 4 additions & 0 deletions src/Generators/Statements/FormRequestGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ protected function populateStub(string $stub, string $name, $context, ValidateSt
$stub = str_replace('{{ class }}', $name, $stub);
$stub = str_replace('{{ rules }}', $this->buildRules($context, $validateStatement), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace(['authorize()','rules()'], ['authorize(): bool','rules(): array'], $stub);
}

return $stub;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Generators/Statements/JobGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ protected function populateStub(string $stub, DispatchStatement $dispatchStateme
$stub = str_replace('{{ class }}', $dispatchStatement->job(), $stub);
$stub = str_replace('{{ properties }}', $this->buildConstructor($dispatchStatement), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace('public function handle()', 'public function handle(): void', $stub);
}

return $stub;
}
}
4 changes: 4 additions & 0 deletions src/Generators/Statements/MailGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ protected function populateStub(string $stub, SendStatement $sendStatement)
$stub = str_replace('{{ class }}', $sendStatement->mail(), $stub);
$stub = str_replace('{{ properties }}', $this->buildConstructor($sendStatement), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace('build()', sprintf('build(): %s', $sendStatement->mail()), $stub);
}

return $stub;
}
}
16 changes: 16 additions & 0 deletions src/Generators/Statements/NotificationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ protected function populateStub(string $stub, SendStatement $sendStatement)
$stub = str_replace('{{ class }}', $sendStatement->mail(), $stub);
$stub = str_replace('{{ properties }}', $this->buildConstructor($sendStatement), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace(
[
'via($notifiable)',
'toMail($notifiable)',
'toArray($notifiable)',
],
[
'via($notifiable): array',
sprintf('toMail($notifiable): %s', $sendStatement->mail()),
'toArray($notifiable): array'
],
$stub
);
}

return $stub;
}
}
3 changes: 3 additions & 0 deletions src/Generators/Statements/ResourceGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ protected function populateStub(string $stub, Controller $controller, ResourceSt
$stub = str_replace('{{ resource }}', $resource->collection() ? 'resource collection' : 'resource', $stub);
$stub = str_replace('{{ body }}', $this->buildData($resource), $stub);

if (Blueprint::supportsReturnTypeHits()) {
$stub = str_replace('toArray($request)', 'toArray($request): array', $stub);
}
return $stub;
}

Expand Down
8 changes: 7 additions & 1 deletion src/Generators/TestGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -507,9 +507,15 @@ protected function buildTestCases(Controller $controller)
$body .= PHP_EOL.PHP_EOL;
$body .= implode(PHP_EOL.PHP_EOL, array_map([$this, 'buildLines'], array_filter($assertions)));

$test_case = str_replace('{{ method }}', $this->buildTestCaseName($name, $tested_bits), $test_case);
$test_case_name = $this->buildTestCaseName($name, $tested_bits);
$test_case = str_replace('{{ method }}', $test_case_name, $test_case);
$test_case = str_replace('{{ body }}', trim($body), $test_case);

if (Blueprint::supportsReturnTypeHits()) {
$test_case = str_replace("$test_case_name()", "$test_case_name(): void", $test_case);
$test_case = str_replace("uses_form_request_validation()", "uses_form_request_validation(): void", $test_case);
}

$test_cases .= PHP_EOL.$test_case.PHP_EOL;
}

Expand Down
3 changes: 1 addition & 2 deletions src/Tracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ private function loadModel(string $class)
}

$reflectionClass = new \ReflectionClass($class);
if (
!$reflectionClass->isSubclassOf(\Illuminate\Database\Eloquent\Model::class) ||
if (!$reflectionClass->isSubclassOf(\Illuminate\Database\Eloquent\Model::class) ||
(class_exists('Jenssegers\Mongodb\Eloquent\Model') &&
$reflectionClass->isSubclassOf('Jenssegers\Mongodb\Eloquent\Model'))
) {
Expand Down
38 changes: 20 additions & 18 deletions src/Translators/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,29 @@

namespace Blueprint\Translators;

use Illuminate\Support\Str;
use Blueprint\Models\Column;
use Illuminate\Support\Str;

class Rules
{
const INTEGER_TYPES = [
'integer',
'tinyInteger',
'smallInteger',
'mediumInteger',
'bigInteger',
'increments',
'tinyIncrements',
'smallIncrements',
'mediumIncrements',
'bigIncrements',
'unsignedBigInteger',
'unsignedInteger',
'unsignedMediumInteger',
'unsignedSmallInteger',
'unsignedTinyInteger',
];

public static function fromColumn(string $context, Column $column)
{
$rules = [];
Expand All @@ -25,23 +43,7 @@ public static function fromColumn(string $context, Column $column)
$rules = array_merge($rules, ['integer', 'exists:' . Str::plural($reference) . ',id']);
}

if (in_array($column->dataType(), [
'integer',
'tinyInteger',
'smallInteger',
'mediumInteger',
'bigInteger',
'increments',
'tinyIncrements',
'smallIncrements',
'mediumIncrements',
'bigIncrements',
'unsignedBigInteger',
'unsignedInteger',
'unsignedMediumInteger',
'unsignedSmallInteger',
'unsignedTinyInteger',
])) {
if (in_array($column->dataType(), self::INTEGER_TYPES)) {
array_push($rules, 'integer');

if (Str::startsWith($column->dataType(), 'unsigned')) {
Expand Down
33 changes: 33 additions & 0 deletions tests/Feature/Generators/ControllerGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,39 @@ public function output_respects_configuration()
$this->assertEquals(['created' => ['src/path/Other/Http/UserController.php']], $this->subject->output($tree));
}


/**
* @test
* @environment-setup useLaravel8
*/
public function output_using_return_types()
{
$this->app['config']->set('blueprint.use_return_types', true);

$this->files->expects('stub')
->with('controller.class.stub')
->andReturn($this->stub('controller.class.stub'));

$this->files->expects('stub')
->with('controller.method.stub')
->andReturn($this->stub('controller.method.stub'));

$this->files->expects('exists')
->with('app/Http/Controllers')
->andReturnFalse();

$this->files->expects('makeDirectory')
->with('app/Http/Controllers', 0755, true);

$this->files->expects('put')
->with('app/Http/Controllers/PostController.php', $this->fixture('controllers/return-type-declarations.php'));

$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example.yaml'));
$tree = $this->blueprint->analyze($tokens);

$this->assertEquals(['created' => ['app/Http/Controllers/PostController.php']], $this->subject->output($tree));
}

public function controllerTreeDataProvider()
{
return [
Expand Down
29 changes: 27 additions & 2 deletions tests/Feature/Generators/FactoryGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace Tests\Feature\Generators;

use Blueprint\Tree;
use Tests\TestCase;
use Blueprint\Blueprint;
use Blueprint\Generators\FactoryGenerator;
use Blueprint\Tree;
use Illuminate\Support\Facades\App;
use Tests\TestCase;

/**
* @see FactoryGenerator
Expand Down Expand Up @@ -144,6 +144,31 @@ public function output_ignores_nullables_if_fake_nullables_configuration_is_set_
$this->assertEquals(['created' => ['database/factories/PostFactory.php']], $this->subject->output($tree));
}

/**
* @test
* @environment-setup useLaravel8
*/
public function output_using_return_types()
{
$this->app['config']->set('blueprint.use_return_types', true);

$this->files->expects('stub')
->with($this->factoryStub)
->andReturn($this->stub($this->factoryStub));

$this->files->expects('exists')
->with('database/factories')
->andReturnTrue();

$this->files->expects('put')
->with('database/factories/PostFactory.php', $this->fixture('factories/return-type-declarations-laravel8.php'));

$tokens = $this->blueprint->parse($this->fixture('drafts/readme-example.yaml'));
$tree = $this->blueprint->analyze($tokens);

$this->assertEquals(['created' => ['database/factories/PostFactory.php']], $this->subject->output($tree));
}

/**
* @test
* @environment-setup useLaravel8
Expand Down
8 changes: 8 additions & 0 deletions tests/Feature/Generators/MigrationGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public function output_writes_nothing_for_empty_tree()
*/
public function output_writes_migration_for_model_tree($definition, $path, $migration)
{
if ($migration === 'migrations/return-type-declarations.php') {
$this->app['config']->set('blueprint.use_return_types', true);
}

$this->files->expects('stub')
->with('migration.stub')
->andReturn($this->stub('migration.stub'));
Expand Down Expand Up @@ -82,6 +86,10 @@ public function output_writes_migration_for_model_tree($definition, $path, $migr
*/
public function output_updates_migration_for_model_tree($definition, $path, $migration)
{
if ($migration === 'migrations/return-type-declarations.php') {
$this->app['config']->set('blueprint.use_return_types', true);
}

$this->files->expects('stub')
->with('migration.stub')
->andReturn($this->stub('migration.stub'));
Expand Down
4 changes: 4 additions & 0 deletions tests/Feature/Generators/ModelGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public function output_generates_nothing_for_empty_tree()
*/
public function output_generates_models($definition, $path, $model)
{
if ($model === 'models/return-type-declarations.php') {
$this->app['config']->set('blueprint.use_return_types', true);
}
$this->files->expects('stub')
->with($this->modelStub)
->andReturn($this->stub($this->modelStub));
Expand Down Expand Up @@ -688,6 +691,7 @@ public function laravel8ModelTreeDataProvider()
['drafts/resource-statements.yaml', 'app/User.php', 'models/resource-statements-laravel8.php'],
['drafts/all-column-types.yaml', 'app/AllType.php', 'models/all-column-types-laravel8.php'],
['drafts/alias-relationships.yaml', 'app/Salesman.php', 'models/alias-relationships-laravel8.php'],
['drafts/alias-relationships.yaml', 'app/Salesman.php', 'models/return-type-declarations.php'],
['drafts/uuid-shorthand-invalid-relationship.yaml', 'app/AgeCohort.php', 'models/uuid-shorthand-invalid-relationship-laravel8.php'],
];
}
Expand Down
Loading