Repository: laravel-shift/blueprint (php)

Issue:
replacement {{ namespaceModel }} not correctly working in case for windows
<!-- PLEASE COMPLETE THIS TEMPLATE -->

- Laravel Version: 7.28.4
- PHP Version: 7.3.9
- Blueprint Version: 1.19.2
- Platform: Windows

### Issue:
 I have Windows 10 pro. When I use `php artisan blueprint:build` I get follow files: `database/factories/ArticleFactory.php` and `database/factories/CategoryFactory.php` with content:

```php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;
use {{ namespacedModel }};

$factory->define(Article::class, function (Faker $faker) {
    return [
        'category_id' => factory(\App\Models\Category::class),
        'title' => $faker->sentence(4),
        'slug' => $faker->slug,
        'content' => $faker->paragraphs(3, true),
    ];
});
```

```php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;
use {{ namespacedModel }};

$factory->define(Category::class, function (Faker $faker) {
    return [
        'parent_id' => factory(\App\Models\Category::class),
        'title' => $faker->sentence(4),
        'slug' => $faker->slug,
    ];
});
```

The problem is that in stubs files the line endings "\n"

In the file `vendor/laravel-shift/blueprint/src/Generators/FactoryGenerator.php` in `protected function populateStub` string 80 used code:
```php
$stub = str_replace('use Faker\Generator as Faker;'.PHP_EOL.'use {{ namespacedModel }};', $this->buildImports($model), $stub);
```
with `PHP_EOL`

For windows `PHP_EOL` is "\r\n" and no replacement occurs.

For test, if I replace `PHP_EOL` on `"\n"` in this case everything works.

Perhaps there are still sections of code where this does not work correctly for Windows

### draft.yaml:
```yaml
# PLEASE PASTE THE DRAFT FILE WHICH REPRODUCES THE ISSUE HERE...
models:
  Category:
    parent_id: id foreign:categories nullable
    title: string required
    slug: string required unique
    timestamps: true
    relationships:
      hasMany: Article

  Article:
    category_id: id foreign
    title: string required
    slug: string required unique
    content: mediumtext
    timestamps: true

seeders: Article, Category
```


Pull request:
fix: correct newline character for windows
closes #390 

