Skip to content

Commit 9b32efd

Browse files
authored
Merge pull request #20 from DirectoryTree/make-metrics-model-command
Add `metrics:model` command
2 parents f9b5a6d + 9d9fad6 commit 9b32efd

File tree

4 files changed

+327
-0
lines changed

4 files changed

+327
-0
lines changed

src/Commands/MakeMetricsModel.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
namespace DirectoryTree\Metrics\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Illuminate\Filesystem\Filesystem;
7+
use Illuminate\Support\Str;
8+
9+
class MakeMetricsModel extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $signature = 'metrics:model {name : The name of the metrics model}';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Create a new metrics model';
24+
25+
/**
26+
* Execute the console command.
27+
*/
28+
public function handle(Filesystem $files): int
29+
{
30+
$name = $this->argument('name');
31+
32+
$this->writeModel($files, $name);
33+
34+
$this->components->info(sprintf('Model [%s] created successfully.', $this->getModelFileName($name)));
35+
36+
return self::SUCCESS;
37+
}
38+
39+
/**
40+
* Write the model file to disk.
41+
*/
42+
protected function writeModel(Filesystem $files, string $name): void
43+
{
44+
$file = $this->getModelPath($name);
45+
46+
$files->ensureDirectoryExists(dirname($file));
47+
48+
$files->put($file, $this->populateStub($name));
49+
}
50+
51+
/**
52+
* Populate the stub with the model name and namespace.
53+
*/
54+
protected function populateStub(string $name): string
55+
{
56+
$stub = $this->getStub();
57+
58+
$className = $this->getClassName($name);
59+
$namespace = $this->getNamespace($name);
60+
61+
return str_replace(
62+
['{{ namespace }}', '{{ class }}'],
63+
[$namespace, $className],
64+
$stub
65+
);
66+
}
67+
68+
/**
69+
* Get the model file path.
70+
*/
71+
protected function getModelPath(string $name): string
72+
{
73+
return app_path($this->getModelFileName($name));
74+
}
75+
76+
/**
77+
* Get the model file name.
78+
*/
79+
protected function getModelFileName(string $name): string
80+
{
81+
return str_replace('\\', '/', $name).'.php';
82+
}
83+
84+
/**
85+
* Get the class name from the model name.
86+
*/
87+
protected function getClassName(string $name): string
88+
{
89+
return class_basename($name);
90+
}
91+
92+
/**
93+
* Get the namespace from the model name.
94+
*/
95+
protected function getNamespace(string $name): string
96+
{
97+
$namespace = 'App';
98+
99+
if (Str::contains($name, '\\')) {
100+
$parts = explode('\\', $name);
101+
array_pop($parts);
102+
$namespace .= '\\'.implode('\\', $parts);
103+
}
104+
105+
return $namespace;
106+
}
107+
108+
/**
109+
* Get the stub file contents.
110+
*/
111+
protected function getStub(): string
112+
{
113+
return file_get_contents(__DIR__.'/../../stubs/metrics.model.stub');
114+
}
115+
}

src/MetricServiceProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace DirectoryTree\Metrics;
44

55
use DirectoryTree\Metrics\Commands\CommitMetrics;
6+
use DirectoryTree\Metrics\Commands\MakeMetricsModel;
67
use DirectoryTree\Metrics\Commands\MakeMetricsTable;
78
use Illuminate\Contracts\Foundation\Application;
89
use Illuminate\Support\Facades\App;
@@ -39,6 +40,7 @@ public function boot(): void
3940
if ($this->app->runningInConsole()) {
4041
$this->commands([
4142
CommitMetrics::class,
43+
MakeMetricsModel::class,
4244
MakeMetricsTable::class,
4345
]);
4446
}

