Repository: laravel-shift/blueprint (php)

Issue:
Custom indexes has no strings, php detects constant.
<!-- PLEASE COMPLETE THIS TEMPLATE -->

- Laravel Version: 8.x (latest)
- PHP Version: 7.4.13
- Blueprint Version: 1.19
- Platform: Mac | Windows | Linux

### Issue:
When generating custom indexes the index will be printed without `''` which causes it to fail on the migrations.

```
Schema::disableForeignKeyConstraints();
     17▕
     18▕         Schema::create('cooltable', function (Blueprint $table) {
     19▕             $table->id();
  ➜  20▕             $table->foreignId('coolcool')->constrained()->cascadeOnDelete()->index(custom_index_coolcool);
     21▕             $table->foreignId('foobar')->constrained()->cascadeOnDelete()->index(custom_index_foobar);
     22▕         });
```

### draft.yaml:
```yaml
# PLEASE PASTE THE DRAFT FILE WHICH REPRODUCES THE ISSUE HERE...
```
Draft is not required, a custom index will fail because it misses strings, therefore php detects is as a constant which is not defined. 

Pull request:
fix: sanitize modifier attributes
I used this`draft.yml` file.
```yaml
models:
   cooltable:
      coolcool: id foreign:coolcool.id index:custom_index_coolcool
      foobar: id foreign:foobars.id index:custom_index_foobar
```

reverse-engineered from the generated code on #402

```php
Schema::create('cooltable', function (Blueprint $table) {
     19▕             $table->id();
  ➜  20▕             $table->foreignId('coolcool')->constrained()->cascadeOnDelete()->index(custom_index_coolcool);
     21▕             $table->foreignId('foobar')->constrained()->cascadeOnDelete()->index(custom_index_foobar);
     22▕         });
```
Closes #402

Patch:
diff --git a/src/Generators/FactoryGenerator.php b/src/Generators/FactoryGenerator.php
index 2a6d942..6221245 100644
--- a/src/Generators/FactoryGenerator.php
+++ b/src/Generators/FactoryGenerator.php
@@ -198,11 +198,11 @@ class FactoryGenerator implements Generator
                     $definition
                 );
             } elseif (in_array($column->dataType(), ['json', 'jsonb'])) {
-                $default = $column->defaultValue() ?? "'{}'";
+                $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()) {
diff --git a/src/Generators/MigrationGenerator.php b/src/Generators/MigrationGenerator.php
index 870f4a6..ca2f6a9 100644
--- a/src/Generators/MigrationGenerator.php
+++ b/src/Generators/MigrationGenerator.php
@@ -198,7 +198,7 @@ class MigrationGenerator implements Generator
 
             foreach ($modifiers as $modifier) {
                 if (is_array($modifier)) {
-                    $column_definition .= '->'.key($modifier).'('.current($modifier).')';
+                    $column_definition .= sprintf("->%s('%s')", key($modifier), addslashes(current($modifier)));
                 } elseif ($modifier === 'unsigned' && Str::startsWith($dataType, 'unsigned')) {
                     continue;
                 } elseif ($modifier === 'nullable' && Str::startsWith($dataType, 'nullable')) {
diff --git a/src/Lexers/ModelLexer.php b/src/Lexers/ModelLexer.php
index 450e6ac..59a9290 100644
--- a/src/Lexers/ModelLexer.php
+++ b/src/Lexers/ModelLexer.php
@@ -241,10 +241,10 @@ class ModelLexer implements Lexer
 
             if (isset(self::$modifiers[strtolower($value)])) {
                 $modifierAttributes = $parts[1] ?? null;
-                if ($modifierAttributes === null) {
+                if (is_null($modifierAttributes)) {
                     $modifiers[] = self::$modifiers[strtolower($value)];
                 } else {
-                    $modifiers[] = [self::$modifiers[strtolower($value)] => $modifierAttributes];
+                    $modifiers[] = [self::$modifiers[strtolower($value)] => preg_replace('~^[\'"]?(.*?)[\'"]?$~', '$1', $modifierAttributes)];
                 }
             }
         }


Test patch:
diff --git a/tests/Feature/Generators/MigrationGeneratorTest.php b/tests/Feature/Generators/MigrationGeneratorTest.php
index 5381e38..4d5af5d 100644
--- a/tests/Feature/Generators/MigrationGeneratorTest.php
+++ b/tests/Feature/Generators/MigrationGeneratorTest.php
@@ -790,6 +790,7 @@ class MigrationGeneratorTest extends TestCase
             ['drafts/with-timezones.yaml', 'database/migrations/timestamp_create_comments_table.php', 'migrations/with-timezones.php'],
             ['drafts/relationships.yaml', 'database/migrations/timestamp_create_comments_table.php', 'migrations/relationships.php'],
             ['drafts/indexes.yaml', 'database/migrations/timestamp_create_posts_table.php', 'migrations/indexes.php'],
+            ['drafts/custom-indexes.yaml', 'database/migrations/timestamp_create_cooltables_table.php', 'migrations/custom-indexes.php'],
             ['drafts/unconventional.yaml', 'database/migrations/timestamp_create_teams_table.php', 'migrations/unconventional.php'],
             ['drafts/optimize.yaml', 'database/migrations/timestamp_create_optimizes_table.php', 'migrations/optimize.php'],
             ['drafts/model-key-constraints.yaml', 'database/migrations/timestamp_create_orders_table.php', 'migrations/model-key-constraints.php'],
diff --git a/tests/Feature/Lexers/ModelLexerTest.php b/tests/Feature/Lexers/ModelLexerTest.php
index da3e30f..ed34f84 100644
--- a/tests/Feature/Lexers/ModelLexerTest.php
+++ b/tests/Feature/Lexers/ModelLexerTest.php
@@ -664,11 +664,12 @@ class ModelLexerTest extends TestCase
             ['default:0.00', 'default', 0.00],
             ['default:0', 'default', 0],
             ['default:string', 'default', 'string'],
-            ["default:'empty'", 'default', "'empty'"],
-            ['default:""', 'default', '""'],
+            ["default:'empty'", 'default', 'empty'],
+            ['default:""', 'default', ''],
             ['charset:utf8', 'charset', 'utf8'],
             ['collation:utf8_unicode', 'collation', 'utf8_unicode'],
-            ['default:"space between"', 'default', '"space between"'],
+            ['default:"space between"', 'default', 'space between'],
+            ["default:'[]'", 'default', '[]'],
         ];
     }
 }