Patch:
diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php
index a0bbb02..2a6d942 100644
--- a/src/Generators/FactoryGenerator.php
+++ b/src/Generators/FactoryGenerator.php
@@ -36,14 +36,14 @@ class FactoryGenerator implements Generator
 
         /** @var \Blueprint\Models\Model $model */
         foreach ($tree->models() as $model) {
-            if (! Blueprint::isLaravel8OrHigher()) {
+            if (!Blueprint::isLaravel8OrHigher()) {
                 $this->addImport($model, 'Faker\Generator as Faker');
             }
             $this->addImport($model, $model->fullyQualifiedClassName());
 
             $path = $this->getPath($model);
 
-            if (! $this->files->exists(dirname($path))) {
+            if (!$this->files->exists(dirname($path))) {
                 $this->files->makeDirectory(dirname($path), 0755, true);
             }
 
@@ -64,22 +64,26 @@ class FactoryGenerator implements Generator
     {
         $path = $model->name();
         if ($model->namespace()) {
-            $path = str_replace('\\', '/', $model->namespace()).'/'.$path;
+            $path = str_replace('\\', '/', $model->namespace()) . '/' . $path;
         }
 
-        return 'database/factories/'.$path.'Factory.php';
+        return 'database/factories/' . $path . 'Factory.php';
     }
 
     protected function populateStub(string $stub, Model $model)
     {
         $stub = str_replace('{{ model }}', $model->name(), $stub);
         $stub = str_replace('//', $this->buildDefinition($model), $stub);
-        if (Blueprint::isLaravel8OrHigher()) {
-            $stub = str_replace('use {{ namespacedModel }};', $this->buildImports($model), $stub);
-        } else {
-            $stub = str_replace('use Faker\Generator as Faker;'.PHP_EOL.'use {{ namespacedModel }};', $this->buildImports($model), $stub);
+
+        if (!Blueprint::isLaravel8OrHigher()) {
+            $stub = str_replace([
+                "use Faker\Generator as Faker;\r\nuse",
+                "use Faker\Generator as Faker;\nuse"
+            ], "use", $stub);
         }
 
+        $stub = str_replace('use {{ namespacedModel }};', $this->buildImports($model), $stub);
+
         return $stub;
     }
 
@@ -109,11 +113,11 @@ class FactoryGenerator implements Generator
                 } elseif ($foreign !== 'foreign') {
                     $table = $foreign;
 
-                    if (Str::startsWith($column->name(), $foreign.'_')) {
-                        $key = Str::after($column->name(), $foreign.'_');
-                    } elseif (Str::startsWith($column->name(), Str::snake(Str::singular($foreign)).'_')) {
-                        $key = Str::after($column->name(), Str::snake(Str::singular($foreign)).'_');
-                    } elseif (! Str::endsWith($column->name(), '_id')) {
+                    if (Str::startsWith($column->name(), $foreign . '_')) {
+                        $key = Str::after($column->name(), $foreign . '_');
+                    } elseif (Str::startsWith($column->name(), Str::snake(Str::singular($foreign)) . '_')) {
+                        $key = Str::after($column->name(), Str::snake(Str::singular($foreign)) . '_');
+                    } elseif (!Str::endsWith($column->name(), '_id')) {
                         $key = $column->name();
                     }
                 }
@@ -121,29 +125,29 @@ class FactoryGenerator implements Generator
                 $class = Str::studly(Str::singular($table));
 
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $this->addImport($model, $model->fullyQualifiedNamespace().'\\'.$class);
+                    $this->addImport($model, $model->fullyQualifiedNamespace() . '\\' . $class);
                 }
                 if ($key === 'id') {
                     if (Blueprint::isLaravel8OrHigher()) {
-                        $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
+                        $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
                         $definition .= sprintf('%s::factory()', $class);
-                        $definition .= ','.PHP_EOL;
+                        $definition .= ',' . PHP_EOL;
                     } else {
-                        $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
-                        $definition .= sprintf('factory(%s::class)', '\\'.$model->fullyQualifiedNamespace().'\\'.$class);
-                        $definition .= ','.PHP_EOL;
+                        $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
+                        $definition .= sprintf('factory(%s::class)', '\\' . $model->fullyQualifiedNamespace() . '\\' . $class);
+                        $definition .= ',' . PHP_EOL;
                     }
                 } else {
                     if (Blueprint::isLaravel8OrHigher()) {
-                        $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
+                        $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
                         $definition .= sprintf('%s::factory()->create()->%s', $class, $key);
-                        $definition .= ','.PHP_EOL;
+                        $definition .= ',' . PHP_EOL;
                     } else {
-                        $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => function () {";
+                        $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => function () {";
                         $definition .= PHP_EOL;
-                        $definition .= str_repeat(self::INDENT, 3).sprintf('return factory(%s::class)->create()->%s;', '\\'.$model->fullyQualifiedNamespace().'\\'.$class, $key);
+                        $definition .= str_repeat(self::INDENT, 3) . sprintf('return factory(%s::class)->create()->%s;', '\\' . $model->fullyQualifiedNamespace() . '\\' . $class, $key);
                         $definition .= PHP_EOL;
-                        $definition .= str_repeat(self::INDENT, 2).'},'.PHP_EOL;
+                        $definition .= str_repeat(self::INDENT, 2) . '},' . PHP_EOL;
                     }
                 }
             } elseif ($column->dataType() === 'id' || ($column->dataType() === 'uuid' && Str::endsWith($column->name(), '_id'))) {
@@ -151,24 +155,24 @@ class FactoryGenerator implements Generator
                 $class = Str::studly($column->attributes()[0] ?? $name);
 
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $this->addImport($model, $model->fullyQualifiedNamespace().'\\'.$class);
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
+                    $this->addImport($model, $model->fullyQualifiedNamespace() . '\\' . $class);
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
                     $definition .= sprintf('%s::factory()', $class);
                 } else {
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
-                    $definition .= sprintf('factory(%s::class)', '\\'.$model->fullyQualifiedNamespace().'\\'.$class);
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
+                    $definition .= sprintf('factory(%s::class)', '\\' . $model->fullyQualifiedNamespace() . '\\' . $class);
                 }
-                $definition .= ','.PHP_EOL;
-            } elseif (in_array($column->dataType(), ['enum', 'set']) && ! empty($column->attributes())) {
+                $definition .= ',' . PHP_EOL;
+            } elseif (in_array($column->dataType(), ['enum', 'set']) && !empty($column->attributes())) {
                 $faker = FakerRegistry::fakerData($column->name()) ?? FakerRegistry::fakerDataType($column->dataType());
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
-                    $definition .= '$this->faker->'.$faker;
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
+                    $definition .= '$this->faker->' . $faker;
                 } else {
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
-                    $definition .= '$faker->'.$faker;
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
+                    $definition .= '$faker->' . $faker;
                 }
-                $definition .= ','.PHP_EOL;
+                $definition .= ',' . PHP_EOL;
                 $definition = str_replace(
                     "/** {$column->dataType()}_attributes **/",
                     json_encode($column->attributes()),
@@ -177,28 +181,28 @@ class FactoryGenerator implements Generator
             } elseif (in_array($column->dataType(), ['decimal', 'double', 'float'])) {
                 $faker = FakerRegistry::fakerData($column->name()) ?? FakerRegistry::fakerDataType($column->dataType());
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
-                    $definition .= '$this->faker->'.$faker;
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
+                    $definition .= '$this->faker->' . $faker;
                 } else {
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
-                    $definition .= '$faker->'.$faker;
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
+                    $definition .= '$faker->' . $faker;
                 }
-                $definition .= ','.PHP_EOL;
+                $definition .= ',' . PHP_EOL;
 
                 $precision = min([65, intval($column->attributes()[0] ?? 10)]);
                 $scale = min([30, max([0, intval($column->attributes()[1] ?? 0)])]);
 
                 $definition = str_replace(
                     "/** {$column->dataType()}_attributes **/",
-                    implode(', ', [$scale, 0, (str_repeat(9, $precision - $scale).'.'.str_repeat(9, $scale))]),
+                    implode(', ', [$scale, 0, (str_repeat(9, $precision - $scale) . '.' . str_repeat(9, $scale))]),
                     $definition
                 );
             } elseif (in_array($column->dataType(), ['json', 'jsonb'])) {
                 $default = $column->defaultValue() ?? "'{}'";
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => {$default},".PHP_EOL;
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => {$default}," . PHP_EOL;
                 } else {
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => {$default},".PHP_EOL;
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => {$default}," . PHP_EOL;
                 }
             } elseif ($column->dataType() === 'morphs') {
                 if ($column->isNullable()) {
@@ -213,22 +217,22 @@ class FactoryGenerator implements Generator
                 }
             } elseif ($column->dataType() === 'rememberToken') {
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
                 } else {
                     $this->addImport($model, 'Illuminate\Support\Str');
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
                 }
                 $definition .= 'Str::random(10)';
-                $definition .= ','.PHP_EOL;
+                $definition .= ',' . PHP_EOL;
             } else {
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= str_repeat(self::INDENT, 3)."'{$column->name()}' => ";
+                    $definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
                 } else {
-                    $definition .= str_repeat(self::INDENT, 2)."'{$column->name()}' => ";
+                    $definition .= str_repeat(self::INDENT, 2) . "'{$column->name()}' => ";
                 }
                 $type = $column->dataType();
                 if ($column->isUnsigned()) {
-                    $type = 'unsigned'.$type;
+                    $type = 'unsigned' . $type;
                 }
 
                 $faker = FakerRegistry::fakerData($column->name()) ?? (FakerRegistry::fakerDataType($type) ?? FakerRegistry::fakerDataType($column->dataType()));