stubs/metrics.model.stub

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace {{ namespace }};
4+
5+
use DirectoryTree\Metrics\MetricBuilder;
6+
use DirectoryTree\Metrics\MetricFactory;
7+
use Illuminate\Database\Eloquent\Factories\HasFactory;
8+
use Illuminate\Database\Eloquent\Model;
9+
10+
class {{ class }} extends Model
11+
{
12+
use HasFactory;
13+
14+
/**
15+
* The attributes that aren't mass assignable.
16+
*
17+
* @var array
18+
*/
19+
protected $guarded = [];
20+
21+
/**
22+
* The factory for the model.
23+
*/
24+
protected static string $factory = MetricFactory::class;
25+
26+
/**
27+
* The attributes that should be cast.
28+
*/
29+
protected function casts(): array
30+
{
31+
return [
32+
'year' => 'integer',
33+
'month' => 'integer',
34+
'day' => 'integer',
35+
'hour' => 'integer',
36+
'value' => 'integer',
37+
];
38+
}
39+
40+
/**
41+
* Create a new Eloquent query builder for the model.
42+
*/
43+
public function newEloquentBuilder($query): MetricBuilder
44+
{
45+
return new MetricBuilder($query);
46+
}
47+
}
48+
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php
2+
3+
use DirectoryTree\Metrics\Commands\MakeMetricsModel;
4+
use Orchestra\Testbench\Concerns\InteractsWithPublishedFiles;
5+
6+
use function Pest\Laravel\artisan;
7+
8+
uses(InteractsWithPublishedFiles::class);
9+
10+
beforeEach(function () {
11+
$this->files = [
12+
'app/CustomMetric.php',
13+
'app/UserMetric.php',
14+
'app/Models/CustomMetric.php',
15+
'app/Models/UserMetric.php',
16+
'app/Metrics/CustomMetric.php',
17+
];
18+
});
19+
20+
it('creates a model file with the correct name', function () {
21+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
22+
->assertSuccessful();
23+
24+
$this->assertFilenameExists('app/CustomMetric.php');
25+
});
26+
27+
it('displays success message with model name', function () {
28+
artisan(MakeMetricsModel::class, ['name' => 'UserMetric'])
29+
->expectsOutputToContain('created successfully')
30+
->assertSuccessful();
31+
});
32+
33+
it('generates model with correct class name', function () {
34+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
35+
->assertSuccessful();
36+
37+
$this->assertFileContains([
38+
'class CustomMetric extends Model',
39+
], 'app/CustomMetric.php');
40+
});
41+
42+
it('generates model with correct namespace', function () {
43+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
44+
->assertSuccessful();
45+
46+
$this->assertFileContains([
47+
'namespace App;',
48+
], 'app/CustomMetric.php');
49+
});
50+
51+
it('generates model with all required imports', function () {
52+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
53+
->assertSuccessful();
54+
55+
$this->assertFileContains([
56+
'use DirectoryTree\Metrics\MetricBuilder;',
57+
'use DirectoryTree\Metrics\MetricFactory;',
58+
'use Illuminate\Database\Eloquent\Factories\HasFactory;',
59+
'use Illuminate\Database\Eloquent\Model;',
60+
], 'app/CustomMetric.php');
61+
});
62+
63+
it('generates model with HasFactory trait', function () {
64+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
65+
->assertSuccessful();
66+
67+
$this->assertFileContains([
68+
'use HasFactory;',
69+
], 'app/CustomMetric.php');
70+
});
71+
72+
it('generates model with guarded property', function () {
73+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
74+
->assertSuccessful();
75+
76+
$this->assertFileContains([
77+
'protected $guarded = [];',
78+
], 'app/CustomMetric.php');
79+
});
80+
81+
it('generates model with factory property', function () {
82+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
83+
->assertSuccessful();
84+
85+
$this->assertFileContains([
86+
'protected static string $factory = MetricFactory::class;',
87+
], 'app/CustomMetric.php');
88+
});
89+
90+
it('generates model with casts method', function () {
91+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
92+
->assertSuccessful();
93+
94+
$this->assertFileContains([
95+
'protected function casts(): array',
96+
'\'year\' => \'integer\',',
97+
'\'month\' => \'integer\',',
98+
'\'day\' => \'integer\',',
99+
'\'hour\' => \'integer\',',
100+
'\'value\' => \'integer\',',
101+
], 'app/CustomMetric.php');
102+
});
103+
104+
it('generates model with custom query builder method', function () {
105+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
106+
->assertSuccessful();
107+
108+
$this->assertFileContains([
109+
'public function newEloquentBuilder($query): MetricBuilder',
110+
'return new MetricBuilder($query);',
111+
], 'app/CustomMetric.php');
112+
});
113+
114+
it('generates valid php model file', function () {
115+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
116+
->assertSuccessful();
117+
118+
$this->assertFileContains([
119+
'<?php',
120+
], 'app/CustomMetric.php');
121+
});
122+
123+
it('supports namespaced model names', function () {
124+
artisan(MakeMetricsModel::class, ['name' => 'Models\CustomMetric'])
125+
->assertSuccessful();
126+
127+
$this->assertFilenameExists('app/Models/CustomMetric.php');
128+
$this->assertFileContains([
129+
'namespace App\Models;',
130+
'class CustomMetric extends Model',
131+
], 'app/Models/CustomMetric.php');
132+
});
133+
134+
it('supports deeply namespaced model names', function () {
135+
artisan(MakeMetricsModel::class, ['name' => 'Metrics\CustomMetric'])
136+
->assertSuccessful();
137+
138+
$this->assertFilenameExists('app/Metrics/CustomMetric.php');
139+
$this->assertFileContains([
140+
'namespace App\Metrics;',
141+
'class CustomMetric extends Model',
142+
], 'app/Metrics/CustomMetric.php');
143+
});
144+
145+
it('can generate multiple different metrics models', function () {
146+
artisan(MakeMetricsModel::class, ['name' => 'UserMetric'])
147+
->assertSuccessful();
148+
149+
artisan(MakeMetricsModel::class, ['name' => 'CustomMetric'])
150+
->assertSuccessful();
151+
152+
$this->assertFilenameExists('app/UserMetric.php');
153+
$this->assertFilenameExists('app/CustomMetric.php');
154+
155+
$this->assertFileContains([
156+
'class UserMetric extends Model',
157+
], 'app/UserMetric.php');
158+
159+
$this->assertFileContains([
160+
'class CustomMetric extends Model',
161+
], 'app/CustomMetric.php');
162+
});

0 commit comments

Comments
 (0)