Skip to content

Commit 69c423d

Browse files
committed
Refactor to support tests
1 parent a3270fe commit 69c423d

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace SalemC\TypeScriptifyLaravelModels\Exceptions;
4+
5+
use Exception;
6+
7+
class InvalidModelException extends Exception {
8+
/**
9+
* Construct this class.
10+
*/
11+
public function __construct() {
12+
$this->message = 'That\'s not a valid Model!';
13+
}
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace SalemC\TypeScriptifyLaravelModels\Exceptions;
4+
5+
use Exception;
6+
7+
class UnsupportedDatabaseConnection extends Exception {
8+
/**
9+
* Construct this class.
10+
*
11+
* @param array<string> $supportedDatabaseConnections The supported database connections.
12+
*/
13+
public function __construct(array $supportedDatabaseConnections) {
14+
$this->message = 'Your database connection is currently unsupported! The following database connections are supported: ' . implode(', ', $supportedDatabaseConnections);
15+
}
16+
}

src/TypeScriptifyModel.php

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace SalemC\TypeScriptifyLaravelModels;
44

5-
use SalemC\TypeScriptifyLaravelModels\Utilities\ModelCollector\ModelCollector;
5+
use SalemC\TypeScriptifyLaravelModels\Exceptions\UnsupportedDatabaseConnection;
6+
use SalemC\TypeScriptifyLaravelModels\Exceptions\InvalidModelException;
7+
use SalemC\TypeScriptifyLaravelModels\Utilities\ModelCollector;
68

79
use Illuminate\Database\Eloquent\Casts\AsStringable;
810
use Illuminate\Database\Eloquent\Model;
@@ -34,6 +36,13 @@ final class TypeScriptifyModel {
3436
*/
3537
private readonly Model $model;
3638

39+
/**
40+
* The model collector.
41+
*
42+
* @var \SalemC\TypeScriptifyLaravelModels\Utilities\ModelCollector
43+
*/
44+
private readonly ModelCollector $modelCollector;
45+
3746
/**
3847
* The target model's foreign key constraits.
3948
*
@@ -58,24 +67,28 @@ final class TypeScriptifyModel {
5867
/**
5968
* @param string $fullyQualifiedModelName The fully qualified model class name.
6069
* @param ?array<string,string> $convertedModelsMap The map of `fully qualified model name => interface name` definitions this class can use instead of generating its own definitions.
70+
* @param ?string $modelCollectorPath The path to be used for scanning for models.
6171
*/
6272
public function __construct(
6373
private string $fullyQualifiedModelName,
64-
private ?array &$convertedModelsMap = []
74+
private ?array &$convertedModelsMap = [],
75+
private ?string $modelCollectorPath = null,
6576
) {
6677
// For consistency in comparisons that happen throughout the lifecycle of this class,
6778
// we need all fully qualified model names to have a leading \.
6879
$this->fullyQualifiedModelName = Str::of($fullyQualifiedModelName)->start('\\')->toString();
6980

7081
if (!$this->hasValidModel()) {
71-
throw new Exception('That\'s not a valid model!');
82+
throw new InvalidModelException;
7283
}
7384

7485
if (!$this->hasSupportedDatabaseConnection()) {
75-
throw new Exception('Your database connection is currently unsupported! The following database connections are supported: ' . implode(', ', self::SUPPORTED_DATABASE_CONNECTIONS));
86+
throw new UnsupportedDatabaseConnection(self::SUPPORTED_DATABASE_CONNECTIONS);
7687
}
7788

78-
$this->model = new $fullyQualifiedModelName;
89+
$this->model = new ($this->fullyQualifiedModelName);
90+
91+
$this->modelCollector = new ModelCollector($this->modelCollectorPath ?? app_path());
7992

8093
$this->modelForeignKeyConstraints = collect(
8194
Schema::getConnection()
@@ -214,11 +227,11 @@ private function mapDatabaseTypeToTypeScriptType(string $columnType): string {
214227
$columnType->startsWith('bigint') => 'number',
215228
$columnType->startsWith('double') => 'number',
216229
$columnType->startsWith('binary') => 'string',
217-
$columnType->startsWith('bigint') => 'number',
218230
$columnType->startsWith('decimal') => 'number',
219231
$columnType->startsWith('integer') => 'number',
220232
$columnType->startsWith('varchar') => 'string',
221233
$columnType->startsWith('boolean') => 'boolean',
234+
$columnType->startsWith('tinyint') => 'boolean',
222235
$columnType->startsWith('tinyblob') => 'string',
223236
$columnType->startsWith('tinytext') => 'string',
224237
$columnType->startsWith('longtext') => 'string',
@@ -277,7 +290,7 @@ private function convertForeignKeyToFullyQualifiedModelName(string $attribute):
277290
->getForeignKeyConstraintForAttribute($attribute)
278291
->getForeignTableName();
279292

280-
return ModelCollector::getModelsMappedByTable()[$foreignTableName];
293+
return $this->modelCollector->getModelsMappedByTable()[$foreignTableName];
281294
}
282295

283296
/**
@@ -302,7 +315,7 @@ private function getTypeScriptType(stdClass $columnSchema): string {
302315
// as many interface definitions for relational attributes as we need.
303316
// We pass our existing convertedModelsMap instance here to prevent this class
304317
// mapping models we've already mapped in this current class instance.
305-
$mappedType = (new self($fullyQualifiedRelatedModelName, $this->convertedModelsMap))
318+
$mappedType = (new self($fullyQualifiedRelatedModelName, $this->convertedModelsMap, $this->modelCollectorPath))
306319
->includeHidden($this->includeHidden)
307320
->includeRelations($this->includeRelations)
308321
->generate();

src/Utilities/ModelCollector/ModelCollector.php renamed to src/Utilities/ModelCollector.php

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php
22

3-
namespace SalemC\TypeScriptifyLaravelModels\Utilities\ModelCollector;
3+
namespace SalemC\TypeScriptifyLaravelModels\Utilities;
44

55
use Illuminate\Database\Eloquent\Model;
66
use Illuminate\Support\Facades\File;
7-
use Illuminate\Container\Container;
7+
use Illuminate\Support\Str;
88

99
use ReflectionClass;
1010

@@ -14,32 +14,37 @@ final class ModelCollector {
1414
*
1515
* @var ?array
1616
*/
17-
private static ?array $modelsCache = null;
17+
private ?array $modelsCache = null;
1818

1919
/**
2020
* The cache for all models mapped by table.
2121
*
2222
* @var ?array
2323
*/
24-
private static ?array $modelsMappedByTableCache = null;
24+
private ?array $modelsMappedByTableCache = null;
25+
26+
/**
27+
* Construct this class.
28+
*
29+
* @param string $path The path to start scanning models at.
30+
*/
31+
public function __construct(private readonly string $path) {
32+
//
33+
}
2534

2635
/**
2736
* Get all existing models.
2837
*
2938
* @return array
3039
*/
31-
public static function getModels(): array {
32-
return self::$modelsCache ??= collect(File::allFiles(app_path()))
40+
public function getModels(): array {
41+
return $this->modelsCache ??= collect(File::allFiles($this->path))
3342
->map(function ($item) {
34-
$path = $item->getRelativePathName();
35-
36-
$className = sprintf(
37-
'\%s%s',
38-
Container::getInstance()->getNamespace(),
39-
strtr(substr($path, 0, strrpos($path, '.')), '/', '\\')
40-
);
41-
42-
return $className;
43+
return Str::of($item->getContents())
44+
->match('/namespace (.*);/')
45+
->start('\\')
46+
->finish('\\' . Str::of($item->getRelativePathName())->afterLast('\\')->beforeLast('.'))
47+
->toString() ?? '\\';
4348
})->filter(function ($className) {
4449
if (!class_exists($className)) return false;
4550

@@ -54,8 +59,8 @@ public static function getModels(): array {
5459
*
5560
* @return array
5661
*/
57-
public static function getModelsMappedByTable(): array {
58-
return self::$modelsMappedByTableCache ??= collect(self::getModels())
62+
public function getModelsMappedByTable(): array {
63+
return $this->modelsMappedByTableCache ??= collect($this->getModels())
5964
->mapWithKeys(fn ($className) => [(new $className)->getTable() => $className])
6065
->all();
6166
}

0 commit comments

Comments
 (0)