@@ -238,11 +242,11 @@ class FactoryGenerator implements Generator
                 }
 
                 if (Blueprint::isLaravel8OrHigher()) {
-                    $definition .= '$this->faker->'.$faker;
+                    $definition .= '$this->faker->' . $faker;
                 } else {
-                    $definition .= '$faker->'.$faker;
+                    $definition .= '$faker->' . $faker;
                 }
-                $definition .= ','.PHP_EOL;
+                $definition .= ',' . PHP_EOL;
             }
         }
 
@@ -255,7 +259,7 @@ class FactoryGenerator implements Generator
         sort($imports);
 
         return implode(PHP_EOL, array_map(function ($class) {
-            return 'use '.$class.';';
+            return 'use ' . $class . ';';
         }, $imports));
     }
 
@@ -271,7 +275,7 @@ class FactoryGenerator implements Generator
         }
 
         return array_filter($columns, function (Column $column) {
-            return ! in_array('nullable', $column->modifiers());
+            return !in_array('nullable', $column->modifiers());
         });
     }
 }
diff --git a/src/Generators/ModelGenerator.php b/src/Generators/ModelGenerator.php
index 335bda3..c2994da 100644
--- a/src/Generators/ModelGenerator.php
+++ b/src/Generators/ModelGenerator.php
@@ -141,9 +141,11 @@ class ModelGenerator implements Generator
             $properties .= PHP_EOL.str_replace('[]', $this->pretty_print_array($columns), $this->files->stub('model.casts.stub'));
         }
 