diff --git a/tests/fixtures/drafts/custom-indexes.yaml b/tests/fixtures/drafts/custom-indexes.yaml
new file mode 100644
index 0000000..deaa579
--- /dev/null
+++ b/tests/fixtures/drafts/custom-indexes.yaml
@@ -0,0 +1,5 @@
+models:
+  cooltable:
+    timestamps: false
+    coolcool: id foreign:coolcool.id index:custom_index_coolcool
+    foobar: id foreign:foobars.id index:custom_index_foobar
diff --git a/tests/fixtures/migrations/columns-with-comments.php b/tests/fixtures/migrations/columns-with-comments.php
index 647c4b0..9249ff1 100644
--- a/tests/fixtures/migrations/columns-with-comments.php
+++ b/tests/fixtures/migrations/columns-with-comments.php
@@ -15,7 +15,7 @@ class CreateProfessionsTable extends Migration
     {
         Schema::create('professions', function (Blueprint $table) {
             $table->id();
-            $table->string('title', 400)->comment("Some title for the profession");
+            $table->string('title', 400)->comment('Some title for the profession');
             $table->string('description', 400)->nullable()->comment('Some description for the profession');
             $table->timestamps();
         });
diff --git a/tests/fixtures/migrations/custom-indexes.php b/tests/fixtures/migrations/custom-indexes.php
new file mode 100644
index 0000000..a1f4258
--- /dev/null
+++ b/tests/fixtures/migrations/custom-indexes.php
@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateCooltablesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::disableForeignKeyConstraints();
+
+        Schema::create('cooltables', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('coolcool')->constrained('coolcool')->cascadeOnDelete()->index('custom_index_coolcool');
+            $table->foreignId('foobar')->constrained('foobars')->cascadeOnDelete()->index('custom_index_foobar');
+        });
+
+        Schema::enableForeignKeyConstraints();
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('cooltables');
+    }
+}