Skip to content

Commit 38307ae

Browse files
committed
Use nullable attributes when saving model
1 parent 1fb44d0 commit 38307ae

File tree

7 files changed

+90
-113
lines changed

7 files changed

+90
-113
lines changed

composer.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121
"autoload": {
2222
"psr-4": {
2323
"McMatters\\NullableAttributes\\": "src/"
24-
},
25-
"files": [
26-
"src/helpers.php"
27-
]
24+
}
2825
}
2926
}

config/nullable-attributes.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
declare(strict_types = 1);
44

55
return [
6-
'folder' => base_path().'/app/Models',
6+
'folder' => base_path('app/Models'),
7+
'cache' => storage_path('app/nullable_attributes.php'),
78
];

src/Console/Cache.php

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
namespace McMatters\NullableAttributes\Console;
66

7-
use File;
87
use Illuminate\Console\Command;
98
use Illuminate\Database\Eloquent\Model;
9+
use Illuminate\Database\Eloquent\Relations\Pivot;
10+
use Illuminate\Support\Facades\DB;
11+
use Illuminate\Support\Facades\File;
1012
use ReflectionClass;
1113
use ReflectionException;
1214
use Symfony\Component\ClassLoader\ClassMapGenerator;
@@ -33,21 +35,24 @@ class Cache extends Command
3335
*/
3436
public function handle()
3537
{
36-
$models = $this->loadModels();
38+
$models = $this->getModels();
3739
$nullables = $this->findNullables($models);
40+
3841
$content = '<?php'.PHP_EOL.'return '.var_export($nullables, true).';';
39-
$fileName = storage_path('app/nullable_attributes.php');
42+
$fileName = config('nullable-attributes.cache');
4043
File::put($fileName, $content);
44+
4145
$this->info("Successfully written to the {$fileName}");
4246
}
4347

4448
/**
4549
* @return array
4650
*/
47-
protected function loadModels(): array
51+
protected function getModels(): array
4852
{
4953
$models = [];
50-
$dir = config('nullable-attributes.folder');
54+
$dir = config('nullable-attributes.models');
55+
5156
foreach (ClassMapGenerator::createMap($dir) as $model => $path) {
5257
try {
5358
$reflection = new ReflectionClass($model);
@@ -56,6 +61,7 @@ protected function loadModels(): array
5661
}
5762

5863
if ($reflection->isInstantiable() &&
64+
!$reflection->isSubclassOf(Pivot::class) &&
5965
$reflection->isSubclassOf(Model::class)
6066
) {
6167
$models[] = $model;
@@ -73,10 +79,43 @@ protected function loadModels(): array
7379
protected function findNullables(array $models): array
7480
{
7581
$nullables = [];
82+
7683
foreach ($models as $model) {
77-
$nullables[$model] = get_model_nullable_attributes($model);
84+
$nullables[$model] = $this->getNullablesFromDb($model);
7885
}
7986

8087
return $nullables;
8188
}
89+
90+
/**
91+
* @param string $model
92+
*
93+
* @return array
94+
*/
95+
protected function getNullablesFromDb(string $model): array
96+
{
97+
static $manager;
98+
99+
if (null === $manager) {
100+
$manager = DB::getDoctrineSchemaManager();
101+
}
102+
103+
$attributes = [];
104+
105+
$table = (new $model)->getTable();
106+
/** @var array $columns */
107+
$columns = $manager->tryMethod('listTableColumns', $table);
108+
109+
if (!$columns) {
110+
return [];
111+
}
112+
113+
foreach ($columns as $column) {
114+
if (!$column->getNotnull() && null === $column->getDefault()) {
115+
$attributes[] = $column->getName();
116+
}
117+
}
118+
119+
return $attributes;
120+
}
82121
}

src/Console/Clear.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace McMatters\NullableAttributes\Console;
66

7-
use File;
87
use Illuminate\Console\Command;
8+
use Illuminate\Support\Facades\File;
99

1010
/**
1111
* Class Clear
@@ -29,7 +29,7 @@ class Clear extends Command
2929
*/
3030
public function handle()
3131
{
32-
$fileName = storage_path('app/nullable_attributes.php');
32+
$fileName = config('nullable-attributes.cache');
3333
File::delete($fileName);
3434
$this->info("Successfully removed {$fileName}");
3535
}

src/ServiceProvider.php

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,21 @@ class ServiceProvider extends BaseServiceProvider
1818
*/
1919
public function boot()
2020
{
21+
$configPath = __DIR__.'/../config/nullable-attributes.php';
22+
2123
$this->publishes([
22-
__DIR__.'/../config/nullable-attributes.php' => config_path(
23-
'nullable-attributes.php'
24-
),
25-
]);
24+
$configPath => config_path('nullable-attributes.php'),
25+
], 'config');
26+
27+
$this->mergeConfigFrom($configPath, 'nullable-attributes');
28+
29+
$this->setNullableAttributes();
2630
}
2731