-        $columns = $this->dateColumns($model->columns());
-        if (! empty($columns)) {
-            $properties .= PHP_EOL.str_replace('[]', $this->pretty_print_array($columns, false), $this->files->stub('model.dates.stub'));
+        if (! Blueprint::isLaravel8OrHigher()) {
+            $columns = $this->dateColumns($model->columns());
+            if (! empty($columns)) {
+                $properties .= PHP_EOL.str_replace('[]', $this->pretty_print_array($columns, false), $this->files->stub('model.dates.stub'));
+            }
         }
 
         return trim($properties);
@@ -285,6 +287,20 @@ class ModelGenerator implements Generator
 
     private function castForColumn(Column $column)
     {
+        if (Blueprint::isLaravel8OrHigher()) {
+            if ($column->dataType() === 'date') {
+                return 'date';
+            }
+
+            if (stripos($column->dataType(), 'datetime') !== false) {
+                return 'datetime';
+            }
+
+            if (stripos($column->dataType(), 'timestamp') !== false) {
+                return 'timestamp';
+            }
+        }
+
         if (stripos($column->dataType(), 'integer') || $column->dataType() === 'id') {
             return 'integer';
         }


Test patch:
diff --git a/tests/Feature/Generators/ModelGeneratorTest.php b/tests/Feature/Generators/ModelGeneratorTest.php
index fae6ed3..2d51ff8 100644
--- a/tests/Feature/Generators/ModelGeneratorTest.php
+++ b/tests/Feature/Generators/ModelGeneratorTest.php
@@ -69,12 +69,6 @@ class ModelGeneratorTest extends TestCase
             ->with('model.casts.stub')
             ->andReturn($this->stub('model.casts.stub'));
 
-        if (in_array($definition, ['drafts/readme-example.yaml', 'drafts/all-column-types.yaml'])) {
-            $this->files->expects('stub')
-                ->with('model.dates.stub')
-                ->andReturn($this->stub('model.dates.stub'));
-        }
-
         $this->files->shouldReceive('stub')
             ->with('model.method.stub')
             ->andReturn($this->stub('model.method.stub'));
@@ -214,9 +208,6 @@ class ModelGeneratorTest extends TestCase
             ->with('model.casts.stub')
             ->andReturn($this->stub('model.casts.stub'))
             ->twice();
-        $this->files->expects('stub')
-            ->with('model.dates.stub')
-            ->andReturn(file_get_contents('stubs/model.dates.stub'));
         $this->files->expects('stub')
             ->with('model.method.stub')
             ->andReturn($this->stub('model.method.stub'))
@@ -421,12 +412,6 @@ class ModelGeneratorTest extends TestCase
             ->with('model.casts.stub')
             ->andReturn($this->stub('model.casts.stub'));
 
-        if ($definition === 'drafts/readme-example.yaml') {
-            $this->files->expects('stub')
-                ->with('model.dates.stub')
-                ->andReturn($this->stub('model.dates.stub'));
-        }
-
         $this->files->shouldReceive('stub')
             ->with('model.method.stub')
             ->andReturn($this->stub('model.method.stub'));
diff --git a/tests/fixtures/models/all-column-types-laravel8.php b/tests/fixtures/models/all-column-types-laravel8.php
index 7e935f5..38b2b12 100644
--- a/tests/fixtures/models/all-column-types-laravel8.php
+++ b/tests/fixtures/models/all-column-types-laravel8.php
@@ -75,12 +75,18 @@ class AllType extends Model
     protected $casts = [
         'bigInteger' => 'integer',
         'boolean' => 'boolean',
+        'date' => 'date',
+        'dateTime' => 'datetime',
+        'dateTimeTz' => 'datetime',
         'decimal' => 'decimal',
         'double' => 'double',
         'float' => 'float',
         'json' => 'array',
         'mediumInteger' => 'integer',
+        'nullableTimestamps' => 'timestamp',
         'smallInteger' => 'integer',
+        'timestamp' => 'timestamp',
+        'timestampTz' => 'timestamp',
         'tinyInteger' => 'integer',
         'unsignedBigInteger' => 'integer',
         'unsignedDecimal' => 'decimal',
@@ -90,20 +96,6 @@ class AllType extends Model
         'unsignedTinyInteger' => 'integer',
     ];
 
-    /**
-     * The attributes that should be mutated to dates.
-     *
-     * @var array
-     */
-    protected $dates = [
-        'date',
-        'dateTime',
-        'dateTimeTz',
-        'nullableTimestamps',
-        'timestamp',
-        'timestampTz',
-    ];
-
 
     public function uuid()
     {
diff --git a/tests/fixtures/models/certificate-pascal-case-example-laravel8.php b/tests/fixtures/models/certificate-pascal-case-example-laravel8.php
index e9e4668..2ff5c42 100644
--- a/tests/fixtures/models/certificate-pascal-case-example-laravel8.php
+++ b/tests/fixtures/models/certificate-pascal-case-example-laravel8.php
@@ -31,15 +31,7 @@ class Certificate extends Model
     protected $casts = [
         'id' => 'integer',
         'certificate_type_id' => 'integer',
-    ];
-
-    /**
-     * The attributes that should be mutated to dates.
-     *
-     * @var array
-     */
-    protected $dates = [
-        'expiry_date',
+        'expiry_date' => 'date',
     ];
 
 
diff --git a/tests/fixtures/models/readme-example-laravel8.php b/tests/fixtures/models/readme-example-laravel8.php
index 2bc4e29..dc07e01 100644
--- a/tests/fixtures/models/readme-example-laravel8.php
+++ b/tests/fixtures/models/readme-example-laravel8.php
@@ -28,18 +28,10 @@ class Post extends Model
      */
     protected $casts = [
         'id' => 'integer',
+        'published_at' => 'timestamp',
         'author_id' => 'integer',
     ];
 
-    /**
-     * The attributes that should be mutated to dates.
-     *
-     * @var array
-     */
-    protected $dates = [
-        'published_at',
-    ];
-
 
     public function author()
     {
diff --git a/tests/fixtures/models/readme-example-phpdoc-laravel8.php b/tests/fixtures/models/readme-example-phpdoc-laravel8.php
index 5dc2245..5c524d6 100644
--- a/tests/fixtures/models/readme-example-phpdoc-laravel8.php
+++ b/tests/fixtures/models/readme-example-phpdoc-laravel8.php
@@ -37,18 +37,10 @@ class Post extends Model
      */
     protected $casts = [
         'id' => 'integer',
+        'published_at' => 'timestamp',
         'author_id' => 'integer',
     ];
 
-    /**
-     * The attributes that should be mutated to dates.
-     *
-     * @var array
-     */
-    protected $dates = [
-        'published_at',
-    ];
-
 
     /**
      * @return \Illuminate\Database\Eloquent\Relations\BelongsTo