2832
/**
2933
* Register methods.
3034
*/
3135
public function register()
32-
{
33-
$this->registerCommands();
34-
}
35-
36-
/**
37-
* Register commands.
38-
*/
39-
protected function registerCommands()
4036
{
4137
$this->app->singleton('command.nullable-attributes.cache', function () {
4238
return new Console\Cache();
@@ -50,4 +46,16 @@ protected function registerCommands()
5046
'command.nullable-attributes.clear',
5147
]);
5248
}
49+
50+
/**
51+
* @return void
52+
*/
53+
protected function setNullableAttributes()
54+
{
55+
$cacheFile = config('nullable-attributes.cache');
56+
$cache = file_exists($cacheFile) ? include $cacheFile : false;
57+
$attributes = is_array($cache) ? $cache : [];
58+
59+
config(['nullable-attributes.attributes' => $attributes]);
60+
}
5361
}

src/Traits/NullableAttributesTrait.php

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,44 @@
44

55
namespace McMatters\NullableAttributes\Traits;
66

7+
use Illuminate\Database\Eloquent\Model;
8+
79
/**
810
* Class NullableAttributesTrait
911
*
1012
* @package McMatters\NullableAttributes\Traits
1113
*/
1214
trait NullableAttributesTrait
1315
{
14-
/**
15-
* @var array
16-
*/
17-
protected static $nullableAttributes = [];
18-
1916
/**
2017
* Boot trait.
2118
*/
2219
public static function bootNullableAttributesTrait()
2320
{
24-
static $cache;
25-
26-
if (null === $cache) {
27-
$cacheFile = storage_path('app/nullable_attributes.php');
28-
$cache = file_exists($cacheFile) ? include $cacheFile : false;
29-
$cache = is_array($cache) ? $cache : false;
30-
}
31-
32-
if (false !== $cache && isset($cache[static::class])) {
33-
self::$nullableAttributes = $cache[static::class];
34-
35-
return;
36-
}
37-
38-
self::$nullableAttributes = get_model_nullable_attributes(
39-
static::class
40-
);
21+
self::saving(function (Model $model) {
22+
$model->convertEmptyToNullableAttributes();
23+
});
4124
}
4225

4326
/**
44-
* Workaround for empty values
45-
*
46-
* @param string $key
47-
* @param mixed $val
27+
* @return void
4828
*/
49-
public function setAttribute($key, $val)
29+
protected function convertEmptyToNullableAttributes()
5030
{
51-
if (is_string($val) &&
52-
!($val = trim($val)) &&
53-
in_array($key, static::$nullableAttributes, true)
54-
) {
55-
$val = null;
56-
}
57-
58-
return parent::setAttribute($key, $val);
59-
}
31+
/** @var array $nullableAttributes */
32+
$nullableAttributes = array_get(
33+
config('nullable-attributes.attributes'),
34+
get_class($this),
35+
[]
36+
);
6037

61-
/**
62-
* @param string|null $modelName
63-
* @return array
64-
*/
65-
public function getNullableAttributes(string $modelName = null): array
66-
{
67-
if (null !== $modelName) {
68-
return self::$nullableAttributes[$modelName] ?? [];
38+
foreach ($nullableAttributes as $attribute) {
39+
$modelAttribute = $this->getAttribute($attribute);
40+
if ((is_array($modelAttribute) && empty($modelAttribute)) ||
41+
(is_string($modelAttribute) && trim($modelAttribute) === '')
42+
) {
43+
$this->setAttribute($attribute, null);
44+
}
6945
}
70-
71-
return self::$nullableAttributes;
7246
}
7347
}

src/helpers.php

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)